]> git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/gtkdlgs.cpp
add a missing cast
[xonotic/netradiant.git] / radiant / gtkdlgs.cpp
1 /*
2    Copyright (c) 2001, Loki software, inc.
3    All rights reserved.
4
5    Redistribution and use in source and binary forms, with or without modification,
6    are permitted provided that the following conditions are met:
7
8    Redistributions of source code must retain the above copyright notice, this list
9    of conditions and the following disclaimer.
10
11    Redistributions in binary form must reproduce the above copyright notice, this
12    list of conditions and the following disclaimer in the documentation and/or
13    other materials provided with the distribution.
14
15    Neither the name of Loki software nor the names of its contributors may be used
16    to endorse or promote products derived from this software without specific prior
17    written permission.
18
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
20    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22    DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
23    DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 //
32 // Some small dialogs that don't need much
33 //
34 // Leonardo Zide (leo@lokigames.com)
35 //
36
37 #include "gtkdlgs.h"
38
39 #include "debugging/debugging.h"
40 #include "version.h"
41 #include "aboutmsg.h"
42
43 #include "igl.h"
44 #include "iscenegraph.h"
45 #include "iselection.h"
46
47 #include <gdk/gdkkeysyms.h>
48 #include <gtk/gtkmain.h>
49 #include <gtk/gtkentry.h>
50 #include <gtk/gtkhbox.h>
51 #include <gtk/gtkvbox.h>
52 #include <gtk/gtkframe.h>
53 #include <gtk/gtklabel.h>
54 #include <gtk/gtktable.h>
55 #include <gtk/gtkbutton.h>
56 #include <gtk/gtkcombobox.h>
57 #include <gtk/gtkscrolledwindow.h>
58 #include <gtk/gtktextview.h>
59 #include <gtk/gtktextbuffer.h>
60 #include <gtk/gtktreeview.h>
61 #include <gtk/gtkcellrenderertext.h>
62 #include <gtk/gtktreeselection.h>
63 #include <gtk/gtkliststore.h>
64
65 #include "os/path.h"
66 #include "math/aabb.h"
67 #include "container/array.h"
68 #include "generic/static.h"
69 #include "stream/stringstream.h"
70 #include "convert.h"
71 #include "gtkutil/messagebox.h"
72 #include "gtkutil/image.h"
73
74 #include "gtkmisc.h"
75 #include "brushmanip.h"
76 #include "build.h"
77 #include "qe3.h"
78 #include "texwindow.h"
79 #include "xywindow.h"
80 #include "mainframe.h"
81 #include "preferences.h"
82 #include "url.h"
83 #include "cmdlib.h"
84
85
86
87 // =============================================================================
88 // Project settings dialog
89
90 class GameComboConfiguration
91 {
92 public:
93 const char* basegame_dir;
94 const char* basegame;
95 const char* known_dir;
96 const char* known;
97 const char* custom;
98
99 GameComboConfiguration() :
100         basegame_dir( g_pGameDescription->getRequiredKeyValue( "basegame" ) ),
101         basegame( g_pGameDescription->getRequiredKeyValue( "basegamename" ) ),
102         known_dir( g_pGameDescription->getKeyValue( "knowngame" ) ),
103         known( g_pGameDescription->getKeyValue( "knowngamename" ) ),
104         custom( g_pGameDescription->getRequiredKeyValue( "unknowngamename" ) ){
105 }
106 };
107
108 typedef LazyStatic<GameComboConfiguration> LazyStaticGameComboConfiguration;
109
110 inline GameComboConfiguration& globalGameComboConfiguration(){
111         return LazyStaticGameComboConfiguration::instance();
112 }
113
114
115 struct gamecombo_t
116 {
117         gamecombo_t( int _game, const char* _fs_game, bool _sensitive )
118                 : game( _game ), fs_game( _fs_game ), sensitive( _sensitive )
119         {}
120         int game;
121         const char* fs_game;
122         bool sensitive;
123 };
124
125 gamecombo_t gamecombo_for_dir( const char* dir ){
126         if ( string_equal( dir, globalGameComboConfiguration().basegame_dir ) ) {
127                 return gamecombo_t( 0, "", false );
128         }
129         else if ( string_equal( dir, globalGameComboConfiguration().known_dir ) ) {
130                 return gamecombo_t( 1, dir, false );
131         }
132         else
133         {
134                 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, dir, true );
135         }
136 }
137
138 gamecombo_t gamecombo_for_gamename( const char* gamename ){
139         if ( ( strlen( gamename ) == 0 ) || !strcmp( gamename, globalGameComboConfiguration().basegame ) ) {
140                 return gamecombo_t( 0, "", false );
141         }
142         else if ( !strcmp( gamename, globalGameComboConfiguration().known ) ) {
143                 return gamecombo_t( 1, globalGameComboConfiguration().known_dir, false );
144         }
145         else
146         {
147                 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, "", true );
148         }
149 }
150
151 inline void path_copy_clean( char* destination, const char* source ){
152         char* i = destination;
153
154         while ( *source != '\0' )
155         {
156                 *i++ = ( *source == '\\' ) ? '/' : *source;
157                 ++source;
158         }
159
160         if ( i != destination && *( i - 1 ) != '/' ) {
161                 *( i++ ) = '/';
162         }
163
164         *i = '\0';
165 }
166
167
168 struct GameCombo
169 {
170         GtkComboBox* game_select;
171         GtkEntry* fsgame_entry;
172 };
173
174 gboolean OnSelchangeComboWhatgame( GtkWidget *widget, GameCombo* combo ){
175         const char *gamename;
176         {
177                 GtkTreeIter iter;
178                 gtk_combo_box_get_active_iter( combo->game_select, &iter );
179                 gtk_tree_model_get( gtk_combo_box_get_model( combo->game_select ), &iter, 0, (gpointer*)&gamename, -1 );
180         }
181
182         gamecombo_t gamecombo = gamecombo_for_gamename( gamename );
183
184         gtk_entry_set_text( combo->fsgame_entry, gamecombo.fs_game );
185         gtk_widget_set_sensitive( GTK_WIDGET( combo->fsgame_entry ), gamecombo.sensitive );
186
187         return FALSE;
188 }
189
190 class MappingMode
191 {
192 public:
193 bool do_mapping_mode;
194 const char* sp_mapping_mode;
195 const char* mp_mapping_mode;
196
197 MappingMode() :
198         do_mapping_mode( !string_empty( g_pGameDescription->getKeyValue( "show_gamemode" ) ) ),
199         sp_mapping_mode( "Single Player mapping mode" ),
200         mp_mapping_mode( "Multiplayer mapping mode" ){
201 }
202 };
203
204 typedef LazyStatic<MappingMode> LazyStaticMappingMode;
205
206 inline MappingMode& globalMappingMode(){
207         return LazyStaticMappingMode::instance();
208 }
209
210 class ProjectSettingsDialog
211 {
212 public:
213 GameCombo game_combo;
214 GtkComboBox* gamemode_combo;
215 };
216
217 GtkWindow* ProjectSettingsDialog_construct( ProjectSettingsDialog& dialog, ModalDialog& modal ){
218         GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Project Settings", G_CALLBACK( dialog_delete_callback ), &modal );
219
220         {
221                 GtkTable* table1 = create_dialog_table( 1, 2, 4, 4, 4 );
222                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( table1 ) );
223                 {
224                         GtkVBox* vbox = create_dialog_vbox( 4 );
225                         gtk_table_attach( table1, GTK_WIDGET( vbox ), 1, 2, 0, 1,
226                                                           (GtkAttachOptions) ( GTK_FILL ),
227                                                           (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
228                         {
229                                 GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &modal );
230                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
231                         }
232                         {
233                                 GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &modal );
234                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
235                         }
236                 }
237                 {
238                         GtkFrame* frame = create_dialog_frame( "Project settings" );
239                         gtk_table_attach( table1, GTK_WIDGET( frame ), 0, 1, 0, 1,
240                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
241                                                           (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
242                         {
243                                 GtkTable* table2 = create_dialog_table( ( globalMappingMode().do_mapping_mode ) ? 4 : 3, 2, 4, 4, 4 );
244                                 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table2 ) );
245
246                                 {
247                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Select mod" ) );
248                                         gtk_widget_show( GTK_WIDGET( label ) );
249                                         gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 0, 1,
250                                                                           (GtkAttachOptions) ( GTK_FILL ),
251                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
252                                         gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
253                                 }
254                                 {
255                                         dialog.game_combo.game_select = GTK_COMBO_BOX( gtk_combo_box_new_text() );
256
257                                         gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().basegame );
258                                         if ( globalGameComboConfiguration().known[0] != '\0' ) {
259                                                 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().known );
260                                         }
261                                         gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().custom );
262
263                                         gtk_widget_show( GTK_WIDGET( dialog.game_combo.game_select ) );
264                                         gtk_table_attach( table2, GTK_WIDGET( dialog.game_combo.game_select ), 1, 2, 0, 1,
265                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
266                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
267
268                                         g_signal_connect( G_OBJECT( dialog.game_combo.game_select ), "changed", G_CALLBACK( OnSelchangeComboWhatgame ), &dialog.game_combo );
269                                 }
270
271                                 {
272                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "fs_game" ) );
273                                         gtk_widget_show( GTK_WIDGET( label ) );
274                                         gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 1, 2,
275                                                                           (GtkAttachOptions) ( GTK_FILL ),
276                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
277                                         gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
278                                 }
279                                 {
280                                         GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
281                                         gtk_widget_show( GTK_WIDGET( entry ) );
282                                         gtk_table_attach( table2, GTK_WIDGET( entry ), 1, 2, 1, 2,
283                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
284                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
285
286                                         dialog.game_combo.fsgame_entry = entry;
287                                 }
288
289                                 if ( globalMappingMode().do_mapping_mode ) {
290                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Mapping mode" ) );
291                                         gtk_widget_show( GTK_WIDGET( label ) );
292                                         gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 3, 4,
293                                                                           (GtkAttachOptions) ( GTK_FILL ),
294                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
295                                         gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
296
297                                         GtkComboBox* combo = GTK_COMBO_BOX( gtk_combo_box_new_text() );
298                                         gtk_combo_box_append_text( combo, globalMappingMode().sp_mapping_mode );
299                                         gtk_combo_box_append_text( combo, globalMappingMode().mp_mapping_mode );
300
301                                         gtk_widget_show( GTK_WIDGET( combo ) );
302                                         gtk_table_attach( table2, GTK_WIDGET( combo ), 1, 2, 3, 4,
303                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
304                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
305
306                                         dialog.gamemode_combo = combo;
307                                 }
308                         }
309                 }
310         }
311
312         // initialise the fs_game selection from the project settings into the dialog
313         const char* dir = gamename_get();
314         gamecombo_t gamecombo = gamecombo_for_dir( dir );
315
316         gtk_combo_box_set_active( dialog.game_combo.game_select, gamecombo.game );
317         gtk_entry_set_text( dialog.game_combo.fsgame_entry, gamecombo.fs_game );
318         gtk_widget_set_sensitive( GTK_WIDGET( dialog.game_combo.fsgame_entry ), gamecombo.sensitive );
319
320         if ( globalMappingMode().do_mapping_mode ) {
321                 const char *gamemode = gamemode_get();
322                 if ( string_empty( gamemode ) || string_equal( gamemode, "sp" ) ) {
323                         gtk_combo_box_set_active( dialog.gamemode_combo, 0 );
324                 }
325                 else
326                 {
327                         gtk_combo_box_set_active( dialog.gamemode_combo, 1 );
328                 }
329         }
330
331         return window;
332 }
333
334 void ProjectSettingsDialog_ok( ProjectSettingsDialog& dialog ){
335         const char* dir = gtk_entry_get_text( dialog.game_combo.fsgame_entry );
336
337         const char* new_gamename = path_equal( dir, globalGameComboConfiguration().basegame_dir )
338                                                            ? ""
339                                                            : dir;
340
341         if ( !path_equal( new_gamename, gamename_get() ) ) {
342                 ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Changing Game Name" );
343
344                 EnginePath_Unrealise();
345
346                 gamename_set( new_gamename );
347
348                 EnginePath_Realise();
349         }
350
351         if ( globalMappingMode().do_mapping_mode ) {
352                 // read from gamemode_combo
353                 int active = gtk_combo_box_get_active( dialog.gamemode_combo );
354                 if ( active == -1 || active == 0 ) {
355                         gamemode_set( "sp" );
356                 }
357                 else
358                 {
359                         gamemode_set( "mp" );
360                 }
361         }
362 }
363
364 void DoProjectSettings(){
365         if ( ConfirmModified( "Edit Project Settings" ) ) {
366                 ModalDialog modal;
367                 ProjectSettingsDialog dialog;
368
369                 GtkWindow* window = ProjectSettingsDialog_construct( dialog, modal );
370
371                 if ( modal_dialog_show( window, modal ) == eIDOK ) {
372                         ProjectSettingsDialog_ok( dialog );
373                 }
374
375                 gtk_widget_destroy( GTK_WIDGET( window ) );
376         }
377 }
378
379 // =============================================================================
380 // Arbitrary Sides dialog
381
382 void DoSides( int type, int axis ){
383         ModalDialog dialog;
384         GtkEntry* sides_entry;
385
386         GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Arbitrary sides", G_CALLBACK( dialog_delete_callback ), &dialog );
387
388         GtkAccelGroup* accel = gtk_accel_group_new();
389         gtk_window_add_accel_group( window, accel );
390
391         {
392                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
393                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
394                 {
395                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Sides:" ) );
396                         gtk_widget_show( GTK_WIDGET( label ) );
397                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
398                 }
399                 {
400                         GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
401                         gtk_widget_show( GTK_WIDGET( entry ) );
402                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( entry ), FALSE, FALSE, 0 );
403                         sides_entry = entry;
404                         gtk_widget_grab_focus( GTK_WIDGET( entry ) );
405                 }
406                 {
407                         GtkVBox* vbox = create_dialog_vbox( 4 );
408                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
409                         {
410                                 GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &dialog );
411                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
412                                 widget_make_default( GTK_WIDGET( button ) );
413                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
414                         }
415                         {
416                                 GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &dialog );
417                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
418                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
419                         }
420                 }
421         }
422
423         if ( modal_dialog_show( window, dialog ) == eIDOK ) {
424                 const char *str = gtk_entry_get_text( sides_entry );
425
426                 Scene_BrushConstructPrefab( GlobalSceneGraph(), (EBrushPrefab)type, atoi( str ), TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ) );
427         }
428
429         gtk_widget_destroy( GTK_WIDGET( window ) );
430 }
431
432 // =============================================================================
433 // About dialog (no program is complete without one)
434
435 void about_button_changelog( GtkWidget *widget, gpointer data ){
436         StringOutputStream log( 256 );
437         log << AppPath_get() << "changelog.txt";
438         OpenURL( log.c_str() );
439 }
440
441 void about_button_credits( GtkWidget *widget, gpointer data ){
442         StringOutputStream cred( 256 );
443         cred << AppPath_get() << "credits.html";
444         OpenURL( cred.c_str() );
445 }
446
447 void DoAbout(){
448         ModalDialog dialog;
449         ModalDialogButton ok_button( dialog, eIDOK );
450
451         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "About NetRadiant", dialog );
452
453         {
454                 GtkVBox* vbox = create_dialog_vbox( 4, 4 );
455                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) );
456
457                 {
458                         GtkHBox* hbox = create_dialog_hbox( 4 );
459                         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
460
461                         {
462                                 GtkVBox* vbox2 = create_dialog_vbox( 4 );
463                                 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), TRUE, FALSE, 0 );
464                                 {
465                                         GtkFrame* frame = create_dialog_frame( 0, GTK_SHADOW_IN );
466                                         gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
467                                         {
468                                                 GtkImage* image = new_local_image( "logo.bmp" );
469                                                 gtk_widget_show( GTK_WIDGET( image ) );
470                                                 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( image ) );
471                                         }
472                                 }
473                         }
474
475                         {
476                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "NetRadiant " RADIANT_VERSION "\n"
477                                                                                                                         __DATE__ "\n\n"
478                                                                                                                         RADIANT_ABOUTMSG "\n\n"
479                                                                                                                                                          "By alientrap.org\n\n"
480                                                                                                                                                          "This program is free software\n"
481                                                                                                                                                          "licensed under the GNU GPL.\n\n"
482                                                                                                                                                          "NetRadiant is unsupported, however\n"
483                                                                                                                                                          "you may report your problems at\n"
484                                                                                                                                                          "http://www.icculus.org/netradiant/"
485                                                                                                                         ) );
486
487                                 gtk_widget_show( GTK_WIDGET( label ) );
488                                 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
489                                 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
490                                 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
491                         }
492
493                         {
494                                 GtkVBox* vbox2 = create_dialog_vbox( 4 );
495                                 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), FALSE, TRUE, 0 );
496                                 {
497                                         GtkButton* button = create_modal_dialog_button( "OK", ok_button );
498                                         gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
499                                 }
500                                 {
501                                         GtkButton* button = create_dialog_button( "Credits", G_CALLBACK( about_button_credits ), 0 );
502                                         gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
503                                 }
504                                 {
505                                         GtkButton* button = create_dialog_button( "Changelog", G_CALLBACK( about_button_changelog ), 0 );
506                                         gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
507                                 }
508                         }
509                 }
510                 {
511                         GtkFrame* frame = create_dialog_frame( "OpenGL Properties" );
512                         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
513                         {
514                                 GtkTable* table = create_dialog_table( 3, 2, 4, 4, 4 );
515                                 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table ) );
516                                 {
517                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Vendor:" ) );
518                                         gtk_widget_show( GTK_WIDGET( label ) );
519                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
520                                                                           (GtkAttachOptions) ( GTK_FILL ),
521                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
522                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
523                                 }
524                                 {
525                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Version:" ) );
526                                         gtk_widget_show( GTK_WIDGET( label ) );
527                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
528                                                                           (GtkAttachOptions) ( GTK_FILL ),
529                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
530                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
531                                 }
532                                 {
533                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Renderer:" ) );
534                                         gtk_widget_show( GTK_WIDGET( label ) );
535                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 2, 3,
536                                                                           (GtkAttachOptions) ( GTK_FILL ),
537                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
538                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
539                                 }
540                                 {
541                                         GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VENDOR ) ) ) );
542                                         gtk_widget_show( GTK_WIDGET( label ) );
543                                         gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 0, 1,
544                                                                           (GtkAttachOptions) ( GTK_FILL ),
545                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
546                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
547                                 }
548                                 {
549                                         GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VERSION ) ) ) );
550                                         gtk_widget_show( GTK_WIDGET( label ) );
551                                         gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 1, 2,
552                                                                           (GtkAttachOptions) ( GTK_FILL ),
553                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
554                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
555                                 }
556                                 {
557                                         GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_RENDERER ) ) ) );
558                                         gtk_widget_show( GTK_WIDGET( label ) );
559                                         gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 2, 3,
560                                                                           (GtkAttachOptions) ( GTK_FILL ),
561                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
562                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
563                                 }
564                         }
565                         {
566                                 GtkFrame* frame = create_dialog_frame( "OpenGL Extensions" );
567                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 );
568                                 {
569                                         GtkScrolledWindow* sc_extensions = create_scrolled_window( GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, 4 );
570                                         gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( sc_extensions ) );
571                                         {
572                                                 GtkWidget* text_extensions = gtk_text_view_new();
573                                                 gtk_text_view_set_editable( GTK_TEXT_VIEW( text_extensions ), FALSE );
574                                                 gtk_container_add( GTK_CONTAINER( sc_extensions ), text_extensions );
575                                                 GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_extensions ) );
576                                                 gtk_text_buffer_set_text( buffer, reinterpret_cast<const char*>( glGetString( GL_EXTENSIONS ) ), -1 );
577                                                 gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text_extensions ), GTK_WRAP_WORD );
578                                                 gtk_widget_show( text_extensions );
579                                         }
580                                 }
581                         }
582                 }
583         }
584
585         modal_dialog_show( window, dialog );
586
587         gtk_widget_destroy( GTK_WIDGET( window ) );
588 }
589
590 // =============================================================================
591 // TextureLayout dialog
592
593 EMessageBoxReturn DoTextureLayout( float *fx, float *fy ){
594         ModalDialog dialog;
595         ModalDialogButton ok_button( dialog, eIDOK );
596         ModalDialogButton cancel_button( dialog, eIDCANCEL );
597         GtkEntry* x;
598         GtkEntry* y;
599
600         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Patch texture layout", dialog );
601
602         GtkAccelGroup* accel = gtk_accel_group_new();
603         gtk_window_add_accel_group( window, accel );
604
605         {
606                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
607                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
608                 {
609                         GtkVBox* vbox = create_dialog_vbox( 4 );
610                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
611                         {
612                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture will be fit across the patch based\n"
613                                                                                                                         "on the x and y values given. Values of 1x1\n"
614                                                                                                                         "will \"fit\" the texture. 2x2 will repeat\n"
615                                                                                                                         "it twice, etc." ) );
616                                 gtk_widget_show( GTK_WIDGET( label ) );
617                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), TRUE, TRUE, 0 );
618                                 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
619                         }
620                         {
621                                 GtkTable* table = create_dialog_table( 2, 2, 4, 4 );
622                                 gtk_widget_show( GTK_WIDGET( table ) );
623                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
624                                 {
625                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture x:" ) );
626                                         gtk_widget_show( GTK_WIDGET( label ) );
627                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
628                                                                           (GtkAttachOptions) ( GTK_FILL ),
629                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
630                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
631                                 }
632                                 {
633                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture y:" ) );
634                                         gtk_widget_show( GTK_WIDGET( label ) );
635                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
636                                                                           (GtkAttachOptions) ( GTK_FILL ),
637                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
638                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
639                                 }
640                                 {
641                                         GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
642                                         gtk_widget_show( GTK_WIDGET( entry ) );
643                                         gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 0, 1,
644                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
645                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
646
647                                         gtk_widget_grab_focus( GTK_WIDGET( entry ) );
648
649                                         x = entry;
650                                 }
651                                 {
652                                         GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
653                                         gtk_widget_show( GTK_WIDGET( entry ) );
654                                         gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 1, 2,
655                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
656                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
657
658                                         y = entry;
659                                 }
660                         }
661                 }
662                 {
663                         GtkVBox* vbox = create_dialog_vbox( 4 );
664                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
665                         {
666                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
667                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
668                                 widget_make_default( GTK_WIDGET( button ) );
669                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
670                         }
671                         {
672                                 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
673                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
674                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
675                         }
676                 }
677         }
678
679         // Initialize
680         gtk_entry_set_text( x, "4.0" );
681         gtk_entry_set_text( y, "4.0" );
682
683
684         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
685         if ( ret == eIDOK ) {
686                 *fx = static_cast<float>( atof( gtk_entry_get_text( x ) ) );
687                 *fy = static_cast<float>( atof( gtk_entry_get_text( y ) ) );
688         }
689
690         gtk_widget_destroy( GTK_WIDGET( window ) );
691
692         return ret;
693 }
694
695 // =============================================================================
696 // Text Editor dialog
697
698 // master window widget
699 static GtkWidget *text_editor = 0;
700 static GtkWidget *text_widget; // slave, text widget from the gtk editor
701
702 static gint editor_delete( GtkWidget *widget, gpointer data ){
703         if ( gtk_MessageBox( widget, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
704                 return TRUE;
705         }
706
707         gtk_widget_hide( text_editor );
708
709         return TRUE;
710 }
711
712 static void editor_save( GtkWidget *widget, gpointer data ){
713         FILE *f = fopen( (char*)g_object_get_data( G_OBJECT( data ), "filename" ), "w" );
714         gpointer text = g_object_get_data( G_OBJECT( data ), "text" );
715
716         if ( f == 0 ) {
717                 gtk_MessageBox( GTK_WIDGET( data ), "Error saving file !" );
718                 return;
719         }
720
721         char *str = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );
722         fwrite( str, 1, strlen( str ), f );
723         fclose( f );
724 }
725
726 static void editor_close( GtkWidget *widget, gpointer data ){
727         if ( gtk_MessageBox( text_editor, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
728                 return;
729         }
730
731         gtk_widget_hide( text_editor );
732 }
733
734 static void CreateGtkTextEditor(){
735         GtkWidget *dlg;
736         GtkWidget *vbox, *hbox, *button, *scr, *text;
737
738         dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
739
740         g_signal_connect( G_OBJECT( dlg ), "delete_event",
741                                           G_CALLBACK( editor_delete ), 0 );
742         gtk_window_set_default_size( GTK_WINDOW( dlg ), 600, 300 );
743
744         vbox = gtk_vbox_new( FALSE, 5 );
745         gtk_widget_show( vbox );
746         gtk_container_add( GTK_CONTAINER( dlg ), GTK_WIDGET( vbox ) );
747         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
748
749         scr = gtk_scrolled_window_new( 0, 0 );
750         gtk_widget_show( scr );
751         gtk_box_pack_start( GTK_BOX( vbox ), scr, TRUE, TRUE, 0 );
752         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
753         gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
754
755         text = gtk_text_view_new();
756         gtk_container_add( GTK_CONTAINER( scr ), text );
757         gtk_widget_show( text );
758         g_object_set_data( G_OBJECT( dlg ), "text", text );
759         gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), TRUE );
760
761         hbox = gtk_hbox_new( FALSE, 5 );
762         gtk_widget_show( hbox );
763         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
764
765         button = gtk_button_new_with_label( "Close" );
766         gtk_widget_show( button );
767         gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
768         g_signal_connect( G_OBJECT( button ), "clicked",
769                                           G_CALLBACK( editor_close ), dlg );
770         gtk_widget_set_usize( button, 60, -2 );
771
772         button = gtk_button_new_with_label( "Save" );
773         gtk_widget_show( button );
774         gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
775         g_signal_connect( G_OBJECT( button ), "clicked",
776                                           G_CALLBACK( editor_save ), dlg );
777         gtk_widget_set_usize( button, 60, -2 );
778
779         text_editor = dlg;
780         text_widget = text;
781 }
782
783 static void DoGtkTextEditor( const char* filename, guint cursorpos ){
784         if ( !text_editor ) {
785                 CreateGtkTextEditor(); // build it the first time we need it
786
787         }
788         // Load file
789         FILE *f = fopen( filename, "r" );
790
791         if ( f == 0 ) {
792                 globalOutputStream() << "Unable to load file " << filename << " in shader editor.\n";
793                 gtk_widget_hide( text_editor );
794         }
795         else
796         {
797                 fseek( f, 0, SEEK_END );
798                 int len = ftell( f );
799                 void *buf = malloc( len );
800                 void *old_filename;
801
802                 rewind( f );
803                 fread( buf, 1, len, f );
804
805                 gtk_window_set_title( GTK_WINDOW( text_editor ), filename );
806
807                 GtkTextBuffer* text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_widget ) );
808                 gtk_text_buffer_set_text( text_buffer, (char*)buf, len );
809
810                 old_filename = g_object_get_data( G_OBJECT( text_editor ), "filename" );
811                 if ( old_filename ) {
812                         free( old_filename );
813                 }
814                 g_object_set_data( G_OBJECT( text_editor ), "filename", strdup( filename ) );
815
816                 // trying to show later
817                 gtk_widget_show( text_editor );
818
819 #ifdef WIN32
820                 process_gui();
821 #endif
822
823                 // only move the cursor if it's not exceeding the size..
824                 // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters
825                 // len is the max size in bytes, not in characters either, but the character count is below that limit..
826                 // thinking .. the difference between character count and byte count would be only because of CR/LF?
827                 {
828                         GtkTextIter text_iter;
829                         // character offset, not byte offset
830                         gtk_text_buffer_get_iter_at_offset( text_buffer, &text_iter, cursorpos );
831                         gtk_text_buffer_place_cursor( text_buffer, &text_iter );
832                 }
833
834 #ifdef WIN32
835                 gtk_widget_queue_draw( text_widget );
836 #endif
837
838                 free( buf );
839                 fclose( f );
840         }
841 }
842
843 // =============================================================================
844 // Light Intensity dialog
845
846 EMessageBoxReturn DoLightIntensityDlg( int *intensity ){
847         ModalDialog dialog;
848         GtkEntry* intensity_entry;
849         ModalDialogButton ok_button( dialog, eIDOK );
850         ModalDialogButton cancel_button( dialog, eIDCANCEL );
851
852         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Light intensity", dialog, -1, -1 );
853
854         GtkAccelGroup *accel_group = gtk_accel_group_new();
855         gtk_window_add_accel_group( window, accel_group );
856
857         {
858                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
859                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
860                 {
861                         GtkVBox* vbox = create_dialog_vbox( 4 );
862                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
863                         {
864                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC for default, ENTER to validate" ) );
865                                 gtk_widget_show( GTK_WIDGET( label ) );
866                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
867                         }
868                         {
869                                 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
870                                 gtk_widget_show( GTK_WIDGET( entry ) );
871                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
872
873                                 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
874
875                                 intensity_entry = entry;
876                         }
877                 }
878                 {
879                         GtkVBox* vbox = create_dialog_vbox( 4 );
880                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
881
882                         {
883                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
884                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
885                                 widget_make_default( GTK_WIDGET( button ) );
886                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
887                         }
888                         {
889                                 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
890                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
891                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
892                         }
893                 }
894         }
895
896         char buf[16];
897         sprintf( buf, "%d", *intensity );
898         gtk_entry_set_text( intensity_entry, buf );
899
900         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
901         if ( ret == eIDOK ) {
902                 *intensity = atoi( gtk_entry_get_text( intensity_entry ) );
903         }
904
905         gtk_widget_destroy( GTK_WIDGET( window ) );
906
907         return ret;
908 }
909
910 // =============================================================================
911 // Add new shader tag dialog
912
913 EMessageBoxReturn DoShaderTagDlg( CopiedString* tag, char* title ){
914         ModalDialog dialog;
915         GtkEntry* textentry;
916         ModalDialogButton ok_button( dialog, eIDOK );
917         ModalDialogButton cancel_button( dialog, eIDCANCEL );
918
919         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
920
921         GtkAccelGroup *accel_group = gtk_accel_group_new();
922         gtk_window_add_accel_group( window, accel_group );
923
924         {
925                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
926                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
927                 {
928                         GtkVBox* vbox = create_dialog_vbox( 4 );
929                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
930                         {
931                                 //GtkLabel* label = GTK_LABEL(gtk_label_new("Enter one ore more tags separated by spaces"));
932                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC to cancel, ENTER to validate" ) );
933                                 gtk_widget_show( GTK_WIDGET( label ) );
934                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
935                         }
936                         {
937                                 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
938                                 gtk_widget_show( GTK_WIDGET( entry ) );
939                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
940
941                                 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
942
943                                 textentry = entry;
944                         }
945                 }
946                 {
947                         GtkVBox* vbox = create_dialog_vbox( 4 );
948                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
949
950                         {
951                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
952                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
953                                 widget_make_default( GTK_WIDGET( button ) );
954                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
955                         }
956                         {
957                                 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
958                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
959                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
960                         }
961                 }
962         }
963
964         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
965         if ( ret == eIDOK ) {
966                 *tag = gtk_entry_get_text( textentry );
967         }
968
969         gtk_widget_destroy( GTK_WIDGET( window ) );
970
971         return ret;
972 }
973
974 EMessageBoxReturn DoShaderInfoDlg( const char* name, const char* filename, char* title ){
975         ModalDialog dialog;
976         ModalDialogButton ok_button( dialog, eIDOK );
977
978         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
979
980         GtkAccelGroup *accel_group = gtk_accel_group_new();
981         gtk_window_add_accel_group( window, accel_group );
982
983         {
984                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
985                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
986                 {
987                         GtkVBox* vbox = create_dialog_vbox( 4 );
988                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
989                         {
990                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "The selected shader" ) );
991                                 gtk_widget_show( GTK_WIDGET( label ) );
992                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
993                         }
994                         {
995                                 GtkLabel* label = GTK_LABEL( gtk_label_new( name ) );
996                                 gtk_widget_show( GTK_WIDGET( label ) );
997                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
998                         }
999                         {
1000                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "is located in file" ) );
1001                                 gtk_widget_show( GTK_WIDGET( label ) );
1002                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1003                         }
1004                         {
1005                                 GtkLabel* label = GTK_LABEL( gtk_label_new( filename ) );
1006                                 gtk_widget_show( GTK_WIDGET( label ) );
1007                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1008                         }
1009                         {
1010                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
1011                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1012                                 widget_make_default( GTK_WIDGET( button ) );
1013                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1014                         }
1015                 }
1016         }
1017
1018         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
1019
1020         gtk_widget_destroy( GTK_WIDGET( window ) );
1021
1022         return ret;
1023 }
1024
1025
1026
1027 #ifdef WIN32
1028 #include <gdk/gdkwin32.h>
1029 #endif
1030
1031 #ifdef WIN32
1032 // use the file associations to open files instead of builtin Gtk editor
1033 bool g_TextEditor_useWin32Editor = true;
1034 #else
1035 // custom shader editor
1036 bool g_TextEditor_useCustomEditor = false;
1037 CopiedString g_TextEditor_editorCommand( "" );
1038 #endif
1039
1040 void DoTextEditor( const char* filename, int cursorpos ){
1041 #ifdef WIN32
1042         if ( g_TextEditor_useWin32Editor ) {
1043                 globalOutputStream() << "opening file '" << filename << "' (line " << cursorpos << " info ignored)\n";
1044                 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", filename, 0, 0, SW_SHOW );
1045                 return;
1046         }
1047 #else
1048         // check if a custom editor is set
1049         if ( g_TextEditor_useCustomEditor && !g_TextEditor_editorCommand.empty() ) {
1050                 StringOutputStream strEditCommand( 256 );
1051                 strEditCommand << g_TextEditor_editorCommand.c_str() << " \"" << filename << "\"";
1052
1053                 globalOutputStream() << "Launching: " << strEditCommand.c_str() << "\n";
1054                 // note: linux does not return false if the command failed so it will assume success
1055                 if ( Q_Exec( 0, const_cast<char*>( strEditCommand.c_str() ), 0, true, false ) == false ) {
1056                         globalOutputStream() << "Failed to execute " << strEditCommand.c_str() << ", using default\n";
1057                 }
1058                 else
1059                 {
1060                         // the command (appeared) to run successfully, no need to do anything more
1061                         return;
1062                 }
1063         }
1064 #endif
1065
1066         DoGtkTextEditor( filename, cursorpos );
1067 }