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"
484 gtk_widget_show( GTK_WIDGET( label ) );
485 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
486 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
487 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
491 GtkVBox* vbox2 = create_dialog_vbox( 4 );
492 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), FALSE, TRUE, 0 );
494 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
495 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
498 GtkButton* button = create_dialog_button( "Credits", G_CALLBACK( about_button_credits ), 0 );
499 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
502 GtkButton* button = create_dialog_button( "Changelog", G_CALLBACK( about_button_changelog ), 0 );
503 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
508 GtkFrame* frame = create_dialog_frame( "OpenGL Properties" );
509 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
511 GtkTable* table = create_dialog_table( 3, 2, 4, 4, 4 );
512 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table ) );
514 GtkLabel* label = GTK_LABEL( gtk_label_new( "Vendor:" ) );
515 gtk_widget_show( GTK_WIDGET( label ) );
516 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
517 (GtkAttachOptions) ( GTK_FILL ),
518 (GtkAttachOptions) ( 0 ), 0, 0 );
519 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
522 GtkLabel* label = GTK_LABEL( gtk_label_new( "Version:" ) );
523 gtk_widget_show( GTK_WIDGET( label ) );
524 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
525 (GtkAttachOptions) ( GTK_FILL ),
526 (GtkAttachOptions) ( 0 ), 0, 0 );
527 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
530 GtkLabel* label = GTK_LABEL( gtk_label_new( "Renderer:" ) );
531 gtk_widget_show( GTK_WIDGET( label ) );
532 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 2, 3,
533 (GtkAttachOptions) ( GTK_FILL ),
534 (GtkAttachOptions) ( 0 ), 0, 0 );
535 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
538 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VENDOR ) ) ) );
539 gtk_widget_show( GTK_WIDGET( label ) );
540 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 0, 1,
541 (GtkAttachOptions) ( GTK_FILL ),
542 (GtkAttachOptions) ( 0 ), 0, 0 );
543 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
546 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VERSION ) ) ) );
547 gtk_widget_show( GTK_WIDGET( label ) );
548 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 1, 2,
549 (GtkAttachOptions) ( GTK_FILL ),
550 (GtkAttachOptions) ( 0 ), 0, 0 );
551 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
554 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_RENDERER ) ) ) );
555 gtk_widget_show( GTK_WIDGET( label ) );
556 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 2, 3,
557 (GtkAttachOptions) ( GTK_FILL ),
558 (GtkAttachOptions) ( 0 ), 0, 0 );
559 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
563 GtkFrame* frame = create_dialog_frame( "OpenGL Extensions" );
564 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 );
566 GtkScrolledWindow* sc_extensions = create_scrolled_window( GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, 4 );
567 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( sc_extensions ) );
569 GtkWidget* text_extensions = gtk_text_view_new();
570 gtk_text_view_set_editable( GTK_TEXT_VIEW( text_extensions ), FALSE );
571 gtk_container_add( GTK_CONTAINER( sc_extensions ), text_extensions );
572 GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_extensions ) );
573 gtk_text_buffer_set_text( buffer, reinterpret_cast<const char*>( glGetString( GL_EXTENSIONS ) ), -1 );
574 gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text_extensions ), GTK_WRAP_WORD );
575 gtk_widget_show( text_extensions );
582 modal_dialog_show( window, dialog );
584 gtk_widget_destroy( GTK_WIDGET( window ) );
587 // =============================================================================
588 // TextureLayout dialog
590 // Last used texture scale values
591 static float last_used_texture_layout_scale_x = 4.0;
592 static float last_used_texture_layout_scale_y = 4.0;
594 EMessageBoxReturn DoTextureLayout( float *fx, float *fy ){
596 ModalDialogButton ok_button( dialog, eIDOK );
597 ModalDialogButton cancel_button( dialog, eIDCANCEL );
601 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Patch texture layout", dialog );
603 GtkAccelGroup* accel = gtk_accel_group_new();
604 gtk_window_add_accel_group( window, accel );
607 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
608 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
610 GtkVBox* vbox = create_dialog_vbox( 4 );
611 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
613 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture will be fit across the patch based\n"
614 "on the x and y values given. Values of 1x1\n"
615 "will \"fit\" the texture. 2x2 will repeat\n"
616 "it twice, etc." ) );
617 gtk_widget_show( GTK_WIDGET( label ) );
618 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), TRUE, TRUE, 0 );
619 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
622 GtkTable* table = create_dialog_table( 2, 2, 4, 4 );
623 gtk_widget_show( GTK_WIDGET( table ) );
624 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
626 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture x:" ) );
627 gtk_widget_show( GTK_WIDGET( label ) );
628 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
629 (GtkAttachOptions) ( GTK_FILL ),
630 (GtkAttachOptions) ( 0 ), 0, 0 );
631 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
634 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture y:" ) );
635 gtk_widget_show( GTK_WIDGET( label ) );
636 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
637 (GtkAttachOptions) ( GTK_FILL ),
638 (GtkAttachOptions) ( 0 ), 0, 0 );
639 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
642 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
643 gtk_widget_show( GTK_WIDGET( entry ) );
644 gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 0, 1,
645 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
646 (GtkAttachOptions) ( 0 ), 0, 0 );
651 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
652 gtk_widget_show( GTK_WIDGET( entry ) );
653 gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 1, 2,
654 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
655 (GtkAttachOptions) ( 0 ), 0, 0 );
662 GtkVBox* vbox = create_dialog_vbox( 4 );
663 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
665 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
666 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
667 widget_make_default( GTK_WIDGET( button ) );
668 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
671 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
672 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
673 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
678 // Initialize with last used values
681 sprintf( buf, "%f", last_used_texture_layout_scale_x );
682 gtk_entry_set_text( x, buf );
684 sprintf( buf, "%f", last_used_texture_layout_scale_y );
685 gtk_entry_set_text( y, buf );
687 // Set focus after intializing the values
688 gtk_widget_grab_focus( GTK_WIDGET( x ) );
690 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
691 if ( ret == eIDOK ) {
692 *fx = static_cast<float>( atof( gtk_entry_get_text( x ) ) );
693 *fy = static_cast<float>( atof( gtk_entry_get_text( y ) ) );
695 // Remember last used values
696 last_used_texture_layout_scale_x = *fx;
697 last_used_texture_layout_scale_y = *fy;
700 gtk_widget_destroy( GTK_WIDGET( window ) );
705 // =============================================================================
706 // Text Editor dialog
708 // master window widget
709 static GtkWidget *text_editor = 0;
710 static GtkWidget *text_widget; // slave, text widget from the gtk editor
712 static gint editor_delete( GtkWidget *widget, gpointer data ){
713 if ( gtk_MessageBox( widget, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
717 gtk_widget_hide( text_editor );
722 static void editor_save( GtkWidget *widget, gpointer data ){
723 FILE *f = fopen( (char*)g_object_get_data( G_OBJECT( data ), "filename" ), "w" );
724 gpointer text = g_object_get_data( G_OBJECT( data ), "text" );
727 gtk_MessageBox( GTK_WIDGET( data ), "Error saving file !" );
731 char *str = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );
732 fwrite( str, 1, strlen( str ), f );
736 static void editor_close( GtkWidget *widget, gpointer data ){
737 if ( gtk_MessageBox( text_editor, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
741 gtk_widget_hide( text_editor );
744 static void CreateGtkTextEditor(){
746 GtkWidget *vbox, *hbox, *button, *scr, *text;
748 dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
750 g_signal_connect( G_OBJECT( dlg ), "delete_event",
751 G_CALLBACK( editor_delete ), 0 );
752 gtk_window_set_default_size( GTK_WINDOW( dlg ), 600, 300 );
754 vbox = gtk_vbox_new( FALSE, 5 );
755 gtk_widget_show( vbox );
756 gtk_container_add( GTK_CONTAINER( dlg ), GTK_WIDGET( vbox ) );
757 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
759 scr = gtk_scrolled_window_new( 0, 0 );
760 gtk_widget_show( scr );
761 gtk_box_pack_start( GTK_BOX( vbox ), scr, TRUE, TRUE, 0 );
762 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
763 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
765 text = gtk_text_view_new();
766 gtk_container_add( GTK_CONTAINER( scr ), text );
767 gtk_widget_show( text );
768 g_object_set_data( G_OBJECT( dlg ), "text", text );
769 gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), TRUE );
771 hbox = gtk_hbox_new( FALSE, 5 );
772 gtk_widget_show( hbox );
773 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
775 button = gtk_button_new_with_label( "Close" );
776 gtk_widget_show( button );
777 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
778 g_signal_connect( G_OBJECT( button ), "clicked",
779 G_CALLBACK( editor_close ), dlg );
780 gtk_widget_set_usize( button, 60, -2 );
782 button = gtk_button_new_with_label( "Save" );
783 gtk_widget_show( button );
784 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
785 g_signal_connect( G_OBJECT( button ), "clicked",
786 G_CALLBACK( editor_save ), dlg );
787 gtk_widget_set_usize( button, 60, -2 );
793 static void DoGtkTextEditor( const char* filename, guint cursorpos ){
794 if ( !text_editor ) {
795 CreateGtkTextEditor(); // build it the first time we need it
799 FILE *f = fopen( filename, "r" );
802 globalOutputStream() << "Unable to load file " << filename << " in shader editor.\n";
803 gtk_widget_hide( text_editor );
807 fseek( f, 0, SEEK_END );
808 int len = ftell( f );
809 void *buf = malloc( len );
813 fread( buf, 1, len, f );
815 gtk_window_set_title( GTK_WINDOW( text_editor ), filename );
817 GtkTextBuffer* text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_widget ) );
818 gtk_text_buffer_set_text( text_buffer, (char*)buf, len );
820 old_filename = g_object_get_data( G_OBJECT( text_editor ), "filename" );
821 if ( old_filename ) {
822 free( old_filename );
824 g_object_set_data( G_OBJECT( text_editor ), "filename", strdup( filename ) );
826 // trying to show later
827 gtk_widget_show( text_editor );
833 // only move the cursor if it's not exceeding the size..
834 // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters
835 // len is the max size in bytes, not in characters either, but the character count is below that limit..
836 // thinking .. the difference between character count and byte count would be only because of CR/LF?
838 GtkTextIter text_iter;
839 // character offset, not byte offset
840 gtk_text_buffer_get_iter_at_offset( text_buffer, &text_iter, cursorpos );
841 gtk_text_buffer_place_cursor( text_buffer, &text_iter );
845 gtk_widget_queue_draw( text_widget );
853 // =============================================================================
854 // Light Intensity dialog
856 EMessageBoxReturn DoLightIntensityDlg( int *intensity ){
858 GtkEntry* intensity_entry;
859 ModalDialogButton ok_button( dialog, eIDOK );
860 ModalDialogButton cancel_button( dialog, eIDCANCEL );
862 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Light intensity", dialog, -1, -1 );
864 GtkAccelGroup *accel_group = gtk_accel_group_new();
865 gtk_window_add_accel_group( window, accel_group );
868 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
869 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
871 GtkVBox* vbox = create_dialog_vbox( 4 );
872 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
874 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC for default, ENTER to validate" ) );
875 gtk_widget_show( GTK_WIDGET( label ) );
876 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
879 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
880 gtk_widget_show( GTK_WIDGET( entry ) );
881 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
883 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
885 intensity_entry = entry;
889 GtkVBox* vbox = create_dialog_vbox( 4 );
890 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
893 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
894 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
895 widget_make_default( GTK_WIDGET( button ) );
896 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
899 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
900 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
901 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
907 sprintf( buf, "%d", *intensity );
908 gtk_entry_set_text( intensity_entry, buf );
910 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
911 if ( ret == eIDOK ) {
912 *intensity = atoi( gtk_entry_get_text( intensity_entry ) );
915 gtk_widget_destroy( GTK_WIDGET( window ) );
920 // =============================================================================
921 // Add new shader tag dialog
923 EMessageBoxReturn DoShaderTagDlg( CopiedString* tag, char* title ){
926 ModalDialogButton ok_button( dialog, eIDOK );
927 ModalDialogButton cancel_button( dialog, eIDCANCEL );
929 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
931 GtkAccelGroup *accel_group = gtk_accel_group_new();
932 gtk_window_add_accel_group( window, accel_group );
935 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
936 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
938 GtkVBox* vbox = create_dialog_vbox( 4 );
939 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
941 //GtkLabel* label = GTK_LABEL(gtk_label_new("Enter one ore more tags separated by spaces"));
942 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC to cancel, ENTER to validate" ) );
943 gtk_widget_show( GTK_WIDGET( label ) );
944 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
947 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
948 gtk_widget_show( GTK_WIDGET( entry ) );
949 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
951 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
957 GtkVBox* vbox = create_dialog_vbox( 4 );
958 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
961 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
962 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
963 widget_make_default( GTK_WIDGET( button ) );
964 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
967 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
968 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
969 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
974 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
975 if ( ret == eIDOK ) {
976 *tag = gtk_entry_get_text( textentry );
979 gtk_widget_destroy( GTK_WIDGET( window ) );
984 EMessageBoxReturn DoShaderInfoDlg( const char* name, const char* filename, char* title ){
986 ModalDialogButton ok_button( dialog, eIDOK );
988 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
990 GtkAccelGroup *accel_group = gtk_accel_group_new();
991 gtk_window_add_accel_group( window, accel_group );
994 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
995 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
997 GtkVBox* vbox = create_dialog_vbox( 4 );
998 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
1000 GtkLabel* label = GTK_LABEL( gtk_label_new( "The selected shader" ) );
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( name ) );
1006 gtk_widget_show( GTK_WIDGET( label ) );
1007 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1010 GtkLabel* label = GTK_LABEL( gtk_label_new( "is located in file" ) );
1011 gtk_widget_show( GTK_WIDGET( label ) );
1012 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1015 GtkLabel* label = GTK_LABEL( gtk_label_new( filename ) );
1016 gtk_widget_show( GTK_WIDGET( label ) );
1017 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1020 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
1021 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1022 widget_make_default( GTK_WIDGET( button ) );
1023 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1028 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
1030 gtk_widget_destroy( GTK_WIDGET( window ) );
1038 #include <gdk/gdkwin32.h>
1042 // use the file associations to open files instead of builtin Gtk editor
1043 bool g_TextEditor_useWin32Editor = true;
1045 // custom shader editor
1046 bool g_TextEditor_useCustomEditor = false;
1047 CopiedString g_TextEditor_editorCommand( "" );
1050 void DoTextEditor( const char* filename, int cursorpos ){
1052 if ( g_TextEditor_useWin32Editor ) {
1053 globalOutputStream() << "opening file '" << filename << "' (line " << cursorpos << " info ignored)\n";
1054 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", filename, 0, 0, SW_SHOW );
1058 // check if a custom editor is set
1059 if ( g_TextEditor_useCustomEditor && !g_TextEditor_editorCommand.empty() ) {
1060 StringOutputStream strEditCommand( 256 );
1061 strEditCommand << g_TextEditor_editorCommand.c_str() << " \"" << filename << "\"";
1063 globalOutputStream() << "Launching: " << strEditCommand.c_str() << "\n";
1064 // note: linux does not return false if the command failed so it will assume success
1065 if ( Q_Exec( 0, const_cast<char*>( strEditCommand.c_str() ), 0, true, false ) == false ) {
1066 globalOutputStream() << "Failed to execute " << strEditCommand.c_str() << ", using default\n";
1070 // the command (appeared) to run successfully, no need to do anything more
1076 DoGtkTextEditor( filename, cursorpos );