2 Copyright (c) 2001, Loki software, inc.
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
8 Redistributions of source code must retain the above copyright notice, this list
9 of conditions and the following disclaimer.
11 Redistributions in binary form must reproduce the above copyright notice, this
12 list of conditions and the following disclaimer in the documentation and/or
13 other materials provided with the distribution.
15 Neither the name of Loki software nor the names of its contributors may be used
16 to endorse or promote products derived from this software without specific prior
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
23 DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 // Some small dialogs that don't need much
34 // Leonardo Zide (leo@lokigames.com)
39 #include "debugging/debugging.h"
44 #include "iscenegraph.h"
45 #include "iselection.h"
47 #include <gdk/gdkkeysyms.h>
48 #include <gtk/gtkmain.h>
49 #include <gtk/gtkentry.h>
50 #include <gtk/gtkhbox.h>
51 #include <gtk/gtkvbox.h>
52 #include <gtk/gtkframe.h>
53 #include <gtk/gtklabel.h>
54 #include <gtk/gtktable.h>
55 #include <gtk/gtkbutton.h>
56 #include <gtk/gtkcombobox.h>
57 #include <gtk/gtkscrolledwindow.h>
58 #include <gtk/gtktextview.h>
59 #include <gtk/gtktextbuffer.h>
60 #include <gtk/gtktreeview.h>
61 #include <gtk/gtkcellrenderertext.h>
62 #include <gtk/gtktreeselection.h>
63 #include <gtk/gtkliststore.h>
66 #include "math/aabb.h"
67 #include "container/array.h"
68 #include "generic/static.h"
69 #include "stream/stringstream.h"
71 #include "gtkutil/messagebox.h"
72 #include "gtkutil/image.h"
75 #include "brushmanip.h"
78 #include "texwindow.h"
80 #include "mainframe.h"
81 #include "preferences.h"
85 #include "qerplugin.h"
90 // =============================================================================
91 // Project settings dialog
93 class GameComboConfiguration
96 const char* basegame_dir;
98 const char* known_dir;
102 GameComboConfiguration() :
103 basegame_dir( g_pGameDescription->getRequiredKeyValue( "basegame" ) ),
104 basegame( g_pGameDescription->getRequiredKeyValue( "basegamename" ) ),
105 known_dir( g_pGameDescription->getKeyValue( "knowngame" ) ),
106 known( g_pGameDescription->getKeyValue( "knowngamename" ) ),
107 custom( g_pGameDescription->getRequiredKeyValue( "unknowngamename" ) ){
111 typedef LazyStatic<GameComboConfiguration> LazyStaticGameComboConfiguration;
113 inline GameComboConfiguration& globalGameComboConfiguration(){
114 return LazyStaticGameComboConfiguration::instance();
120 gamecombo_t( int _game, const char* _fs_game, bool _sensitive )
121 : game( _game ), fs_game( _fs_game ), sensitive( _sensitive )
128 gamecombo_t gamecombo_for_dir( const char* dir ){
129 if ( string_equal( dir, globalGameComboConfiguration().basegame_dir ) ) {
130 return gamecombo_t( 0, "", false );
132 else if ( string_equal( dir, globalGameComboConfiguration().known_dir ) ) {
133 return gamecombo_t( 1, dir, false );
137 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, dir, true );
141 gamecombo_t gamecombo_for_gamename( const char* gamename ){
142 if ( ( strlen( gamename ) == 0 ) || !strcmp( gamename, globalGameComboConfiguration().basegame ) ) {
143 return gamecombo_t( 0, "", false );
145 else if ( !strcmp( gamename, globalGameComboConfiguration().known ) ) {
146 return gamecombo_t( 1, globalGameComboConfiguration().known_dir, false );
150 return gamecombo_t( string_empty( globalGameComboConfiguration().known_dir ) ? 1 : 2, "", true );
154 inline void path_copy_clean( char* destination, const char* source ){
155 char* i = destination;
157 while ( *source != '\0' )
159 *i++ = ( *source == '\\' ) ? '/' : *source;
163 if ( i != destination && *( i - 1 ) != '/' ) {
173 GtkComboBox* game_select;
174 GtkEntry* fsgame_entry;
177 gboolean OnSelchangeComboWhatgame( GtkWidget *widget, GameCombo* combo ){
178 const char *gamename;
181 gtk_combo_box_get_active_iter( combo->game_select, &iter );
182 gtk_tree_model_get( gtk_combo_box_get_model( combo->game_select ), &iter, 0, (gpointer*)&gamename, -1 );
185 gamecombo_t gamecombo = gamecombo_for_gamename( gamename );
187 gtk_entry_set_text( combo->fsgame_entry, gamecombo.fs_game );
188 gtk_widget_set_sensitive( GTK_WIDGET( combo->fsgame_entry ), gamecombo.sensitive );
196 bool do_mapping_mode;
197 const char* sp_mapping_mode;
198 const char* mp_mapping_mode;
201 do_mapping_mode( !string_empty( g_pGameDescription->getKeyValue( "show_gamemode" ) ) ),
202 sp_mapping_mode( "Single Player mapping mode" ),
203 mp_mapping_mode( "Multiplayer mapping mode" ){
207 typedef LazyStatic<MappingMode> LazyStaticMappingMode;
209 inline MappingMode& globalMappingMode(){
210 return LazyStaticMappingMode::instance();
213 class ProjectSettingsDialog
216 GameCombo game_combo;
217 GtkComboBox* gamemode_combo;
220 GtkWindow* ProjectSettingsDialog_construct( ProjectSettingsDialog& dialog, ModalDialog& modal ){
221 GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Project Settings", G_CALLBACK( dialog_delete_callback ), &modal );
224 GtkTable* table1 = create_dialog_table( 1, 2, 4, 4, 4 );
225 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( table1 ) );
227 GtkVBox* vbox = create_dialog_vbox( 4 );
228 gtk_table_attach( table1, GTK_WIDGET( vbox ), 1, 2, 0, 1,
229 (GtkAttachOptions) ( GTK_FILL ),
230 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
232 GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &modal );
233 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
236 GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &modal );
237 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
241 GtkFrame* frame = create_dialog_frame( "Project settings" );
242 gtk_table_attach( table1, GTK_WIDGET( frame ), 0, 1, 0, 1,
243 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
244 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
246 GtkTable* table2 = create_dialog_table( ( globalMappingMode().do_mapping_mode ) ? 4 : 3, 2, 4, 4, 4 );
247 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table2 ) );
250 GtkLabel* label = GTK_LABEL( gtk_label_new( "Select mod" ) );
251 gtk_widget_show( GTK_WIDGET( label ) );
252 gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 0, 1,
253 (GtkAttachOptions) ( GTK_FILL ),
254 (GtkAttachOptions) ( 0 ), 0, 0 );
255 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
258 dialog.game_combo.game_select = GTK_COMBO_BOX( gtk_combo_box_new_text() );
260 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().basegame );
261 if ( globalGameComboConfiguration().known[0] != '\0' ) {
262 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().known );
264 gtk_combo_box_append_text( dialog.game_combo.game_select, globalGameComboConfiguration().custom );
266 gtk_widget_show( GTK_WIDGET( dialog.game_combo.game_select ) );
267 gtk_table_attach( table2, GTK_WIDGET( dialog.game_combo.game_select ), 1, 2, 0, 1,
268 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
269 (GtkAttachOptions) ( 0 ), 0, 0 );
271 g_signal_connect( G_OBJECT( dialog.game_combo.game_select ), "changed", G_CALLBACK( OnSelchangeComboWhatgame ), &dialog.game_combo );
275 GtkLabel* label = GTK_LABEL( gtk_label_new( "fs_game" ) );
276 gtk_widget_show( GTK_WIDGET( label ) );
277 gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 1, 2,
278 (GtkAttachOptions) ( GTK_FILL ),
279 (GtkAttachOptions) ( 0 ), 0, 0 );
280 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
283 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
284 gtk_widget_show( GTK_WIDGET( entry ) );
285 gtk_table_attach( table2, GTK_WIDGET( entry ), 1, 2, 1, 2,
286 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
287 (GtkAttachOptions) ( 0 ), 0, 0 );
289 dialog.game_combo.fsgame_entry = entry;
292 if ( globalMappingMode().do_mapping_mode ) {
293 GtkLabel* label = GTK_LABEL( gtk_label_new( "Mapping mode" ) );
294 gtk_widget_show( GTK_WIDGET( label ) );
295 gtk_table_attach( table2, GTK_WIDGET( label ), 0, 1, 3, 4,
296 (GtkAttachOptions) ( GTK_FILL ),
297 (GtkAttachOptions) ( 0 ), 0, 0 );
298 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
300 GtkComboBox* combo = GTK_COMBO_BOX( gtk_combo_box_new_text() );
301 gtk_combo_box_append_text( combo, globalMappingMode().sp_mapping_mode );
302 gtk_combo_box_append_text( combo, globalMappingMode().mp_mapping_mode );
304 gtk_widget_show( GTK_WIDGET( combo ) );
305 gtk_table_attach( table2, GTK_WIDGET( combo ), 1, 2, 3, 4,
306 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
307 (GtkAttachOptions) ( 0 ), 0, 0 );
309 dialog.gamemode_combo = combo;
315 // initialise the fs_game selection from the project settings into the dialog
316 const char* dir = gamename_get();
317 gamecombo_t gamecombo = gamecombo_for_dir( dir );
319 gtk_combo_box_set_active( dialog.game_combo.game_select, gamecombo.game );
320 gtk_entry_set_text( dialog.game_combo.fsgame_entry, gamecombo.fs_game );
321 gtk_widget_set_sensitive( GTK_WIDGET( dialog.game_combo.fsgame_entry ), gamecombo.sensitive );
323 if ( globalMappingMode().do_mapping_mode ) {
324 const char *gamemode = gamemode_get();
325 if ( string_empty( gamemode ) || string_equal( gamemode, "sp" ) ) {
326 gtk_combo_box_set_active( dialog.gamemode_combo, 0 );
330 gtk_combo_box_set_active( dialog.gamemode_combo, 1 );
337 void ProjectSettingsDialog_ok( ProjectSettingsDialog& dialog ){
338 const char* dir = gtk_entry_get_text( dialog.game_combo.fsgame_entry );
340 const char* new_gamename = path_equal( dir, globalGameComboConfiguration().basegame_dir )
344 if ( !path_equal( new_gamename, gamename_get() ) ) {
345 ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Changing Game Name" );
347 EnginePath_Unrealise();
349 gamename_set( new_gamename );
351 EnginePath_Realise();
354 if ( globalMappingMode().do_mapping_mode ) {
355 // read from gamemode_combo
356 int active = gtk_combo_box_get_active( dialog.gamemode_combo );
357 if ( active == -1 || active == 0 ) {
358 gamemode_set( "sp" );
362 gamemode_set( "mp" );
367 void DoProjectSettings(){
368 //if ( ConfirmModified( "Edit Project Settings" ) ) {
370 ProjectSettingsDialog dialog;
372 GtkWindow* window = ProjectSettingsDialog_construct( dialog, modal );
374 if ( modal_dialog_show( window, modal ) == eIDOK ) {
375 ProjectSettingsDialog_ok( dialog );
378 gtk_widget_destroy( GTK_WIDGET( window ) );
382 // =============================================================================
383 // Arbitrary Sides dialog
385 void DoSides( int type, int axis ){
387 GtkEntry* sides_entry;
389 GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Arbitrary sides", G_CALLBACK( dialog_delete_callback ), &dialog );
391 GtkAccelGroup* accel = gtk_accel_group_new();
392 gtk_window_add_accel_group( window, accel );
395 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
396 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
398 GtkLabel* label = GTK_LABEL( gtk_label_new( "Sides:" ) );
399 gtk_widget_show( GTK_WIDGET( label ) );
400 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
403 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
404 gtk_widget_show( GTK_WIDGET( entry ) );
405 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( entry ), FALSE, FALSE, 0 );
407 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
410 GtkVBox* vbox = create_dialog_vbox( 4 );
411 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
413 GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &dialog );
414 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
415 widget_make_default( GTK_WIDGET( button ) );
416 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
419 GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &dialog );
420 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
421 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
426 if ( modal_dialog_show( window, dialog ) == eIDOK ) {
427 const char *str = gtk_entry_get_text( sides_entry );
429 Scene_BrushConstructPrefab( GlobalSceneGraph(), (EBrushPrefab)type, atoi( str ), TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ) );
432 gtk_widget_destroy( GTK_WIDGET( window ) );
435 // =============================================================================
436 // About dialog (no program is complete without one)
438 void about_button_changelog( GtkWidget *widget, gpointer data ){
439 StringOutputStream log( 256 );
440 log << AppPath_get() << "changelog.txt";
441 OpenURL( log.c_str() );
444 void about_button_credits( GtkWidget *widget, gpointer data ){
445 StringOutputStream cred( 256 );
446 cred << AppPath_get() << "credits.html";
447 OpenURL( cred.c_str() );
452 ModalDialogButton ok_button( dialog, eIDOK );
454 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "About NetRadiant", dialog );
457 GtkVBox* vbox = create_dialog_vbox( 4, 4 );
458 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) );
461 GtkHBox* hbox = create_dialog_hbox( 4 );
462 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
465 GtkVBox* vbox2 = create_dialog_vbox( 4 );
466 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), TRUE, FALSE, 0 );
468 GtkFrame* frame = create_dialog_frame( 0, GTK_SHADOW_IN );
469 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
471 GtkImage* image = new_local_image( "logo.png" );
472 gtk_widget_show( GTK_WIDGET( image ) );
473 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( image ) );
479 GtkLabel* label = GTK_LABEL( gtk_label_new( "NetRadiant " RADIANT_VERSION "\n"
481 RADIANT_ABOUTMSG "\n\n"
482 "By alientrap.org\n\n"
483 "This program is free software\n"
484 "licensed under the GNU GPL.\n"
487 gtk_widget_show( GTK_WIDGET( label ) );
488 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
489 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
490 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
494 GtkVBox* vbox2 = create_dialog_vbox( 4 );
495 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), FALSE, TRUE, 0 );
497 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
498 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
501 GtkButton* button = create_dialog_button( "Credits", G_CALLBACK( about_button_credits ), 0 );
502 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
503 gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE);
506 GtkButton* button = create_dialog_button( "Changelog", G_CALLBACK( about_button_changelog ), 0 );
507 gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
508 gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE);
513 GtkFrame* frame = create_dialog_frame( "OpenGL Properties" );
514 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
516 GtkTable* table = create_dialog_table( 3, 2, 4, 4, 4 );
517 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( table ) );
519 GtkLabel* label = GTK_LABEL( gtk_label_new( "Vendor:" ) );
520 gtk_widget_show( GTK_WIDGET( label ) );
521 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
522 (GtkAttachOptions) ( GTK_FILL ),
523 (GtkAttachOptions) ( 0 ), 0, 0 );
524 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
527 GtkLabel* label = GTK_LABEL( gtk_label_new( "Version:" ) );
528 gtk_widget_show( GTK_WIDGET( label ) );
529 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
530 (GtkAttachOptions) ( GTK_FILL ),
531 (GtkAttachOptions) ( 0 ), 0, 0 );
532 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
535 GtkLabel* label = GTK_LABEL( gtk_label_new( "Renderer:" ) );
536 gtk_widget_show( GTK_WIDGET( label ) );
537 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 2, 3,
538 (GtkAttachOptions) ( GTK_FILL ),
539 (GtkAttachOptions) ( 0 ), 0, 0 );
540 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
543 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VENDOR ) ) ) );
544 gtk_widget_show( GTK_WIDGET( label ) );
545 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 0, 1,
546 (GtkAttachOptions) ( GTK_FILL ),
547 (GtkAttachOptions) ( 0 ), 0, 0 );
548 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
551 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_VERSION ) ) ) );
552 gtk_widget_show( GTK_WIDGET( label ) );
553 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 1, 2,
554 (GtkAttachOptions) ( GTK_FILL ),
555 (GtkAttachOptions) ( 0 ), 0, 0 );
556 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
559 GtkLabel* label = GTK_LABEL( gtk_label_new( reinterpret_cast<const char*>( glGetString( GL_RENDERER ) ) ) );
560 gtk_widget_show( GTK_WIDGET( label ) );
561 gtk_table_attach( table, GTK_WIDGET( label ), 1, 2, 2, 3,
562 (GtkAttachOptions) ( GTK_FILL ),
563 (GtkAttachOptions) ( 0 ), 0, 0 );
564 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
568 GtkFrame* frame = create_dialog_frame( "OpenGL Extensions" );
569 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 );
571 GtkScrolledWindow* sc_extensions = create_scrolled_window( GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, 4 );
572 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( sc_extensions ) );
574 GtkWidget* text_extensions = gtk_text_view_new();
575 gtk_text_view_set_editable( GTK_TEXT_VIEW( text_extensions ), FALSE );
576 gtk_container_add( GTK_CONTAINER( sc_extensions ), text_extensions );
577 GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_extensions ) );
578 gtk_text_buffer_set_text( buffer, reinterpret_cast<const char*>( glGetString( GL_EXTENSIONS ) ), -1 );
579 gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text_extensions ), GTK_WRAP_WORD );
580 gtk_widget_show( text_extensions );
587 modal_dialog_show( window, dialog );
589 gtk_widget_destroy( GTK_WIDGET( window ) );
592 // =============================================================================
593 // TextureLayout dialog
595 // Last used texture scale values
596 static float last_used_texture_layout_scale_x = 4.0;
597 static float last_used_texture_layout_scale_y = 4.0;
599 EMessageBoxReturn DoTextureLayout( float *fx, float *fy ){
601 ModalDialogButton ok_button( dialog, eIDOK );
602 ModalDialogButton cancel_button( dialog, eIDCANCEL );
606 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Patch texture layout", dialog );
608 GtkAccelGroup* accel = gtk_accel_group_new();
609 gtk_window_add_accel_group( window, accel );
612 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
613 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
615 GtkVBox* vbox = create_dialog_vbox( 4 );
616 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
618 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture will be fit across the patch based\n"
619 "on the x and y values given. Values of 1x1\n"
620 "will \"fit\" the texture. 2x2 will repeat\n"
621 "it twice, etc." ) );
622 gtk_widget_show( GTK_WIDGET( label ) );
623 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), TRUE, TRUE, 0 );
624 gtk_label_set_justify( label, GTK_JUSTIFY_LEFT );
627 GtkTable* table = create_dialog_table( 2, 2, 4, 4 );
628 gtk_widget_show( GTK_WIDGET( table ) );
629 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
631 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture x:" ) );
632 gtk_widget_show( GTK_WIDGET( label ) );
633 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 0, 1,
634 (GtkAttachOptions) ( GTK_FILL ),
635 (GtkAttachOptions) ( 0 ), 0, 0 );
636 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
639 GtkLabel* label = GTK_LABEL( gtk_label_new( "Texture y:" ) );
640 gtk_widget_show( GTK_WIDGET( label ) );
641 gtk_table_attach( table, GTK_WIDGET( label ), 0, 1, 1, 2,
642 (GtkAttachOptions) ( GTK_FILL ),
643 (GtkAttachOptions) ( 0 ), 0, 0 );
644 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
647 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
648 gtk_widget_show( GTK_WIDGET( entry ) );
649 gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 0, 1,
650 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
651 (GtkAttachOptions) ( 0 ), 0, 0 );
656 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
657 gtk_widget_show( GTK_WIDGET( entry ) );
658 gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 1, 2,
659 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
660 (GtkAttachOptions) ( 0 ), 0, 0 );
667 GtkVBox* vbox = create_dialog_vbox( 4 );
668 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
670 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
671 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
672 widget_make_default( GTK_WIDGET( button ) );
673 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 );
676 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
677 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
678 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 );
683 // Initialize with last used values
686 sprintf( buf, "%f", last_used_texture_layout_scale_x );
687 gtk_entry_set_text( x, buf );
689 sprintf( buf, "%f", last_used_texture_layout_scale_y );
690 gtk_entry_set_text( y, buf );
692 // Set focus after intializing the values
693 gtk_widget_grab_focus( GTK_WIDGET( x ) );
695 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
696 if ( ret == eIDOK ) {
697 *fx = static_cast<float>( atof( gtk_entry_get_text( x ) ) );
698 *fy = static_cast<float>( atof( gtk_entry_get_text( y ) ) );
700 // Remember last used values
701 last_used_texture_layout_scale_x = *fx;
702 last_used_texture_layout_scale_y = *fy;
705 gtk_widget_destroy( GTK_WIDGET( window ) );
710 // =============================================================================
711 // Text Editor dialog
713 // master window widget
714 static GtkWidget *text_editor = 0;
715 static GtkWidget *text_widget; // slave, text widget from the gtk editor
716 static GtkTextBuffer* text_buffer_;
718 static gint editor_delete( GtkWidget *widget, gpointer data ){
719 /* if ( gtk_MessageBox( widget, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
723 gtk_widget_hide( text_editor );
728 static void editor_save( GtkWidget *widget, gpointer data ){
729 FILE *f = fopen( (char*)g_object_get_data( G_OBJECT( data ), "filename" ), "w" );
730 //gpointer text = g_object_get_data( G_OBJECT( data ), "text" );
733 gtk_MessageBox( GTK_WIDGET( data ), "Error saving file !" );
737 /* Obtain iters for the start and end of points of the buffer */
740 gtk_text_buffer_get_start_iter (text_buffer_, &start);
741 gtk_text_buffer_get_end_iter (text_buffer_, &end);
743 /* Get the entire buffer text. */
744 char *str = gtk_text_buffer_get_text (text_buffer_, &start, &end, FALSE);
746 //char *str = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );
747 fwrite( str, 1, strlen( str ), f );
752 static void editor_close( GtkWidget *widget, gpointer data ){
753 /* if ( gtk_MessageBox( text_editor, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION ) == eIDNO ) {
757 gtk_widget_hide( text_editor );
760 static void CreateGtkTextEditor(){
762 GtkWidget *vbox, *hbox, *button, *scr, *text;
764 dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
766 g_signal_connect( G_OBJECT( dlg ), "delete_event",
767 G_CALLBACK( editor_delete ), 0 );
768 gtk_window_set_default_size( GTK_WINDOW( dlg ), 400, 600 );
770 vbox = gtk_vbox_new( FALSE, 5 );
771 gtk_widget_show( vbox );
772 gtk_container_add( GTK_CONTAINER( dlg ), GTK_WIDGET( vbox ) );
773 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
775 scr = gtk_scrolled_window_new( 0, 0 );
776 gtk_widget_show( scr );
777 gtk_box_pack_start( GTK_BOX( vbox ), scr, TRUE, TRUE, 0 );
778 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
779 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
781 text = gtk_text_view_new();
782 gtk_container_add( GTK_CONTAINER( scr ), text );
783 gtk_widget_show( text );
784 g_object_set_data( G_OBJECT( dlg ), "text", text );
785 gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), TRUE );
787 hbox = gtk_hbox_new( FALSE, 5 );
788 gtk_widget_show( hbox );
789 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 );
791 button = gtk_button_new_with_label( "Close" );
792 gtk_widget_show( button );
793 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
794 g_signal_connect( G_OBJECT( button ), "clicked",
795 G_CALLBACK( editor_close ), dlg );
796 gtk_widget_set_usize( button, 60, -2 );
798 button = gtk_button_new_with_label( "Save" );
799 gtk_widget_show( button );
800 gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
801 g_signal_connect( G_OBJECT( button ), "clicked",
802 G_CALLBACK( editor_save ), dlg );
803 gtk_widget_set_usize( button, 60, -2 );
809 static void DoGtkTextEditor( const char* filename, guint cursorpos, int length ){
810 if ( !text_editor ) {
811 CreateGtkTextEditor(); // build it the first time we need it
815 FILE *f = fopen( filename, "r" );
818 globalOutputStream() << "Unable to load file " << filename << " in shader editor.\n";
819 gtk_widget_hide( text_editor );
823 fseek( f, 0, SEEK_END );
824 int len = ftell( f );
825 void *buf = malloc( len );
829 fread( buf, 1, len, f );
831 gtk_window_set_title( GTK_WINDOW( text_editor ), filename );
833 GtkTextBuffer* text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_widget ) );
834 gtk_text_buffer_set_text( text_buffer, (char*)buf, length );
836 old_filename = g_object_get_data( G_OBJECT( text_editor ), "filename" );
837 if ( old_filename ) {
838 free( old_filename );
840 g_object_set_data( G_OBJECT( text_editor ), "filename", strdup( filename ) );
842 // trying to show later
843 gtk_widget_show( text_editor );
844 gtk_window_present( GTK_WINDOW( text_editor ) );
850 // only move the cursor if it's not exceeding the size..
851 // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters
852 // len is the max size in bytes, not in characters either, but the character count is below that limit..
853 // thinking .. the difference between character count and byte count would be only because of CR/LF?
855 GtkTextIter text_iter;
856 // character offset, not byte offset
857 gtk_text_buffer_get_iter_at_offset( text_buffer, &text_iter, cursorpos );
858 gtk_text_buffer_place_cursor( text_buffer, &text_iter );
859 gtk_text_view_scroll_to_iter( GTK_TEXT_VIEW( text_widget ), &text_iter, 0, TRUE, 0, 0);
863 gtk_widget_queue_draw( text_widget );
866 text_buffer_ = text_buffer;
872 // =============================================================================
873 // Light Intensity dialog
875 EMessageBoxReturn DoLightIntensityDlg( int *intensity ){
877 GtkEntry* intensity_entry;
878 ModalDialogButton ok_button( dialog, eIDOK );
879 ModalDialogButton cancel_button( dialog, eIDCANCEL );
881 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), "Light intensity", dialog, -1, -1 );
883 GtkAccelGroup *accel_group = gtk_accel_group_new();
884 gtk_window_add_accel_group( window, accel_group );
887 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
888 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
890 GtkVBox* vbox = create_dialog_vbox( 4 );
891 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
893 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC for default, ENTER to validate" ) );
894 gtk_widget_show( GTK_WIDGET( label ) );
895 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
898 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
899 gtk_widget_show( GTK_WIDGET( entry ) );
900 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
902 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
904 intensity_entry = entry;
908 GtkVBox* vbox = create_dialog_vbox( 4 );
909 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
912 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
913 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
914 widget_make_default( GTK_WIDGET( button ) );
915 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
918 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
919 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
920 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
926 sprintf( buf, "%d", *intensity );
927 gtk_entry_set_text( intensity_entry, buf );
929 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
930 if ( ret == eIDOK ) {
931 *intensity = atoi( gtk_entry_get_text( intensity_entry ) );
934 gtk_widget_destroy( GTK_WIDGET( window ) );
939 // =============================================================================
940 // Add new shader tag dialog
942 EMessageBoxReturn DoShaderTagDlg( CopiedString* tag, char* title ){
945 ModalDialogButton ok_button( dialog, eIDOK );
946 ModalDialogButton cancel_button( dialog, eIDCANCEL );
948 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
950 GtkAccelGroup *accel_group = gtk_accel_group_new();
951 gtk_window_add_accel_group( window, accel_group );
954 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
955 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
957 GtkVBox* vbox = create_dialog_vbox( 4 );
958 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), TRUE, TRUE, 0 );
960 //GtkLabel* label = GTK_LABEL(gtk_label_new("Enter one ore more tags separated by spaces"));
961 GtkLabel* label = GTK_LABEL( gtk_label_new( "ESC to cancel, ENTER to validate" ) );
962 gtk_widget_show( GTK_WIDGET( label ) );
963 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
966 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
967 gtk_widget_show( GTK_WIDGET( entry ) );
968 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
970 gtk_widget_grab_focus( GTK_WIDGET( entry ) );
976 GtkVBox* vbox = create_dialog_vbox( 4 );
977 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
980 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
981 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
982 widget_make_default( GTK_WIDGET( button ) );
983 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
986 GtkButton* button = create_modal_dialog_button( "Cancel", cancel_button );
987 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
988 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
993 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
994 if ( ret == eIDOK ) {
995 *tag = gtk_entry_get_text( textentry );
998 gtk_widget_destroy( GTK_WIDGET( window ) );
1003 EMessageBoxReturn DoShaderInfoDlg( const char* name, const char* filename, char* title ){
1005 ModalDialogButton ok_button( dialog, eIDOK );
1007 GtkWindow* window = create_modal_dialog_window( MainFrame_getWindow(), title, dialog, -1, -1 );
1009 GtkAccelGroup *accel_group = gtk_accel_group_new();
1010 gtk_window_add_accel_group( window, accel_group );
1013 GtkHBox* hbox = create_dialog_hbox( 4, 4 );
1014 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
1016 GtkVBox* vbox = create_dialog_vbox( 4 );
1017 gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox ), FALSE, FALSE, 0 );
1019 GtkLabel* label = GTK_LABEL( gtk_label_new( "The selected shader" ) );
1020 gtk_widget_show( GTK_WIDGET( label ) );
1021 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1024 GtkLabel* label = GTK_LABEL( gtk_label_new( name ) );
1025 gtk_widget_show( GTK_WIDGET( label ) );
1026 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1029 GtkLabel* label = GTK_LABEL( gtk_label_new( "is located in file" ) );
1030 gtk_widget_show( GTK_WIDGET( label ) );
1031 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1034 GtkLabel* label = GTK_LABEL( gtk_label_new( filename ) );
1035 gtk_widget_show( GTK_WIDGET( label ) );
1036 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, FALSE, 0 );
1039 GtkButton* button = create_modal_dialog_button( "OK", ok_button );
1040 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
1041 widget_make_default( GTK_WIDGET( button ) );
1042 gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE );
1047 EMessageBoxReturn ret = modal_dialog_show( window, dialog );
1049 gtk_widget_destroy( GTK_WIDGET( window ) );
1057 #include <gdk/gdkwin32.h>
1061 // use the file associations to open files instead of builtin Gtk editor
1062 bool g_TextEditor_useWin32Editor = false;
1064 // custom shader editor
1065 bool g_TextEditor_useCustomEditor = false;
1066 CopiedString g_TextEditor_editorCommand( "" );
1069 void DoTextEditor( const char* filename, int cursorpos, int length ){
1071 if ( g_TextEditor_useWin32Editor ) {
1072 StringOutputStream path( 256 );
1073 StringOutputStream modpath( 256 );
1074 const char* gamename = GlobalRadiant().getGameName();
1075 const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue( "basegame" );
1076 const char* enginePath = GlobalRadiant().getEnginePath();
1077 path << enginePath << basegame << '/' << filename;
1078 modpath << enginePath << gamename << '/' << filename;
1079 if ( file_exists( modpath.c_str() ) ){
1080 globalOutputStream() << "opening file '" << modpath.c_str() << "' (line " << cursorpos << " info ignored)\n";
1081 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", modpath.c_str(), 0, 0, SW_SHOW );
1083 else if ( file_exists( path.c_str() ) ){
1084 globalOutputStream() << "opening file '" << path.c_str() << "' (line " << cursorpos << " info ignored)\n";
1085 ShellExecute( (HWND)GDK_WINDOW_HWND( GTK_WIDGET( MainFrame_getWindow() )->window ), "open", path.c_str(), 0, 0, SW_SHOW );
1088 globalOutputStream() << "Failed to open '" << filename << "'\nOne sits in .pk3 most likely!\n";
1093 StringOutputStream path( 256 );
1094 StringOutputStream modpath( 256 );
1095 const char* gamename = GlobalRadiant().getGameName();
1096 const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue( "basegame" );
1097 const char* enginePath = GlobalRadiant().getEnginePath();
1098 path << enginePath << basegame << '/' << filename;
1099 modpath << enginePath << gamename << '/' << filename;
1100 if ( file_exists( modpath.c_str() ) ){
1101 globalOutputStream() << "opening file '" << modpath.c_str() << "' (line " << cursorpos << " info ignored)\n";
1102 DoGtkTextEditor( modpath.c_str(), cursorpos, length );
1104 else if ( file_exists( path.c_str() ) ){
1105 globalOutputStream() << "opening file '" << path.c_str() << "' (line " << cursorpos << " info ignored)\n";
1106 DoGtkTextEditor( path.c_str(), cursorpos, length );
1109 globalOutputStream() << "Failed to open '" << filename << "'\nOne sits in .pk3 most likely!\n";
1114 // check if a custom editor is set
1115 if ( g_TextEditor_useCustomEditor && !g_TextEditor_editorCommand.empty() ) {
1116 StringOutputStream strEditCommand( 256 );
1117 strEditCommand << g_TextEditor_editorCommand.c_str() << " \"" << filename << "\"";
1119 globalOutputStream() << "Launching: " << strEditCommand.c_str() << "\n";
1120 // note: linux does not return false if the command failed so it will assume success
1121 if ( Q_Exec( 0, const_cast<char*>( strEditCommand.c_str() ), 0, true, false ) == false ) {
1122 globalOutputStream() << "Failed to execute " << strEditCommand.c_str() << ", using default\n";
1126 // the command (appeared) to run successfully, no need to do anything more
1131 DoGtkTextEditor( filename, cursorpos, length );