]> git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/gtkdlgs.cpp
8f841e5fdacd0a6634686ad9854a141a4062e8cd
[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 #include "qerplugin.h"
86 #include "os/file.h"
87
88
89
90 // =============================================================================
91 // Project settings dialog
92
93 class GameComboConfiguration
94 {
95 public:
96 const char* basegame_dir;
97 const char* basegame;
98 const char* known_dir;
99 const char* known;
100 const char* custom;
101
102 GameComboConfiguration() :
103         basegame_dir( g_pGameDescription->getRequiredKeyValue( "basegame" ) ),
104         basegame( g_pGameDescription->getRequiredKeyValue( "basegamename" ) ),
105         known_dir( g_pGameDescription->getKeyValue( "knowngame" ) ),
106         known( g_pGameDescription->getKeyValue( "knowngamename" ) ),
107         custom( g_pGameDescription->getRequiredKeyValue( "unknowngamename" ) ){
108 }
109 };
110
111 typedef LazyStatic<GameComboConfiguration> LazyStaticGameComboConfiguration;
112
113 inline GameComboConfiguration& globalGameComboConfiguration(){
114         return LazyStaticGameComboConfiguration::instance();
115 }
116
117
118 struct gamecombo_t
119 {
120         gamecombo_t( int _game, const char* _fs_game, bool _sensitive )
121                 : game( _game ), fs_game( _fs_game ), sensitive( _sensitive )
122         {}
123         int game;
124         const char* fs_game;
125         bool sensitive;
126 };
127
128 gamecombo_t gamecombo_for_dir( const char* dir ){
129         if ( string_equal( dir, globalGameComboConfiguration().basegame_dir ) ) {
130                 return gamecombo_t( 0, "", false );
131         }
132         else if ( string_equal( dir, globalGameComboConfiguration().known_dir ) ) {
133                 return gamecombo_t( 1, dir, false );
134         }
135         else
136         {
137                 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, dir, true );
138         }
139 }
140
141 gamecombo_t gamecombo_for_gamename( const char* gamename ){
142         if ( ( strlen( gamename ) == 0 ) || !strcmp( gamename, globalGameComboConfiguration().basegame ) ) {
143                 return gamecombo_t( 0, "", false );
144         }
145         else if ( !strcmp( gamename, globalGameComboConfiguration().known ) ) {
146                 return gamecombo_t( 1, globalGameComboConfiguration().known_dir, false );
147         }
148         else
149         {
150                 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, "", true );
151         }
152 }
153
154 inline void path_copy_clean( char* destination, const char* source ){
155         char* i = destination;
156
157         while ( *source != '\0' )
158         {
159                 *i++ = ( *source == '\\' ) ? '/' : *source;
160                 ++source;
161         }
162
163         if ( i != destination && *( i - 1 ) != '/' ) {
164                 *( i++ ) = '/';
165         }
166
167         *i = '\0';
168 }
169
170
171 struct GameCombo
172 {
173         GtkComboBox* game_select;
174         GtkEntry* fsgame_entry;
175 };
176
177 gboolean OnSelchangeComboWhatgame( GtkWidget *widget, GameCombo* combo ){
178         const char *gamename;
179         {
180                 GtkTreeIter iter;
181                 gtk_combo_box_get_active_iter( combo->game_select, &iter );
182                 gtk_tree_model_get( gtk_combo_box_get_model( combo->game_select ), &iter, 0, (gpointer*)&gamename, -1 );
183         }
184
185         gamecombo_t gamecombo = gamecombo_for_gamename( gamename );
186
187         gtk_entry_set_text( combo->fsgame_entry, gamecombo.fs_game );
188         gtk_widget_set_sensitive( GTK_WIDGET( combo->fsgame_entry ), gamecombo.sensitive );
189
190         return FALSE;
191 }
192
193 class MappingMode
194 {
195 public:
196 bool do_mapping_mode;
197 const char* sp_mapping_mode;
198 const char* mp_mapping_mode;
199
200 MappingMode() :
201         do_mapping_mode( !string_empty( g_pGameDescription->getKeyValue( "show_gamemode" ) ) ),
202         sp_mapping_mode( "Single Player mapping mode" ),
203         mp_mapping_mode( "Multiplayer mapping mode" ){
204 }
205 };
206
207 typedef LazyStatic<MappingMode> LazyStaticMappingMode;
208
209 inline MappingMode& globalMappingMode(){
210         return LazyStaticMappingMode::instance();
211 }
212
213 class ProjectSettingsDialog
214 {
215 public:
216 GameCombo game_combo;
217 GtkComboBox* gamemode_combo;
218 };
219
220 GtkWindow* ProjectSettingsDialog_construct( ProjectSettingsDialog& dialog, ModalDialog& modal ){
221         GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Project Settings", G_CALLBACK( dialog_delete_callback ), &modal );
222
223         {
224                 GtkTable* table1 = create_dialog_table( 1, 2, 4, 4, 4 );
225                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( table1 ) );
226                 {
227                         GtkVBox* vbox = create_dialog_vbox( 4 );
228                         gtk_table_attach( table1, GTK_WIDGET( vbox ), 1, 2, 0, 1,
229                                                           (GtkAttachOptions) ( GTK_FILL ),
230                                                           (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
231                         {
232                                 GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &modal );
233                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
234                         }
235                         {
236                                 GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &modal );
237                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
238                         }
239                 }
240                 {
241                         GtkFrame* frame = create_dialog_frame( "Project settings" );
242                         gtk_table_attach( table1, GTK_WIDGET( frame ), 0, 1, 0, 1,
243                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
244                                                           (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
245                         {
246                                 GtkTable* table2 = create_dialog_table( ( globalMappingMode().do_mapping_mode ) ? 4 : 3, 2, 4, 4, 4 );
247                                 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table2 ) );
248
249                                 {
250                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Select mod" ) );
251                                         gtk_widget_show( GTK_WIDGET( label ) );
252                                         gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 0, 1,
253                                                                           (GtkAttachOptions) ( GTK_FILL ),
254                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
255                                         gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
256                                 }
257                                 {
258                                         dialog.game_combo.game_select = GTK_COMBO_BOX( gtk_combo_box_new_text() );
259
260                                         gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().basegame );
261                                         if ( globalGameComboConfiguration().known[0] != '\0' ) {
262                                                 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().known );
263                                         }
264                                         gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().custom );
265
266                                         gtk_widget_show( GTK_WIDGET( dialog.game_combo.game_select ) );
267                                         gtk_table_attach( table2, GTK_WIDGET( dialog.game_combo.game_select ), 1, 2, 0, 1,
268                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
269                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
270
271                                         g_signal_connect( G_OBJECT( dialog.game_combo.game_select ), "changed", G_CALLBACK( OnSelchangeComboWhatgame ), &dialog.game_combo );
272                                 }
273
274                                 {
275                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "fs_game" ) );
276                                         gtk_widget_show( GTK_WIDGET( label ) );
277                                         gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 1, 2,
278                                                                           (GtkAttachOptions) ( GTK_FILL ),
279                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
280                                         gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
281                                 }
282                                 {
283                                         GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
284                                         gtk_widget_show( GTK_WIDGET( entry ) );
285                                         gtk_table_attach( table2, GTK_WIDGET( entry ), 1, 2, 1, 2,
286                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
287                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
288
289                                         dialog.game_combo.fsgame_entry = entry;
290                                 }
291
292                                 if ( globalMappingMode().do_mapping_mode ) {
293                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Mapping mode" ) );
294                                         gtk_widget_show( GTK_WIDGET( label ) );
295                                         gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 3, 4,
296                                                                           (GtkAttachOptions) ( GTK_FILL ),
297                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
298                                         gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
299
300                                         GtkComboBox* combo = GTK_COMBO_BOX( gtk_combo_box_new_text() );
301                                         gtk_combo_box_append_text( combo, globalMappingMode().sp_mapping_mode );
302                                         gtk_combo_box_append_text( combo, globalMappingMode().mp_mapping_mode );
303
304                                         gtk_widget_show( GTK_WIDGET( combo ) );
305                                         gtk_table_attach( table2, GTK_WIDGET( combo ), 1, 2, 3, 4,
306                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
307                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
308
309                                         dialog.gamemode_combo = combo;
310                                 }
311                         }
312                 }
313         }
314
315         // initialise the fs_game selection from the project settings into the dialog
316         const char* dir = gamename_get();
317         gamecombo_t gamecombo = gamecombo_for_dir( dir );
318
319         gtk_combo_box_set_active( dialog.game_combo.game_select, gamecombo.game );
320         gtk_entry_set_text( dialog.game_combo.fsgame_entry, gamecombo.fs_game );
321         gtk_widget_set_sensitive( GTK_WIDGET( dialog.game_combo.fsgame_entry ), gamecombo.sensitive );
322
323         if ( globalMappingMode().do_mapping_mode ) {
324                 const char *gamemode = gamemode_get();
325                 if ( string_empty( gamemode ) || string_equal( gamemode, "sp" ) ) {
326                         gtk_combo_box_set_active( dialog.gamemode_combo, 0 );
327                 }
328                 else
329                 {
330                         gtk_combo_box_set_active( dialog.gamemode_combo, 1 );
331                 }
332         }
333
334         return window;
335 }
336
337 void ProjectSettingsDialog_ok( ProjectSettingsDialog& dialog ){
338         const char* dir = gtk_entry_get_text( dialog.game_combo.fsgame_entry );
339
340         const char* new_gamename = path_equal( dir, globalGameComboConfiguration().basegame_dir )
341                                                            ? ""
342                                                            : dir;
343
344         if ( !path_equal( new_gamename, gamename_get() ) ) {
345                 ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Changing Game Name" );
346
347                 EnginePath_Unrealise();
348
349                 gamename_set( new_gamename );
350
351                 EnginePath_Realise();
352         }
353
354         if ( globalMappingMode().do_mapping_mode ) {
355                 // read from gamemode_combo
356                 int active = gtk_combo_box_get_active( dialog.gamemode_combo );
357                 if ( active == -1 || active == 0 ) {
358                         gamemode_set( "sp" );
359                 }
360                 else
361                 {
362                         gamemode_set( "mp" );
363                 }
364         }
365 }
366
367 void DoProjectSettings(){
368         //if ( ConfirmModified( "Edit Project Settings" ) ) {
369                 ModalDialog modal;
370                 ProjectSettingsDialog dialog;
371
372                 GtkWindow* window = ProjectSettingsDialog_construct( dialog, modal );
373
374                 if ( modal_dialog_show( window, modal ) == eIDOK ) {
375                         ProjectSettingsDialog_ok( dialog );
376                 }
377
378                 gtk_widget_destroy( GTK_WIDGET( window ) );
379         //}
380 }
381
382 // =============================================================================
383 // Arbitrary Sides dialog
384
385 void DoSides( int type, int axis ){
386         ModalDialog dialog;
387         GtkEntry* sides_entry;
388
389         GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Arbitrary sides", G_CALLBACK( dialog_delete_callback ), &dialog );
390
391         GtkAccelGroup* accel = gtk_accel_group_new();
392         gtk_window_add_accel_group( window, accel );
393
394         {
395                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
396                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
397                 {
398                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Sides:" ) );
399                         gtk_widget_show( GTK_WIDGET( label ) );
400                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
401                 }
402                 {
403                         GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
404                         gtk_widget_show( GTK_WIDGET( entry ) );
405                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( entry ), FALSE, FALSE, 0 );
406                         sides_entry = entry;
407                         gtk_widget_grab_focus( GTK_WIDGET( entry ) );
408                 }
409                 {
410                         GtkVBox* vbox = create_dialog_vbox( 4 );
411                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
412                         {
413                                 GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &dialog );
414                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
415                                 widget_make_default( GTK_WIDGET( button ) );
416                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
417                         }
418                         {
419                                 GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &dialog );
420                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
421                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
422                         }
423                 }
424         }
425
426         if ( modal_dialog_show( window, dialog ) == eIDOK ) {
427                 const char *str = gtk_entry_get_text( sides_entry );
428
429                 Scene_BrushConstructPrefab( GlobalSceneGraph(), (EBrushPrefab)type, atoi( str ), TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ) );
430         }
431
432         gtk_widget_destroy( GTK_WIDGET( window ) );
433 }
434
435 // =============================================================================
436 // About dialog (no program is complete without one)
437
438 void about_button_changelog( GtkWidget *widget, gpointer data ){
439         StringOutputStream log( 256 );
440         log << AppPath_get() << "changelog.txt";
441         OpenURL( log.c_str() );
442 }
443
444 void about_button_credits( GtkWidget *widget, gpointer data ){
445         StringOutputStream cred( 256 );
446         cred << AppPath_get() << "credits.html";
447         OpenURL( cred.c_str() );
448 }
449
450 void DoAbout(){
451         ModalDialog dialog;
452         ModalDialogButton ok_button( dialog, eIDOK );
453
454         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "About NetRadiant", dialog );
455
456         {
457                 GtkVBox* vbox = create_dialog_vbox( 4, 4 );
458                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) );
459
460                 {
461                         GtkHBox* hbox = create_dialog_hbox( 4 );
462                         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
463
464                         {
465                                 GtkVBox* vbox2 = create_dialog_vbox( 4 );
466                                 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), TRUE, FALSE, 0 );
467                                 {
468                                         GtkFrame* frame = create_dialog_frame( 0, GTK_SHADOW_IN );
469                                         gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
470                                         {
471                                                 GtkImage* image = new_local_image( "logo.png" );
472                                                 gtk_widget_show( GTK_WIDGET( image ) );
473                                                 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( image ) );
474                                         }
475                                 }
476                         }
477
478                         {
479                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "NetRadiant " RADIANT_VERSION "\n"
480                                                                                                                         __DATE__ "\n\n"
481                                                                                                                         RADIANT_ABOUTMSG "\n\n"
482                                                                                                                                                          "By alientrap.org\n\n"
483                                                                                                                                                          "This program is free software\n"
484                                                                                                                                                          "licensed under the GNU GPL.\n"
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                                         gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE);
504                                 }
505                                 {
506                                         GtkButton* button = create_dialog_button( "Changelog", G_CALLBACK( about_button_changelog ), 0 );
507                                         gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
508                                         gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE);
509                                 }
510                         }
511                 }
512                 {
513                         GtkFrame* frame = create_dialog_frame( "OpenGL Properties" );
514                         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
515                         {
516                                 GtkTable* table = create_dialog_table( 3, 2, 4, 4, 4 );
517                                 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table ) );
518                                 {
519                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Vendor:" ) );
520                                         gtk_widget_show( GTK_WIDGET( label ) );
521                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
522                                                                           (GtkAttachOptions) ( GTK_FILL ),
523                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
524                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
525                                 }
526                                 {
527                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Version:" ) );
528                                         gtk_widget_show( GTK_WIDGET( label ) );
529                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
530                                                                           (GtkAttachOptions) ( GTK_FILL ),
531                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
532                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
533                                 }
534                                 {
535                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Renderer:" ) );
536                                         gtk_widget_show( GTK_WIDGET( label ) );
537                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 2, 3,
538                                                                           (GtkAttachOptions) ( GTK_FILL ),
539                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
540                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
541                                 }
542                                 {
543                                         GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VENDOR ) ) ) );
544                                         gtk_widget_show( GTK_WIDGET( label ) );
545                                         gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 0, 1,
546                                                                           (GtkAttachOptions) ( GTK_FILL ),
547                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
548                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
549                                 }
550                                 {
551                                         GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VERSION ) ) ) );
552                                         gtk_widget_show( GTK_WIDGET( label ) );
553                                         gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 1, 2,
554                                                                           (GtkAttachOptions) ( GTK_FILL ),
555                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
556                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
557                                 }
558                                 {
559                                         GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_RENDERER ) ) ) );
560                                         gtk_widget_show( GTK_WIDGET( label ) );
561                                         gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 2, 3,
562                                                                           (GtkAttachOptions) ( GTK_FILL ),
563                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
564                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
565                                 }
566                         }
567                         {
568                                 GtkFrame* frame = create_dialog_frame( "OpenGL Extensions" );
569                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 );
570                                 {
571                                         GtkScrolledWindow* sc_extensions = create_scrolled_window( GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, 4 );
572                                         gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( sc_extensions ) );
573                                         {
574                                                 GtkWidget* text_extensions = gtk_text_view_new();
575                                                 gtk_text_view_set_editable( GTK_TEXT_VIEW( text_extensions ), FALSE );
576                                                 gtk_container_add( GTK_CONTAINER( sc_extensions ), text_extensions );
577                                                 GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_extensions ) );
578                                                 gtk_text_buffer_set_text( buffer, reinterpret_cast<const char*>( glGetString( GL_EXTENSIONS ) ), -1 );
579                                                 gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text_extensions ), GTK_WRAP_WORD );
580                                                 gtk_widget_show( text_extensions );
581                                         }
582                                 }
583                         }
584                 }
585         }
586
587         modal_dialog_show( window, dialog );
588
589         gtk_widget_destroy( GTK_WIDGET( window ) );
590 }
591
592 // =============================================================================
593 // TextureLayout dialog
594
595 // Last used texture scale values
596 static float last_used_texture_layout_scale_x = 4.0;
597 static float last_used_texture_layout_scale_y = 4.0;
598
599 EMessageBoxReturn DoTextureLayout( float *fx, float *fy ){
600         ModalDialog dialog;
601         ModalDialogButton ok_button( dialog, eIDOK );
602         ModalDialogButton cancel_button( dialog, eIDCANCEL );
603         GtkEntry* x;
604         GtkEntry* y;
605
606         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Patch texture layout", dialog );
607
608         GtkAccelGroup* accel = gtk_accel_group_new();
609         gtk_window_add_accel_group( window, accel );
610
611         {
612                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
613                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
614                 {
615                         GtkVBox* vbox = create_dialog_vbox( 4 );
616                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
617                         {
618                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture will be fit across the patch based\n"
619                                                                                                                         "on the x and y values given. Values of 1x1\n"
620                                                                                                                         "will \"fit\" the texture. 2x2 will repeat\n"
621                                                                                                                         "it twice, etc." ) );
622                                 gtk_widget_show( GTK_WIDGET( label ) );
623                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), TRUE, TRUE, 0 );
624                                 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
625                         }
626                         {
627                                 GtkTable* table = create_dialog_table( 2, 2, 4, 4 );
628                                 gtk_widget_show( GTK_WIDGET( table ) );
629                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
630                                 {
631                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture x:" ) );
632                                         gtk_widget_show( GTK_WIDGET( label ) );
633                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
634                                                                           (GtkAttachOptions) ( GTK_FILL ),
635                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
636                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
637                                 }
638                                 {
639                                         GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture y:" ) );
640                                         gtk_widget_show( GTK_WIDGET( label ) );
641                                         gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
642                                                                           (GtkAttachOptions) ( GTK_FILL ),
643                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
644                                         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
645                                 }
646                                 {
647                                         GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
648                                         gtk_widget_show( GTK_WIDGET( entry ) );
649                                         gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 0, 1,
650                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
651                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
652
653                                         x = entry;
654                                 }
655                                 {
656                                         GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
657                                         gtk_widget_show( GTK_WIDGET( entry ) );
658                                         gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 1, 2,
659                                                                           (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
660                                                                           (GtkAttachOptions) ( 0 ), 0, 0 );
661
662                                         y = entry;
663                                 }
664                         }
665                 }
666                 {
667                         GtkVBox* vbox = create_dialog_vbox( 4 );
668                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
669                         {
670                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
671                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
672                                 widget_make_default( GTK_WIDGET( button ) );
673                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
674                         }
675                         {
676                                 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
677                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
678                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
679                         }
680                 }
681         }
682
683         // Initialize with last used values
684         char buf[16];
685
686         sprintf( buf, "%f", last_used_texture_layout_scale_x );
687         gtk_entry_set_text( x, buf );
688
689         sprintf( buf, "%f", last_used_texture_layout_scale_y );
690         gtk_entry_set_text( y, buf );
691
692         // Set focus after intializing the values
693         gtk_widget_grab_focus( GTK_WIDGET( x ) );
694
695         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
696         if ( ret == eIDOK ) {
697                 *fx = static_cast<float>( atof( gtk_entry_get_text( x ) ) );
698                 *fy = static_cast<float>( atof( gtk_entry_get_text( y ) ) );
699
700                 // Remember last used values
701                 last_used_texture_layout_scale_x = *fx;
702                 last_used_texture_layout_scale_y = *fy;
703         }
704
705         gtk_widget_destroy( GTK_WIDGET( window ) );
706
707         return ret;
708 }
709
710 // =============================================================================
711 // Text Editor dialog
712
713 // master window widget
714 static GtkWidget *text_editor = 0;
715 static GtkWidget *text_widget; // slave, text widget from the gtk editor
716 static GtkTextBuffer* text_buffer_;
717
718 static gint editor_delete( GtkWidget *widget, gpointer data ){
719 /*      if ( gtk_MessageBox( widget, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
720                 return TRUE;
721         }
722 */
723         gtk_widget_hide( text_editor );
724
725         return TRUE;
726 }
727
728 static void editor_save( GtkWidget *widget, gpointer data ){
729         FILE *f = fopen( (char*)g_object_get_data( G_OBJECT( data ), "filename" ), "w" );
730         //gpointer text = g_object_get_data( G_OBJECT( data ), "text" );
731
732         if ( f == 0 ) {
733                 gtk_MessageBox( GTK_WIDGET( data ), "Error saving file !" );
734                 return;
735         }
736
737         /* Obtain iters for the start and end of points of the buffer */
738         GtkTextIter start;
739         GtkTextIter end;
740         gtk_text_buffer_get_start_iter (text_buffer_, &start);
741         gtk_text_buffer_get_end_iter (text_buffer_, &end);
742
743         /* Get the entire buffer text. */
744         char *str = gtk_text_buffer_get_text (text_buffer_, &start, &end, FALSE);
745
746         //char *str = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );
747         fwrite( str, 1, strlen( str ), f );
748         fclose( f );
749         g_free (str);
750 }
751
752 static void editor_close( GtkWidget *widget, gpointer data ){
753 /*      if ( gtk_MessageBox( text_editor, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
754                 return;
755         }
756 */
757         gtk_widget_hide( text_editor );
758 }
759
760 static void CreateGtkTextEditor(){
761         GtkWidget *dlg;
762         GtkWidget *vbox, *hbox, *button, *scr, *text;
763
764         dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
765
766         g_signal_connect( G_OBJECT( dlg ), "delete_event",
767                                           G_CALLBACK( editor_delete ), 0 );
768         gtk_window_set_default_size( GTK_WINDOW( dlg ), 400, 600 );
769
770         vbox = gtk_vbox_new( FALSE, 5 );
771         gtk_widget_show( vbox );
772         gtk_container_add( GTK_CONTAINER( dlg ), GTK_WIDGET( vbox ) );
773         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
774
775         scr = gtk_scrolled_window_new( 0, 0 );
776         gtk_widget_show( scr );
777         gtk_box_pack_start( GTK_BOX( vbox ), scr, TRUE, TRUE, 0 );
778         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
779         gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
780
781         text = gtk_text_view_new();
782         gtk_container_add( GTK_CONTAINER( scr ), text );
783         gtk_widget_show( text );
784         g_object_set_data( G_OBJECT( dlg ), "text", text );
785         gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), TRUE );
786
787         hbox = gtk_hbox_new( FALSE, 5 );
788         gtk_widget_show( hbox );
789         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
790
791         button = gtk_button_new_with_label( "Close" );
792         gtk_widget_show( button );
793         gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
794         g_signal_connect( G_OBJECT( button ), "clicked",
795                                           G_CALLBACK( editor_close ), dlg );
796         gtk_widget_set_usize( button, 60, -2 );
797
798         button = gtk_button_new_with_label( "Save" );
799         gtk_widget_show( button );
800         gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
801         g_signal_connect( G_OBJECT( button ), "clicked",
802                                           G_CALLBACK( editor_save ), dlg );
803         gtk_widget_set_usize( button, 60, -2 );
804
805         text_editor = dlg;
806         text_widget = text;
807 }
808
809 static void DoGtkTextEditor( const char* filename, guint cursorpos, int length ){
810         if ( !text_editor ) {
811                 CreateGtkTextEditor(); // build it the first time we need it
812
813         }
814         // Load file
815         FILE *f = fopen( filename, "r" );
816
817         if ( f == 0 ) {
818                 globalOutputStream() << "Unable to load file " << filename << " in shader editor.\n";
819                 gtk_widget_hide( text_editor );
820         }
821         else
822         {
823                 fseek( f, 0, SEEK_END );
824                 int len = ftell( f );
825                 void *buf = malloc( len );
826                 void *old_filename;
827
828                 rewind( f );
829                 fread( buf, 1, len, f );
830
831                 gtk_window_set_title( GTK_WINDOW( text_editor ), filename );
832
833                 GtkTextBuffer* text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_widget ) );
834                 gtk_text_buffer_set_text( text_buffer, (char*)buf, length );
835
836                 old_filename = g_object_get_data( G_OBJECT( text_editor ), "filename" );
837                 if ( old_filename ) {
838                         free( old_filename );
839                 }
840                 g_object_set_data( G_OBJECT( text_editor ), "filename", strdup( filename ) );
841
842                 // trying to show later
843                 gtk_widget_show( text_editor );
844                 gtk_window_present( GTK_WINDOW( text_editor ) );
845
846 #ifdef WIN32
847                 process_gui();
848 #endif
849
850                 // only move the cursor if it's not exceeding the size..
851                 // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters
852                 // len is the max size in bytes, not in characters either, but the character count is below that limit..
853                 // thinking .. the difference between character count and byte count would be only because of CR/LF?
854                 {
855                         GtkTextIter text_iter;
856                         // character offset, not byte offset
857                         gtk_text_buffer_get_iter_at_offset( text_buffer, &text_iter, cursorpos );
858                         gtk_text_buffer_place_cursor( text_buffer, &text_iter );
859                         gtk_text_view_scroll_to_iter( GTK_TEXT_VIEW( text_widget ), &text_iter, 0, TRUE, 0, 0);
860                 }
861
862 #ifdef WIN32
863                 gtk_widget_queue_draw( text_widget );
864 #endif
865
866                 text_buffer_ = text_buffer;
867                 free( buf );
868                 fclose( f );
869         }
870 }
871
872 // =============================================================================
873 // Light Intensity dialog
874
875 EMessageBoxReturn DoLightIntensityDlg( int *intensity ){
876         ModalDialog dialog;
877         GtkEntry* intensity_entry;
878         ModalDialogButton ok_button( dialog, eIDOK );
879         ModalDialogButton cancel_button( dialog, eIDCANCEL );
880
881         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Light intensity", dialog, -1, -1 );
882
883         GtkAccelGroup *accel_group = gtk_accel_group_new();
884         gtk_window_add_accel_group( window, accel_group );
885
886         {
887                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
888                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
889                 {
890                         GtkVBox* vbox = create_dialog_vbox( 4 );
891                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
892                         {
893                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC for default, ENTER to validate" ) );
894                                 gtk_widget_show( GTK_WIDGET( label ) );
895                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
896                         }
897                         {
898                                 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
899                                 gtk_widget_show( GTK_WIDGET( entry ) );
900                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
901
902                                 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
903
904                                 intensity_entry = entry;
905                         }
906                 }
907                 {
908                         GtkVBox* vbox = create_dialog_vbox( 4 );
909                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
910
911                         {
912                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
913                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
914                                 widget_make_default( GTK_WIDGET( button ) );
915                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
916                         }
917                         {
918                                 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
919                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
920                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
921                         }
922                 }
923         }
924
925         char buf[16];
926         sprintf( buf, "%d", *intensity );
927         gtk_entry_set_text( intensity_entry, buf );
928
929         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
930         if ( ret == eIDOK ) {
931                 *intensity = atoi( gtk_entry_get_text( intensity_entry ) );
932         }
933
934         gtk_widget_destroy( GTK_WIDGET( window ) );
935
936         return ret;
937 }
938
939 // =============================================================================
940 // Add new shader tag dialog
941
942 EMessageBoxReturn DoShaderTagDlg( CopiedString* tag, char* title ){
943         ModalDialog dialog;
944         GtkEntry* textentry;
945         ModalDialogButton ok_button( dialog, eIDOK );
946         ModalDialogButton cancel_button( dialog, eIDCANCEL );
947
948         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
949
950         GtkAccelGroup *accel_group = gtk_accel_group_new();
951         gtk_window_add_accel_group( window, accel_group );
952
953         {
954                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
955                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
956                 {
957                         GtkVBox* vbox = create_dialog_vbox( 4 );
958                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
959                         {
960                                 //GtkLabel* label = GTK_LABEL(gtk_label_new("Enter one ore more tags separated by spaces"));
961                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC to cancel, ENTER to validate" ) );
962                                 gtk_widget_show( GTK_WIDGET( label ) );
963                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
964                         }
965                         {
966                                 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
967                                 gtk_widget_show( GTK_WIDGET( entry ) );
968                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
969
970                                 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
971
972                                 textentry = entry;
973                         }
974                 }
975                 {
976                         GtkVBox* vbox = create_dialog_vbox( 4 );
977                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
978
979                         {
980                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
981                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
982                                 widget_make_default( GTK_WIDGET( button ) );
983                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
984                         }
985                         {
986                                 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
987                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
988                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
989                         }
990                 }
991         }
992
993         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
994         if ( ret == eIDOK ) {
995                 *tag = gtk_entry_get_text( textentry );
996         }
997
998         gtk_widget_destroy( GTK_WIDGET( window ) );
999
1000         return ret;
1001 }
1002
1003 EMessageBoxReturn DoShaderInfoDlg( const char* name, const char* filename, char* title ){
1004         ModalDialog dialog;
1005         ModalDialogButton ok_button( dialog, eIDOK );
1006
1007         GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
1008
1009         GtkAccelGroup *accel_group = gtk_accel_group_new();
1010         gtk_window_add_accel_group( window, accel_group );
1011
1012         {
1013                 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
1014                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
1015                 {
1016                         GtkVBox* vbox = create_dialog_vbox( 4 );
1017                         gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
1018                         {
1019                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "The selected shader" ) );
1020                                 gtk_widget_show( GTK_WIDGET( label ) );
1021                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1022                         }
1023                         {
1024                                 GtkLabel* label = GTK_LABEL( gtk_label_new( name ) );
1025                                 gtk_widget_show( GTK_WIDGET( label ) );
1026                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1027                         }
1028                         {
1029                                 GtkLabel* label = GTK_LABEL( gtk_label_new( "is located in file" ) );
1030                                 gtk_widget_show( GTK_WIDGET( label ) );
1031                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1032                         }
1033                         {
1034                                 GtkLabel* label = GTK_LABEL( gtk_label_new( filename ) );
1035                                 gtk_widget_show( GTK_WIDGET( label ) );
1036                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1037                         }
1038                         {
1039                                 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
1040                                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1041                                 widget_make_default( GTK_WIDGET( button ) );
1042                                 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1043                         }
1044                 }
1045         }
1046
1047         EMessageBoxReturn ret = modal_dialog_show( window, dialog );
1048
1049         gtk_widget_destroy( GTK_WIDGET( window ) );
1050
1051         return ret;
1052 }
1053
1054
1055
1056 #ifdef WIN32
1057 #include <gdk/gdkwin32.h>
1058 #endif
1059
1060 #ifdef WIN32
1061 // use the file associations to open files instead of builtin Gtk editor
1062 bool g_TextEditor_useWin32Editor = false;
1063 #else
1064 // custom shader editor
1065 bool g_TextEditor_useCustomEditor = false;
1066 CopiedString g_TextEditor_editorCommand( "" );
1067 #endif
1068
1069 void DoTextEditor( const char* filename, int cursorpos, int length ){
1070 #ifdef WIN32
1071         if ( g_TextEditor_useWin32Editor ) {
1072                 StringOutputStream path( 256 );
1073                 StringOutputStream modpath( 256 );
1074                 const char* gamename = GlobalRadiant().getGameName();
1075                 const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue( "basegame" );
1076                 const char* enginePath = GlobalRadiant().getEnginePath();
1077                 path << enginePath << basegame << '/' << filename;
1078                 modpath << enginePath << gamename << '/' << filename;
1079                 if ( file_exists( modpath.c_str() ) ){
1080                         globalOutputStream() << "opening file '" << modpath.c_str() << "' (line " << cursorpos << " info ignored)\n";
1081                         ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", modpath.c_str(), 0, 0, SW_SHOW );
1082                 }
1083                 else if ( file_exists( path.c_str() ) ){
1084                         globalOutputStream() << "opening file '" << path.c_str() << "' (line " << cursorpos << " info ignored)\n";
1085                         ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", path.c_str(), 0, 0, SW_SHOW );
1086                 }
1087                 else{
1088                         globalOutputStream() << "Failed to open '" << filename << "'\nOne sits in .pk3 most likely!\n";
1089                 }
1090                 return;
1091         }
1092         else{
1093                 StringOutputStream path( 256 );
1094                 StringOutputStream modpath( 256 );
1095                 const char* gamename = GlobalRadiant().getGameName();
1096                 const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue( "basegame" );
1097                 const char* enginePath = GlobalRadiant().getEnginePath();
1098                 path << enginePath << basegame << '/' << filename;
1099                 modpath << enginePath << gamename << '/' << filename;
1100                 if ( file_exists( modpath.c_str() ) ){
1101                         globalOutputStream() << "opening file '" << modpath.c_str() << "' (line " << cursorpos << " info ignored)\n";
1102                         DoGtkTextEditor( modpath.c_str(), cursorpos, length );
1103                 }
1104                 else if ( file_exists( path.c_str() ) ){
1105                         globalOutputStream() << "opening file '" << path.c_str() << "' (line " << cursorpos << " info ignored)\n";
1106                         DoGtkTextEditor( path.c_str(), cursorpos, length );
1107                 }
1108                 else{
1109                         globalOutputStream() << "Failed to open '" << filename << "'\nOne sits in .pk3 most likely!\n";
1110                 }
1111                 return;
1112         }
1113 #else
1114         // check if a custom editor is set
1115         if ( g_TextEditor_useCustomEditor && !g_TextEditor_editorCommand.empty() ) {
1116                 StringOutputStream strEditCommand( 256 );
1117                 strEditCommand << g_TextEditor_editorCommand.c_str() << " \"" << filename << "\"";
1118
1119                 globalOutputStream() << "Launching: " << strEditCommand.c_str() << "\n";
1120                 // note: linux does not return false if the command failed so it will assume success
1121                 if ( Q_Exec( 0, const_cast<char*>( strEditCommand.c_str() ), 0, true, false ) == false ) {
1122                         globalOutputStream() << "Failed to execute " << strEditCommand.c_str() << ", using default\n";
1123                 }
1124                 else
1125                 {
1126                         // the command (appeared) to run successfully, no need to do anything more
1127                         return;
1128                 }
1129         }
1130
1131         DoGtkTextEditor( filename, cursorpos, length );
1132 #endif
1133 }