]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/camera/dialogs.cpp
GTK: wrap gtk_table_attach
[xonotic/netradiant.git] / contrib / camera / dialogs.cpp
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 /*
23    Camera plugin for GtkRadiant
24    Copyright (C) 2002 Splash Damage Ltd.
25  */
26
27 #include "camera.h"
28
29 static GSList *g_pEditTypeRadio = NULL;
30 static GtkWidget *g_pEditModeEditRadioButton = NULL;
31 GtkWidget *g_pEditModeAddRadioButton = NULL;
32 static GtkWidget *g_pSecondsEntry = NULL;
33 static GtkWidget *g_pEventsList = NULL;
34 static GtkLabel *g_pCurrentTime = NULL;
35 static GtkLabel *g_pTotalTime = NULL;
36 static GtkAdjustment *g_pTimeLine = NULL;
37 static GtkWidget *g_pTrackCamera = NULL;
38 static GtkWidget *g_pCamName = NULL;
39 static char *g_cNull = '\0';
40
41 static gint ci_editmode_edit( GtkWidget *widget, gpointer data ){
42         g_iEditMode = 0;
43
44         return TRUE;
45 }
46
47 static gint ci_editmode_add( GtkWidget *widget, gpointer data ){
48         g_iEditMode = 1;
49
50         return TRUE;
51 }
52
53 /*static gint ci_delete_selected( GtkWidget *widget, gpointer data )
54    {
55    return TRUE;
56    }
57
58    static gint ci_select_all( GtkWidget *widget, gpointer data )
59    {
60    return TRUE;
61    }*/
62
63 static gint ci_new( GtkWidget *widget, gpointer data ){
64         GtkWidget *w, *hbox; //, *name;
65         GtkWidget *fixed, *interpolated, *spline;
66         EMessageBoxReturn ret;
67         int loop = 1;
68         GSList *targetTypeRadio = NULL;
69 //      char buf[128];
70
71         // create the window
72         auto window = ui::Window( ui::window_type::TOP );
73         gtk_window_set_title( window, "New Camera" );
74         window.connect( "delete_event", G_CALLBACK( dialog_delete_callback ), NULL );
75         window.connect( "destroy", G_CALLBACK( gtk_widget_destroy ), NULL );
76         gtk_window_set_transient_for( window, g_pCameraInspectorWnd );
77
78         g_object_set_data( G_OBJECT( window ), "loop", &loop );
79         g_object_set_data( G_OBJECT( window ), "ret", &ret );
80
81         gtk_widget_realize( window );
82
83         // fill the window
84         auto vbox = ui::VBox( FALSE, 5 );
85         window.add(vbox);
86         vbox.show();
87
88         // -------------------------- //
89
90         hbox = ui::HBox( FALSE, 5 );
91         vbox.pack_start( hbox, FALSE, FALSE, 0 );
92         hbox.show();
93
94         auto frame = ui::Frame( "Type" );
95         hbox.pack_start( frame, TRUE, TRUE, 0 );
96         frame.show();
97
98         auto vbox2 = ui::VBox( FALSE, 5 );
99         frame.add(vbox2);
100         gtk_container_set_border_width( GTK_CONTAINER( vbox2 ), 5 );
101         vbox2.show();
102
103         // -------------------------- //
104
105         fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" );
106         vbox2.pack_start( fixed, FALSE, FALSE, 3 );
107         fixed.show();
108         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( fixed ) );
109
110         interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" );
111         vbox2.pack_start( interpolated, FALSE, FALSE, 3 );
112         interpolated.show();
113         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( interpolated ) );
114
115         spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" );
116         vbox2.pack_start( spline, FALSE, FALSE, 3 );
117         spline.show();
118         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( spline ) );
119
120         // -------------------------- //
121
122         w = gtk_hseparator_new();
123         vbox.pack_start( w, FALSE, FALSE, 2 );
124         w.show();
125
126         // -------------------------- //
127
128         hbox = ui::HBox( FALSE, 5 );
129         vbox.pack_start( hbox, FALSE, FALSE, 0 );
130         hbox.show();
131
132         w = ui::Button( "Ok" );
133         hbox.pack_start( w, TRUE, TRUE, 0 );
134         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDOK ) );
135         w.show();
136
137         gtk_widget_set_can_default( w, true );
138         gtk_widget_grab_default( w );
139
140         w = ui::Button( "Cancel" );
141         hbox.pack_start( w, TRUE, TRUE, 0 );
142         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDCANCEL ) );
143         w.show();
144         ret = eIDCANCEL;
145
146         // -------------------------- //
147
148         gtk_window_set_position( window, GTK_WIN_POS_CENTER );
149         window.show();
150         gtk_grab_add( window );
151
152         bool dialogError = TRUE;
153         while ( dialogError ) {
154                 loop = 1;
155                 while ( loop )
156                         gtk_main_iteration();
157
158                 dialogError = FALSE;
159
160                 if ( ret == eIDOK ) {
161                         if ( gtk_toggle_button_get_active( (GtkToggleButton*)fixed ) ) {
162                                 DoNewFixedCamera();
163                         }
164                         else if ( gtk_toggle_button_get_active( (GtkToggleButton*)interpolated ) ) {
165                                 DoNewInterpolatedCamera();
166                         }
167                         else if ( gtk_toggle_button_get_active( (GtkToggleButton*)spline ) ) {
168                                 DoNewSplineCamera();
169                         }
170                 }
171         }
172
173         gtk_grab_remove( window );
174         window.destroy();
175
176         return TRUE;
177 }
178
179 static gint ci_load( GtkWidget *widget, gpointer data ){
180         DoLoadCamera();
181
182         return TRUE;
183 }
184
185 static gint ci_save( GtkWidget *widget, gpointer data ){
186         DoSaveCamera();
187
188         return TRUE;
189 }
190
191 static gint ci_unload( GtkWidget *widget, gpointer data ){
192         DoUnloadCamera();
193
194         return TRUE;
195 }
196
197 static gint ci_apply( GtkWidget *widget, gpointer data ){
198         if ( GetCurrentCam() ) {
199                 const char *str;
200                 char buf[128];
201                 bool build = false;
202
203                 str = gtk_entry_get_text( GTK_ENTRY( g_pCamName ) );
204
205                 if ( str ) {
206                         GetCurrentCam()->GetCam()->setName( str );
207                         build = true;
208                 }
209
210                 str = gtk_entry_get_text( GTK_ENTRY( g_pSecondsEntry ) );
211
212                 if ( str ) {
213                         GetCurrentCam()->GetCam()->setBaseTime( atof( str ) );
214                         build = true;
215                 }
216
217                 if ( build ) {
218                         GetCurrentCam()->GetCam()->buildCamera();
219                 }
220
221                 sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getBaseTime() );
222                 gtk_entry_set_text( GTK_ENTRY( g_pSecondsEntry ), buf );
223
224                 sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() );
225                 gtk_label_set_text( g_pCurrentTime, "0.00" );
226                 gtk_label_set_text( g_pTotalTime, buf );
227
228                 gtk_adjustment_set_value( g_pTimeLine, 0.f );
229                 g_pTimeLine->upper = GetCurrentCam()->GetCam()->getTotalTime() * 1000;
230
231                 GetCurrentCam()->HasBeenModified();
232         }
233
234         return TRUE;
235 }
236
237 static gint ci_preview( GtkWidget *widget, gpointer data ){
238         if ( GetCurrentCam() ) {
239                 g_iPreviewRunning = 1;
240                 g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA );
241         }
242
243         return TRUE;
244 }
245
246 static gint ci_expose( GtkWidget *widget, gpointer data ){
247         // start edit mode
248         DoStartEdit( GetCurrentCam() );
249
250         return FALSE;
251 }
252
253 static gint ci_close( GtkWidget *widget, gpointer data ){
254         gtk_widget_hide( g_pCameraInspectorWnd );
255
256         // exit edit mode
257         DoStopEdit();
258
259         return TRUE;
260 }
261
262 static GtkWidget *g_pPathListCombo = NULL;
263 static GtkLabel *g_pPathType = NULL;
264
265 static void RefreshPathListCombo( void ){
266         if ( !g_pPathListCombo ) {
267                 return;
268         }
269
270         GList *combo_list = (GList*)NULL;
271
272         if ( GetCurrentCam() ) {
273                 combo_list = g_list_append( combo_list, (void *)GetCurrentCam()->GetCam()->getPositionObj()->getName() );
274                 for ( int i = 0; i < GetCurrentCam()->GetCam()->numTargets(); i++ ) {
275                         combo_list = g_list_append( combo_list, (void *)GetCurrentCam()->GetCam()->getActiveTarget( i )->getName() );
276                 }
277         }
278         else {
279                 // add one empty string make gtk be quiet
280                 combo_list = g_list_append( combo_list, (gpointer)g_cNull );
281         }
282
283         gtk_combo_set_popdown_strings( GTK_COMBO( g_pPathListCombo ), combo_list );
284         g_list_free( combo_list );
285 }
286
287 static gint ci_pathlist_changed( GtkWidget *widget, gpointer data ){
288         const char *str = gtk_entry_get_text( GTK_ENTRY( widget ) );
289
290         if ( !str || !GetCurrentCam() ) {
291                 return TRUE;
292         }
293
294         int i;
295         for ( i = 0; i < GetCurrentCam()->GetCam()->numTargets(); i++ ) {
296                 if ( !strcmp( str, GetCurrentCam()->GetCam()->getActiveTarget( i )->getName() ) ) {
297                         break;
298                 }
299         }
300
301         if ( i >= 0 && i < GetCurrentCam()->GetCam()->numTargets() ) {
302                 GetCurrentCam()->GetCam()->setActiveTarget( i );
303
304                 g_iActiveTarget = i;
305                 if ( g_pPathType ) {
306                         gtk_label_set_text( g_pPathType, GetCurrentCam()->GetCam()->getActiveTarget( g_iActiveTarget )->typeStr() );
307                 }
308         }
309         else {
310                 g_iActiveTarget = -1;
311                 if ( g_pPathType ) {
312                         gtk_label_set_text( g_pPathType, GetCurrentCam()->GetCam()->getPositionObj()->typeStr() );
313                 }
314         }
315
316         // start edit mode
317         if ( g_pCameraInspectorWnd && gtk_widget_get_visible( g_pCameraInspectorWnd ) ) {
318                 DoStartEdit( GetCurrentCam() );
319         }
320
321         return TRUE;
322 }
323
324 static void RefreshEventList( void ){
325         int i;
326         char buf[128];
327
328         // Clear events list
329         gtk_clist_freeze( GTK_CLIST( g_pEventsList ) );
330         gtk_clist_clear( GTK_CLIST( g_pEventsList ) );
331
332         if ( GetCurrentCam() ) {
333                 // Fill events list
334                 for ( i = 0; i < GetCurrentCam()->GetCam()->numEvents(); i++ ) {
335                         char rowbuf[3][128], *row[3];
336                         // FIXME: sort by time?
337                         sprintf( rowbuf[0], "%li", GetCurrentCam()->GetCam()->getEvent( i )->getTime() );                 row[0] = rowbuf[0];
338                         strncpy( rowbuf[1], GetCurrentCam()->GetCam()->getEvent( i )->typeStr(), sizeof( rowbuf[0] ) );     row[1] = rowbuf[1];
339                         strncpy( rowbuf[2], GetCurrentCam()->GetCam()->getEvent( i )->getParam(), sizeof( rowbuf[1] ) );    row[2] = rowbuf[2];
340                         gtk_clist_append( GTK_CLIST( g_pEventsList ), row );
341                 }
342
343                 // Total duration might have changed
344                 sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() );
345                 gtk_label_set_text( g_pCurrentTime, "0.00" );
346                 gtk_label_set_text( g_pTotalTime, buf );
347
348                 gtk_adjustment_set_value( g_pTimeLine, 0.f );
349                 g_pTimeLine->upper = ( GetCurrentCam()->GetCam()->getTotalTime() * 1000 );
350         }
351
352         gtk_clist_thaw( GTK_CLIST( g_pEventsList ) );
353 }
354
355 static gint ci_rename( GtkWidget *widget, gpointer data ){
356         GtkWidget *w, *hbox, *name;
357         EMessageBoxReturn ret;
358         int loop = 1;
359
360         if ( !GetCurrentCam() ) {
361                 return TRUE;
362         }
363
364         // create the window
365         auto window = ui::Window( ui::window_type::TOP );
366         gtk_window_set_title( window, "Rename Path" );
367         window.connect( "delete_event", G_CALLBACK( dialog_delete_callback ), NULL );
368         window.connect( "destroy", G_CALLBACK( gtk_widget_destroy ), NULL );
369         gtk_window_set_transient_for( window, g_pCameraInspectorWnd );
370
371         g_object_set_data( G_OBJECT( window ), "loop", &loop );
372         g_object_set_data( G_OBJECT( window ), "ret", &ret );
373
374         gtk_widget_realize( window );
375
376         // fill the window
377         auto vbox = ui::VBox( FALSE, 5 );
378         window.add(vbox);
379         vbox.show();
380
381         // -------------------------- //
382
383         hbox = ui::HBox( FALSE, 5 );
384         vbox.pack_start( hbox, FALSE, FALSE, 0 );
385         hbox.show();
386
387         w = ui::Label( "Name:" );
388         hbox.pack_start( w, FALSE, FALSE, 0 );
389         w.show();
390
391         name = ui::Entry();
392         hbox.pack_start( name, FALSE, FALSE, 0 );
393         name.show();
394
395         if ( g_iActiveTarget < 0 ) {
396                 gtk_entry_set_text( GTK_ENTRY( name ), GetCurrentCam()->GetCam()->getPositionObj()->getName() );
397         }
398         else{
399                 gtk_entry_set_text( GTK_ENTRY( name ), GetCurrentCam()->GetCam()->getActiveTarget( g_iActiveTarget )->getName() );
400         }
401
402         // -------------------------- //
403
404         w = gtk_hseparator_new();
405         vbox.pack_start( w, FALSE, FALSE, 2 );
406         w.show();
407
408         // -------------------------- //
409
410         hbox = ui::HBox( FALSE, 5 );
411         vbox.pack_start( hbox, FALSE, FALSE, 0 );
412         hbox.show();
413
414         w = ui::Button( "Ok" );
415         hbox.pack_start( w, TRUE, TRUE, 0 );
416         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDOK ) );
417         w.show();
418
419         gtk_widget_set_can_default( w, true );
420         gtk_widget_grab_default( w );
421
422         w = ui::Button( "Cancel" );
423         hbox.pack_start( w, TRUE, TRUE, 0 );
424         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDCANCEL ) );
425         w.show();
426         ret = eIDCANCEL;
427
428         // -------------------------- //
429
430         gtk_window_set_position( window, GTK_WIN_POS_CENTER );
431         window.show();
432         gtk_grab_add( window );
433
434         bool dialogError = TRUE;
435         while ( dialogError ) {
436                 loop = 1;
437                 while ( loop )
438                         gtk_main_iteration();
439
440                 dialogError = FALSE;
441
442                 if ( ret == eIDOK ) {
443                         const char *str = gtk_entry_get_text( GTK_ENTRY( name ) );
444
445                         if ( str && str[0] ) {
446                                 // Update the path
447                                 if ( g_iActiveTarget < 0 ) {
448                                         GetCurrentCam()->GetCam()->getPositionObj()->setName( str );
449                                 }
450                                 else{
451                                         GetCurrentCam()->GetCam()->getActiveTarget( g_iActiveTarget )->setName( str );
452                                 }
453
454                                 GetCurrentCam()->GetCam()->buildCamera();
455
456                                 // Rebuild the listbox
457                                 RefreshPathListCombo();
458                         }
459                         else {
460                                 dialogError = TRUE;
461                         }
462                 }
463         }
464
465         gtk_grab_remove( window );
466         window.destroy();
467
468         return TRUE;
469 }
470
471 static gint ci_add_target( GtkWidget *widget, gpointer data ){
472         GtkWidget *w, *hbox, *name;
473         GtkWidget *fixed, *interpolated, *spline;
474         EMessageBoxReturn ret;
475         int loop = 1;
476         GSList *targetTypeRadio = NULL;
477         char buf[128];
478
479         if ( !GetCurrentCam() ) {
480                 return TRUE;
481         }
482
483         // create the window
484         auto window = ui::Window( ui::window_type::TOP );
485         gtk_window_set_title( window, "Add Target" );
486         window.connect( "delete_event", G_CALLBACK( dialog_delete_callback ), NULL );
487         window.connect( "destroy", G_CALLBACK( gtk_widget_destroy ), NULL );
488         gtk_window_set_transient_for( window, g_pCameraInspectorWnd );
489
490         g_object_set_data( G_OBJECT( window ), "loop", &loop );
491         g_object_set_data( G_OBJECT( window ), "ret", &ret );
492
493         gtk_widget_realize( window );
494
495         // fill the window
496         auto vbox = ui::VBox( FALSE, 5 );
497         window.add(vbox);
498         vbox.show();
499
500         // -------------------------- //
501
502         hbox = ui::HBox( FALSE, 5 );
503         vbox.pack_start( hbox, FALSE, FALSE, 0 );
504         hbox.show();
505
506         w = ui::Label( "Name:" );
507         hbox.pack_start( w, FALSE, FALSE, 0 );
508         w.show();
509
510         name = ui::Entry();
511         hbox.pack_start( name, TRUE, TRUE, 0 );
512         name.show();
513
514         sprintf( buf, "target%i", GetCurrentCam()->GetCam()->numTargets() + 1 );
515         gtk_entry_set_text( GTK_ENTRY( name ), buf );
516
517         // -------------------------- //
518
519         hbox = ui::HBox( FALSE, 5 );
520         vbox.pack_start( hbox, FALSE, FALSE, 0 );
521         hbox.show();
522
523         auto frame = ui::Frame( "Type" );
524         hbox.pack_start( frame, TRUE, TRUE, 0 );
525         frame.show();
526
527         auto vbox2 = ui::VBox( FALSE, 5 );
528         frame.add(vbox2);
529         gtk_container_set_border_width( GTK_CONTAINER( vbox2 ), 5 );
530         vbox2.show();
531
532         // -------------------------- //
533
534         fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" );
535         vbox2.pack_start( fixed, FALSE, FALSE, 3 );
536         fixed.show();
537         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( fixed ) );
538
539         interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" );
540         vbox2.pack_start( interpolated, FALSE, FALSE, 3 );
541         interpolated.show();
542         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( interpolated ) );
543
544         spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" );
545         vbox2.pack_start( spline, FALSE, FALSE, 3 );
546         spline.show();
547         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( spline ) );
548
549         // -------------------------- //
550
551         w = gtk_hseparator_new();
552         vbox.pack_start( w, FALSE, FALSE, 2 );
553         w.show();
554
555         // -------------------------- //
556
557         hbox = ui::HBox( FALSE, 5 );
558         vbox.pack_start( hbox, FALSE, FALSE, 0 );
559         hbox.show();
560
561         w = ui::Button( "Ok" );
562         hbox.pack_start( w, TRUE, TRUE, 0 );
563         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDOK ) );
564         w.show();
565
566         gtk_widget_set_can_default( w, true );
567         gtk_widget_grab_default( w );
568
569         w = ui::Button( "Cancel" );
570         hbox.pack_start( w, TRUE, TRUE, 0 );
571         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDCANCEL ) );
572         w.show();
573         ret = eIDCANCEL;
574
575         // -------------------------- //
576
577         gtk_window_set_position( window, GTK_WIN_POS_CENTER );
578         window.show();
579         gtk_grab_add( window );
580
581         bool dialogError = TRUE;
582         while ( dialogError ) {
583                 loop = 1;
584                 while ( loop )
585                         gtk_main_iteration();
586
587                 dialogError = FALSE;
588
589                 if ( ret == eIDOK ) {
590                         const char *str = gtk_entry_get_text( GTK_ENTRY( name ) );
591
592                         if ( str && str[0] ) {
593                                 int type;
594                                 GList *li;
595
596                                 if ( gtk_toggle_button_get_active( (GtkToggleButton*)fixed ) ) {
597                                         type = 0;
598                                 }
599                                 else if ( gtk_toggle_button_get_active( (GtkToggleButton*)interpolated ) ) {
600                                         type = 1;
601                                 }
602                                 else if ( gtk_toggle_button_get_active( (GtkToggleButton*)spline ) ) {
603                                         type = 2;
604                                 }
605
606                                 // Add the target
607                                 GetCurrentCam()->GetCam()->addTarget( str, static_cast<idCameraPosition::positionType>( type ) );
608
609                                 // Rebuild the listbox
610                                 RefreshPathListCombo();
611
612                                 // Select the last item in the listbox
613                                 li = g_list_last( GTK_LIST( GTK_COMBO( g_pPathListCombo )->list )->children );
614                                 gtk_list_select_child( GTK_LIST( GTK_COMBO( g_pPathListCombo )->list ), li->data  );
615
616                                 // If this was the first one, refresh the event list
617                                 if ( GetCurrentCam()->GetCam()->numTargets() == 1 ) {
618                                         RefreshEventList();
619                                 }
620
621                                 // Go to editmode Add
622                                 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( g_pEditModeAddRadioButton ), TRUE );
623
624                         }
625                         else {
626                                 dialogError = TRUE;
627                         }
628                 }
629         }
630
631         gtk_grab_remove( window );
632         window.destroy();
633
634         return TRUE;
635 }
636
637 static GtkWidget *g_pCamListCombo = NULL;
638 static GtkLabel *g_pCamType = NULL;
639
640 void RefreshCamListCombo( void ){
641         if ( !g_pCamListCombo ) {
642                 return;
643         }
644
645         GList *combo_list = (GList*)NULL;
646         CCamera *combo_cam = firstCam;
647         if ( combo_cam ) {
648                 while ( combo_cam ) {
649                         //combo_list = g_list_append( combo_list, (void *)combo_cam->GetCam()->getName() );
650                         //if( combo_cam->HasBeenSaved() ) {
651                         combo_list = g_list_append( combo_list, (void *)combo_cam->GetFileName() );
652                         /*} else {
653                             char buf[128];
654                             sprintf( buf, "Unsaved Camera %i", combo_cam->GetCamNum() );
655                             combo_list = g_list_append( combo_list, (void *)buf );
656
657                             //combo_list = g_list_append( combo_list, (void *)combo_cam->GetCam()->getName() ); // FIXME: this requires camera.dll to create unique names for new cams
658                            }*/
659                         combo_cam = combo_cam->GetNext();
660                 }
661         }
662         else {
663                 // add one empty string make gtk be quiet
664                 combo_list = g_list_append( combo_list, (gpointer)g_cNull );
665         }
666         gtk_combo_set_popdown_strings( GTK_COMBO( g_pCamListCombo ), combo_list );
667         g_list_free( combo_list );
668
669         // select our current entry in the list
670         if ( GetCurrentCam() ) {
671                 // stop editing on the current cam
672                 //GetCurrentCam()->GetCam()->stopEdit();        // FIXME: this crashed on creating new cameras, why is it here?
673
674                 GList *li = GTK_LIST( GTK_COMBO( g_pCamListCombo )->list )->children;
675                 combo_cam = firstCam;
676                 while ( li && combo_cam ) {
677                         if ( combo_cam == GetCurrentCam() ) {
678                                 gtk_list_select_child( GTK_LIST( GTK_COMBO( g_pCamListCombo )->list ), li->data  );
679                                 break;
680                         }
681                         li = li->next;
682                         combo_cam = combo_cam->GetNext();
683                 }
684         }
685
686         RefreshPathListCombo();
687 }
688
689 static gint ci_camlist_changed( GtkWidget *widget, gpointer data ){
690         const char *str = gtk_entry_get_text( GTK_ENTRY( widget ) );
691
692         CCamera *combo_cam = firstCam;
693         while ( str && combo_cam ) {
694                 //if( !strcmp( str, combo_cam->GetCam()->getName() ) )
695                 //if( combo_cam->HasBeenSaved() ) {
696                 if ( !strcmp( str, combo_cam->GetFileName() ) ) {
697                         break;
698                 }
699                 /*} else {
700                     char buf[128];
701                     sprintf( buf, "Unsaved Camera %i", combo_cam->GetCamNum() );
702                     if( !strcmp( str, buf ) )
703                     //if( !strcmp( str, combo_cam->GetCam()->getName() ) )
704                         break;
705                    }*/
706
707                 combo_cam = combo_cam->GetNext();
708         }
709
710         SetCurrentCam( combo_cam );
711
712         if ( g_pCamType ) {
713                 if ( GetCurrentCam() ) {
714                         // Fill in our widgets fields for this camera
715                         char buf[128];
716
717                         // Set Name
718                         gtk_entry_set_text( GTK_ENTRY( g_pCamName ), GetCurrentCam()->GetCam()->getName() );
719
720                         // Set type
721                         gtk_label_set_text( g_pCamType, GetCurrentCam()->GetCam()->getPositionObj()->typeStr() );
722
723                         // Set duration
724                         sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getBaseTime() );
725                         gtk_entry_set_text( GTK_ENTRY( g_pSecondsEntry ), buf );
726
727                         sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() );
728                         gtk_label_set_text( g_pCurrentTime, "0.00" );
729                         gtk_label_set_text( g_pTotalTime, buf );
730
731                         gtk_adjustment_set_value( g_pTimeLine, 0.f );
732                         g_pTimeLine->upper = GetCurrentCam()->GetCam()->getTotalTime() * 1000;
733                 }
734                 else {
735                         // Set Name
736                         gtk_entry_set_text( GTK_ENTRY( g_pCamName ), "" );
737
738                         // Set type
739                         gtk_label_set_text( g_pCamType, "" );
740
741                         // Set duration
742                         gtk_entry_set_text( GTK_ENTRY( g_pSecondsEntry ), "30.00" );
743
744                         gtk_label_set_text( g_pCurrentTime, "0.00" );
745                         gtk_label_set_text( g_pTotalTime, "30.00" );
746
747                         gtk_adjustment_set_value( g_pTimeLine, 0.f );
748                         g_pTimeLine->upper = 30000;
749                 }
750
751                 // Refresh event list
752                 RefreshEventList();
753         }
754
755         RefreshPathListCombo();
756
757         // start edit mode
758         g_iActiveTarget = -1;
759         if ( g_pCameraInspectorWnd && gtk_widget_get_visible( g_pCameraInspectorWnd ) ) {
760                 DoStartEdit( GetCurrentCam() );
761         }
762
763         return TRUE;
764 }
765
766 enum camEventType {
767         EVENT_NA = 0x00,
768         EVENT_WAIT,             //
769         EVENT_TARGETWAIT,   //
770         EVENT_SPEED,            //
771         EVENT_TARGET,           // char(name)
772         EVENT_SNAPTARGET,   //
773         EVENT_FOV,              // int(time), int(targetfov)
774         EVENT_CMD,              //
775         EVENT_TRIGGER,      //
776         EVENT_STOP,             //
777         EVENT_CAMERA,           //
778         EVENT_FADEOUT,      // int(time)
779         EVENT_FADEIN,           // int(time)
780         EVENT_FEATHER,      //
781         EVENT_COUNT
782 };
783
784 // { requires parameters, enabled }
785 const bool camEventFlags[][2] = {
786         { false, false },
787         { false, true },
788         { false, false },
789         { false, false },
790         { true, true },
791         { false, false },
792         { true, true },
793         { false, false },
794         { false, false },
795         { false, true },
796         { true, true },
797         { true, true },
798         { true, true },
799         { false, true },
800 };
801
802 const char *camEventStr[] = {
803         "n/a",
804         "Wait",
805         "Target wait",
806         "Speed",
807         "Change Target <string:name>",
808         "Snap Target",
809         "FOV <int:duration> <int:targetfov>",
810         "Run Script",
811         "Trigger",
812         "Stop",
813         "Change to Camera <string:camera> (or <int:cameranum> <string:camera>",
814         "Fade Out <int:duration>",
815         "Fade In <int:duration>",
816         "Feather"
817 };
818
819 static gint ci_add( GtkWidget *widget, gpointer data ){
820         GtkWidget *w, *hbox, *parameters;
821         GtkWidget *eventWidget[EVENT_COUNT];
822         EMessageBoxReturn ret;
823         int i, loop = 1;
824         GSList *eventTypeRadio = NULL;
825 //      char buf[128];
826
827         if ( !GetCurrentCam() ) {
828                 return TRUE;
829         }
830
831         // create the window
832         auto window = ui::Window( ui::window_type::TOP );
833         gtk_window_set_title( window, "Add Event" );
834         window.connect( "delete_event", G_CALLBACK( dialog_delete_callback ), NULL );
835         window.connect( "destroy", G_CALLBACK( gtk_widget_destroy ), NULL );
836         gtk_window_set_transient_for( window, g_pCameraInspectorWnd );
837
838         g_object_set_data( G_OBJECT( window ), "loop", &loop );
839         g_object_set_data( G_OBJECT( window ), "ret", &ret );
840
841         gtk_widget_realize( window );
842
843         // fill the window
844         auto vbox = ui::VBox( FALSE, 5 );
845         window.add(vbox);
846         vbox.show();
847
848         // -------------------------- //
849
850         hbox = ui::HBox( FALSE, 5 );
851         vbox.pack_start( hbox, FALSE, FALSE, 0 );
852         hbox.show();
853
854         auto frame = ui::Frame( "Type" );
855         hbox.pack_start( frame, TRUE, TRUE, 0 );
856         frame.show();
857
858         auto vbox2 = ui::VBox( FALSE, 5 );
859         frame.add(vbox2);
860         gtk_container_set_border_width( GTK_CONTAINER( vbox2 ), 5 );
861         vbox2.show();
862
863         // -------------------------- //
864
865         for ( i = 1; i < EVENT_COUNT; i++ ) {
866                 eventWidget[i] = gtk_radio_button_new_with_label( eventTypeRadio, camEventStr[i] );
867                 vbox2.pack_start( eventWidget[i], FALSE, FALSE, 3 );
868                 eventWidget[i].show();
869                 eventTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( eventWidget[i] ) );
870                 if ( camEventFlags[i][1] == false ) {
871                         gtk_widget_set_sensitive( eventWidget[i], FALSE );
872                 }
873         }
874
875         // -------------------------- //
876
877         hbox = ui::HBox( FALSE, 5 );
878         vbox.pack_start( hbox, FALSE, FALSE, 0 );
879         hbox.show();
880
881         w = ui::Label( "Parameters:" );
882         hbox.pack_start( w, FALSE, FALSE, 0 );
883         w.show();
884
885         parameters = ui::Entry();
886         hbox.pack_start( parameters, TRUE, TRUE, 0 );
887         parameters.show();
888
889         // -------------------------- //
890
891         w = gtk_hseparator_new();
892         vbox.pack_start( w, FALSE, FALSE, 2 );
893         w.show();
894
895         // -------------------------- //
896
897         hbox = ui::HBox( FALSE, 5 );
898         vbox.pack_start( hbox, FALSE, FALSE, 0 );
899         hbox.show();
900
901         w = ui::Button( "Ok" );
902         hbox.pack_start( w, TRUE, TRUE, 0 );
903         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDOK ) );
904         w.show();
905
906         gtk_widget_set_can_default( w, true );
907         gtk_widget_grab_default( w );
908
909         w = ui::Button( "Cancel" );
910         hbox.pack_start( w, TRUE, TRUE, 0 );
911         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDCANCEL ) );
912         w.show();
913         ret = eIDCANCEL;
914
915         // -------------------------- //
916
917         gtk_window_set_position( window, GTK_WIN_POS_CENTER );
918         window.show();
919         gtk_grab_add( window );
920
921         bool dialogError = TRUE;
922         while ( dialogError ) {
923                 loop = 1;
924                 while ( loop )
925                         gtk_main_iteration();
926
927                 dialogError = FALSE;
928
929                 if ( ret == eIDOK ) {
930                         const char *str = gtk_entry_get_text( GTK_ENTRY( parameters ) );
931
932                         if ( !camEventFlags[i][0] || ( str && str[0] ) ) {
933                                 int type = 0;
934 //                              GList *li;
935
936                                 for ( type = 1; type < EVENT_COUNT; type++ ) {
937                                         if ( gtk_toggle_button_get_active( (GtkToggleButton*)eventWidget[type] ) ) {
938                                                 break;
939                                         }
940                                 }
941
942                                 // Add the event
943                                 GetCurrentCam()->GetCam()->addEvent( static_cast<idCameraEvent::eventType>( type ), str, (long)( g_pTimeLine->value ) );
944
945                                 // Refresh event list
946                                 RefreshEventList();
947                         }
948                         else {
949                                 dialogError = TRUE;
950                         }
951                 }
952         }
953
954         gtk_grab_remove( window );
955         window.destroy();
956
957         return TRUE;
958 }
959
960 static gint ci_del( GtkWidget *widget, gpointer data ){
961         // TODO: add support to splines lib
962         if ( GetCurrentCam() && GTK_CLIST( g_pEventsList )->focus_row >= 0 ) {
963                 GetCurrentCam()->GetCam()->removeEvent( GTK_CLIST( g_pEventsList )->focus_row );
964                 // Refresh event list
965                 RefreshEventList();
966         }
967
968         return TRUE;
969 }
970
971 static gint ci_timeline_changed( GtkAdjustment *adjustment ){
972         char buf[128];
973
974         sprintf( buf, "%.2f", adjustment->value / 1000.f );
975         gtk_label_set_text( g_pCurrentTime, buf );
976
977         // FIXME: this will never work completely perfect. Startcamera calls buildcamera, which sets all events to 'nottriggered'.
978         // So if you have a wait at the end of the path, this will go to nontriggered immediately when you go over it and the camera
979         // will have no idea where on the track it should be.
980         if ( GetCurrentCam() && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_pTrackCamera ) ) ) {
981                 float fov;
982                 vec3_t origin = { 0.0f, 0.0f, 0.0f }, dir = { 0.0f, 0.0f, 0.0f}, angles;
983
984                 GetCurrentCam()->GetCam()->startCamera( 0 );
985
986                 GetCurrentCam()->GetCam()->getCameraInfo( (long)( adjustment->value ), &origin[0], &dir[0], &fov );
987                 VectorSet( angles, asin( dir[2] ) * 180 / 3.14159, atan2( dir[1], dir[0] ) * 180 / 3.14159, 0 );
988                 g_CameraTable.m_pfnSetCamera( origin, angles );
989         }
990
991         return TRUE;
992 }
993
994 GtkWidget *CreateCameraInspectorDialog( void ){
995         GtkWidget *w, *hbox;
996
997         // create the window
998         auto window = ui::Window( ui::window_type::TOP );
999         gtk_window_set_title( window, "Camera Inspector" );
1000         window.connect( "delete_event", G_CALLBACK( ci_close ), NULL );
1001         window.connect( "expose_event", G_CALLBACK( ci_expose ), NULL );
1002         //  window.connect( "destroy", G_CALLBACK( gtk_widget_destroy ), NULL );
1003         gtk_window_set_transient_for( window, g_pRadiantWnd );
1004
1005         // don't use show, as you don't want to have it displayed on startup ;-)
1006         gtk_widget_realize( window );
1007
1008         // fill the window
1009
1010         // the table
1011         // -------------------------- //
1012
1013         auto table = ui::Table( 3, 2, FALSE );
1014         table.show();
1015         window.add(table);
1016         gtk_container_set_border_width( GTK_CONTAINER( table ), 5 );
1017     gtk_table_set_row_spacings(table, 5);
1018     gtk_table_set_col_spacings(table, 5);
1019
1020         // the properties column
1021         // -------------------------- //
1022
1023         vbox = ui::VBox( FALSE, 5 );
1024         vbox.show();
1025         table.attach(vbox, {0, 1, 0, 1}, {GTK_EXPAND | GTK_FILL, GTK_FILL});
1026
1027         // -------------------------- //
1028
1029         hbox = ui::HBox( FALSE, 5 );
1030         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1031         hbox.show();
1032
1033         w = ui::Label( "File:" );
1034         hbox.pack_start( w, FALSE, FALSE, 0 );
1035         w.show();
1036
1037         g_pCamListCombo = gtk_combo_new();
1038         hbox.pack_start( g_pCamListCombo, TRUE, TRUE, 0 );
1039         g_pCamListCombo.show();
1040
1041         // -------------------------- //
1042
1043         hbox = ui::HBox( FALSE, 5 );
1044         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1045         hbox.show();
1046
1047         w = ui::Label( "Name:" );
1048         hbox.pack_start( w, FALSE, FALSE, 0 );
1049         w.show();
1050
1051         g_pCamName = ui::Entry();
1052         hbox.pack_start( g_pCamName, FALSE, FALSE, 0 );
1053         g_pCamName.show();
1054
1055         w = ui::Label( "Type: " );
1056         hbox.pack_start( w, FALSE, FALSE, 0 );
1057         w.show();
1058
1059         w = ui::Label( "" );
1060         hbox.pack_start( w, FALSE, FALSE, 0 );
1061         w.show();
1062         g_pCamType = GTK_LABEL( w );
1063
1064         RefreshCamListCombo();
1065
1066         gtk_editable_set_editable( GTK_EDITABLE( GTK_COMBO( g_pCamListCombo )->entry ), FALSE );
1067         ( GTK_COMBO( g_pCamListCombo )->entry ).connect( "changed", G_CALLBACK( ci_camlist_changed ), NULL );
1068
1069         // -------------------------- //
1070
1071         auto frame = ui::Frame( "Path and Target editing" );
1072         frame.show();
1073         table.attach(frame, {0, 1, 1, 2}, {GTK_EXPAND | GTK_FILL, GTK_FILL});
1074
1075         auto vbox = ui::VBox( FALSE, 5 );
1076         frame.add(vbox);
1077         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
1078         vbox.show();
1079
1080         // -------------------------- //
1081
1082         hbox = ui::HBox( FALSE, 5 );
1083         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1084         hbox.show();
1085
1086         w = ui::Label( "Edit:" );
1087         hbox.pack_start( w, FALSE, FALSE, 0 );
1088         w.show();
1089
1090         g_pPathListCombo = gtk_combo_new();
1091         hbox.pack_start( g_pPathListCombo, TRUE, TRUE, 0 );
1092         g_pPathListCombo.show();
1093
1094         RefreshPathListCombo();
1095
1096         gtk_editable_set_editable( GTK_EDITABLE( GTK_COMBO( g_pPathListCombo )->entry ), FALSE );
1097         ( GTK_COMBO( g_pPathListCombo )->entry ).connect( "changed", G_CALLBACK( ci_pathlist_changed ), NULL );
1098
1099         // -------------------------- //
1100
1101         hbox = ui::HBox( FALSE, 5 );
1102         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1103         hbox.show();
1104
1105         g_pEditModeEditRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Edit Points" );
1106         hbox.pack_start( g_pEditModeEditRadioButton, FALSE, FALSE, 3 );
1107         g_pEditModeEditRadioButton.show();
1108         g_pEditTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( g_pEditModeEditRadioButton ) );
1109
1110         g_pEditModeEditRadioButton.connect( "clicked", G_CALLBACK( ci_editmode_edit ), NULL );
1111
1112         g_pEditModeAddRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Add Points" );
1113         hbox.pack_start( g_pEditModeAddRadioButton, FALSE, FALSE, 3 );
1114         g_pEditModeAddRadioButton.show();
1115         g_pEditTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( g_pEditModeAddRadioButton ) );
1116
1117         g_pEditModeAddRadioButton.connect( "clicked", G_CALLBACK( ci_editmode_add ), NULL );
1118
1119         // see if we should use a different default
1120         if ( g_iEditMode == 1 ) {
1121                 // Go to editmode Add
1122                 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( g_pEditModeAddRadioButton ), TRUE );
1123         }
1124
1125         w = ui::Label( "Type: " );
1126         hbox.pack_start( w, FALSE, FALSE, 0 );
1127         w.show();
1128
1129         w = ui::Label( "" );
1130         hbox.pack_start( w, FALSE, FALSE, 0 );
1131         w.show();
1132         g_pPathType = GTK_LABEL( w );
1133
1134         // -------------------------- //
1135
1136         hbox = ui::HBox( FALSE, 5 );
1137         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1138         hbox.show();
1139
1140         w = ui::Button( "Rename..." );
1141         hbox.pack_start( w, FALSE, TRUE, 0 );
1142         w.connect( "clicked", G_CALLBACK( ci_rename ), NULL );
1143         w.show();
1144
1145         w = ui::Button( "Add Target..." );
1146         hbox.pack_start( w, FALSE, TRUE, 0 );
1147         w.connect( "clicked", G_CALLBACK( ci_add_target ), NULL );
1148         w.show();
1149
1150         // not available in splines library
1151         /*w = gtk_button_new_with_label( "Delete Selected" );
1152            hbox.pack_start( w, FALSE, TRUE, 0);
1153            w.connect( "clicked", G_CALLBACK( ci_delete_selected ), NULL );
1154            w.show();
1155
1156            w = gtk_button_new_with_label( "Select All" );
1157            hbox.pack_start( w, FALSE, TRUE, 0);
1158            w.connect( "clicked", G_CALLBACK( ci_select_all ), NULL );
1159            w.show();*/
1160
1161         // -------------------------- //
1162
1163         frame = ui::Frame( "Time" );
1164         frame.show();
1165         table.attach(frame, {0, 1, 2, 3}, {GTK_EXPAND | GTK_FILL, GTK_FILL});
1166
1167         vbox = ui::VBox( FALSE, 5 );
1168         frame.add(vbox);
1169         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
1170         vbox.show();
1171
1172         // -------------------------- //
1173
1174         hbox = ui::HBox( FALSE, 5 );
1175         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1176         hbox.show();
1177
1178         w = ui::Label( "Length (seconds):" );
1179         hbox.pack_start( w, FALSE, FALSE, 0 );
1180         w.show();
1181
1182         g_pSecondsEntry = ui::Entry();
1183         hbox.pack_start( g_pSecondsEntry, FALSE, FALSE, 0 );
1184         g_pSecondsEntry.show();
1185
1186         // -------------------------- //
1187
1188         hbox = ui::HBox( FALSE, 5 );
1189         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1190         hbox.show();
1191
1192         w = ui::Label( "Current Time: " );
1193         hbox.pack_start( w, FALSE, FALSE, 0 );
1194         w.show();
1195
1196         w = ui::Label( "0.00" );
1197         hbox.pack_start( w, FALSE, FALSE, 0 );
1198         w.show();
1199         g_pCurrentTime = GTK_LABEL( w );
1200
1201         w = ui::Label( " of " );
1202         hbox.pack_start( w, FALSE, FALSE, 0 );
1203         w.show();
1204
1205         w = ui::Label( "0.00" );
1206         hbox.pack_start( w, FALSE, FALSE, 0 );
1207         w.show();
1208         g_pTotalTime = GTK_LABEL( w );
1209
1210         // -------------------------- //
1211
1212         hbox = ui::HBox( FALSE, 5 );
1213         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1214         hbox.show();
1215
1216         g_pTimeLine = ui::Adjustment( 0, 0, 30000, 100, 250, 0 );
1217         g_pTimeLine.connect( "value_changed", G_CALLBACK( ci_timeline_changed ), NULL );
1218         w = ui::HScale( g_pTimeLine );
1219         hbox.pack_start( w, TRUE, TRUE, 0 );
1220         w.show();
1221         gtk_scale_set_draw_value( GTK_SCALE( w ), FALSE );
1222
1223         // -------------------------- //
1224
1225         hbox = ui::HBox( FALSE, 5 );
1226         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1227         hbox.show();
1228
1229         g_pTrackCamera = ui::CheckButton( "Track Camera" );
1230         hbox.pack_start( g_pTrackCamera, FALSE, FALSE, 0 );
1231         g_pTrackCamera.show();
1232
1233         // -------------------------- //
1234
1235         hbox = ui::HBox( FALSE, 5 );
1236         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1237         hbox.show();
1238
1239         w = ui::Label( "Events:" );
1240         hbox.pack_start( w, FALSE, FALSE, 0 );
1241         w.show();
1242
1243         // -------------------------- //
1244
1245         hbox = ui::HBox( FALSE, 5 );
1246         vbox.pack_start( hbox, FALSE, FALSE, 0 );
1247         hbox.show();
1248
1249         auto scr = w = ui::ScrolledWindow();
1250         gtk_widget_set_size_request( w, 0, 150 );
1251         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( w ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1252         hbox.pack_start( w, TRUE, TRUE, 0 );
1253         w.show();
1254
1255         g_pEventsList = gtk_clist_new( 3 );
1256         scr.add(g_pEventsList);
1257         //g_pEventsList.connect( "select_row", G_CALLBACK (proplist_select_row), NULL);
1258         gtk_clist_set_selection_mode( GTK_CLIST( g_pEventsList ), GTK_SELECTION_BROWSE );
1259         gtk_clist_column_titles_hide( GTK_CLIST( g_pEventsList ) );
1260         gtk_clist_set_column_auto_resize( GTK_CLIST( g_pEventsList ), 0, TRUE );
1261         gtk_clist_set_column_auto_resize( GTK_CLIST( g_pEventsList ), 1, TRUE );
1262         gtk_clist_set_column_auto_resize( GTK_CLIST( g_pEventsList ), 2, TRUE );
1263         g_pEventsList.show();
1264
1265         vbox = ui::VBox( FALSE, 5 );
1266         hbox.pack_start( vbox, FALSE, FALSE, 0 );
1267         vbox.show();
1268
1269         w = ui::Button( "Add..." );
1270         vbox.pack_start( w, FALSE, FALSE, 0 );
1271         w.connect( "clicked", G_CALLBACK( ci_add ), NULL );
1272         w.show();
1273
1274         w = ui::Button( "Del" );
1275         vbox.pack_start( w, FALSE, FALSE, 0 );
1276         w.connect( "clicked", G_CALLBACK( ci_del ), NULL );
1277         w.show();
1278
1279         // -------------------------- //
1280
1281         /*/
1282         |
1283         |
1284         |
1285         * /
1286
1287         // the buttons column
1288         // -------------------------- //
1289
1290         vbox = gtk_vbox_new( FALSE, 5 );
1291         vbox.show();
1292         table.attach(vbox, {1, 2, 0, 1}, {GTK_FILL, GTK_FILL});
1293
1294         w = gtk_button_new_with_label( "New..." );
1295         vbox.pack_start( w, FALSE, FALSE, 0 );
1296         w.connect( "clicked", G_CALLBACK( ci_new ), NULL );
1297         w.show();
1298
1299         w = gtk_button_new_with_label( "Load..." );
1300         vbox.pack_start( w, FALSE, FALSE, 0 );
1301         w.connect( "clicked", G_CALLBACK( ci_load ), NULL );
1302         w.show();
1303
1304         // -------------------------- //
1305
1306         vbox = gtk_vbox_new( FALSE, 5 );
1307         vbox.show();
1308         table.attach( vbox, {1, 2, 1, 2}, {GTK_FILL, GTK_FILL});
1309
1310         w = gtk_button_new_with_label( "Save..." );
1311         vbox.pack_start( w, FALSE, FALSE, 0 );
1312         w.connect( "clicked", G_CALLBACK( ci_save ), NULL );
1313         w.show();
1314
1315         w = gtk_button_new_with_label( "Unload" );
1316         vbox.pack_start( w, FALSE, FALSE, 0 );
1317         w.connect( "clicked", G_CALLBACK( ci_unload ), NULL );
1318         w.show();
1319
1320         hbox = gtk_hbox_new( FALSE, 5 );
1321         vbox.pack_start( hbox, TRUE, TRUE, 0 );
1322         hbox.show();
1323
1324         w = gtk_button_new_with_label( "Apply" );
1325         vbox.pack_start( w, FALSE, FALSE, 0 );
1326         w.connect( "clicked", G_CALLBACK( ci_apply ), NULL );
1327         w.show();
1328
1329         w = gtk_button_new_with_label( "Preview" );
1330         vbox.pack_start( w, FALSE, FALSE, 0 );
1331         w.connect( "clicked", G_CALLBACK( ci_preview ), NULL );
1332         w.show();
1333
1334         // -------------------------- //
1335
1336         vbox = gtk_vbox_new( FALSE, 5 );
1337         vbox.show();
1338         table.attach(vbox, {1, 2, 2, 3}, {GTK_FILL, GTK_FILL});
1339
1340         hbox = gtk_hbox_new( FALSE, 5 );
1341         vbox.pack_start( hbox, TRUE, TRUE, 0 );
1342         hbox.show();
1343
1344         w = gtk_button_new_with_label( "Close" );
1345         vbox.pack_start( w, FALSE, FALSE, 0 );
1346         w.connect( "clicked", G_CALLBACK( ci_close ), NULL );
1347         gtk_widget_set_can_default( w, true );
1348         gtk_widget_grab_default( w );
1349         w.show();
1350
1351         // -------------------------- //
1352
1353         return window;
1354 }