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"))
109 typedef LazyStatic<GameComboConfiguration> LazyStaticGameComboConfiguration;
111 inline GameComboConfiguration& globalGameComboConfiguration()
113 return LazyStaticGameComboConfiguration::instance();
119 gamecombo_t(int _game, const char* _fs_game, bool _sensitive)
120 : game(_game), fs_game(_fs_game), sensitive(_sensitive)
127 gamecombo_t gamecombo_for_dir(const char* dir)
129 if(string_equal(dir, globalGameComboConfiguration().basegame_dir))
131 return gamecombo_t(0, "", false);
133 else if(string_equal(dir, globalGameComboConfiguration().known_dir))
135 return gamecombo_t(1, dir, false);
139 return gamecombo_t(string_empty(globalGameComboConfiguration().known_dir) ? 1 : 2, dir, true);
143 gamecombo_t gamecombo_for_gamename(const char* gamename)
145 if ((strlen(gamename) == 0) || !strcmp(gamename, globalGameComboConfiguration().basegame))
147 return gamecombo_t(0, "", false);
149 else if (!strcmp(gamename, globalGameComboConfiguration().known))
151 return gamecombo_t(1, globalGameComboConfiguration().known_dir, false);
155 return gamecombo_t(string_empty(globalGameComboConfiguration().known_dir) ? 1 : 2, "", true);
159 inline void path_copy_clean(char* destination, const char* source)
161 char* i = destination;
163 while(*source != '\0')
165 *i++ = (*source == '\\') ? '/' : *source;
169 if(i != destination && *(i-1) != '/')
178 GtkComboBox* game_select;
179 GtkEntry* fsgame_entry;
182 gboolean OnSelchangeComboWhatgame(GtkWidget *widget, GameCombo* combo)
184 const char *gamename;
187 gtk_combo_box_get_active_iter(combo->game_select, &iter);
188 gtk_tree_model_get(gtk_combo_box_get_model(combo->game_select), &iter, 0, (gpointer*)&gamename, -1);
191 gamecombo_t gamecombo = gamecombo_for_gamename(gamename);
193 gtk_entry_set_text(combo->fsgame_entry, gamecombo.fs_game);
194 gtk_widget_set_sensitive(GTK_WIDGET(combo->fsgame_entry), gamecombo.sensitive);
202 bool do_mapping_mode;
203 const char* sp_mapping_mode;
204 const char* mp_mapping_mode;
207 do_mapping_mode(!string_empty(g_pGameDescription->getKeyValue("show_gamemode"))),
208 sp_mapping_mode("Single Player mapping mode"),
209 mp_mapping_mode("Multiplayer mapping mode")
214 typedef LazyStatic<MappingMode> LazyStaticMappingMode;
216 inline MappingMode& globalMappingMode()
218 return LazyStaticMappingMode::instance();
221 class ProjectSettingsDialog
224 GameCombo game_combo;
225 GtkComboBox* gamemode_combo;
228 GtkWindow* ProjectSettingsDialog_construct(ProjectSettingsDialog& dialog, ModalDialog& modal)
230 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Project Settings", G_CALLBACK(dialog_delete_callback), &modal);
233 GtkTable* table1 = create_dialog_table(1, 2, 4, 4, 4);
234 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(table1));
236 GtkVBox* vbox = create_dialog_vbox(4);
237 gtk_table_attach(table1, GTK_WIDGET(vbox), 1, 2, 0, 1,
238 (GtkAttachOptions) (GTK_FILL),
239 (GtkAttachOptions) (GTK_FILL), 0, 0);
241 GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &modal);
242 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
245 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &modal);
246 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
250 GtkFrame* frame = create_dialog_frame("Project settings");
251 gtk_table_attach(table1, GTK_WIDGET(frame), 0, 1, 0, 1,
252 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
253 (GtkAttachOptions) (GTK_FILL), 0, 0);
255 GtkTable* table2 = create_dialog_table((globalMappingMode().do_mapping_mode) ? 4 : 3, 2, 4, 4, 4);
256 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(table2));
259 GtkLabel* label = GTK_LABEL(gtk_label_new("Select mod"));
260 gtk_widget_show(GTK_WIDGET(label));
261 gtk_table_attach(table2, GTK_WIDGET(label), 0, 1, 0, 1,
262 (GtkAttachOptions) (GTK_FILL),
263 (GtkAttachOptions) (0), 0, 0);
264 gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
267 dialog.game_combo.game_select = GTK_COMBO_BOX(gtk_combo_box_new_text());
269 gtk_combo_box_append_text(dialog.game_combo.game_select, globalGameComboConfiguration().basegame);
270 if(globalGameComboConfiguration().known[0] != '\0')
271 gtk_combo_box_append_text(dialog.game_combo.game_select, globalGameComboConfiguration().known);
272 gtk_combo_box_append_text(dialog.game_combo.game_select, globalGameComboConfiguration().custom);
274 gtk_widget_show(GTK_WIDGET(dialog.game_combo.game_select));
275 gtk_table_attach(table2, GTK_WIDGET(dialog.game_combo.game_select), 1, 2, 0, 1,
276 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
277 (GtkAttachOptions) (0), 0, 0);
279 g_signal_connect(G_OBJECT(dialog.game_combo.game_select), "changed", G_CALLBACK(OnSelchangeComboWhatgame), &dialog.game_combo);
283 GtkLabel* label = GTK_LABEL(gtk_label_new("fs_game"));
284 gtk_widget_show(GTK_WIDGET(label));
285 gtk_table_attach(table2, GTK_WIDGET(label), 0, 1, 1, 2,
286 (GtkAttachOptions) (GTK_FILL),
287 (GtkAttachOptions) (0), 0, 0);
288 gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
291 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
292 gtk_widget_show(GTK_WIDGET(entry));
293 gtk_table_attach(table2, GTK_WIDGET(entry), 1, 2, 1, 2,
294 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
295 (GtkAttachOptions) (0), 0, 0);
297 dialog.game_combo.fsgame_entry = entry;
300 if(globalMappingMode().do_mapping_mode)
302 GtkLabel* label = GTK_LABEL(gtk_label_new("Mapping mode"));
303 gtk_widget_show(GTK_WIDGET(label));
304 gtk_table_attach(table2, GTK_WIDGET(label), 0, 1, 3, 4,
305 (GtkAttachOptions) (GTK_FILL),
306 (GtkAttachOptions) (0), 0, 0);
307 gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
309 GtkComboBox* combo = GTK_COMBO_BOX(gtk_combo_box_new_text());
310 gtk_combo_box_append_text(combo, globalMappingMode().sp_mapping_mode);
311 gtk_combo_box_append_text(combo, globalMappingMode().mp_mapping_mode);
313 gtk_widget_show(GTK_WIDGET(combo));
314 gtk_table_attach(table2, GTK_WIDGET(combo), 1, 2, 3, 4,
315 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
316 (GtkAttachOptions) (0), 0, 0);
318 dialog.gamemode_combo = combo;
324 // initialise the fs_game selection from the project settings into the dialog
325 const char* dir = gamename_get();
326 gamecombo_t gamecombo = gamecombo_for_dir(dir);
328 gtk_combo_box_set_active(dialog.game_combo.game_select, gamecombo.game);
329 gtk_entry_set_text(dialog.game_combo.fsgame_entry, gamecombo.fs_game);
330 gtk_widget_set_sensitive(GTK_WIDGET(dialog.game_combo.fsgame_entry), gamecombo.sensitive);
332 if(globalMappingMode().do_mapping_mode)
334 const char *gamemode = gamemode_get();
335 if (string_empty(gamemode) || string_equal(gamemode, "sp"))
337 gtk_combo_box_set_active(dialog.gamemode_combo, 0);
341 gtk_combo_box_set_active(dialog.gamemode_combo, 1);
348 void ProjectSettingsDialog_ok(ProjectSettingsDialog& dialog)
350 const char* dir = gtk_entry_get_text(dialog.game_combo.fsgame_entry);
352 const char* new_gamename = path_equal(dir, globalGameComboConfiguration().basegame_dir)
356 if(!path_equal(new_gamename, gamename_get()))
358 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Changing Game Name");
360 EnginePath_Unrealise();
362 gamename_set(new_gamename);
364 EnginePath_Realise();
367 if(globalMappingMode().do_mapping_mode)
369 // read from gamemode_combo
370 int active = gtk_combo_box_get_active(dialog.gamemode_combo);
371 if(active == -1 || active == 0)
382 void DoProjectSettings()
384 if(ConfirmModified("Edit Project Settings"))
387 ProjectSettingsDialog dialog;
389 GtkWindow* window = ProjectSettingsDialog_construct(dialog, modal);
391 if(modal_dialog_show(window, modal) == eIDOK)
393 ProjectSettingsDialog_ok(dialog);
396 gtk_widget_destroy(GTK_WIDGET(window));
400 // =============================================================================
401 // Arbitrary Sides dialog
403 void DoSides (int type, int axis)
406 GtkEntry* sides_entry;
408 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Arbitrary sides", G_CALLBACK(dialog_delete_callback), &dialog);
410 GtkAccelGroup* accel = gtk_accel_group_new();
411 gtk_window_add_accel_group(window, accel);
414 GtkHBox* hbox = create_dialog_hbox(4, 4);
415 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
417 GtkLabel* label = GTK_LABEL(gtk_label_new("Sides:"));
418 gtk_widget_show(GTK_WIDGET(label));
419 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 0);
422 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
423 gtk_widget_show(GTK_WIDGET(entry));
424 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(entry), FALSE, FALSE, 0);
426 gtk_widget_grab_focus(GTK_WIDGET(entry));
429 GtkVBox* vbox = create_dialog_vbox(4);
430 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
432 GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &dialog);
433 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
434 widget_make_default(GTK_WIDGET(button));
435 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
438 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &dialog);
439 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
440 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
445 if(modal_dialog_show(window, dialog) == eIDOK)
447 const char *str = gtk_entry_get_text(sides_entry);
449 Scene_BrushConstructPrefab(GlobalSceneGraph(), (EBrushPrefab)type, atoi(str), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
452 gtk_widget_destroy(GTK_WIDGET(window));
455 // =============================================================================
456 // About dialog (no program is complete without one)
458 void about_button_changelog (GtkWidget *widget, gpointer data)
460 StringOutputStream log(256);
461 log << AppPath_get() << "changelog.txt";
462 OpenURL(log.c_str());
465 void about_button_credits (GtkWidget *widget, gpointer data)
467 StringOutputStream cred(256);
468 cred << AppPath_get() << "credits.html";
469 OpenURL(cred.c_str());
475 ModalDialogButton ok_button(dialog, eIDOK);
477 GtkWindow* window = create_modal_dialog_window(MainFrame_getWindow(), "About GtkRadiant", dialog);
480 GtkVBox* vbox = create_dialog_vbox(4, 4);
481 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
484 GtkHBox* hbox = create_dialog_hbox(4);
485 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, TRUE, 0);
488 GtkVBox* vbox2 = create_dialog_vbox(4);
489 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox2), TRUE, FALSE, 0);
491 GtkFrame* frame = create_dialog_frame(0, GTK_SHADOW_IN);
492 gtk_box_pack_start(GTK_BOX (vbox2), GTK_WIDGET(frame), FALSE, FALSE, 0);
494 GtkImage* image = new_local_image("logo.bmp");
495 gtk_widget_show(GTK_WIDGET(image));
496 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(image));
502 GtkLabel* label = GTK_LABEL(gtk_label_new("GtkRadiant " RADIANT_VERSION "\n"
504 RADIANT_ABOUTMSG "\n\n"
505 "By qeradiant.com\n\n"
506 "This program is free software\n"
507 "licensed under the GNU GPL.\n\n"
508 "GtkRadiant is unsupported, however\n"
509 "you may report your problems at\n"
510 "http://zerowing.idsoftware.com/bugzilla"
513 gtk_widget_show(GTK_WIDGET(label));
514 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 0);
515 gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
516 gtk_label_set_justify(label, GTK_JUSTIFY_LEFT);
520 GtkVBox* vbox2 = create_dialog_vbox(4);
521 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox2), FALSE, TRUE, 0);
523 GtkButton* button = create_modal_dialog_button("OK", ok_button);
524 gtk_box_pack_start (GTK_BOX (vbox2), GTK_WIDGET(button), FALSE, FALSE, 0);
527 GtkButton* button = create_dialog_button("Credits", G_CALLBACK(about_button_credits), 0);
528 gtk_box_pack_start (GTK_BOX (vbox2), GTK_WIDGET(button), FALSE, FALSE, 0);
531 GtkButton* button = create_dialog_button("Changelog", G_CALLBACK(about_button_changelog), 0);
532 gtk_box_pack_start (GTK_BOX (vbox2), GTK_WIDGET(button), FALSE, FALSE, 0);
537 GtkFrame* frame = create_dialog_frame("OpenGL Properties");
538 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(frame), FALSE, FALSE, 0);
540 GtkTable* table = create_dialog_table(3, 2, 4, 4, 4);
541 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(table));
543 GtkLabel* label = GTK_LABEL(gtk_label_new("Vendor:"));
544 gtk_widget_show(GTK_WIDGET(label));
545 gtk_table_attach(table, GTK_WIDGET(label), 0, 1, 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("Version:"));
552 gtk_widget_show(GTK_WIDGET(label));
553 gtk_table_attach(table, GTK_WIDGET(label), 0, 1, 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("Renderer:"));
560 gtk_widget_show(GTK_WIDGET(label));
561 gtk_table_attach(table, GTK_WIDGET(label), 0, 1, 2, 3,
562 (GtkAttachOptions) (GTK_FILL),
563 (GtkAttachOptions) (0), 0, 0);
564 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
567 GtkLabel* label = GTK_LABEL(gtk_label_new(reinterpret_cast<const char*>(glGetString(GL_VENDOR))));
568 gtk_widget_show(GTK_WIDGET(label));
569 gtk_table_attach(table, GTK_WIDGET(label), 1, 2, 0, 1,
570 (GtkAttachOptions) (GTK_FILL),
571 (GtkAttachOptions) (0), 0, 0);
572 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
575 GtkLabel* label = GTK_LABEL(gtk_label_new(reinterpret_cast<const char*>(glGetString(GL_VERSION))));
576 gtk_widget_show(GTK_WIDGET(label));
577 gtk_table_attach(table, GTK_WIDGET(label), 1, 2, 1, 2,
578 (GtkAttachOptions) (GTK_FILL),
579 (GtkAttachOptions) (0), 0, 0);
580 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
583 GtkLabel* label = GTK_LABEL(gtk_label_new(reinterpret_cast<const char*>(glGetString(GL_RENDERER))));
584 gtk_widget_show(GTK_WIDGET(label));
585 gtk_table_attach(table, GTK_WIDGET(label), 1, 2, 2, 3,
586 (GtkAttachOptions) (GTK_FILL),
587 (GtkAttachOptions) (0), 0, 0);
588 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
592 GtkFrame* frame = create_dialog_frame("OpenGL Extensions");
593 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(frame), TRUE, TRUE, 0);
595 GtkScrolledWindow* sc_extensions = create_scrolled_window(GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, 4);
596 gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET(sc_extensions));
598 GtkWidget* text_extensions = gtk_text_view_new();
599 gtk_text_view_set_editable(GTK_TEXT_VIEW(text_extensions), FALSE);
600 gtk_container_add (GTK_CONTAINER (sc_extensions), text_extensions);
601 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_extensions));
602 gtk_text_buffer_set_text(buffer, reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)), -1);
603 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_extensions), GTK_WRAP_WORD);
604 gtk_widget_show(text_extensions);
611 modal_dialog_show(window, dialog);
613 gtk_widget_destroy(GTK_WIDGET(window));
616 // =============================================================================
617 // Texture List dialog
619 void DoTextureListDlg()
622 ModalDialogButton ok_button(dialog, eIDOK);
623 ModalDialogButton cancel_button(dialog, eIDCANCEL);
624 GtkWidget* texture_list;
626 GtkWindow* window = create_modal_dialog_window(MainFrame_getWindow(), "Textures", dialog, 400, 400);
628 GtkHBox* hbox = create_dialog_hbox(4, 4);
629 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
632 GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
633 gtk_box_pack_start(GTK_BOX (hbox), GTK_WIDGET(scr), TRUE, TRUE, 0);
637 GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING);
639 GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
640 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
643 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
644 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, 0);
645 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
648 gtk_widget_show(view);
649 gtk_container_add(GTK_CONTAINER (scr), view);
653 GSList *textures = 0;
654 TextureGroupsMenu_ListItems(textures);
655 while (textures != 0)
659 gtk_list_store_append(store, &iter);
660 StringOutputStream name(64);
661 name << ConvertLocaleToUTF8(reinterpret_cast<const char*>(textures->data));
662 gtk_list_store_set(store, &iter, 0, name.c_str(), -1);
664 textures = g_slist_remove (textures, textures->data);
668 g_object_unref(G_OBJECT(store));
674 GtkVBox* vbox = create_dialog_vbox(4);
675 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, TRUE, 0);
677 GtkButton* button = create_modal_dialog_button("Load", ok_button);
678 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
681 GtkButton* button = create_modal_dialog_button("Close", cancel_button);
682 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
685 if(modal_dialog_show(window, dialog) == eIDOK)
687 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(texture_list));
691 if(gtk_tree_selection_get_selected(selection, &model, &iter))
693 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
694 if(gtk_tree_path_get_depth(path) == 1)
695 TextureBrowser_ShowDirectory(GlobalTextureBrowser(), TextureGroupsMenu_GetName(gtk_tree_path_get_indices(path)[0]));
696 gtk_tree_path_free(path);
700 gtk_widget_destroy(GTK_WIDGET(window));
703 // =============================================================================
704 // TextureLayout dialog
706 EMessageBoxReturn DoTextureLayout (float *fx, float *fy)
709 ModalDialogButton ok_button(dialog, eIDOK);
710 ModalDialogButton cancel_button(dialog, eIDCANCEL);
714 GtkWindow* window = create_modal_dialog_window(MainFrame_getWindow(), "Patch texture layout", dialog);
716 GtkAccelGroup* accel = gtk_accel_group_new();
717 gtk_window_add_accel_group(window, accel);
720 GtkHBox* hbox = create_dialog_hbox(4, 4);
721 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
723 GtkVBox* vbox = create_dialog_vbox(4);
724 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
726 GtkLabel* label = GTK_LABEL(gtk_label_new("Texture will be fit across the patch based\n"
727 "on the x and y values given. Values of 1x1\n"
728 "will \"fit\" the texture. 2x2 will repeat\n"
730 gtk_widget_show(GTK_WIDGET(label));
731 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), TRUE, TRUE, 0);
732 gtk_label_set_justify(label, GTK_JUSTIFY_LEFT);
735 GtkTable* table = create_dialog_table(2, 2, 4, 4);
736 gtk_widget_show(GTK_WIDGET(table));
737 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
739 GtkLabel* label = GTK_LABEL(gtk_label_new("Texture x:"));
740 gtk_widget_show(GTK_WIDGET(label));
741 gtk_table_attach(table, GTK_WIDGET(label), 0, 1, 0, 1,
742 (GtkAttachOptions) (GTK_FILL),
743 (GtkAttachOptions) (0), 0, 0);
744 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
747 GtkLabel* label = GTK_LABEL(gtk_label_new("Texture y:"));
748 gtk_widget_show(GTK_WIDGET(label));
749 gtk_table_attach(table, GTK_WIDGET(label), 0, 1, 1, 2,
750 (GtkAttachOptions) (GTK_FILL),
751 (GtkAttachOptions) (0), 0, 0);
752 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
755 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
756 gtk_widget_show(GTK_WIDGET(entry));
757 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
758 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
759 (GtkAttachOptions) (0), 0, 0);
761 gtk_widget_grab_focus(GTK_WIDGET(entry));
766 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
767 gtk_widget_show(GTK_WIDGET(entry));
768 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
769 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
770 (GtkAttachOptions) (0), 0, 0);
777 GtkVBox* vbox = create_dialog_vbox(4);
778 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 0);
780 GtkButton* button = create_modal_dialog_button("OK", ok_button);
781 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
782 widget_make_default(GTK_WIDGET(button));
783 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
786 GtkButton* button = create_modal_dialog_button("Cancel", cancel_button);
787 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
788 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
794 gtk_entry_set_text(x, "4.0");
795 gtk_entry_set_text(y, "4.0");
798 EMessageBoxReturn ret = modal_dialog_show(window, dialog);
801 *fx = static_cast<float>(atof(gtk_entry_get_text(x)));
802 *fy = static_cast<float>(atof(gtk_entry_get_text(y)));
805 gtk_widget_destroy(GTK_WIDGET(window));
810 // =============================================================================
811 // Text Editor dialog
813 // master window widget
814 static GtkWidget *text_editor = 0;
815 static GtkWidget *text_widget; // slave, text widget from the gtk editor
817 static gint editor_delete (GtkWidget *widget, gpointer data)
819 if (gtk_MessageBox (widget, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION) == eIDNO)
822 gtk_widget_hide (text_editor);
827 static void editor_save (GtkWidget *widget, gpointer data)
829 FILE *f = fopen ((char*)g_object_get_data (G_OBJECT (data), "filename"), "w");
830 gpointer text = g_object_get_data (G_OBJECT (data), "text");
834 gtk_MessageBox (GTK_WIDGET(data), "Error saving file !");
838 char *str = gtk_editable_get_chars (GTK_EDITABLE (text), 0, -1);
839 fwrite (str, 1, strlen (str), f);
843 static void editor_close (GtkWidget *widget, gpointer data)
845 if (gtk_MessageBox (text_editor, "Close the shader editor ?", "Radiant", eMB_YESNO, eMB_ICONQUESTION) == eIDNO)
848 gtk_widget_hide (text_editor);
851 static void CreateGtkTextEditor()
854 GtkWidget *vbox, *hbox, *button, *scr, *text;
856 dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
858 g_signal_connect(G_OBJECT(dlg), "delete_event",
859 G_CALLBACK(editor_delete), 0);
860 gtk_window_set_default_size (GTK_WINDOW (dlg), 600, 300);
862 vbox = gtk_vbox_new (FALSE, 5);
863 gtk_widget_show (vbox);
864 gtk_container_add(GTK_CONTAINER(dlg), GTK_WIDGET(vbox));
865 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
867 scr = gtk_scrolled_window_new (0, 0);
868 gtk_widget_show (scr);
869 gtk_box_pack_start(GTK_BOX(vbox), scr, TRUE, TRUE, 0);
870 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
871 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN);
873 text = gtk_text_view_new();
874 gtk_container_add (GTK_CONTAINER (scr), text);
875 gtk_widget_show (text);
876 g_object_set_data (G_OBJECT (dlg), "text", text);
877 gtk_text_view_set_editable (GTK_TEXT_VIEW(text), TRUE);
879 hbox = gtk_hbox_new (FALSE, 5);
880 gtk_widget_show (hbox);
881 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, TRUE, 0);
883 button = gtk_button_new_with_label ("Close");
884 gtk_widget_show (button);
885 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
886 g_signal_connect(G_OBJECT(button), "clicked",
887 G_CALLBACK(editor_close), dlg);
888 gtk_widget_set_usize (button, 60, -2);
890 button = gtk_button_new_with_label ("Save");
891 gtk_widget_show (button);
892 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
893 g_signal_connect(G_OBJECT(button), "clicked",
894 G_CALLBACK(editor_save), dlg);
895 gtk_widget_set_usize (button, 60, -2);
901 static void DoGtkTextEditor (const char* filename, guint cursorpos)
904 CreateGtkTextEditor(); // build it the first time we need it
907 FILE *f = fopen (filename, "r");
911 globalOutputStream() << "Unable to load file " << filename << " in shader editor.\n";
912 gtk_widget_hide (text_editor);
916 fseek (f, 0, SEEK_END);
918 void *buf = malloc (len);
922 fread (buf, 1, len, f);
924 gtk_window_set_title (GTK_WINDOW (text_editor), filename);
926 GtkTextBuffer* text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_widget));
927 gtk_text_buffer_set_text(text_buffer, (char*)buf, len);
929 old_filename = g_object_get_data (G_OBJECT (text_editor), "filename");
932 g_object_set_data (G_OBJECT (text_editor), "filename", strdup (filename));
934 // trying to show later
935 gtk_widget_show (text_editor);
941 // only move the cursor if it's not exceeding the size..
942 // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters
943 // len is the max size in bytes, not in characters either, but the character count is below that limit..
944 // thinking .. the difference between character count and byte count would be only because of CR/LF?
946 GtkTextIter text_iter;
947 // character offset, not byte offset
948 gtk_text_buffer_get_iter_at_offset(text_buffer, &text_iter, cursorpos);
949 gtk_text_buffer_place_cursor(text_buffer, &text_iter);
953 gtk_widget_queue_draw(text_widget);
961 // =============================================================================
962 // Light Intensity dialog
964 EMessageBoxReturn DoLightIntensityDlg (int *intensity)
967 GtkEntry* intensity_entry;
968 ModalDialogButton ok_button(dialog, eIDOK);
969 ModalDialogButton cancel_button(dialog, eIDCANCEL);
971 GtkWindow* window = create_modal_dialog_window(MainFrame_getWindow(), "Light intensity", dialog, -1, -1);
973 GtkAccelGroup *accel_group = gtk_accel_group_new();
974 gtk_window_add_accel_group(window, accel_group);
977 GtkHBox* hbox = create_dialog_hbox(4, 4);
978 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
980 GtkVBox* vbox = create_dialog_vbox(4);
981 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
983 GtkLabel* label = GTK_LABEL(gtk_label_new("ESC for default, ENTER to validate"));
984 gtk_widget_show(GTK_WIDGET(label));
985 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), FALSE, FALSE, 0);
988 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
989 gtk_widget_show(GTK_WIDGET(entry));
990 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(entry), TRUE, TRUE, 0);
992 gtk_widget_grab_focus(GTK_WIDGET(entry));
994 intensity_entry = entry;
998 GtkVBox* vbox = create_dialog_vbox(4);
999 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 0);
1002 GtkButton* button = create_modal_dialog_button("OK", ok_button);
1003 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1004 widget_make_default(GTK_WIDGET(button));
1005 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE);
1008 GtkButton* button = create_modal_dialog_button("Cancel", cancel_button);
1009 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1010 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE);
1016 sprintf (buf, "%d", *intensity);
1017 gtk_entry_set_text(intensity_entry, buf);
1019 EMessageBoxReturn ret = modal_dialog_show(window, dialog);
1021 *intensity = atoi (gtk_entry_get_text(intensity_entry));
1023 gtk_widget_destroy(GTK_WIDGET(window));
1030 #include <gdk/gdkwin32.h>
1034 // use the file associations to open files instead of builtin Gtk editor
1035 bool g_TextEditor_useWin32Editor = true;
1037 // custom shader editor
1038 bool g_TextEditor_useCustomEditor = false;
1039 CopiedString g_TextEditor_editorCommand("");
1042 void DoTextEditor (const char* filename, int cursorpos)
1045 if (g_TextEditor_useWin32Editor)
1047 globalOutputStream() << "opening file '" << filename << "' (line " << cursorpos << " info ignored)\n";
1048 ShellExecute((HWND)GDK_WINDOW_HWND (GTK_WIDGET(MainFrame_getWindow())->window), "open", filename, 0, 0, SW_SHOW );
1052 // check if a custom editor is set
1053 if(g_TextEditor_useCustomEditor && !g_TextEditor_editorCommand.empty())
1055 StringOutputStream strEditCommand(256);
1056 strEditCommand << g_TextEditor_editorCommand.c_str() << " \"" << filename << "\"";
1058 globalOutputStream() << "Launching: " << strEditCommand.c_str() << "\n";
1059 // note: linux does not return false if the command failed so it will assume success
1060 if (Q_Exec(0, const_cast<char*>(strEditCommand.c_str()), 0, true) == false)
1062 globalOutputStream() << "Failed to execute " << strEditCommand.c_str() << ", using default\n";
1066 // the command (appeared) to run successfully, no need to do anything more
1072 DoGtkTextEditor (filename, cursorpos);