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>
66 #include "math/aabb.h"
67 #include "container/array.h"
68 #include "generic/static.h"
69 #include "stream/stringstream.h"
71 #include "gtkutil/messagebox.h"
72 #include "gtkutil/image.h"
75 #include "brushmanip.h"
78 #include "texwindow.h"
80 #include "mainframe.h"
81 #include "preferences.h"
85 #include "qerplugin.h"
90 // =============================================================================
91 // Project settings dialog
93 class GameComboConfiguration
96 const char* basegame_dir;
98 const char* known_dir;
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" ) ){
111 typedef LazyStatic<GameComboConfiguration> LazyStaticGameComboConfiguration;
113 inline GameComboConfiguration& globalGameComboConfiguration(){
114 return LazyStaticGameComboConfiguration::instance();
120 gamecombo_t( int _game, const char* _fs_game, bool _sensitive )
121 : game( _game ), fs_game( _fs_game ), sensitive( _sensitive )
128 gamecombo_t gamecombo_for_dir( const char* dir ){
129 if ( string_equal( dir, globalGameComboConfiguration().basegame_dir ) ) {
130 return gamecombo_t( 0, "", false );
132 else if ( string_equal( dir, globalGameComboConfiguration().known_dir ) ) {
133 return gamecombo_t( 1, dir, false );
137 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, dir, true );
141 gamecombo_t gamecombo_for_gamename( const char* gamename ){
142 if ( ( strlen( gamename ) == 0 ) || !strcmp( gamename, globalGameComboConfiguration().basegame ) ) {
143 return gamecombo_t( 0, "", false );
145 else if ( !strcmp( gamename, globalGameComboConfiguration().known ) ) {
146 return gamecombo_t( 1, globalGameComboConfiguration().known_dir, false );
150 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, "", true );
154 inline void path_copy_clean( char* destination, const char* source ){
155 char* i = destination;
157 while ( *source != '\0' )
159 *i++ = ( *source == '\\' ) ? '/' : *source;
163 if ( i != destination && *( i - 1 ) != '/' ) {
173 GtkComboBox* game_select;
174 GtkEntry* fsgame_entry;
177 gboolean OnSelchangeComboWhatgame( GtkWidget *widget, GameCombo* combo ){
178 const char *gamename;
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 );
185 gamecombo_t gamecombo = gamecombo_for_gamename( gamename );
187 gtk_entry_set_text( combo->fsgame_entry, gamecombo.fs_game );
188 gtk_widget_set_sensitive( GTK_WIDGET( combo->fsgame_entry ), gamecombo.sensitive );
196 bool do_mapping_mode;
197 const char* sp_mapping_mode;
198 const char* mp_mapping_mode;
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" ){
207 typedef LazyStatic<MappingMode> LazyStaticMappingMode;
209 inline MappingMode& globalMappingMode(){
210 return LazyStaticMappingMode::instance();
213 class ProjectSettingsDialog
216 GameCombo game_combo;
217 GtkComboBox* gamemode_combo;
220 GtkWindow* ProjectSettingsDialog_construct( ProjectSettingsDialog& dialog, ModalDialog& modal ){
221 GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Project Settings", G_CALLBACK( dialog_delete_callback ), &modal );
224 GtkTable* table1 = create_dialog_table( 1, 2, 4, 4, 4 );
225 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( table1 ) );
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 );
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 );
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 );
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 );
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 ) );
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 );
258 dialog.game_combo.game_select = GTK_COMBO_BOX( gtk_combo_box_new_text() );
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 );
264 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().custom );
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 );
271 g_signal_connect( G_OBJECT( dialog.game_combo.game_select ), "changed", G_CALLBACK( OnSelchangeComboWhatgame ), &dialog.game_combo );
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 );
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 );
289 dialog.game_combo.fsgame_entry = entry;
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 );
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 );
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 );
309 dialog.gamemode_combo = combo;
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 );
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 );
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 );
330 gtk_combo_box_set_active( dialog.gamemode_combo, 1 );
337 void ProjectSettingsDialog_ok( ProjectSettingsDialog& dialog ){
338 const char* dir = gtk_entry_get_text( dialog.game_combo.fsgame_entry );
340 const char* new_gamename = path_equal( dir, globalGameComboConfiguration().basegame_dir )
344 if ( !path_equal( new_gamename, gamename_get() ) ) {
345 ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Changing Game Name" );
347 EnginePath_Unrealise();
349 gamename_set( new_gamename );
351 EnginePath_Realise();
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" );
362 gamemode_set( "mp" );
367 void DoProjectSettings(){
368 //if ( ConfirmModified( "Edit Project Settings" ) ) {
370 ProjectSettingsDialog dialog;
372 GtkWindow* window = ProjectSettingsDialog_construct( dialog, modal );
374 if ( modal_dialog_show( window, modal ) == eIDOK ) {
375 ProjectSettingsDialog_ok( dialog );
378 gtk_widget_destroy( GTK_WIDGET( window ) );
382 // =============================================================================
383 // Arbitrary Sides dialog
385 void DoSides( int type, int axis ){
387 GtkEntry* sides_entry;
389 GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Arbitrary sides", G_CALLBACK( dialog_delete_callback ), &dialog );
391 GtkAccelGroup* accel = gtk_accel_group_new();
392 gtk_window_add_accel_group( window, accel );
395 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
396 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
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 );
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 );
407 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
410 GtkVBox* vbox = create_dialog_vbox( 4 );
411 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
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 );
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 );
426 if ( modal_dialog_show( window, dialog ) == eIDOK ) {
427 const char *str = gtk_entry_get_text( sides_entry );
429 Scene_BrushConstructPrefab( GlobalSceneGraph(), (EBrushPrefab)type, atoi( str ), TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ) );
432 gtk_widget_destroy( GTK_WIDGET( window ) );
435 // =============================================================================
436 // About dialog (no program is complete without one)
438 void about_button_changelog( GtkWidget *widget, gpointer data ){
439 StringOutputStream log( 256 );
440 log << AppPath_get() << "changelog.txt";
441 OpenURL( log.c_str() );
444 void about_button_credits( GtkWidget *widget, gpointer data ){
445 StringOutputStream cred( 256 );
446 cred << AppPath_get() << "credits.html";
447 OpenURL( cred.c_str() );
452 ModalDialogButton ok_button( dialog, eIDOK );
454 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "About NetRadiant", dialog );
457 GtkVBox* vbox = create_dialog_vbox( 4, 4 );
458 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) );
461 GtkHBox* hbox = create_dialog_hbox( 4 );
462 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
465 GtkVBox* vbox2 = create_dialog_vbox( 4 );
466 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), TRUE, FALSE, 0 );
468 GtkFrame* frame = create_dialog_frame( 0, GTK_SHADOW_IN );
469 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
471 GtkImage* image = new_local_image( "logo.bmp" );
472 gtk_widget_show( GTK_WIDGET( image ) );
473 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( image ) );
479 GtkLabel* label = GTK_LABEL( gtk_label_new( "NetRadiant " RADIANT_VERSION "\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"
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 );
494 GtkVBox* vbox2 = create_dialog_vbox( 4 );
495 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), FALSE, TRUE, 0 );
497 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
498 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
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 );
505 GtkButton* button = create_dialog_button( "Changelog", G_CALLBACK( about_button_changelog ), 0 );
506 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
511 GtkFrame* frame = create_dialog_frame( "OpenGL Properties" );
512 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
514 GtkTable* table = create_dialog_table( 3, 2, 4, 4, 4 );
515 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table ) );
517 GtkLabel* label = GTK_LABEL( gtk_label_new( "Vendor:" ) );
518 gtk_widget_show( GTK_WIDGET( label ) );
519 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
520 (GtkAttachOptions) ( GTK_FILL ),
521 (GtkAttachOptions) ( 0 ), 0, 0 );
522 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
525 GtkLabel* label = GTK_LABEL( gtk_label_new( "Version:" ) );
526 gtk_widget_show( GTK_WIDGET( label ) );
527 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
528 (GtkAttachOptions) ( GTK_FILL ),
529 (GtkAttachOptions) ( 0 ), 0, 0 );
530 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
533 GtkLabel* label = GTK_LABEL( gtk_label_new( "Renderer:" ) );
534 gtk_widget_show( GTK_WIDGET( label ) );
535 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 2, 3,
536 (GtkAttachOptions) ( GTK_FILL ),
537 (GtkAttachOptions) ( 0 ), 0, 0 );
538 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
541 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VENDOR ) ) ) );
542 gtk_widget_show( GTK_WIDGET( label ) );
543 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 0, 1,
544 (GtkAttachOptions) ( GTK_FILL ),
545 (GtkAttachOptions) ( 0 ), 0, 0 );
546 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
549 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VERSION ) ) ) );
550 gtk_widget_show( GTK_WIDGET( label ) );
551 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 1, 2,
552 (GtkAttachOptions) ( GTK_FILL ),
553 (GtkAttachOptions) ( 0 ), 0, 0 );
554 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
557 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_RENDERER ) ) ) );
558 gtk_widget_show( GTK_WIDGET( label ) );
559 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 2, 3,
560 (GtkAttachOptions) ( GTK_FILL ),
561 (GtkAttachOptions) ( 0 ), 0, 0 );
562 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
566 GtkFrame* frame = create_dialog_frame( "OpenGL Extensions" );
567 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 );
569 GtkScrolledWindow* sc_extensions = create_scrolled_window( GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, 4 );
570 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( sc_extensions ) );
572 GtkWidget* text_extensions = gtk_text_view_new();
573 gtk_text_view_set_editable( GTK_TEXT_VIEW( text_extensions ), FALSE );
574 gtk_container_add( GTK_CONTAINER( sc_extensions ), text_extensions );
575 GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_extensions ) );
576 gtk_text_buffer_set_text( buffer, reinterpret_cast<const char*>( glGetString( GL_EXTENSIONS ) ), -1 );
577 gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text_extensions ), GTK_WRAP_WORD );
578 gtk_widget_show( text_extensions );
585 modal_dialog_show( window, dialog );
587 gtk_widget_destroy( GTK_WIDGET( window ) );
590 // =============================================================================
591 // TextureLayout dialog
593 // Last used texture scale values
594 static float last_used_texture_layout_scale_x = 4.0;
595 static float last_used_texture_layout_scale_y = 4.0;
597 EMessageBoxReturn DoTextureLayout( float *fx, float *fy ){
599 ModalDialogButton ok_button( dialog, eIDOK );
600 ModalDialogButton cancel_button( dialog, eIDCANCEL );
604 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Patch texture layout", dialog );
606 GtkAccelGroup* accel = gtk_accel_group_new();
607 gtk_window_add_accel_group( window, accel );
610 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
611 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
613 GtkVBox* vbox = create_dialog_vbox( 4 );
614 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
616 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture will be fit across the patch based\n"
617 "on the x and y values given. Values of 1x1\n"
618 "will \"fit\" the texture. 2x2 will repeat\n"
619 "it twice, etc." ) );
620 gtk_widget_show( GTK_WIDGET( label ) );
621 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), TRUE, TRUE, 0 );
622 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
625 GtkTable* table = create_dialog_table( 2, 2, 4, 4 );
626 gtk_widget_show( GTK_WIDGET( table ) );
627 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
629 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture x:" ) );
630 gtk_widget_show( GTK_WIDGET( label ) );
631 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
632 (GtkAttachOptions) ( GTK_FILL ),
633 (GtkAttachOptions) ( 0 ), 0, 0 );
634 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
637 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture y:" ) );
638 gtk_widget_show( GTK_WIDGET( label ) );
639 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
640 (GtkAttachOptions) ( GTK_FILL ),
641 (GtkAttachOptions) ( 0 ), 0, 0 );
642 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
645 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
646 gtk_widget_show( GTK_WIDGET( entry ) );
647 gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 0, 1,
648 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
649 (GtkAttachOptions) ( 0 ), 0, 0 );
654 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
655 gtk_widget_show( GTK_WIDGET( entry ) );
656 gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 1, 2,
657 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
658 (GtkAttachOptions) ( 0 ), 0, 0 );
665 GtkVBox* vbox = create_dialog_vbox( 4 );
666 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
668 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
669 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
670 widget_make_default( GTK_WIDGET( button ) );
671 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
674 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
675 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
676 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
681 // Initialize with last used values
684 sprintf( buf, "%f", last_used_texture_layout_scale_x );
685 gtk_entry_set_text( x, buf );
687 sprintf( buf, "%f", last_used_texture_layout_scale_y );
688 gtk_entry_set_text( y, buf );
690 // Set focus after intializing the values
691 gtk_widget_grab_focus( GTK_WIDGET( x ) );
693 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
694 if ( ret == eIDOK ) {
695 *fx = static_cast<float>( atof( gtk_entry_get_text( x ) ) );
696 *fy = static_cast<float>( atof( gtk_entry_get_text( y ) ) );
698 // Remember last used values
699 last_used_texture_layout_scale_x = *fx;
700 last_used_texture_layout_scale_y = *fy;
703 gtk_widget_destroy( GTK_WIDGET( window ) );
708 // =============================================================================
709 // Text Editor dialog
711 // master window widget
712 static GtkWidget *text_editor = 0;
713 static GtkWidget *text_widget; // slave, text widget from the gtk editor
714 static GtkTextBuffer* text_buffer_;
716 static gint editor_delete( GtkWidget *widget, gpointer data ){
717 /* if ( gtk_MessageBox( widget, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
721 gtk_widget_hide( text_editor );
726 static void editor_save( GtkWidget *widget, gpointer data ){
727 FILE *f = fopen( (char*)g_object_get_data( G_OBJECT( data ), "filename" ), "w" );
728 //gpointer text = g_object_get_data( G_OBJECT( data ), "text" );
731 gtk_MessageBox( GTK_WIDGET( data ), "Error saving file !" );
735 /* Obtain iters for the start and end of points of the buffer */
738 gtk_text_buffer_get_start_iter (text_buffer_, &start);
739 gtk_text_buffer_get_end_iter (text_buffer_, &end);
741 /* Get the entire buffer text. */
742 char *str = gtk_text_buffer_get_text (text_buffer_, &start, &end, FALSE);
744 //char *str = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );
745 fwrite( str, 1, strlen( str ), f );
750 static void editor_close( GtkWidget *widget, gpointer data ){
751 /* if ( gtk_MessageBox( text_editor, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
755 gtk_widget_hide( text_editor );
758 static void CreateGtkTextEditor(){
760 GtkWidget *vbox, *hbox, *button, *scr, *text;
762 dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
764 g_signal_connect( G_OBJECT( dlg ), "delete_event",
765 G_CALLBACK( editor_delete ), 0 );
766 gtk_window_set_default_size( GTK_WINDOW( dlg ), 400, 600 );
768 vbox = gtk_vbox_new( FALSE, 5 );
769 gtk_widget_show( vbox );
770 gtk_container_add( GTK_CONTAINER( dlg ), GTK_WIDGET( vbox ) );
771 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
773 scr = gtk_scrolled_window_new( 0, 0 );
774 gtk_widget_show( scr );
775 gtk_box_pack_start( GTK_BOX( vbox ), scr, TRUE, TRUE, 0 );
776 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
777 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
779 text = gtk_text_view_new();
780 gtk_container_add( GTK_CONTAINER( scr ), text );
781 gtk_widget_show( text );
782 g_object_set_data( G_OBJECT( dlg ), "text", text );
783 gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), TRUE );
785 hbox = gtk_hbox_new( FALSE, 5 );
786 gtk_widget_show( hbox );
787 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
789 button = gtk_button_new_with_label( "Close" );
790 gtk_widget_show( button );
791 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
792 g_signal_connect( G_OBJECT( button ), "clicked",
793 G_CALLBACK( editor_close ), dlg );
794 gtk_widget_set_usize( button, 60, -2 );
796 button = gtk_button_new_with_label( "Save" );
797 gtk_widget_show( button );
798 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
799 g_signal_connect( G_OBJECT( button ), "clicked",
800 G_CALLBACK( editor_save ), dlg );
801 gtk_widget_set_usize( button, 60, -2 );
807 static void DoGtkTextEditor( const char* filename, guint cursorpos, int length ){
808 if ( !text_editor ) {
809 CreateGtkTextEditor(); // build it the first time we need it
813 FILE *f = fopen( filename, "r" );
816 globalOutputStream() << "Unable to load file " << filename << " in shader editor.\n";
817 gtk_widget_hide( text_editor );
821 fseek( f, 0, SEEK_END );
822 int len = ftell( f );
823 void *buf = malloc( len );
827 fread( buf, 1, len, f );
829 gtk_window_set_title( GTK_WINDOW( text_editor ), filename );
831 GtkTextBuffer* text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_widget ) );
832 gtk_text_buffer_set_text( text_buffer, (char*)buf, length );
834 old_filename = g_object_get_data( G_OBJECT( text_editor ), "filename" );
835 if ( old_filename ) {
836 free( old_filename );
838 g_object_set_data( G_OBJECT( text_editor ), "filename", strdup( filename ) );
840 // trying to show later
841 gtk_widget_show( text_editor );
847 // only move the cursor if it's not exceeding the size..
848 // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters
849 // len is the max size in bytes, not in characters either, but the character count is below that limit..
850 // thinking .. the difference between character count and byte count would be only because of CR/LF?
852 GtkTextIter text_iter;
853 // character offset, not byte offset
854 gtk_text_buffer_get_iter_at_offset( text_buffer, &text_iter, cursorpos );
855 gtk_text_buffer_place_cursor( text_buffer, &text_iter );
856 gtk_text_view_scroll_to_iter( GTK_TEXT_VIEW( text_widget ), &text_iter, 0, TRUE, 0, 0);
860 gtk_widget_queue_draw( text_widget );
863 text_buffer_ = text_buffer;
869 // =============================================================================
870 // Light Intensity dialog
872 EMessageBoxReturn DoLightIntensityDlg( int *intensity ){
874 GtkEntry* intensity_entry;
875 ModalDialogButton ok_button( dialog, eIDOK );
876 ModalDialogButton cancel_button( dialog, eIDCANCEL );
878 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Light intensity", dialog, -1, -1 );
880 GtkAccelGroup *accel_group = gtk_accel_group_new();
881 gtk_window_add_accel_group( window, accel_group );
884 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
885 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
887 GtkVBox* vbox = create_dialog_vbox( 4 );
888 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
890 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC for default, ENTER to validate" ) );
891 gtk_widget_show( GTK_WIDGET( label ) );
892 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
895 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
896 gtk_widget_show( GTK_WIDGET( entry ) );
897 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
899 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
901 intensity_entry = entry;
905 GtkVBox* vbox = create_dialog_vbox( 4 );
906 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
909 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
910 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
911 widget_make_default( GTK_WIDGET( button ) );
912 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
915 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
916 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
917 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
923 sprintf( buf, "%d", *intensity );
924 gtk_entry_set_text( intensity_entry, buf );
926 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
927 if ( ret == eIDOK ) {
928 *intensity = atoi( gtk_entry_get_text( intensity_entry ) );
931 gtk_widget_destroy( GTK_WIDGET( window ) );
936 // =============================================================================
937 // Add new shader tag dialog
939 EMessageBoxReturn DoShaderTagDlg( CopiedString* tag, char* title ){
942 ModalDialogButton ok_button( dialog, eIDOK );
943 ModalDialogButton cancel_button( dialog, eIDCANCEL );
945 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
947 GtkAccelGroup *accel_group = gtk_accel_group_new();
948 gtk_window_add_accel_group( window, accel_group );
951 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
952 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
954 GtkVBox* vbox = create_dialog_vbox( 4 );
955 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
957 //GtkLabel* label = GTK_LABEL(gtk_label_new("Enter one ore more tags separated by spaces"));
958 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC to cancel, ENTER to validate" ) );
959 gtk_widget_show( GTK_WIDGET( label ) );
960 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
963 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
964 gtk_widget_show( GTK_WIDGET( entry ) );
965 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
967 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
973 GtkVBox* vbox = create_dialog_vbox( 4 );
974 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
977 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
978 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
979 widget_make_default( GTK_WIDGET( button ) );
980 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
983 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
984 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
985 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
990 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
991 if ( ret == eIDOK ) {
992 *tag = gtk_entry_get_text( textentry );
995 gtk_widget_destroy( GTK_WIDGET( window ) );
1000 EMessageBoxReturn DoShaderInfoDlg( const char* name, const char* filename, char* title ){
1002 ModalDialogButton ok_button( dialog, eIDOK );
1004 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
1006 GtkAccelGroup *accel_group = gtk_accel_group_new();
1007 gtk_window_add_accel_group( window, accel_group );
1010 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
1011 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
1013 GtkVBox* vbox = create_dialog_vbox( 4 );
1014 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
1016 GtkLabel* label = GTK_LABEL( gtk_label_new( "The selected shader" ) );
1017 gtk_widget_show( GTK_WIDGET( label ) );
1018 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1021 GtkLabel* label = GTK_LABEL( gtk_label_new( name ) );
1022 gtk_widget_show( GTK_WIDGET( label ) );
1023 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1026 GtkLabel* label = GTK_LABEL( gtk_label_new( "is located in file" ) );
1027 gtk_widget_show( GTK_WIDGET( label ) );
1028 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1031 GtkLabel* label = GTK_LABEL( gtk_label_new( filename ) );
1032 gtk_widget_show( GTK_WIDGET( label ) );
1033 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1036 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
1037 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1038 widget_make_default( GTK_WIDGET( button ) );
1039 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1044 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
1046 gtk_widget_destroy( GTK_WIDGET( window ) );
1054 #include <gdk/gdkwin32.h>
1058 // use the file associations to open files instead of builtin Gtk editor
1059 bool g_TextEditor_useWin32Editor = false;
1061 // custom shader editor
1062 bool g_TextEditor_useCustomEditor = false;
1063 CopiedString g_TextEditor_editorCommand( "" );
1066 void DoTextEditor( const char* filename, int cursorpos, int length ){
1068 if ( g_TextEditor_useWin32Editor ) {
1069 StringOutputStream path( 256 );
1070 StringOutputStream modpath( 256 );
1071 const char* gamename = GlobalRadiant().getGameName();
1072 const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue( "basegame" );
1073 const char* enginePath = GlobalRadiant().getEnginePath();
1074 path << enginePath << basegame << '/' << filename;
1075 modpath << enginePath << gamename << '/' << filename;
1076 if ( file_exists( modpath.c_str() ) ){
1077 globalOutputStream() << "opening file '" << modpath.c_str() << "' (line " << cursorpos << " info ignored)\n";
1078 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", modpath.c_str(), 0, 0, SW_SHOW );
1080 else if ( file_exists( path.c_str() ) ){
1081 globalOutputStream() << "opening file '" << path.c_str() << "' (line " << cursorpos << " info ignored)\n";
1082 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", path.c_str(), 0, 0, SW_SHOW );
1085 globalOutputStream() << "Failed to open '" << filename << "\n";
1090 StringOutputStream path( 256 );
1091 StringOutputStream modpath( 256 );
1092 const char* gamename = GlobalRadiant().getGameName();
1093 const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue( "basegame" );
1094 const char* enginePath = GlobalRadiant().getEnginePath();
1095 path << enginePath << basegame << '/' << filename;
1096 modpath << enginePath << gamename << '/' << filename;
1097 if ( file_exists( modpath.c_str() ) ){
1098 globalOutputStream() << "opening file '" << modpath.c_str() << "' (line " << cursorpos << " info ignored)\n";
1099 DoGtkTextEditor( modpath.c_str(), cursorpos, length );
1101 else if ( file_exists( path.c_str() ) ){
1102 globalOutputStream() << "opening file '" << path.c_str() << "' (line " << cursorpos << " info ignored)\n";
1103 DoGtkTextEditor( path.c_str(), cursorpos, length );
1106 globalOutputStream() << "Failed to open '" << filename << "\n";
1111 // check if a custom editor is set
1112 if ( g_TextEditor_useCustomEditor && !g_TextEditor_editorCommand.empty() ) {
1113 StringOutputStream strEditCommand( 256 );
1114 strEditCommand << g_TextEditor_editorCommand.c_str() << " \"" << filename << "\"";
1116 globalOutputStream() << "Launching: " << strEditCommand.c_str() << "\n";
1117 // note: linux does not return false if the command failed so it will assume success
1118 if ( Q_Exec( 0, const_cast<char*>( strEditCommand.c_str() ), 0, true, false ) == false ) {
1119 globalOutputStream() << "Failed to execute " << strEditCommand.c_str() << ", using default\n";
1123 // the command (appeared) to run successfully, no need to do anything more
1128 DoGtkTextEditor( filename, cursorpos, length );