GTK: wrap gtk_list_store_append
[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( GTK_WINDOW( 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( GTK_WINDOW( window ), GTK_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         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
92         gtk_widget_show( hbox );
93
94         auto frame = ui::Frame( "Type" );
95         gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 );
96         gtk_widget_show( frame );
97
98         auto vbox2 = ui::VBox( FALSE, 5 );
99         frame.add(vbox2);
100         gtk_container_set_border_width( GTK_CONTAINER( vbox2 ), 5 );
101         gtk_widget_show( vbox2 );
102
103         // -------------------------- //
104
105         fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" );
106         gtk_box_pack_start( GTK_BOX( vbox2 ), fixed, FALSE, FALSE, 3 );
107         gtk_widget_show( fixed );
108         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( fixed ) );
109
110         interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" );
111         gtk_box_pack_start( GTK_BOX( vbox2 ), interpolated, FALSE, FALSE, 3 );
112         gtk_widget_show( interpolated );
113         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( interpolated ) );
114
115         spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" );
116         gtk_box_pack_start( GTK_BOX( vbox2 ), spline, FALSE, FALSE, 3 );
117         gtk_widget_show( spline );
118         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( spline ) );
119
120         // -------------------------- //
121
122         w = gtk_hseparator_new();
123         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 2 );
124         gtk_widget_show( w );
125
126         // -------------------------- //
127
128         hbox = ui::HBox( FALSE, 5 );
129         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
130         gtk_widget_show( hbox );
131
132         w = ui::Button( "Ok" );
133         gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 );
134         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDOK ) );
135         gtk_widget_show( w );
136
137         gtk_widget_set_can_default( w, true );
138         gtk_widget_grab_default( w );
139
140         w = ui::Button( "Cancel" );
141         gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 );
142         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDCANCEL ) );
143         gtk_widget_show( w );
144         ret = eIDCANCEL;
145
146         // -------------------------- //
147
148         gtk_window_set_position( GTK_WINDOW( window ),GTK_WIN_POS_CENTER );
149         gtk_widget_show( window );
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         gtk_widget_destroy( window );
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( GTK_WINDOW( 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( GTK_WINDOW( window ), GTK_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         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
385         gtk_widget_show( hbox );
386
387         w = ui::Label( "Name:" );
388         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
389         gtk_widget_show( w );
390
391         name = ui::Entry();
392         gtk_box_pack_start( GTK_BOX( hbox ), name, FALSE, FALSE, 0 );
393         gtk_widget_show( name );
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         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 2 );
406         gtk_widget_show( w );
407
408         // -------------------------- //
409
410         hbox = ui::HBox( FALSE, 5 );
411         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
412         gtk_widget_show( hbox );
413
414         w = ui::Button( "Ok" );
415         gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 );
416         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDOK ) );
417         gtk_widget_show( w );
418
419         gtk_widget_set_can_default( w, true );
420         gtk_widget_grab_default( w );
421
422         w = ui::Button( "Cancel" );
423         gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 );
424         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDCANCEL ) );
425         gtk_widget_show( w );
426         ret = eIDCANCEL;
427
428         // -------------------------- //
429
430         gtk_window_set_position( GTK_WINDOW( window ),GTK_WIN_POS_CENTER );
431         gtk_widget_show( window );
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         gtk_widget_destroy( window );
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( GTK_WINDOW( 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( GTK_WINDOW( window ), GTK_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         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
504         gtk_widget_show( hbox );
505
506         w = ui::Label( "Name:" );
507         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
508         gtk_widget_show( w );
509
510         name = ui::Entry();
511         gtk_box_pack_start( GTK_BOX( hbox ), name, TRUE, TRUE, 0 );
512         gtk_widget_show( name );
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         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
521         gtk_widget_show( hbox );
522
523         auto frame = ui::Frame( "Type" );
524         gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 );
525         gtk_widget_show( frame );
526
527         auto vbox2 = ui::VBox( FALSE, 5 );
528         frame.add(vbox2);
529         gtk_container_set_border_width( GTK_CONTAINER( vbox2 ), 5 );
530         gtk_widget_show( vbox2 );
531
532         // -------------------------- //
533
534         fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" );
535         gtk_box_pack_start( GTK_BOX( vbox2 ), fixed, FALSE, FALSE, 3 );
536         gtk_widget_show( fixed );
537         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( fixed ) );
538
539         interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" );
540         gtk_box_pack_start( GTK_BOX( vbox2 ), interpolated, FALSE, FALSE, 3 );
541         gtk_widget_show( interpolated );
542         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( interpolated ) );
543
544         spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" );
545         gtk_box_pack_start( GTK_BOX( vbox2 ), spline, FALSE, FALSE, 3 );
546         gtk_widget_show( spline );
547         targetTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( spline ) );
548
549         // -------------------------- //
550
551         w = gtk_hseparator_new();
552         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 2 );
553         gtk_widget_show( w );
554
555         // -------------------------- //
556
557         hbox = ui::HBox( FALSE, 5 );
558         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
559         gtk_widget_show( hbox );
560
561         w = ui::Button( "Ok" );
562         gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 );
563         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDOK ) );
564         gtk_widget_show( w );
565
566         gtk_widget_set_can_default( w, true );
567         gtk_widget_grab_default( w );
568
569         w = ui::Button( "Cancel" );
570         gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 );
571         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDCANCEL ) );
572         gtk_widget_show( w );
573         ret = eIDCANCEL;
574
575         // -------------------------- //
576
577         gtk_window_set_position( GTK_WINDOW( window ),GTK_WIN_POS_CENTER );
578         gtk_widget_show( window );
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 ), GTK_WIDGET( 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         gtk_widget_destroy( window );
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 ), GTK_WIDGET( 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( GTK_WINDOW( 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( GTK_WINDOW( window ), GTK_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         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
852         gtk_widget_show( hbox );
853
854         auto frame = ui::Frame( "Type" );
855         gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 );
856         gtk_widget_show( frame );
857
858         auto vbox2 = ui::VBox( FALSE, 5 );
859         frame.add(vbox2);
860         gtk_container_set_border_width( GTK_CONTAINER( vbox2 ), 5 );
861         gtk_widget_show( vbox2 );
862
863         // -------------------------- //
864
865         for ( i = 1; i < EVENT_COUNT; i++ ) {
866                 eventWidget[i] = gtk_radio_button_new_with_label( eventTypeRadio, camEventStr[i] );
867                 gtk_box_pack_start( GTK_BOX( vbox2 ), eventWidget[i], FALSE, FALSE, 3 );
868                 gtk_widget_show( eventWidget[i] );
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         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
879         gtk_widget_show( hbox );
880
881         w = ui::Label( "Parameters:" );
882         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
883         gtk_widget_show( w );
884
885         parameters = ui::Entry();
886         gtk_box_pack_start( GTK_BOX( hbox ), parameters, TRUE, TRUE, 0 );
887         gtk_widget_show( parameters );
888
889         // -------------------------- //
890
891         w = gtk_hseparator_new();
892         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 2 );
893         gtk_widget_show( w );
894
895         // -------------------------- //
896
897         hbox = ui::HBox( FALSE, 5 );
898         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
899         gtk_widget_show( hbox );
900
901         w = ui::Button( "Ok" );
902         gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 );
903         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDOK ) );
904         gtk_widget_show( w );
905
906         gtk_widget_set_can_default( w, true );
907         gtk_widget_grab_default( w );
908
909         w = ui::Button( "Cancel" );
910         gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 );
911         w.connect( "clicked", G_CALLBACK( dialog_button_callback ), GINT_TO_POINTER( eIDCANCEL ) );
912         gtk_widget_show( w );
913         ret = eIDCANCEL;
914
915         // -------------------------- //
916
917         gtk_window_set_position( GTK_WINDOW( window ),GTK_WIN_POS_CENTER );
918         gtk_widget_show( window );
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         gtk_widget_destroy( window );
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( GTK_WINDOW( 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( GTK_WINDOW( window ), GTK_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( GTK_TABLE( table ), 5 );
1018         gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
1019
1020         // the properties column
1021         // -------------------------- //
1022
1023         vbox = ui::VBox( FALSE, 5 );
1024         gtk_widget_show( vbox );
1025         gtk_table_attach( GTK_TABLE( table ), vbox, 0, 1, 0, 1,
1026                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
1027                                           (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1028
1029         // -------------------------- //
1030
1031         hbox = ui::HBox( FALSE, 5 );
1032         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1033         gtk_widget_show( hbox );
1034
1035         w = ui::Label( "File:" );
1036         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1037         gtk_widget_show( w );
1038
1039         g_pCamListCombo = gtk_combo_new();
1040         gtk_box_pack_start( GTK_BOX( hbox ), g_pCamListCombo, TRUE, TRUE, 0 );
1041         gtk_widget_show( g_pCamListCombo );
1042
1043         // -------------------------- //
1044
1045         hbox = ui::HBox( FALSE, 5 );
1046         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1047         gtk_widget_show( hbox );
1048
1049         w = ui::Label( "Name:" );
1050         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1051         gtk_widget_show( w );
1052
1053         g_pCamName = ui::Entry();
1054         gtk_box_pack_start( GTK_BOX( hbox ), g_pCamName, FALSE, FALSE, 0 );
1055         gtk_widget_show( g_pCamName );
1056
1057         w = ui::Label( "Type: " );
1058         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1059         gtk_widget_show( w );
1060
1061         w = ui::Label( "" );
1062         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1063         gtk_widget_show( w );
1064         g_pCamType = GTK_LABEL( w );
1065
1066         RefreshCamListCombo();
1067
1068         gtk_editable_set_editable( GTK_EDITABLE( GTK_COMBO( g_pCamListCombo )->entry ), FALSE );
1069         ( GTK_COMBO( g_pCamListCombo )->entry ).connect( "changed", G_CALLBACK( ci_camlist_changed ), NULL );
1070
1071         // -------------------------- //
1072
1073         auto frame = ui::Frame( "Path and Target editing" );
1074         frame.show();
1075         gtk_table_attach( GTK_TABLE( table ), frame, 0, 1, 1, 2,
1076                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
1077                                           (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1078
1079         auto vbox = ui::VBox( FALSE, 5 );
1080         frame.add(vbox);
1081         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
1082         vbox.show();
1083
1084         // -------------------------- //
1085
1086         hbox = ui::HBox( FALSE, 5 );
1087         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1088         gtk_widget_show( hbox );
1089
1090         w = ui::Label( "Edit:" );
1091         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1092         gtk_widget_show( w );
1093
1094         g_pPathListCombo = gtk_combo_new();
1095         gtk_box_pack_start( GTK_BOX( hbox ), g_pPathListCombo, TRUE, TRUE, 0 );
1096         gtk_widget_show( g_pPathListCombo );
1097
1098         RefreshPathListCombo();
1099
1100         gtk_editable_set_editable( GTK_EDITABLE( GTK_COMBO( g_pPathListCombo )->entry ), FALSE );
1101         ( GTK_COMBO( g_pPathListCombo )->entry ).connect( "changed", G_CALLBACK( ci_pathlist_changed ), NULL );
1102
1103         // -------------------------- //
1104
1105         hbox = ui::HBox( FALSE, 5 );
1106         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1107         gtk_widget_show( hbox );
1108
1109         g_pEditModeEditRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Edit Points" );
1110         gtk_box_pack_start( GTK_BOX( hbox ), g_pEditModeEditRadioButton, FALSE, FALSE, 3 );
1111         gtk_widget_show( g_pEditModeEditRadioButton );
1112         g_pEditTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( g_pEditModeEditRadioButton ) );
1113
1114         g_pEditModeEditRadioButton.connect( "clicked", G_CALLBACK( ci_editmode_edit ), NULL );
1115
1116         g_pEditModeAddRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Add Points" );
1117         gtk_box_pack_start( GTK_BOX( hbox ), g_pEditModeAddRadioButton, FALSE, FALSE, 3 );
1118         gtk_widget_show( g_pEditModeAddRadioButton );
1119         g_pEditTypeRadio = gtk_radio_button_get_group( GTK_RADIO_BUTTON( g_pEditModeAddRadioButton ) );
1120
1121         g_pEditModeAddRadioButton.connect( "clicked", G_CALLBACK( ci_editmode_add ), NULL );
1122
1123         // see if we should use a different default
1124         if ( g_iEditMode == 1 ) {
1125                 // Go to editmode Add
1126                 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( g_pEditModeAddRadioButton ), TRUE );
1127         }
1128
1129         w = ui::Label( "Type: " );
1130         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1131         gtk_widget_show( w );
1132
1133         w = ui::Label( "" );
1134         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1135         gtk_widget_show( w );
1136         g_pPathType = GTK_LABEL( w );
1137
1138         // -------------------------- //
1139
1140         hbox = ui::HBox( FALSE, 5 );
1141         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1142         gtk_widget_show( hbox );
1143
1144         w = ui::Button( "Rename..." );
1145         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0 );
1146         w.connect( "clicked", G_CALLBACK( ci_rename ), NULL );
1147         gtk_widget_show( w );
1148
1149         w = ui::Button( "Add Target..." );
1150         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0 );
1151         w.connect( "clicked", G_CALLBACK( ci_add_target ), NULL );
1152         gtk_widget_show( w );
1153
1154         // not available in splines library
1155         /*w = gtk_button_new_with_label( "Delete Selected" );
1156            gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0);
1157            w.connect( "clicked", G_CALLBACK( ci_delete_selected ), NULL );
1158            gtk_widget_show( w );
1159
1160            w = gtk_button_new_with_label( "Select All" );
1161            gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0);
1162            w.connect( "clicked", G_CALLBACK( ci_select_all ), NULL );
1163            gtk_widget_show( w );*/
1164
1165         // -------------------------- //
1166
1167         frame = ui::Frame( "Time" );
1168         gtk_widget_show( frame );
1169         gtk_table_attach( GTK_TABLE( table ), frame, 0, 1, 2, 3,
1170                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
1171                                           (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1172
1173         vbox = ui::VBox( FALSE, 5 );
1174         frame.add(vbox);
1175         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
1176         vbox.show();
1177
1178         // -------------------------- //
1179
1180         hbox = ui::HBox( FALSE, 5 );
1181         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1182         gtk_widget_show( hbox );
1183
1184         w = ui::Label( "Length (seconds):" );
1185         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1186         gtk_widget_show( w );
1187
1188         g_pSecondsEntry = ui::Entry();
1189         gtk_box_pack_start( GTK_BOX( hbox ), g_pSecondsEntry, FALSE, FALSE, 0 );
1190         gtk_widget_show( g_pSecondsEntry );
1191
1192         // -------------------------- //
1193
1194         hbox = ui::HBox( FALSE, 5 );
1195         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1196         gtk_widget_show( hbox );
1197
1198         w = ui::Label( "Current Time: " );
1199         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1200         gtk_widget_show( w );
1201
1202         w = ui::Label( "0.00" );
1203         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1204         gtk_widget_show( w );
1205         g_pCurrentTime = GTK_LABEL( w );
1206
1207         w = ui::Label( " of " );
1208         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1209         gtk_widget_show( w );
1210
1211         w = ui::Label( "0.00" );
1212         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1213         gtk_widget_show( w );
1214         g_pTotalTime = GTK_LABEL( w );
1215
1216         // -------------------------- //
1217
1218         hbox = ui::HBox( FALSE, 5 );
1219         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1220         gtk_widget_show( hbox );
1221
1222         g_pTimeLine = ui::Adjustment( 0, 0, 30000, 100, 250, 0 );
1223         g_pTimeLine.connect( "value_changed", G_CALLBACK( ci_timeline_changed ), NULL );
1224         w = ui::HScale( g_pTimeLine );
1225         gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 );
1226         gtk_widget_show( w );
1227         gtk_scale_set_draw_value( GTK_SCALE( w ), FALSE );
1228
1229         // -------------------------- //
1230
1231         hbox = ui::HBox( FALSE, 5 );
1232         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1233         gtk_widget_show( hbox );
1234
1235         g_pTrackCamera = ui::CheckButton( "Track Camera" );
1236         gtk_box_pack_start( GTK_BOX( hbox ), g_pTrackCamera, FALSE, FALSE, 0 );
1237         gtk_widget_show( g_pTrackCamera );
1238
1239         // -------------------------- //
1240
1241         hbox = ui::HBox( FALSE, 5 );
1242         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1243         gtk_widget_show( hbox );
1244
1245         w = ui::Label( "Events:" );
1246         gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 );
1247         gtk_widget_show( w );
1248
1249         // -------------------------- //
1250
1251         hbox = ui::HBox( FALSE, 5 );
1252         gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
1253         gtk_widget_show( hbox );
1254
1255         auto scr = w = ui::ScrolledWindow();
1256         gtk_widget_set_size_request( w, 0, 150 );
1257         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( w ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1258         gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 );
1259         gtk_widget_show( w );
1260
1261         g_pEventsList = gtk_clist_new( 3 );
1262         scr.add(g_pEventsList);
1263         //g_pEventsList.connect( "select_row", G_CALLBACK (proplist_select_row), NULL);
1264         gtk_clist_set_selection_mode( GTK_CLIST( g_pEventsList ), GTK_SELECTION_BROWSE );
1265         gtk_clist_column_titles_hide( GTK_CLIST( g_pEventsList ) );
1266         gtk_clist_set_column_auto_resize( GTK_CLIST( g_pEventsList ), 0, TRUE );
1267         gtk_clist_set_column_auto_resize( GTK_CLIST( g_pEventsList ), 1, TRUE );
1268         gtk_clist_set_column_auto_resize( GTK_CLIST( g_pEventsList ), 2, TRUE );
1269         gtk_widget_show( g_pEventsList );
1270
1271         vbox = ui::VBox( FALSE, 5 );
1272         gtk_box_pack_start( GTK_BOX( hbox ), vbox, FALSE, FALSE, 0 );
1273         gtk_widget_show( vbox );
1274
1275         w = ui::Button( "Add..." );
1276         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 );
1277         w.connect( "clicked", G_CALLBACK( ci_add ), NULL );
1278         gtk_widget_show( w );
1279
1280         w = ui::Button( "Del" );
1281         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 );
1282         w.connect( "clicked", G_CALLBACK( ci_del ), NULL );
1283         gtk_widget_show( w );
1284
1285         // -------------------------- //
1286
1287         /*/
1288         |
1289         |
1290         |
1291         * /
1292
1293         // the buttons column
1294         // -------------------------- //
1295
1296         vbox = gtk_vbox_new( FALSE, 5 );
1297         gtk_widget_show( vbox );
1298         gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 0, 1,
1299                                           (GtkAttachOptions) ( GTK_FILL ),
1300                                           (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1301
1302         w = gtk_button_new_with_label( "New..." );
1303         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 );
1304         w.connect( "clicked", G_CALLBACK( ci_new ), NULL );
1305         gtk_widget_show( w );
1306
1307         w = gtk_button_new_with_label( "Load..." );
1308         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 );
1309         w.connect( "clicked", G_CALLBACK( ci_load ), NULL );
1310         gtk_widget_show( w );
1311
1312         // -------------------------- //
1313
1314         vbox = gtk_vbox_new( FALSE, 5 );
1315         gtk_widget_show( vbox );
1316         gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 1, 2,
1317                                           (GtkAttachOptions) ( GTK_FILL ),
1318                                           (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1319
1320         w = gtk_button_new_with_label( "Save..." );
1321         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 );
1322         w.connect( "clicked", G_CALLBACK( ci_save ), NULL );
1323         gtk_widget_show( w );
1324
1325         w = gtk_button_new_with_label( "Unload" );
1326         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 );
1327         w.connect( "clicked", G_CALLBACK( ci_unload ), NULL );
1328         gtk_widget_show( w );
1329
1330         hbox = gtk_hbox_new( FALSE, 5 );
1331         gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 );
1332         gtk_widget_show( hbox );
1333
1334         w = gtk_button_new_with_label( "Apply" );
1335         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 );
1336         w.connect( "clicked", G_CALLBACK( ci_apply ), NULL );
1337         gtk_widget_show( w );
1338
1339         w = gtk_button_new_with_label( "Preview" );
1340         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 );
1341         w.connect( "clicked", G_CALLBACK( ci_preview ), NULL );
1342         gtk_widget_show( w );
1343
1344         // -------------------------- //
1345
1346         vbox = gtk_vbox_new( FALSE, 5 );
1347         gtk_widget_show( vbox );
1348         gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 2, 3,
1349                                           (GtkAttachOptions) ( GTK_FILL ),
1350                                           (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1351
1352         hbox = gtk_hbox_new( FALSE, 5 );
1353         gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 );
1354         gtk_widget_show( hbox );
1355
1356         w = gtk_button_new_with_label( "Close" );
1357         gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 );
1358         w.connect( "clicked", G_CALLBACK( ci_close ), NULL );
1359         gtk_widget_set_can_default( w, true );
1360         gtk_widget_grab_default( w );
1361         gtk_widget_show( w );
1362
1363         // -------------------------- //
1364
1365         return window;
1366 }