2 Copyright (c) 2001, Loki software, inc.
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
8 Redistributions of source code must retain the above copyright notice, this list
9 of conditions and the following disclaimer.
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.
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
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.
32 // Some small dialogs that don't need much
34 // Leonardo Zide (leo@lokigames.com)
39 #include "debugging/debugging.h"
44 #include "iscenegraph.h"
45 #include "iselection.h"
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 #include <gtk/gtkspinbutton.h>
67 #include "math/aabb.h"
68 #include "container/array.h"
69 #include "generic/static.h"
70 #include "stream/stringstream.h"
72 #include "gtkutil/messagebox.h"
73 #include "gtkutil/image.h"
76 #include "brushmanip.h"
79 #include "texwindow.h"
81 #include "mainframe.h"
82 #include "preferences.h"
86 #include "qerplugin.h"
91 // =============================================================================
92 // Project settings dialog
94 class GameComboConfiguration
97 const char* basegame_dir;
99 const char* known_dir;
103 GameComboConfiguration() :
104 basegame_dir( g_pGameDescription->getRequiredKeyValue( "basegame" ) ),
105 basegame( g_pGameDescription->getRequiredKeyValue( "basegamename" ) ),
106 known_dir( g_pGameDescription->getKeyValue( "knowngame" ) ),
107 known( g_pGameDescription->getKeyValue( "knowngamename" ) ),
108 custom( g_pGameDescription->getRequiredKeyValue( "unknowngamename" ) ){
112 typedef LazyStatic<GameComboConfiguration> LazyStaticGameComboConfiguration;
114 inline GameComboConfiguration& globalGameComboConfiguration(){
115 return LazyStaticGameComboConfiguration::instance();
121 gamecombo_t( int _game, const char* _fs_game, bool _sensitive )
122 : game( _game ), fs_game( _fs_game ), sensitive( _sensitive )
129 gamecombo_t gamecombo_for_dir( const char* dir ){
130 if ( string_equal( dir, globalGameComboConfiguration().basegame_dir ) ) {
131 return gamecombo_t( 0, "", false );
133 else if ( string_equal( dir, globalGameComboConfiguration().known_dir ) ) {
134 return gamecombo_t( 1, dir, false );
138 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, dir, true );
142 gamecombo_t gamecombo_for_gamename( const char* gamename ){
143 if ( ( strlen( gamename ) == 0 ) || !strcmp( gamename, globalGameComboConfiguration().basegame ) ) {
144 return gamecombo_t( 0, "", false );
146 else if ( !strcmp( gamename, globalGameComboConfiguration().known ) ) {
147 return gamecombo_t( 1, globalGameComboConfiguration().known_dir, false );
151 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, "", true );
155 inline void path_copy_clean( char* destination, const char* source ){
156 char* i = destination;
158 while ( *source != '\0' )
160 *i++ = ( *source == '\\' ) ? '/' : *source;
164 if ( i != destination && *( i - 1 ) != '/' ) {
174 GtkComboBox* game_select;
175 GtkEntry* fsgame_entry;
178 gboolean OnSelchangeComboWhatgame( GtkWidget *widget, GameCombo* combo ){
179 const char *gamename;
182 gtk_combo_box_get_active_iter( combo->game_select, &iter );
183 gtk_tree_model_get( gtk_combo_box_get_model( combo->game_select ), &iter, 0, (gpointer*)&gamename, -1 );
186 gamecombo_t gamecombo = gamecombo_for_gamename( gamename );
188 gtk_entry_set_text( combo->fsgame_entry, gamecombo.fs_game );
189 gtk_widget_set_sensitive( GTK_WIDGET( combo->fsgame_entry ), gamecombo.sensitive );
197 bool do_mapping_mode;
198 const char* sp_mapping_mode;
199 const char* mp_mapping_mode;
202 do_mapping_mode( !string_empty( g_pGameDescription->getKeyValue( "show_gamemode" ) ) ),
203 sp_mapping_mode( "Single Player mapping mode" ),
204 mp_mapping_mode( "Multiplayer mapping mode" ){
208 typedef LazyStatic<MappingMode> LazyStaticMappingMode;
210 inline MappingMode& globalMappingMode(){
211 return LazyStaticMappingMode::instance();
214 class ProjectSettingsDialog
217 GameCombo game_combo;
218 GtkComboBox* gamemode_combo;
221 GtkWindow* ProjectSettingsDialog_construct( ProjectSettingsDialog& dialog, ModalDialog& modal ){
222 GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Project Settings", G_CALLBACK( dialog_delete_callback ), &modal );
225 GtkTable* table1 = create_dialog_table( 1, 2, 4, 4, 4 );
226 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( table1 ) );
228 GtkVBox* vbox = create_dialog_vbox( 4 );
229 gtk_table_attach( table1, GTK_WIDGET( vbox ), 1, 2, 0, 1,
230 (GtkAttachOptions) ( GTK_FILL ),
231 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
233 GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &modal );
234 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
237 GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &modal );
238 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
242 GtkFrame* frame = create_dialog_frame( "Project settings" );
243 gtk_table_attach( table1, GTK_WIDGET( frame ), 0, 1, 0, 1,
244 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
245 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
247 GtkTable* table2 = create_dialog_table( ( globalMappingMode().do_mapping_mode ) ? 4 : 3, 2, 4, 4, 4 );
248 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table2 ) );
251 GtkLabel* label = GTK_LABEL( gtk_label_new( "Select mod" ) );
252 gtk_widget_show( GTK_WIDGET( label ) );
253 gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 0, 1,
254 (GtkAttachOptions) ( GTK_FILL ),
255 (GtkAttachOptions) ( 0 ), 0, 0 );
256 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
259 dialog.game_combo.game_select = GTK_COMBO_BOX( gtk_combo_box_new_text() );
261 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().basegame );
262 if ( globalGameComboConfiguration().known[0] != '\0' ) {
263 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().known );
265 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().custom );
267 gtk_widget_show( GTK_WIDGET( dialog.game_combo.game_select ) );
268 gtk_table_attach( table2, GTK_WIDGET( dialog.game_combo.game_select ), 1, 2, 0, 1,
269 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
270 (GtkAttachOptions) ( 0 ), 0, 0 );
272 g_signal_connect( G_OBJECT( dialog.game_combo.game_select ), "changed", G_CALLBACK( OnSelchangeComboWhatgame ), &dialog.game_combo );
276 GtkLabel* label = GTK_LABEL( gtk_label_new( "fs_game" ) );
277 gtk_widget_show( GTK_WIDGET( label ) );
278 gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 1, 2,
279 (GtkAttachOptions) ( GTK_FILL ),
280 (GtkAttachOptions) ( 0 ), 0, 0 );
281 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
284 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
285 gtk_widget_show( GTK_WIDGET( entry ) );
286 gtk_table_attach( table2, GTK_WIDGET( entry ), 1, 2, 1, 2,
287 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
288 (GtkAttachOptions) ( 0 ), 0, 0 );
290 dialog.game_combo.fsgame_entry = entry;
293 if ( globalMappingMode().do_mapping_mode ) {
294 GtkLabel* label = GTK_LABEL( gtk_label_new( "Mapping mode" ) );
295 gtk_widget_show( GTK_WIDGET( label ) );
296 gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 3, 4,
297 (GtkAttachOptions) ( GTK_FILL ),
298 (GtkAttachOptions) ( 0 ), 0, 0 );
299 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
301 GtkComboBox* combo = GTK_COMBO_BOX( gtk_combo_box_new_text() );
302 gtk_combo_box_append_text( combo, globalMappingMode().sp_mapping_mode );
303 gtk_combo_box_append_text( combo, globalMappingMode().mp_mapping_mode );
305 gtk_widget_show( GTK_WIDGET( combo ) );
306 gtk_table_attach( table2, GTK_WIDGET( combo ), 1, 2, 3, 4,
307 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
308 (GtkAttachOptions) ( 0 ), 0, 0 );
310 dialog.gamemode_combo = combo;
316 // initialise the fs_game selection from the project settings into the dialog
317 const char* dir = gamename_get();
318 gamecombo_t gamecombo = gamecombo_for_dir( dir );
320 gtk_combo_box_set_active( dialog.game_combo.game_select, gamecombo.game );
321 gtk_entry_set_text( dialog.game_combo.fsgame_entry, gamecombo.fs_game );
322 gtk_widget_set_sensitive( GTK_WIDGET( dialog.game_combo.fsgame_entry ), gamecombo.sensitive );
324 if ( globalMappingMode().do_mapping_mode ) {
325 const char *gamemode = gamemode_get();
326 if ( string_empty( gamemode ) || string_equal( gamemode, "sp" ) ) {
327 gtk_combo_box_set_active( dialog.gamemode_combo, 0 );
331 gtk_combo_box_set_active( dialog.gamemode_combo, 1 );
338 void ProjectSettingsDialog_ok( ProjectSettingsDialog& dialog ){
339 const char* dir = gtk_entry_get_text( dialog.game_combo.fsgame_entry );
341 const char* new_gamename = path_equal( dir, globalGameComboConfiguration().basegame_dir )
345 if ( !path_equal( new_gamename, gamename_get() ) ) {
346 ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Changing Game Name" );
348 EnginePath_Unrealise();
350 gamename_set( new_gamename );
352 EnginePath_Realise();
355 if ( globalMappingMode().do_mapping_mode ) {
356 // read from gamemode_combo
357 int active = gtk_combo_box_get_active( dialog.gamemode_combo );
358 if ( active == -1 || active == 0 ) {
359 gamemode_set( "sp" );
363 gamemode_set( "mp" );
368 void DoProjectSettings(){
369 //if ( ConfirmModified( "Edit Project Settings" ) ) {
371 ProjectSettingsDialog dialog;
373 GtkWindow* window = ProjectSettingsDialog_construct( dialog, modal );
375 if ( modal_dialog_show( window, modal ) == eIDOK ) {
376 ProjectSettingsDialog_ok( dialog );
379 gtk_widget_destroy( GTK_WIDGET( window ) );
383 // =============================================================================
384 // Arbitrary Sides dialog
386 void DoSides( int type, int axis ){
388 //GtkEntry* sides_entry;
389 GtkWidget* sides_spin;
391 GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Arbitrary sides", G_CALLBACK( dialog_delete_callback ), &dialog );
393 GtkAccelGroup* accel = gtk_accel_group_new();
394 gtk_window_add_accel_group( window, accel );
397 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
398 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
400 GtkLabel* label = GTK_LABEL( gtk_label_new( "Sides:" ) );
401 gtk_widget_show( GTK_WIDGET( label ) );
402 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
405 // GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
406 // gtk_widget_show( GTK_WIDGET( entry ) );
407 // gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( entry ), FALSE, FALSE, 0 );
408 // sides_entry = entry;
409 // gtk_widget_grab_focus( GTK_WIDGET( entry ) );
413 EBrushPrefab BrushPrefabType = (EBrushPrefab)type;
414 switch ( BrushPrefabType )
418 adj = GTK_ADJUSTMENT( gtk_adjustment_new( 8, 3, 1022, 1, 10, 0 ) );
421 adj = GTK_ADJUSTMENT( gtk_adjustment_new( 8, 3, 31, 1, 10, 0 ) );
424 adj = GTK_ADJUSTMENT( gtk_adjustment_new( 32, 10, 1000, 1, 10, 0 ) );
427 adj = GTK_ADJUSTMENT( gtk_adjustment_new( 8, 3, 31, 1, 10, 0 ) );
431 GtkWidget* spin = gtk_spin_button_new( adj, 1, 0 );
432 gtk_widget_show( spin );
433 gtk_box_pack_start( GTK_BOX( hbox ), spin, FALSE, FALSE, 0 );
434 gtk_widget_set_size_request( spin, 64, -1 );
435 gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( spin ), TRUE );
440 GtkVBox* vbox = create_dialog_vbox( 4 );
441 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
443 GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &dialog );
444 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
445 widget_make_default( GTK_WIDGET( button ) );
446 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
449 GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &dialog );
450 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
451 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
456 if ( modal_dialog_show( window, dialog ) == eIDOK ) {
457 // const char *str = gtk_entry_get_text( sides_entry );
459 // Scene_BrushConstructPrefab( GlobalSceneGraph(), (EBrushPrefab)type, atoi( str ), TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ) );
460 gtk_spin_button_update ( GTK_SPIN_BUTTON( sides_spin ) );
461 int sides = static_cast<int>( gtk_spin_button_get_value( GTK_SPIN_BUTTON( sides_spin ) ) );
462 Scene_BrushConstructPrefab( GlobalSceneGraph(), (EBrushPrefab)type, sides, TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ) );
465 gtk_widget_destroy( GTK_WIDGET( window ) );
468 // =============================================================================
469 // About dialog (no program is complete without one)
471 void about_button_changelog( GtkWidget *widget, gpointer data ){
472 StringOutputStream log( 256 );
473 log << AppPath_get() << "changelog.txt";
474 OpenURL( log.c_str() );
477 void about_button_credits( GtkWidget *widget, gpointer data ){
478 StringOutputStream cred( 256 );
479 cred << AppPath_get() << "credits.html";
480 OpenURL( cred.c_str() );
485 ModalDialogButton ok_button( dialog, eIDOK );
487 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "About NetRadiant", dialog );
490 GtkVBox* vbox = create_dialog_vbox( 4, 4 );
491 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) );
494 GtkHBox* hbox = create_dialog_hbox( 4 );
495 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
498 GtkVBox* vbox2 = create_dialog_vbox( 4 );
499 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), TRUE, FALSE, 0 );
501 GtkFrame* frame = create_dialog_frame( 0, GTK_SHADOW_IN );
502 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
504 GtkImage* image = new_local_image( "logo.png" );
505 gtk_widget_show( GTK_WIDGET( image ) );
506 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( image ) );
512 GtkLabel* label = GTK_LABEL( gtk_label_new( "NetRadiant " RADIANT_VERSION "\n"
514 RADIANT_ABOUTMSG "\n\n"
515 "By alientrap.org\n\n"
516 "This program is free software\n"
517 "licensed under the GNU GPL.\n"
520 gtk_widget_show( GTK_WIDGET( label ) );
521 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
522 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
523 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
527 GtkVBox* vbox2 = create_dialog_vbox( 4 );
528 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), FALSE, TRUE, 0 );
530 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
531 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
534 GtkButton* button = create_dialog_button( "Credits", G_CALLBACK( about_button_credits ), 0 );
535 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
536 gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE);
539 GtkButton* button = create_dialog_button( "Changelog", G_CALLBACK( about_button_changelog ), 0 );
540 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
541 gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE);
546 GtkFrame* frame = create_dialog_frame( "OpenGL Properties" );
547 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
549 GtkTable* table = create_dialog_table( 3, 2, 4, 4, 4 );
550 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table ) );
552 GtkLabel* label = GTK_LABEL( gtk_label_new( "Vendor:" ) );
553 gtk_widget_show( GTK_WIDGET( label ) );
554 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
555 (GtkAttachOptions) ( GTK_FILL ),
556 (GtkAttachOptions) ( 0 ), 0, 0 );
557 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
560 GtkLabel* label = GTK_LABEL( gtk_label_new( "Version:" ) );
561 gtk_widget_show( GTK_WIDGET( label ) );
562 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
563 (GtkAttachOptions) ( GTK_FILL ),
564 (GtkAttachOptions) ( 0 ), 0, 0 );
565 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
568 GtkLabel* label = GTK_LABEL( gtk_label_new( "Renderer:" ) );
569 gtk_widget_show( GTK_WIDGET( label ) );
570 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 2, 3,
571 (GtkAttachOptions) ( GTK_FILL ),
572 (GtkAttachOptions) ( 0 ), 0, 0 );
573 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
576 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VENDOR ) ) ) );
577 gtk_widget_show( GTK_WIDGET( label ) );
578 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 0, 1,
579 (GtkAttachOptions) ( GTK_FILL ),
580 (GtkAttachOptions) ( 0 ), 0, 0 );
581 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
584 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VERSION ) ) ) );
585 gtk_widget_show( GTK_WIDGET( label ) );
586 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 1, 2,
587 (GtkAttachOptions) ( GTK_FILL ),
588 (GtkAttachOptions) ( 0 ), 0, 0 );
589 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
592 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_RENDERER ) ) ) );
593 gtk_widget_show( GTK_WIDGET( label ) );
594 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 2, 3,
595 (GtkAttachOptions) ( GTK_FILL ),
596 (GtkAttachOptions) ( 0 ), 0, 0 );
597 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
601 GtkFrame* frame = create_dialog_frame( "OpenGL Extensions" );
602 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 );
604 GtkScrolledWindow* sc_extensions = create_scrolled_window( GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, 4 );
605 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( sc_extensions ) );
607 GtkWidget* text_extensions = gtk_text_view_new();
608 gtk_text_view_set_editable( GTK_TEXT_VIEW( text_extensions ), FALSE );
609 gtk_container_add( GTK_CONTAINER( sc_extensions ), text_extensions );
610 GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_extensions ) );
611 gtk_text_buffer_set_text( buffer, reinterpret_cast<const char*>( glGetString( GL_EXTENSIONS ) ), -1 );
612 gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text_extensions ), GTK_WRAP_WORD );
613 gtk_widget_show( text_extensions );
620 modal_dialog_show( window, dialog );
622 gtk_widget_destroy( GTK_WIDGET( window ) );
625 // =============================================================================
626 // TextureLayout dialog
628 // Last used texture scale values
629 static float last_used_texture_layout_scale_x = 4.0;
630 static float last_used_texture_layout_scale_y = 4.0;
632 EMessageBoxReturn DoTextureLayout( float *fx, float *fy ){
634 ModalDialogButton ok_button( dialog, eIDOK );
635 ModalDialogButton cancel_button( dialog, eIDCANCEL );
639 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Patch texture layout", dialog );
641 GtkAccelGroup* accel = gtk_accel_group_new();
642 gtk_window_add_accel_group( window, accel );
645 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
646 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
648 GtkVBox* vbox = create_dialog_vbox( 4 );
649 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
651 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture will be fit across the patch based\n"
652 "on the x and y values given. Values of 1x1\n"
653 "will \"fit\" the texture. 2x2 will repeat\n"
654 "it twice, etc." ) );
655 gtk_widget_show( GTK_WIDGET( label ) );
656 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), TRUE, TRUE, 0 );
657 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
660 GtkTable* table = create_dialog_table( 2, 2, 4, 4 );
661 gtk_widget_show( GTK_WIDGET( table ) );
662 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
664 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture x:" ) );
665 gtk_widget_show( GTK_WIDGET( label ) );
666 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
667 (GtkAttachOptions) ( GTK_FILL ),
668 (GtkAttachOptions) ( 0 ), 0, 0 );
669 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
672 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture y:" ) );
673 gtk_widget_show( GTK_WIDGET( label ) );
674 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
675 (GtkAttachOptions) ( GTK_FILL ),
676 (GtkAttachOptions) ( 0 ), 0, 0 );
677 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
680 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
681 gtk_widget_show( GTK_WIDGET( entry ) );
682 gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 0, 1,
683 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
684 (GtkAttachOptions) ( 0 ), 0, 0 );
689 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
690 gtk_widget_show( GTK_WIDGET( entry ) );
691 gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 1, 2,
692 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
693 (GtkAttachOptions) ( 0 ), 0, 0 );
700 GtkVBox* vbox = create_dialog_vbox( 4 );
701 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
703 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
704 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
705 widget_make_default( GTK_WIDGET( button ) );
706 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
709 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
710 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
711 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
716 // Initialize with last used values
719 sprintf( buf, "%f", last_used_texture_layout_scale_x );
720 gtk_entry_set_text( x, buf );
722 sprintf( buf, "%f", last_used_texture_layout_scale_y );
723 gtk_entry_set_text( y, buf );
725 // Set focus after intializing the values
726 gtk_widget_grab_focus( GTK_WIDGET( x ) );
728 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
729 if ( ret == eIDOK ) {
730 *fx = static_cast<float>( atof( gtk_entry_get_text( x ) ) );
731 *fy = static_cast<float>( atof( gtk_entry_get_text( y ) ) );
733 // Remember last used values
734 last_used_texture_layout_scale_x = *fx;
735 last_used_texture_layout_scale_y = *fy;
738 gtk_widget_destroy( GTK_WIDGET( window ) );
743 // =============================================================================
744 // Text Editor dialog
746 // master window widget
747 static GtkWidget *text_editor = 0;
748 static GtkWidget *text_widget; // slave, text widget from the gtk editor
749 static GtkTextBuffer* text_buffer_;
751 static gint editor_delete( GtkWidget *widget, gpointer data ){
752 /* if ( gtk_MessageBox( widget, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
756 gtk_widget_hide( text_editor );
761 static void editor_save( GtkWidget *widget, gpointer data ){
762 FILE *f = fopen( (char*)g_object_get_data( G_OBJECT( data ), "filename" ), "w" );
763 //gpointer text = g_object_get_data( G_OBJECT( data ), "text" );
766 gtk_MessageBox( GTK_WIDGET( data ), "Error saving file !" );
770 /* Obtain iters for the start and end of points of the buffer */
773 gtk_text_buffer_get_start_iter (text_buffer_, &start);
774 gtk_text_buffer_get_end_iter (text_buffer_, &end);
776 /* Get the entire buffer text. */
777 char *str = gtk_text_buffer_get_text (text_buffer_, &start, &end, FALSE);
779 //char *str = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );
780 fwrite( str, 1, strlen( str ), f );
785 static void editor_close( GtkWidget *widget, gpointer data ){
786 /* if ( gtk_MessageBox( text_editor, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
790 gtk_widget_hide( text_editor );
793 static void CreateGtkTextEditor(){
795 GtkWidget *vbox, *hbox, *button, *scr, *text;
797 dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
799 g_signal_connect( G_OBJECT( dlg ), "delete_event",
800 G_CALLBACK( editor_delete ), 0 );
801 gtk_window_set_default_size( GTK_WINDOW( dlg ), 400, 600 );
803 vbox = gtk_vbox_new( FALSE, 5 );
804 gtk_widget_show( vbox );
805 gtk_container_add( GTK_CONTAINER( dlg ), GTK_WIDGET( vbox ) );
806 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
808 scr = gtk_scrolled_window_new( 0, 0 );
809 gtk_widget_show( scr );
810 gtk_box_pack_start( GTK_BOX( vbox ), scr, TRUE, TRUE, 0 );
811 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
812 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
814 text = gtk_text_view_new();
815 gtk_container_add( GTK_CONTAINER( scr ), text );
816 gtk_widget_show( text );
817 g_object_set_data( G_OBJECT( dlg ), "text", text );
818 gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), TRUE );
820 hbox = gtk_hbox_new( FALSE, 5 );
821 gtk_widget_show( hbox );
822 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
824 button = gtk_button_new_with_label( "Close" );
825 gtk_widget_show( button );
826 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
827 g_signal_connect( G_OBJECT( button ), "clicked",
828 G_CALLBACK( editor_close ), dlg );
829 gtk_widget_set_usize( button, 60, -2 );
831 button = gtk_button_new_with_label( "Save" );
832 gtk_widget_show( button );
833 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
834 g_signal_connect( G_OBJECT( button ), "clicked",
835 G_CALLBACK( editor_save ), dlg );
836 gtk_widget_set_usize( button, 60, -2 );
842 static void DoGtkTextEditor( const char* filename, guint cursorpos, int length ){
843 if ( !text_editor ) {
844 CreateGtkTextEditor(); // build it the first time we need it
848 FILE *f = fopen( filename, "r" );
851 globalOutputStream() << "Unable to load file " << filename << " in shader editor.\n";
852 gtk_widget_hide( text_editor );
856 fseek( f, 0, SEEK_END );
857 int len = ftell( f );
858 void *buf = malloc( len );
862 fread( buf, 1, len, f );
864 gtk_window_set_title( GTK_WINDOW( text_editor ), filename );
866 GtkTextBuffer* text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_widget ) );
867 gtk_text_buffer_set_text( text_buffer, (char*)buf, length );
869 old_filename = g_object_get_data( G_OBJECT( text_editor ), "filename" );
870 if ( old_filename ) {
871 free( old_filename );
873 g_object_set_data( G_OBJECT( text_editor ), "filename", strdup( filename ) );
875 // trying to show later
876 gtk_widget_show( text_editor );
877 gtk_window_present( GTK_WINDOW( text_editor ) );
883 // only move the cursor if it's not exceeding the size..
884 // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters
885 // len is the max size in bytes, not in characters either, but the character count is below that limit..
886 // thinking .. the difference between character count and byte count would be only because of CR/LF?
888 GtkTextIter text_iter;
889 // character offset, not byte offset
890 gtk_text_buffer_get_iter_at_offset( text_buffer, &text_iter, cursorpos );
891 gtk_text_buffer_place_cursor( text_buffer, &text_iter );
892 gtk_text_view_scroll_to_iter( GTK_TEXT_VIEW( text_widget ), &text_iter, 0, TRUE, 0, 0);
896 gtk_widget_queue_draw( text_widget );
899 text_buffer_ = text_buffer;
905 // =============================================================================
906 // Light Intensity dialog
908 EMessageBoxReturn DoLightIntensityDlg( int *intensity ){
910 GtkEntry* intensity_entry;
911 ModalDialogButton ok_button( dialog, eIDOK );
912 ModalDialogButton cancel_button( dialog, eIDCANCEL );
914 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Light intensity", dialog, -1, -1 );
916 GtkAccelGroup *accel_group = gtk_accel_group_new();
917 gtk_window_add_accel_group( window, accel_group );
920 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
921 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
923 GtkVBox* vbox = create_dialog_vbox( 4 );
924 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
926 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC for default, ENTER to validate" ) );
927 gtk_widget_show( GTK_WIDGET( label ) );
928 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
931 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
932 gtk_widget_show( GTK_WIDGET( entry ) );
933 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
935 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
937 intensity_entry = entry;
941 GtkVBox* vbox = create_dialog_vbox( 4 );
942 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
945 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
946 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
947 widget_make_default( GTK_WIDGET( button ) );
948 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
951 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
952 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
953 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
959 sprintf( buf, "%d", *intensity );
960 gtk_entry_set_text( intensity_entry, buf );
962 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
963 if ( ret == eIDOK ) {
964 *intensity = atoi( gtk_entry_get_text( intensity_entry ) );
967 gtk_widget_destroy( GTK_WIDGET( window ) );
972 // =============================================================================
973 // Add new shader tag dialog
975 EMessageBoxReturn DoShaderTagDlg( CopiedString* tag, char* title ){
978 ModalDialogButton ok_button( dialog, eIDOK );
979 ModalDialogButton cancel_button( dialog, eIDCANCEL );
981 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
983 GtkAccelGroup *accel_group = gtk_accel_group_new();
984 gtk_window_add_accel_group( window, accel_group );
987 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
988 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
990 GtkVBox* vbox = create_dialog_vbox( 4 );
991 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
993 //GtkLabel* label = GTK_LABEL(gtk_label_new("Enter one ore more tags separated by spaces"));
994 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC to cancel, ENTER to validate" ) );
995 gtk_widget_show( GTK_WIDGET( label ) );
996 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
999 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
1000 gtk_widget_show( GTK_WIDGET( entry ) );
1001 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
1003 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
1009 GtkVBox* vbox = create_dialog_vbox( 4 );
1010 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
1013 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
1014 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1015 widget_make_default( GTK_WIDGET( button ) );
1016 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1019 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
1020 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1021 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1026 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
1027 if ( ret == eIDOK ) {
1028 *tag = gtk_entry_get_text( textentry );
1031 gtk_widget_destroy( GTK_WIDGET( window ) );
1036 EMessageBoxReturn DoShaderInfoDlg( const char* name, const char* filename, char* title ){
1038 ModalDialogButton ok_button( dialog, eIDOK );
1040 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
1042 GtkAccelGroup *accel_group = gtk_accel_group_new();
1043 gtk_window_add_accel_group( window, accel_group );
1046 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
1047 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
1049 GtkVBox* vbox = create_dialog_vbox( 4 );
1050 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
1052 GtkLabel* label = GTK_LABEL( gtk_label_new( "The selected shader" ) );
1053 gtk_widget_show( GTK_WIDGET( label ) );
1054 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1057 GtkLabel* label = GTK_LABEL( gtk_label_new( name ) );
1058 gtk_widget_show( GTK_WIDGET( label ) );
1059 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1062 GtkLabel* label = GTK_LABEL( gtk_label_new( "is located in file" ) );
1063 gtk_widget_show( GTK_WIDGET( label ) );
1064 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1067 GtkLabel* label = GTK_LABEL( gtk_label_new( filename ) );
1068 gtk_widget_show( GTK_WIDGET( label ) );
1069 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1072 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
1073 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1074 widget_make_default( GTK_WIDGET( button ) );
1075 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1080 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
1082 gtk_widget_destroy( GTK_WIDGET( window ) );
1090 #include <gdk/gdkwin32.h>
1094 // use the file associations to open files instead of builtin Gtk editor
1095 bool g_TextEditor_useWin32Editor = false;
1097 // custom shader editor
1098 bool g_TextEditor_useCustomEditor = false;
1099 CopiedString g_TextEditor_editorCommand( "" );
1102 void DoTextEditor( const char* filename, int cursorpos, int length ){
1104 if ( g_TextEditor_useWin32Editor ) {
1105 StringOutputStream path( 256 );
1106 StringOutputStream modpath( 256 );
1107 const char* gamename = GlobalRadiant().getGameName();
1108 const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue( "basegame" );
1109 const char* enginePath = GlobalRadiant().getEnginePath();
1110 path << enginePath << basegame << '/' << filename;
1111 modpath << enginePath << gamename << '/' << filename;
1112 if ( file_exists( modpath.c_str() ) ){
1113 globalOutputStream() << "opening file '" << modpath.c_str() << "' (line " << cursorpos << " info ignored)\n";
1114 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", modpath.c_str(), 0, 0, SW_SHOW );
1116 else if ( file_exists( path.c_str() ) ){
1117 globalOutputStream() << "opening file '" << path.c_str() << "' (line " << cursorpos << " info ignored)\n";
1118 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", path.c_str(), 0, 0, SW_SHOW );
1121 globalOutputStream() << "Failed to open '" << filename << "'\nOne sits in .pk3 most likely!\n";
1126 StringOutputStream path( 256 );
1127 StringOutputStream modpath( 256 );
1128 const char* gamename = GlobalRadiant().getGameName();
1129 const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue( "basegame" );
1130 const char* enginePath = GlobalRadiant().getEnginePath();
1131 path << enginePath << basegame << '/' << filename;
1132 modpath << enginePath << gamename << '/' << filename;
1133 if ( file_exists( modpath.c_str() ) ){
1134 globalOutputStream() << "opening file '" << modpath.c_str() << "' (line " << cursorpos << " info ignored)\n";
1135 DoGtkTextEditor( modpath.c_str(), cursorpos, length );
1137 else if ( file_exists( path.c_str() ) ){
1138 globalOutputStream() << "opening file '" << path.c_str() << "' (line " << cursorpos << " info ignored)\n";
1139 DoGtkTextEditor( path.c_str(), cursorpos, length );
1142 globalOutputStream() << "Failed to open '" << filename << "'\nOne sits in .pk3 most likely!\n";
1147 // check if a custom editor is set
1148 if ( g_TextEditor_useCustomEditor && !g_TextEditor_editorCommand.empty() ) {
1149 StringOutputStream strEditCommand( 256 );
1150 strEditCommand << g_TextEditor_editorCommand.c_str() << " \"" << filename << "\"";
1152 globalOutputStream() << "Launching: " << strEditCommand.c_str() << "\n";
1153 // note: linux does not return false if the command failed so it will assume success
1154 if ( Q_Exec( 0, const_cast<char*>( strEditCommand.c_str() ), 0, true, false ) == false ) {
1155 globalOutputStream() << "Failed to execute " << strEditCommand.c_str() << ", using default\n";
1159 // the command (appeared) to run successfully, no need to do anything more
1164 DoGtkTextEditor( filename, cursorpos, length );