]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/gtkdlgs.cpp
7bdea67d7ada63463151199f5e8426723e50769b
[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"
482                                                                                                                         ) );
483
484                                 gtk_widget_show( GTK_WIDGET( label ) );
485                                 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
486                                 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
487                                 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
488                         }
489
490                         {
491                                 GtkVBox* vbox2 = create_dialog_vbox( 4 );
492                                 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), FALSE, TRUE, 0 );
493                                 {
494                                         GtkButton* button = create_modal_dialog_button( "OK", ok_button );
495                                         gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
496                                 }
497                                 {
498                                         GtkButton* button = create_dialog_button( "Credits", G_CALLBACK( about_button_credits ), 0 );
499                                         gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
500                                 }
501                                 {
502                                         GtkButton* button = create_dialog_button( "Changelog", G_CALLBACK( about_button_changelog ), 0 );
503                                         gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
504                                 }
505                         }
506                 }
507                 {
508                         GtkFrame* frame = create_dialog_frame( "OpenGL Properties" );
509                         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
510                         {
511                                 GtkTable* table = create_dialog_table( 3, 2, 4, 4, 4 );
512                                 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table ) );
513                                 {
514                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Vendor:" ) );
515                                         gtk_widget_show( GTK_WIDGET( label ) );
516                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
517                                                                           (GtkAttachOptions) ( GTK_FILL ),
518                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
519                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
520                                 }
521                                 {
522                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Version:" ) );
523                                         gtk_widget_show( GTK_WIDGET( label ) );
524                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
525                                                                           (GtkAttachOptions) ( GTK_FILL ),
526                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
527                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
528                                 }
529                                 {
530                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Renderer:" ) );
531                                         gtk_widget_show( GTK_WIDGET( label ) );
532                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 2, 3,
533                                                                           (GtkAttachOptions) ( GTK_FILL ),
534                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
535                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
536                                 }
537                                 {
538                                         GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VENDOR ) ) ) );
539                                         gtk_widget_show( GTK_WIDGET( label ) );
540                                         gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 0, 1,
541                                                                           (GtkAttachOptions) ( GTK_FILL ),
542                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
543                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
544                                 }
545                                 {
546                                         GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VERSION ) ) ) );
547                                         gtk_widget_show( GTK_WIDGET( label ) );
548                                         gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 1, 2,
549                                                                           (GtkAttachOptions) ( GTK_FILL ),
550                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
551                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
552                                 }
553                                 {
554                                         GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_RENDERER ) ) ) );
555                                         gtk_widget_show( GTK_WIDGET( label ) );
556                                         gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 2, 3,
557                                                                           (GtkAttachOptions) ( GTK_FILL ),
558                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
559                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
560                                 }
561                         }
562                         {
563                                 GtkFrame* frame = create_dialog_frame( "OpenGL Extensions" );
564                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 );
565                                 {
566                                         GtkScrolledWindow* sc_extensions = create_scrolled_window( GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, 4 );
567                                         gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( sc_extensions ) );
568                                         {
569                                                 GtkWidget* text_extensions = gtk_text_view_new();
570                                                 gtk_text_view_set_editable( GTK_TEXT_VIEW( text_extensions ), FALSE );
571                                                 gtk_container_add( GTK_CONTAINER( sc_extensions ), text_extensions );
572                                                 GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_extensions ) );
573                                                 gtk_text_buffer_set_text( buffer, reinterpret_cast<const char*>( glGetString( GL_EXTENSIONS ) ), -1 );
574                                                 gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text_extensions ), GTK_WRAP_WORD );
575                                                 gtk_widget_show( text_extensions );
576                                         }
577                                 }
578                         }
579                 }
580         }
581
582         modal_dialog_show( window, dialog );
583
584         gtk_widget_destroy( GTK_WIDGET( window ) );
585 }
586
587 // =============================================================================
588 // TextureLayout dialog
589
590 // Last used texture scale values
591 static float last_used_texture_layout_scale_x = 4.0;
592 static float last_used_texture_layout_scale_y = 4.0;
593
594 EMessageBoxReturn DoTextureLayout( float *fx, float *fy ){
595         ModalDialog dialog;
596         ModalDialogButton ok_button( dialog, eIDOK );
597         ModalDialogButton cancel_button( dialog, eIDCANCEL );
598         GtkEntry* x;
599         GtkEntry* y;
600
601         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Patch texture layout", dialog );
602
603         GtkAccelGroup* accel = gtk_accel_group_new();
604         gtk_window_add_accel_group( window, accel );
605
606         {
607                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
608                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
609                 {
610                         GtkVBox* vbox = create_dialog_vbox( 4 );
611                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
612                         {
613                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture will be fit across the patch based\n"
614                                                                                                                         "on the x and y values given. Values of 1x1\n"
615                                                                                                                         "will \"fit\" the texture. 2x2 will repeat\n"
616                                                                                                                         "it twice, etc." ) );
617                                 gtk_widget_show( GTK_WIDGET( label ) );
618                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), TRUE, TRUE, 0 );
619                                 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
620                         }
621                         {
622                                 GtkTable* table = create_dialog_table( 2, 2, 4, 4 );
623                                 gtk_widget_show( GTK_WIDGET( table ) );
624                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
625                                 {
626                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture x:" ) );
627                                         gtk_widget_show( GTK_WIDGET( label ) );
628                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
629                                                                           (GtkAttachOptions) ( GTK_FILL ),
630                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
631                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
632                                 }
633                                 {
634                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture y:" ) );
635                                         gtk_widget_show( GTK_WIDGET( label ) );
636                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
637                                                                           (GtkAttachOptions) ( GTK_FILL ),
638                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
639                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
640                                 }
641                                 {
642                                         GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
643                                         gtk_widget_show( GTK_WIDGET( entry ) );
644                                         gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 0, 1,
645                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
646                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
647
648                                         x = entry;
649                                 }
650                                 {
651                                         GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
652                                         gtk_widget_show( GTK_WIDGET( entry ) );
653                                         gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 1, 2,
654                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
655                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
656
657                                         y = entry;
658                                 }
659                         }
660                 }
661                 {
662                         GtkVBox* vbox = create_dialog_vbox( 4 );
663                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
664                         {
665                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
666                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
667                                 widget_make_default( GTK_WIDGET( button ) );
668                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
669                         }
670                         {
671                                 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
672                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
673                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
674                         }
675                 }
676         }
677
678         // Initialize with last used values
679         char buf[16];
680
681         sprintf( buf, "%f", last_used_texture_layout_scale_x );
682         gtk_entry_set_text( x, buf );
683
684         sprintf( buf, "%f", last_used_texture_layout_scale_y );
685         gtk_entry_set_text( y, buf );
686
687         // Set focus after intializing the values
688         gtk_widget_grab_focus( GTK_WIDGET( x ) );
689
690         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
691         if ( ret == eIDOK ) {
692                 *fx = static_cast<float>( atof( gtk_entry_get_text( x ) ) );
693                 *fy = static_cast<float>( atof( gtk_entry_get_text( y ) ) );
694
695                 // Remember last used values
696                 last_used_texture_layout_scale_x = *fx;
697                 last_used_texture_layout_scale_y = *fy;
698         }
699
700         gtk_widget_destroy( GTK_WIDGET( window ) );
701
702         return ret;
703 }
704
705 // =============================================================================
706 // Text Editor dialog
707
708 // master window widget
709 static GtkWidget *text_editor = 0;
710 static GtkWidget *text_widget; // slave, text widget from the gtk editor
711
712 static gint editor_delete( GtkWidget *widget, gpointer data ){
713         if ( gtk_MessageBox( widget, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
714                 return TRUE;
715         }
716
717         gtk_widget_hide( text_editor );
718
719         return TRUE;
720 }
721
722 static void editor_save( GtkWidget *widget, gpointer data ){
723         FILE *f = fopen( (char*)g_object_get_data( G_OBJECT( data ), "filename" ), "w" );
724         gpointer text = g_object_get_data( G_OBJECT( data ), "text" );
725
726         if ( f == 0 ) {
727                 gtk_MessageBox( GTK_WIDGET( data ), "Error saving file !" );
728                 return;
729         }
730
731         char *str = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );
732         fwrite( str, 1, strlen( str ), f );
733         fclose( f );
734 }
735
736 static void editor_close( GtkWidget *widget, gpointer data ){
737         if ( gtk_MessageBox( text_editor, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
738                 return;
739         }
740
741         gtk_widget_hide( text_editor );
742 }
743
744 static void CreateGtkTextEditor(){
745         GtkWidget *dlg;
746         GtkWidget *vbox, *hbox, *button, *scr, *text;
747
748         dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
749
750         g_signal_connect( G_OBJECT( dlg ), "delete_event",
751                                           G_CALLBACK( editor_delete ), 0 );
752         gtk_window_set_default_size( GTK_WINDOW( dlg ), 600, 300 );
753
754         vbox = gtk_vbox_new( FALSE, 5 );
755         gtk_widget_show( vbox );
756         gtk_container_add( GTK_CONTAINER( dlg ), GTK_WIDGET( vbox ) );
757         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
758
759         scr = gtk_scrolled_window_new( 0, 0 );
760         gtk_widget_show( scr );
761         gtk_box_pack_start( GTK_BOX( vbox ), scr, TRUE, TRUE, 0 );
762         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
763         gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
764
765         text = gtk_text_view_new();
766         gtk_container_add( GTK_CONTAINER( scr ), text );
767         gtk_widget_show( text );
768         g_object_set_data( G_OBJECT( dlg ), "text", text );
769         gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), TRUE );
770
771         hbox = gtk_hbox_new( FALSE, 5 );
772         gtk_widget_show( hbox );
773         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
774
775         button = gtk_button_new_with_label( "Close" );
776         gtk_widget_show( button );
777         gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
778         g_signal_connect( G_OBJECT( button ), "clicked",
779                                           G_CALLBACK( editor_close ), dlg );
780         gtk_widget_set_usize( button, 60, -2 );
781
782         button = gtk_button_new_with_label( "Save" );
783         gtk_widget_show( button );
784         gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
785         g_signal_connect( G_OBJECT( button ), "clicked",
786                                           G_CALLBACK( editor_save ), dlg );
787         gtk_widget_set_usize( button, 60, -2 );
788
789         text_editor = dlg;
790         text_widget = text;
791 }
792
793 static void DoGtkTextEditor( const char* filename, guint cursorpos ){
794         if ( !text_editor ) {
795                 CreateGtkTextEditor(); // build it the first time we need it
796
797         }
798         // Load file
799         FILE *f = fopen( filename, "r" );
800
801         if ( f == 0 ) {
802                 globalOutputStream() << "Unable to load file " << filename << " in shader editor.\n";
803                 gtk_widget_hide( text_editor );
804         }
805         else
806         {
807                 fseek( f, 0, SEEK_END );
808                 int len = ftell( f );
809                 void *buf = malloc( len );
810                 void *old_filename;
811
812                 rewind( f );
813                 fread( buf, 1, len, f );
814
815                 gtk_window_set_title( GTK_WINDOW( text_editor ), filename );
816
817                 GtkTextBuffer* text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_widget ) );
818                 gtk_text_buffer_set_text( text_buffer, (char*)buf, len );
819
820                 old_filename = g_object_get_data( G_OBJECT( text_editor ), "filename" );
821                 if ( old_filename ) {
822                         free( old_filename );
823                 }
824                 g_object_set_data( G_OBJECT( text_editor ), "filename", strdup( filename ) );
825
826                 // trying to show later
827                 gtk_widget_show( text_editor );
828
829 #ifdef WIN32
830                 process_gui();
831 #endif
832
833                 // only move the cursor if it's not exceeding the size..
834                 // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters
835                 // len is the max size in bytes, not in characters either, but the character count is below that limit..
836                 // thinking .. the difference between character count and byte count would be only because of CR/LF?
837                 {
838                         GtkTextIter text_iter;
839                         // character offset, not byte offset
840                         gtk_text_buffer_get_iter_at_offset( text_buffer, &text_iter, cursorpos );
841                         gtk_text_buffer_place_cursor( text_buffer, &text_iter );
842                 }
843
844 #ifdef WIN32
845                 gtk_widget_queue_draw( text_widget );
846 #endif
847
848                 free( buf );
849                 fclose( f );
850         }
851 }
852
853 // =============================================================================
854 // Light Intensity dialog
855
856 EMessageBoxReturn DoLightIntensityDlg( int *intensity ){
857         ModalDialog dialog;
858         GtkEntry* intensity_entry;
859         ModalDialogButton ok_button( dialog, eIDOK );
860         ModalDialogButton cancel_button( dialog, eIDCANCEL );
861
862         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Light intensity", dialog, -1, -1 );
863
864         GtkAccelGroup *accel_group = gtk_accel_group_new();
865         gtk_window_add_accel_group( window, accel_group );
866
867         {
868                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
869                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
870                 {
871                         GtkVBox* vbox = create_dialog_vbox( 4 );
872                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
873                         {
874                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC for default, ENTER to validate" ) );
875                                 gtk_widget_show( GTK_WIDGET( label ) );
876                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
877                         }
878                         {
879                                 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
880                                 gtk_widget_show( GTK_WIDGET( entry ) );
881                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
882
883                                 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
884
885                                 intensity_entry = entry;
886                         }
887                 }
888                 {
889                         GtkVBox* vbox = create_dialog_vbox( 4 );
890                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
891
892                         {
893                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
894                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
895                                 widget_make_default( GTK_WIDGET( button ) );
896                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
897                         }
898                         {
899                                 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
900                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
901                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
902                         }
903                 }
904         }
905
906         char buf[16];
907         sprintf( buf, "%d", *intensity );
908         gtk_entry_set_text( intensity_entry, buf );
909
910         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
911         if ( ret == eIDOK ) {
912                 *intensity = atoi( gtk_entry_get_text( intensity_entry ) );
913         }
914
915         gtk_widget_destroy( GTK_WIDGET( window ) );
916
917         return ret;
918 }
919
920 // =============================================================================
921 // Add new shader tag dialog
922
923 EMessageBoxReturn DoShaderTagDlg( CopiedString* tag, char* title ){
924         ModalDialog dialog;
925         GtkEntry* textentry;
926         ModalDialogButton ok_button( dialog, eIDOK );
927         ModalDialogButton cancel_button( dialog, eIDCANCEL );
928
929         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
930
931         GtkAccelGroup *accel_group = gtk_accel_group_new();
932         gtk_window_add_accel_group( window, accel_group );
933
934         {
935                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
936                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
937                 {
938                         GtkVBox* vbox = create_dialog_vbox( 4 );
939                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
940                         {
941                                 //GtkLabel* label = GTK_LABEL(gtk_label_new("Enter one ore more tags separated by spaces"));
942                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC to cancel, ENTER to validate" ) );
943                                 gtk_widget_show( GTK_WIDGET( label ) );
944                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
945                         }
946                         {
947                                 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
948                                 gtk_widget_show( GTK_WIDGET( entry ) );
949                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
950
951                                 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
952
953                                 textentry = entry;
954                         }
955                 }
956                 {
957                         GtkVBox* vbox = create_dialog_vbox( 4 );
958                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
959
960                         {
961                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
962                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
963                                 widget_make_default( GTK_WIDGET( button ) );
964                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
965                         }
966                         {
967                                 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
968                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
969                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
970                         }
971                 }
972         }
973
974         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
975         if ( ret == eIDOK ) {
976                 *tag = gtk_entry_get_text( textentry );
977         }
978
979         gtk_widget_destroy( GTK_WIDGET( window ) );
980
981         return ret;
982 }
983
984 EMessageBoxReturn DoShaderInfoDlg( const char* name, const char* filename, char* title ){
985         ModalDialog dialog;
986         ModalDialogButton ok_button( dialog, eIDOK );
987
988         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
989
990         GtkAccelGroup *accel_group = gtk_accel_group_new();
991         gtk_window_add_accel_group( window, accel_group );
992
993         {
994                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
995                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
996                 {
997                         GtkVBox* vbox = create_dialog_vbox( 4 );
998                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
999                         {
1000                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "The selected shader" ) );
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( name ) );
1006                                 gtk_widget_show( GTK_WIDGET( label ) );
1007                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1008                         }
1009                         {
1010                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "is located in file" ) );
1011                                 gtk_widget_show( GTK_WIDGET( label ) );
1012                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1013                         }
1014                         {
1015                                 GtkLabel* label = GTK_LABEL( gtk_label_new( filename ) );
1016                                 gtk_widget_show( GTK_WIDGET( label ) );
1017                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1018                         }
1019                         {
1020                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
1021                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1022                                 widget_make_default( GTK_WIDGET( button ) );
1023                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1024                         }
1025                 }
1026         }
1027
1028         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
1029
1030         gtk_widget_destroy( GTK_WIDGET( window ) );
1031
1032         return ret;
1033 }
1034
1035
1036
1037 #ifdef WIN32
1038 #include <gdk/gdkwin32.h>
1039 #endif
1040
1041 #ifdef WIN32
1042 // use the file associations to open files instead of builtin Gtk editor
1043 bool g_TextEditor_useWin32Editor = true;
1044 #else
1045 // custom shader editor
1046 bool g_TextEditor_useCustomEditor = false;
1047 CopiedString g_TextEditor_editorCommand( "" );
1048 #endif
1049
1050 void DoTextEditor( const char* filename, int cursorpos ){
1051 #ifdef WIN32
1052         if ( g_TextEditor_useWin32Editor ) {
1053                 globalOutputStream() << "opening file '" << filename << "' (line " << cursorpos << " info ignored)\n";
1054                 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", filename, 0, 0, SW_SHOW );
1055                 return;
1056         }
1057 #else
1058         // check if a custom editor is set
1059         if ( g_TextEditor_useCustomEditor && !g_TextEditor_editorCommand.empty() ) {
1060                 StringOutputStream strEditCommand( 256 );
1061                 strEditCommand << g_TextEditor_editorCommand.c_str() << " \"" << filename << "\"";
1062
1063                 globalOutputStream() << "Launching: " << strEditCommand.c_str() << "\n";
1064                 // note: linux does not return false if the command failed so it will assume success
1065                 if ( Q_Exec( 0, const_cast<char*>( strEditCommand.c_str() ), 0, true, false ) == false ) {
1066                         globalOutputStream() << "Failed to execute " << strEditCommand.c_str() << ", using default\n";
1067                 }
1068                 else
1069                 {
1070                         // the command (appeared) to run successfully, no need to do anything more
1071                         return;
1072                 }
1073         }
1074 #endif
1075
1076         DoGtkTextEditor( filename, cursorpos );
1077 }