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 EMessageBoxReturn DoTextureLayout( float *fx, float *fy ){
595 ModalDialogButton ok_button( dialog, eIDOK );
596 ModalDialogButton cancel_button( dialog, eIDCANCEL );
600 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Patch texture layout", dialog );
602 GtkAccelGroup* accel = gtk_accel_group_new();
603 gtk_window_add_accel_group( window, accel );
606 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
607 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
609 GtkVBox* vbox = create_dialog_vbox( 4 );
610 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
612 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture will be fit across the patch based\n"
613 "on the x and y values given. Values of 1x1\n"
614 "will \"fit\" the texture. 2x2 will repeat\n"
615 "it twice, etc." ) );
616 gtk_widget_show( GTK_WIDGET( label ) );
617 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), TRUE, TRUE, 0 );
618 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
621 GtkTable* table = create_dialog_table( 2, 2, 4, 4 );
622 gtk_widget_show( GTK_WIDGET( table ) );
623 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
625 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture x:" ) );
626 gtk_widget_show( GTK_WIDGET( label ) );
627 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
628 (GtkAttachOptions) ( GTK_FILL ),
629 (GtkAttachOptions) ( 0 ), 0, 0 );
630 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
633 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture y:" ) );
634 gtk_widget_show( GTK_WIDGET( label ) );
635 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
636 (GtkAttachOptions) ( GTK_FILL ),
637 (GtkAttachOptions) ( 0 ), 0, 0 );
638 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
641 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
642 gtk_widget_show( GTK_WIDGET( entry ) );
643 gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 0, 1,
644 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
645 (GtkAttachOptions) ( 0 ), 0, 0 );
647 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
652 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
653 gtk_widget_show( GTK_WIDGET( entry ) );
654 gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 1, 2,
655 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
656 (GtkAttachOptions) ( 0 ), 0, 0 );
663 GtkVBox* vbox = create_dialog_vbox( 4 );
664 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
666 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
667 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
668 widget_make_default( GTK_WIDGET( button ) );
669 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
672 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
673 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
674 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
680 gtk_entry_set_text( x, "4.0" );
681 gtk_entry_set_text( y, "4.0" );
684 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
685 if ( ret == eIDOK ) {
686 *fx = static_cast<float>( atof( gtk_entry_get_text( x ) ) );
687 *fy = static_cast<float>( atof( gtk_entry_get_text( y ) ) );
690 gtk_widget_destroy( GTK_WIDGET( window ) );
695 // =============================================================================
696 // Text Editor dialog
698 // master window widget
699 static GtkWidget *text_editor = 0;
700 static GtkWidget *text_widget; // slave, text widget from the gtk editor
702 static gint editor_delete( GtkWidget *widget, gpointer data ){
703 if ( gtk_MessageBox( widget, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
707 gtk_widget_hide( text_editor );
712 static void editor_save( GtkWidget *widget, gpointer data ){
713 FILE *f = fopen( (char*)g_object_get_data( G_OBJECT( data ), "filename" ), "w" );
714 gpointer text = g_object_get_data( G_OBJECT( data ), "text" );
717 gtk_MessageBox( GTK_WIDGET( data ), "Error saving file !" );
721 char *str = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );
722 fwrite( str, 1, strlen( str ), f );
726 static void editor_close( GtkWidget *widget, gpointer data ){
727 if ( gtk_MessageBox( text_editor, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
731 gtk_widget_hide( text_editor );
734 static void CreateGtkTextEditor(){
736 GtkWidget *vbox, *hbox, *button, *scr, *text;
738 dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
740 g_signal_connect( G_OBJECT( dlg ), "delete_event",
741 G_CALLBACK( editor_delete ), 0 );
742 gtk_window_set_default_size( GTK_WINDOW( dlg ), 600, 300 );
744 vbox = gtk_vbox_new( FALSE, 5 );
745 gtk_widget_show( vbox );
746 gtk_container_add( GTK_CONTAINER( dlg ), GTK_WIDGET( vbox ) );
747 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
749 scr = gtk_scrolled_window_new( 0, 0 );
750 gtk_widget_show( scr );
751 gtk_box_pack_start( GTK_BOX( vbox ), scr, TRUE, TRUE, 0 );
752 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
753 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
755 text = gtk_text_view_new();
756 gtk_container_add( GTK_CONTAINER( scr ), text );
757 gtk_widget_show( text );
758 g_object_set_data( G_OBJECT( dlg ), "text", text );
759 gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), TRUE );
761 hbox = gtk_hbox_new( FALSE, 5 );
762 gtk_widget_show( hbox );
763 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
765 button = gtk_button_new_with_label( "Close" );
766 gtk_widget_show( button );
767 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
768 g_signal_connect( G_OBJECT( button ), "clicked",
769 G_CALLBACK( editor_close ), dlg );
770 gtk_widget_set_usize( button, 60, -2 );
772 button = gtk_button_new_with_label( "Save" );
773 gtk_widget_show( button );
774 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
775 g_signal_connect( G_OBJECT( button ), "clicked",
776 G_CALLBACK( editor_save ), dlg );
777 gtk_widget_set_usize( button, 60, -2 );
783 static void DoGtkTextEditor( const char* filename, guint cursorpos ){
784 if ( !text_editor ) {
785 CreateGtkTextEditor(); // build it the first time we need it
789 FILE *f = fopen( filename, "r" );
792 globalOutputStream() << "Unable to load file " << filename << " in shader editor.\n";
793 gtk_widget_hide( text_editor );
797 fseek( f, 0, SEEK_END );
798 int len = ftell( f );
799 void *buf = malloc( len );
803 fread( buf, 1, len, f );
805 gtk_window_set_title( GTK_WINDOW( text_editor ), filename );
807 GtkTextBuffer* text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_widget ) );
808 gtk_text_buffer_set_text( text_buffer, (char*)buf, len );
810 old_filename = g_object_get_data( G_OBJECT( text_editor ), "filename" );
811 if ( old_filename ) {
812 free( old_filename );
814 g_object_set_data( G_OBJECT( text_editor ), "filename", strdup( filename ) );
816 // trying to show later
817 gtk_widget_show( text_editor );
823 // only move the cursor if it's not exceeding the size..
824 // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters
825 // len is the max size in bytes, not in characters either, but the character count is below that limit..
826 // thinking .. the difference between character count and byte count would be only because of CR/LF?
828 GtkTextIter text_iter;
829 // character offset, not byte offset
830 gtk_text_buffer_get_iter_at_offset( text_buffer, &text_iter, cursorpos );
831 gtk_text_buffer_place_cursor( text_buffer, &text_iter );
835 gtk_widget_queue_draw( text_widget );
843 // =============================================================================
844 // Light Intensity dialog
846 EMessageBoxReturn DoLightIntensityDlg( int *intensity ){
848 GtkEntry* intensity_entry;
849 ModalDialogButton ok_button( dialog, eIDOK );
850 ModalDialogButton cancel_button( dialog, eIDCANCEL );
852 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Light intensity", dialog, -1, -1 );
854 GtkAccelGroup *accel_group = gtk_accel_group_new();
855 gtk_window_add_accel_group( window, accel_group );
858 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
859 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
861 GtkVBox* vbox = create_dialog_vbox( 4 );
862 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
864 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC for default, ENTER to validate" ) );
865 gtk_widget_show( GTK_WIDGET( label ) );
866 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
869 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
870 gtk_widget_show( GTK_WIDGET( entry ) );
871 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
873 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
875 intensity_entry = entry;
879 GtkVBox* vbox = create_dialog_vbox( 4 );
880 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
883 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
884 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
885 widget_make_default( GTK_WIDGET( button ) );
886 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
889 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
890 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
891 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
897 sprintf( buf, "%d", *intensity );
898 gtk_entry_set_text( intensity_entry, buf );
900 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
901 if ( ret == eIDOK ) {
902 *intensity = atoi( gtk_entry_get_text( intensity_entry ) );
905 gtk_widget_destroy( GTK_WIDGET( window ) );
910 // =============================================================================
911 // Add new shader tag dialog
913 EMessageBoxReturn DoShaderTagDlg( CopiedString* tag, char* title ){
916 ModalDialogButton ok_button( dialog, eIDOK );
917 ModalDialogButton cancel_button( dialog, eIDCANCEL );
919 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
921 GtkAccelGroup *accel_group = gtk_accel_group_new();
922 gtk_window_add_accel_group( window, accel_group );
925 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
926 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
928 GtkVBox* vbox = create_dialog_vbox( 4 );
929 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
931 //GtkLabel* label = GTK_LABEL(gtk_label_new("Enter one ore more tags separated by spaces"));
932 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC to cancel, ENTER to validate" ) );
933 gtk_widget_show( GTK_WIDGET( label ) );
934 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
937 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
938 gtk_widget_show( GTK_WIDGET( entry ) );
939 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
941 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
947 GtkVBox* vbox = create_dialog_vbox( 4 );
948 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
951 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
952 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
953 widget_make_default( GTK_WIDGET( button ) );
954 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
957 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
958 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
959 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
964 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
965 if ( ret == eIDOK ) {
966 *tag = gtk_entry_get_text( textentry );
969 gtk_widget_destroy( GTK_WIDGET( window ) );
974 EMessageBoxReturn DoShaderInfoDlg( const char* name, const char* filename, char* title ){
976 ModalDialogButton ok_button( dialog, eIDOK );
978 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
980 GtkAccelGroup *accel_group = gtk_accel_group_new();
981 gtk_window_add_accel_group( window, accel_group );
984 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
985 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
987 GtkVBox* vbox = create_dialog_vbox( 4 );
988 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
990 GtkLabel* label = GTK_LABEL( gtk_label_new( "The selected shader" ) );
991 gtk_widget_show( GTK_WIDGET( label ) );
992 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
995 GtkLabel* label = GTK_LABEL( gtk_label_new( name ) );
996 gtk_widget_show( GTK_WIDGET( label ) );
997 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1000 GtkLabel* label = GTK_LABEL( gtk_label_new( "is located in file" ) );
1001 gtk_widget_show( GTK_WIDGET( label ) );
1002 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1005 GtkLabel* label = GTK_LABEL( gtk_label_new( filename ) );
1006 gtk_widget_show( GTK_WIDGET( label ) );
1007 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1010 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
1011 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1012 widget_make_default( GTK_WIDGET( button ) );
1013 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1018 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
1020 gtk_widget_destroy( GTK_WIDGET( window ) );
1028 #include <gdk/gdkwin32.h>
1032 // use the file associations to open files instead of builtin Gtk editor
1033 bool g_TextEditor_useWin32Editor = true;
1035 // custom shader editor
1036 bool g_TextEditor_useCustomEditor = false;
1037 CopiedString g_TextEditor_editorCommand( "" );
1040 void DoTextEditor( const char* filename, int cursorpos ){
1042 if ( g_TextEditor_useWin32Editor ) {
1043 globalOutputStream() << "opening file '" << filename << "' (line " << cursorpos << " info ignored)\n";
1044 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", filename, 0, 0, SW_SHOW );
1048 // check if a custom editor is set
1049 if ( g_TextEditor_useCustomEditor && !g_TextEditor_editorCommand.empty() ) {
1050 StringOutputStream strEditCommand( 256 );
1051 strEditCommand << g_TextEditor_editorCommand.c_str() << " \"" << filename << "\"";
1053 globalOutputStream() << "Launching: " << strEditCommand.c_str() << "\n";
1054 // note: linux does not return false if the command failed so it will assume success
1055 if ( Q_Exec( 0, const_cast<char*>( strEditCommand.c_str() ), 0, true, false ) == false ) {
1056 globalOutputStream() << "Failed to execute " << strEditCommand.c_str() << ", using default\n";
1060 // the command (appeared) to run successfully, no need to do anything more
1066 DoGtkTextEditor( filename, cursorpos );