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"
87 // =============================================================================
88 // Project settings dialog
90 class GameComboConfiguration
93 const char* basegame_dir;
95 const char* known_dir;
99 GameComboConfiguration() :
100 basegame_dir( g_pGameDescription->getRequiredKeyValue( "basegame" ) ),
101 basegame( g_pGameDescription->getRequiredKeyValue( "basegamename" ) ),
102 known_dir( g_pGameDescription->getKeyValue( "knowngame" ) ),
103 known( g_pGameDescription->getKeyValue( "knowngamename" ) ),
104 custom( g_pGameDescription->getRequiredKeyValue( "unknowngamename" ) ){
108 typedef LazyStatic<GameComboConfiguration> LazyStaticGameComboConfiguration;
110 inline GameComboConfiguration& globalGameComboConfiguration(){
111 return LazyStaticGameComboConfiguration::instance();
117 gamecombo_t( int _game, const char* _fs_game, bool _sensitive )
118 : game( _game ), fs_game( _fs_game ), sensitive( _sensitive )
125 gamecombo_t gamecombo_for_dir( const char* dir ){
126 if ( string_equal( dir, globalGameComboConfiguration().basegame_dir ) ) {
127 return gamecombo_t( 0, "", false );
129 else if ( string_equal( dir, globalGameComboConfiguration().known_dir ) ) {
130 return gamecombo_t( 1, dir, false );
134 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, dir, true );
138 gamecombo_t gamecombo_for_gamename( const char* gamename ){
139 if ( ( strlen( gamename ) == 0 ) || !strcmp( gamename, globalGameComboConfiguration().basegame ) ) {
140 return gamecombo_t( 0, "", false );
142 else if ( !strcmp( gamename, globalGameComboConfiguration().known ) ) {
143 return gamecombo_t( 1, globalGameComboConfiguration().known_dir, false );
147 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, "", true );
151 inline void path_copy_clean( char* destination, const char* source ){
152 char* i = destination;
154 while ( *source != '\0' )
156 *i++ = ( *source == '\\' ) ? '/' : *source;
160 if ( i != destination && *( i - 1 ) != '/' ) {
170 GtkComboBox* game_select;
171 GtkEntry* fsgame_entry;
174 gboolean OnSelchangeComboWhatgame( GtkWidget *widget, GameCombo* combo ){
175 const char *gamename;
178 gtk_combo_box_get_active_iter( combo->game_select, &iter );
179 gtk_tree_model_get( gtk_combo_box_get_model( combo->game_select ), &iter, 0, (gpointer*)&gamename, -1 );
182 gamecombo_t gamecombo = gamecombo_for_gamename( gamename );
184 gtk_entry_set_text( combo->fsgame_entry, gamecombo.fs_game );
185 gtk_widget_set_sensitive( GTK_WIDGET( combo->fsgame_entry ), gamecombo.sensitive );
193 bool do_mapping_mode;
194 const char* sp_mapping_mode;
195 const char* mp_mapping_mode;
198 do_mapping_mode( !string_empty( g_pGameDescription->getKeyValue( "show_gamemode" ) ) ),
199 sp_mapping_mode( "Single Player mapping mode" ),
200 mp_mapping_mode( "Multiplayer mapping mode" ){
204 typedef LazyStatic<MappingMode> LazyStaticMappingMode;
206 inline MappingMode& globalMappingMode(){
207 return LazyStaticMappingMode::instance();
210 class ProjectSettingsDialog
213 GameCombo game_combo;
214 GtkComboBox* gamemode_combo;
217 GtkWindow* ProjectSettingsDialog_construct( ProjectSettingsDialog& dialog, ModalDialog& modal ){
218 GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Project Settings", G_CALLBACK( dialog_delete_callback ), &modal );
221 GtkTable* table1 = create_dialog_table( 1, 2, 4, 4, 4 );
222 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( table1 ) );
224 GtkVBox* vbox = create_dialog_vbox( 4 );
225 gtk_table_attach( table1, GTK_WIDGET( vbox ), 1, 2, 0, 1,
226 (GtkAttachOptions) ( GTK_FILL ),
227 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
229 GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &modal );
230 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
233 GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &modal );
234 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
238 GtkFrame* frame = create_dialog_frame( "Project settings" );
239 gtk_table_attach( table1, GTK_WIDGET( frame ), 0, 1, 0, 1,
240 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
241 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
243 GtkTable* table2 = create_dialog_table( ( globalMappingMode().do_mapping_mode ) ? 4 : 3, 2, 4, 4, 4 );
244 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table2 ) );
247 GtkLabel* label = GTK_LABEL( gtk_label_new( "Select mod" ) );
248 gtk_widget_show( GTK_WIDGET( label ) );
249 gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 0, 1,
250 (GtkAttachOptions) ( GTK_FILL ),
251 (GtkAttachOptions) ( 0 ), 0, 0 );
252 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
255 dialog.game_combo.game_select = GTK_COMBO_BOX( gtk_combo_box_new_text() );
257 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().basegame );
258 if ( globalGameComboConfiguration().known[0] != '\0' ) {
259 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().known );
261 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().custom );
263 gtk_widget_show( GTK_WIDGET( dialog.game_combo.game_select ) );
264 gtk_table_attach( table2, GTK_WIDGET( dialog.game_combo.game_select ), 1, 2, 0, 1,
265 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
266 (GtkAttachOptions) ( 0 ), 0, 0 );
268 g_signal_connect( G_OBJECT( dialog.game_combo.game_select ), "changed", G_CALLBACK( OnSelchangeComboWhatgame ), &dialog.game_combo );
272 GtkLabel* label = GTK_LABEL( gtk_label_new( "fs_game" ) );
273 gtk_widget_show( GTK_WIDGET( label ) );
274 gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 1, 2,
275 (GtkAttachOptions) ( GTK_FILL ),
276 (GtkAttachOptions) ( 0 ), 0, 0 );
277 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
280 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
281 gtk_widget_show( GTK_WIDGET( entry ) );
282 gtk_table_attach( table2, GTK_WIDGET( entry ), 1, 2, 1, 2,
283 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
284 (GtkAttachOptions) ( 0 ), 0, 0 );
286 dialog.game_combo.fsgame_entry = entry;
289 if ( globalMappingMode().do_mapping_mode ) {
290 GtkLabel* label = GTK_LABEL( gtk_label_new( "Mapping mode" ) );
291 gtk_widget_show( GTK_WIDGET( label ) );
292 gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 3, 4,
293 (GtkAttachOptions) ( GTK_FILL ),
294 (GtkAttachOptions) ( 0 ), 0, 0 );
295 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
297 GtkComboBox* combo = GTK_COMBO_BOX( gtk_combo_box_new_text() );
298 gtk_combo_box_append_text( combo, globalMappingMode().sp_mapping_mode );
299 gtk_combo_box_append_text( combo, globalMappingMode().mp_mapping_mode );
301 gtk_widget_show( GTK_WIDGET( combo ) );
302 gtk_table_attach( table2, GTK_WIDGET( combo ), 1, 2, 3, 4,
303 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
304 (GtkAttachOptions) ( 0 ), 0, 0 );
306 dialog.gamemode_combo = combo;
312 // initialise the fs_game selection from the project settings into the dialog
313 const char* dir = gamename_get();
314 gamecombo_t gamecombo = gamecombo_for_dir( dir );
316 gtk_combo_box_set_active( dialog.game_combo.game_select, gamecombo.game );
317 gtk_entry_set_text( dialog.game_combo.fsgame_entry, gamecombo.fs_game );
318 gtk_widget_set_sensitive( GTK_WIDGET( dialog.game_combo.fsgame_entry ), gamecombo.sensitive );
320 if ( globalMappingMode().do_mapping_mode ) {
321 const char *gamemode = gamemode_get();
322 if ( string_empty( gamemode ) || string_equal( gamemode, "sp" ) ) {
323 gtk_combo_box_set_active( dialog.gamemode_combo, 0 );
327 gtk_combo_box_set_active( dialog.gamemode_combo, 1 );
334 void ProjectSettingsDialog_ok( ProjectSettingsDialog& dialog ){
335 const char* dir = gtk_entry_get_text( dialog.game_combo.fsgame_entry );
337 const char* new_gamename = path_equal( dir, globalGameComboConfiguration().basegame_dir )
341 if ( !path_equal( new_gamename, gamename_get() ) ) {
342 ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Changing Game Name" );
344 EnginePath_Unrealise();
346 gamename_set( new_gamename );
348 EnginePath_Realise();
351 if ( globalMappingMode().do_mapping_mode ) {
352 // read from gamemode_combo
353 int active = gtk_combo_box_get_active( dialog.gamemode_combo );
354 if ( active == -1 || active == 0 ) {
355 gamemode_set( "sp" );
359 gamemode_set( "mp" );
364 void DoProjectSettings(){
365 if ( ConfirmModified( "Edit Project Settings" ) ) {
367 ProjectSettingsDialog dialog;
369 GtkWindow* window = ProjectSettingsDialog_construct( dialog, modal );
371 if ( modal_dialog_show( window, modal ) == eIDOK ) {
372 ProjectSettingsDialog_ok( dialog );
375 gtk_widget_destroy( GTK_WIDGET( window ) );
379 // =============================================================================
380 // Arbitrary Sides dialog
382 void DoSides( int type, int axis ){
384 GtkEntry* sides_entry;
386 GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Arbitrary sides", G_CALLBACK( dialog_delete_callback ), &dialog );
388 GtkAccelGroup* accel = gtk_accel_group_new();
389 gtk_window_add_accel_group( window, accel );
392 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
393 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
395 GtkLabel* label = GTK_LABEL( gtk_label_new( "Sides:" ) );
396 gtk_widget_show( GTK_WIDGET( label ) );
397 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
400 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
401 gtk_widget_show( GTK_WIDGET( entry ) );
402 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( entry ), FALSE, FALSE, 0 );
404 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
407 GtkVBox* vbox = create_dialog_vbox( 4 );
408 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
410 GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &dialog );
411 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
412 widget_make_default( GTK_WIDGET( button ) );
413 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
416 GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &dialog );
417 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
418 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
423 if ( modal_dialog_show( window, dialog ) == eIDOK ) {
424 const char *str = gtk_entry_get_text( sides_entry );
426 Scene_BrushConstructPrefab( GlobalSceneGraph(), (EBrushPrefab)type, atoi( str ), TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ) );
429 gtk_widget_destroy( GTK_WIDGET( window ) );
432 // =============================================================================
433 // About dialog (no program is complete without one)
435 void about_button_changelog( GtkWidget *widget, gpointer data ){
436 StringOutputStream log( 256 );
437 log << AppPath_get() << "changelog.txt";
438 OpenURL( log.c_str() );
441 void about_button_credits( GtkWidget *widget, gpointer data ){
442 StringOutputStream cred( 256 );
443 cred << AppPath_get() << "credits.html";
444 OpenURL( cred.c_str() );
449 ModalDialogButton ok_button( dialog, eIDOK );
451 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "About NetRadiant", dialog );
454 GtkVBox* vbox = create_dialog_vbox( 4, 4 );
455 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) );
458 GtkHBox* hbox = create_dialog_hbox( 4 );
459 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
462 GtkVBox* vbox2 = create_dialog_vbox( 4 );
463 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), TRUE, FALSE, 0 );
465 GtkFrame* frame = create_dialog_frame( 0, GTK_SHADOW_IN );
466 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
468 GtkImage* image = new_local_image( "logo.bmp" );
469 gtk_widget_show( GTK_WIDGET( image ) );
470 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( image ) );
476 GtkLabel* label = GTK_LABEL( gtk_label_new( "NetRadiant " RADIANT_VERSION "\n"
478 RADIANT_ABOUTMSG "\n\n"
479 "By alientrap.org\n\n"
480 "This program is free software\n"
481 "licensed under the GNU GPL.\n\n"
482 "NetRadiant is unsupported, however\n"
483 "you may report your problems at\n"
484 "http://www.icculus.org/netradiant/"
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 // remembers 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 );
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 last_used_texture_layout_scale_x = *fx;
699 last_used_texture_layout_scale_y = *fy;
702 gtk_widget_destroy( GTK_WIDGET( window ) );
707 // =============================================================================
708 // Text Editor dialog
710 // master window widget
711 static GtkWidget *text_editor = 0;
712 static GtkWidget *text_widget; // slave, text widget from the gtk editor
714 static gint editor_delete( GtkWidget *widget, gpointer data ){
715 if ( gtk_MessageBox( widget, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
719 gtk_widget_hide( text_editor );
724 static void editor_save( GtkWidget *widget, gpointer data ){
725 FILE *f = fopen( (char*)g_object_get_data( G_OBJECT( data ), "filename" ), "w" );
726 gpointer text = g_object_get_data( G_OBJECT( data ), "text" );
729 gtk_MessageBox( GTK_WIDGET( data ), "Error saving file !" );
733 char *str = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );
734 fwrite( str, 1, strlen( str ), f );
738 static void editor_close( GtkWidget *widget, gpointer data ){
739 if ( gtk_MessageBox( text_editor, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
743 gtk_widget_hide( text_editor );
746 static void CreateGtkTextEditor(){
748 GtkWidget *vbox, *hbox, *button, *scr, *text;
750 dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
752 g_signal_connect( G_OBJECT( dlg ), "delete_event",
753 G_CALLBACK( editor_delete ), 0 );
754 gtk_window_set_default_size( GTK_WINDOW( dlg ), 600, 300 );
756 vbox = gtk_vbox_new( FALSE, 5 );
757 gtk_widget_show( vbox );
758 gtk_container_add( GTK_CONTAINER( dlg ), GTK_WIDGET( vbox ) );
759 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
761 scr = gtk_scrolled_window_new( 0, 0 );
762 gtk_widget_show( scr );
763 gtk_box_pack_start( GTK_BOX( vbox ), scr, TRUE, TRUE, 0 );
764 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
765 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
767 text = gtk_text_view_new();
768 gtk_container_add( GTK_CONTAINER( scr ), text );
769 gtk_widget_show( text );
770 g_object_set_data( G_OBJECT( dlg ), "text", text );
771 gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), TRUE );
773 hbox = gtk_hbox_new( FALSE, 5 );
774 gtk_widget_show( hbox );
775 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
777 button = gtk_button_new_with_label( "Close" );
778 gtk_widget_show( button );
779 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
780 g_signal_connect( G_OBJECT( button ), "clicked",
781 G_CALLBACK( editor_close ), dlg );
782 gtk_widget_set_usize( button, 60, -2 );
784 button = gtk_button_new_with_label( "Save" );
785 gtk_widget_show( button );
786 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
787 g_signal_connect( G_OBJECT( button ), "clicked",
788 G_CALLBACK( editor_save ), dlg );
789 gtk_widget_set_usize( button, 60, -2 );
795 static void DoGtkTextEditor( const char* filename, guint cursorpos ){
796 if ( !text_editor ) {
797 CreateGtkTextEditor(); // build it the first time we need it
801 FILE *f = fopen( filename, "r" );
804 globalOutputStream() << "Unable to load file " << filename << " in shader editor.\n";
805 gtk_widget_hide( text_editor );
809 fseek( f, 0, SEEK_END );
810 int len = ftell( f );
811 void *buf = malloc( len );
815 fread( buf, 1, len, f );
817 gtk_window_set_title( GTK_WINDOW( text_editor ), filename );
819 GtkTextBuffer* text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_widget ) );
820 gtk_text_buffer_set_text( text_buffer, (char*)buf, len );
822 old_filename = g_object_get_data( G_OBJECT( text_editor ), "filename" );
823 if ( old_filename ) {
824 free( old_filename );
826 g_object_set_data( G_OBJECT( text_editor ), "filename", strdup( filename ) );
828 // trying to show later
829 gtk_widget_show( text_editor );
835 // only move the cursor if it's not exceeding the size..
836 // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters
837 // len is the max size in bytes, not in characters either, but the character count is below that limit..
838 // thinking .. the difference between character count and byte count would be only because of CR/LF?
840 GtkTextIter text_iter;
841 // character offset, not byte offset
842 gtk_text_buffer_get_iter_at_offset( text_buffer, &text_iter, cursorpos );
843 gtk_text_buffer_place_cursor( text_buffer, &text_iter );
847 gtk_widget_queue_draw( text_widget );
855 // =============================================================================
856 // Light Intensity dialog
858 EMessageBoxReturn DoLightIntensityDlg( int *intensity ){
860 GtkEntry* intensity_entry;
861 ModalDialogButton ok_button( dialog, eIDOK );
862 ModalDialogButton cancel_button( dialog, eIDCANCEL );
864 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Light intensity", dialog, -1, -1 );
866 GtkAccelGroup *accel_group = gtk_accel_group_new();
867 gtk_window_add_accel_group( window, accel_group );
870 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
871 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
873 GtkVBox* vbox = create_dialog_vbox( 4 );
874 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
876 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC for default, ENTER to validate" ) );
877 gtk_widget_show( GTK_WIDGET( label ) );
878 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
881 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
882 gtk_widget_show( GTK_WIDGET( entry ) );
883 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
885 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
887 intensity_entry = entry;
891 GtkVBox* vbox = create_dialog_vbox( 4 );
892 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
895 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
896 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
897 widget_make_default( GTK_WIDGET( button ) );
898 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
901 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
902 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
903 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
909 sprintf( buf, "%d", *intensity );
910 gtk_entry_set_text( intensity_entry, buf );
912 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
913 if ( ret == eIDOK ) {
914 *intensity = atoi( gtk_entry_get_text( intensity_entry ) );
917 gtk_widget_destroy( GTK_WIDGET( window ) );
922 // =============================================================================
923 // Add new shader tag dialog
925 EMessageBoxReturn DoShaderTagDlg( CopiedString* tag, char* title ){
928 ModalDialogButton ok_button( dialog, eIDOK );
929 ModalDialogButton cancel_button( dialog, eIDCANCEL );
931 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
933 GtkAccelGroup *accel_group = gtk_accel_group_new();
934 gtk_window_add_accel_group( window, accel_group );
937 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
938 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
940 GtkVBox* vbox = create_dialog_vbox( 4 );
941 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
943 //GtkLabel* label = GTK_LABEL(gtk_label_new("Enter one ore more tags separated by spaces"));
944 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC to cancel, ENTER to validate" ) );
945 gtk_widget_show( GTK_WIDGET( label ) );
946 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
949 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
950 gtk_widget_show( GTK_WIDGET( entry ) );
951 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
953 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
959 GtkVBox* vbox = create_dialog_vbox( 4 );
960 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
963 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
964 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
965 widget_make_default( GTK_WIDGET( button ) );
966 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
969 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
970 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
971 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
976 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
977 if ( ret == eIDOK ) {
978 *tag = gtk_entry_get_text( textentry );
981 gtk_widget_destroy( GTK_WIDGET( window ) );
986 EMessageBoxReturn DoShaderInfoDlg( const char* name, const char* filename, char* title ){
988 ModalDialogButton ok_button( dialog, eIDOK );
990 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
992 GtkAccelGroup *accel_group = gtk_accel_group_new();
993 gtk_window_add_accel_group( window, accel_group );
996 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
997 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
999 GtkVBox* vbox = create_dialog_vbox( 4 );
1000 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
1002 GtkLabel* label = GTK_LABEL( gtk_label_new( "The selected shader" ) );
1003 gtk_widget_show( GTK_WIDGET( label ) );
1004 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1007 GtkLabel* label = GTK_LABEL( gtk_label_new( name ) );
1008 gtk_widget_show( GTK_WIDGET( label ) );
1009 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1012 GtkLabel* label = GTK_LABEL( gtk_label_new( "is located in file" ) );
1013 gtk_widget_show( GTK_WIDGET( label ) );
1014 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1017 GtkLabel* label = GTK_LABEL( gtk_label_new( filename ) );
1018 gtk_widget_show( GTK_WIDGET( label ) );
1019 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1022 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
1023 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1024 widget_make_default( GTK_WIDGET( button ) );
1025 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1030 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
1032 gtk_widget_destroy( GTK_WIDGET( window ) );
1040 #include <gdk/gdkwin32.h>
1044 // use the file associations to open files instead of builtin Gtk editor
1045 bool g_TextEditor_useWin32Editor = true;
1047 // custom shader editor
1048 bool g_TextEditor_useCustomEditor = false;
1049 CopiedString g_TextEditor_editorCommand( "" );
1052 void DoTextEditor( const char* filename, int cursorpos ){
1054 if ( g_TextEditor_useWin32Editor ) {
1055 globalOutputStream() << "opening file '" << filename << "' (line " << cursorpos << " info ignored)\n";
1056 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", filename, 0, 0, SW_SHOW );
1060 // check if a custom editor is set
1061 if ( g_TextEditor_useCustomEditor && !g_TextEditor_editorCommand.empty() ) {
1062 StringOutputStream strEditCommand( 256 );
1063 strEditCommand << g_TextEditor_editorCommand.c_str() << " \"" << filename << "\"";
1065 globalOutputStream() << "Launching: " << strEditCommand.c_str() << "\n";
1066 // note: linux does not return false if the command failed so it will assume success
1067 if ( Q_Exec( 0, const_cast<char*>( strEditCommand.c_str() ), 0, true, false ) == false ) {
1068 globalOutputStream() << "Failed to execute " << strEditCommand.c_str() << ", using default\n";
1072 // the command (appeared) to run successfully, no need to do anything more
1078 DoGtkTextEditor( filename, cursorpos );