2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 // Leonardo Zide (leo@lokigames.com)
28 #include "preferences.h"
29 #include "globaldefs.h"
32 #include "environment.h"
34 #include "debugging/debugging.h"
36 #include "generic/callback.h"
37 #include "math/vector.h"
38 #include "string/string.h"
39 #include "stream/stringstream.h"
43 #include "gtkutil/filechooser.h"
44 #include "gtkutil/messagebox.h"
50 #include "mainframe.h"
55 void Global_constructPreferences(PreferencesPage &page)
57 page.appendCheckBox("Console", "Enable Logging", g_Console_enableLogging);
60 void Interface_constructPreferences(PreferencesPage &page)
63 page.appendCheckBox( "", "Default Text Editor", g_TextEditor_useWin32Editor );
66 ui::CheckButton use_custom = page.appendCheckBox("Text Editor", "Custom", g_TextEditor_useCustomEditor);
67 ui::Widget custom_editor = page.appendPathEntry("Text Editor Command", g_TextEditor_editorCommand, true);
68 Widget_connectToggleDependency(custom_editor, use_custom);
73 void Mouse_constructPreferences(PreferencesPage &page)
76 const char *buttons[] = {"2 button", "3 button",};
77 page.appendRadio("Mouse Type", g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE(buttons));
79 page.appendCheckBox("Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick);
82 void Mouse_constructPage(PreferenceGroup &group)
84 PreferencesPage page(group.createPage("Mouse", "Mouse Preferences"));
85 Mouse_constructPreferences(page);
88 void Mouse_registerPreferencesPage()
90 PreferencesDialog_addInterfacePage(makeCallbackF(Mouse_constructPage));
95 =========================================================
96 Games selection dialog
97 =========================================================
101 #include <uilib/uilib.h>
103 inline const char *xmlAttr_getName(xmlAttrPtr attr)
105 return reinterpret_cast<const char *>( attr->name );
108 inline const char *xmlAttr_getValue(xmlAttrPtr attr)
110 return reinterpret_cast<const char *>( attr->children->content );
113 CGameDescription::CGameDescription(xmlDocPtr pDoc, const CopiedString &gameFile)
115 // read the user-friendly game name
116 xmlNodePtr pNode = pDoc->children;
118 while (strcmp((const char *) pNode->name, "game") && pNode != 0) {
122 Error("Didn't find 'game' node in the game description file '%s'\n", pDoc->URL);
125 for (xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next) {
126 m_gameDescription.insert(GameDescription::value_type(xmlAttr_getName(attr), xmlAttr_getValue(attr)));
130 StringOutputStream path(256);
131 path << AppPath_get() << gameFile.c_str() << "/";
132 mGameToolsPath = path.c_str();
135 ASSERT_MESSAGE(file_exists(mGameToolsPath.c_str()),
136 "game directory not found: " << makeQuoted(mGameToolsPath.c_str()));
138 mGameFile = gameFile;
141 GameDescription::iterator i = m_gameDescription.find("type");
142 if (i == m_gameDescription.end()) {
143 globalErrorStream() << "Warning, 'type' attribute not found in '"
144 << reinterpret_cast<const char *>( pDoc->URL ) << "'\n";
148 mGameType = (*i).second.c_str();
153 void CGameDescription::Dump()
155 globalOutputStream() << "game description file: " << makeQuoted(mGameFile.c_str()) << "\n";
156 for (GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i) {
157 globalOutputStream() << (*i).first.c_str() << " = " << makeQuoted((*i).second.c_str()) << "\n";
161 CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentDescription
164 #include "warnings.h"
165 #include "stream/textfilestream.h"
166 #include "container/array.h"
167 #include "xml/ixml.h"
168 #include "xml/xmlparser.h"
169 #include "xml/xmlwriter.h"
171 #include "preferencedictionary.h"
172 #include "stringio.h"
174 const char *const PREFERENCES_VERSION = "1.0";
176 bool Preferences_Load(PreferenceDictionary &preferences, const char *filename, const char *cmdline_prefix)
179 TextFileInputStream file(filename);
180 if (!file.failed()) {
181 XMLStreamParser parser(file);
182 XMLPreferenceDictionaryImporter importer(preferences, PREFERENCES_VERSION);
183 parser.exportXML(importer);
187 int l = strlen(cmdline_prefix);
188 for (int i = 1; i < g_argc - 1; ++i) {
189 if (g_argv[i][0] == '-') {
190 if (!strncmp(g_argv[i] + 1, cmdline_prefix, l)) {
191 if (g_argv[i][l + 1] == '-') {
192 preferences.importPref(g_argv[i] + l + 2, g_argv[i + 1]);
202 bool Preferences_Save(PreferenceDictionary &preferences, const char *filename)
204 TextFileOutputStream file(filename);
205 if (!file.failed()) {
206 XMLStreamWriter writer(file);
207 XMLPreferenceDictionaryExporter exporter(preferences, PREFERENCES_VERSION);
208 exporter.exportXML(writer);
214 bool Preferences_Save_Safe(PreferenceDictionary &preferences, const char *filename)
216 Array<char> tmpName(filename, filename + strlen(filename) + 1 + 3);
217 *(tmpName.end() - 4) = 'T';
218 *(tmpName.end() - 3) = 'M';
219 *(tmpName.end() - 2) = 'P';
220 *(tmpName.end() - 1) = '\0';
222 return Preferences_Save(preferences, tmpName.data())
223 && (!file_exists(filename) || file_remove(filename))
224 && file_move(tmpName.data(), filename);
229 static void Export(const Callback<void(bool)> &returnz)
231 returnz(g_Console_enableLogging);
234 static void Import(bool value)
236 g_Console_enableLogging = value;
237 Sys_LogFile(g_Console_enableLogging);
242 void RegisterGlobalPreferences(PreferenceSystem &preferences)
244 preferences.registerPreference("gamefile", make_property_string(g_GamesDialog.m_sGameFile));
245 preferences.registerPreference("gamePrompt", make_property_string(g_GamesDialog.m_bGamePrompt));
246 preferences.registerPreference("log console", make_property_string<LogConsole>());
250 PreferenceDictionary g_global_preferences;
252 void GlobalPreferences_Init()
254 RegisterGlobalPreferences(g_global_preferences);
257 void CGameDialog::LoadPrefs()
259 // load global .pref file
260 StringOutputStream strGlobalPref(256);
261 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
263 globalOutputStream() << "loading global preferences from " << makeQuoted(strGlobalPref.c_str()) << "\n";
265 if (!Preferences_Load(g_global_preferences, strGlobalPref.c_str(), "global")) {
266 globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
270 void CGameDialog::SavePrefs()
272 StringOutputStream strGlobalPref(256);
273 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
275 globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
277 if (!Preferences_Save_Safe(g_global_preferences, strGlobalPref.c_str())) {
278 globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
282 void CGameDialog::DoGameDialog()
287 // we save the prefs file
291 void CGameDialog::GameFileImport(int value)
293 m_nComboSelect = value;
294 // use value to set m_sGameFile
295 std::list<CGameDescription *>::iterator iGame = mGames.begin();
297 for (i = 0; i < value; i++) {
300 m_sGameFile = (*iGame)->mGameFile;
303 void CGameDialog::GameFileExport(const Callback<void(int)> &importCallback) const
305 // use m_sGameFile to set value
306 std::list<CGameDescription *>::const_iterator iGame;
308 for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame) {
309 if ((*iGame)->mGameFile == m_sGameFile) {
315 importCallback(m_nComboSelect);
318 struct CGameDialog_GameFile {
319 static void Export(const CGameDialog &self, const Callback<void(int)> &returnz)
321 self.GameFileExport(returnz);
324 static void Import(CGameDialog &self, int value)
326 self.GameFileImport(value);
330 void CGameDialog::CreateGlobalFrame(PreferencesPage &page)
332 std::vector<const char *> games;
333 games.reserve(mGames.size() + 1);
334 for (std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i) {
335 games.push_back((*i)->getRequiredKeyValue("name"));
337 games.push_back(nullptr);
340 StringArrayRange(&(*games.begin()), &(*--games.end())),
341 make_property<CGameDialog_GameFile>(*this)
343 page.appendCheckBox("Startup", "Show Global Preferences", m_bGamePrompt);
346 ui::Window CGameDialog::BuildDialog()
348 auto frame = create_dialog_frame("Game settings", ui::Shadow::ETCHED_IN);
350 auto vbox2 = create_dialog_vbox(0, 4);
354 PreferencesPage preferencesPage(*this, vbox2);
355 Global_constructPreferences(preferencesPage);
356 CreateGlobalFrame(preferencesPage);
359 return create_simple_modal_dialog_window("Global Preferences", m_modal, frame);
362 void CGameDialog::ScanForGames()
364 StringOutputStream strGamesPath(256);
365 strGamesPath << AppPath_get() << "games/";
366 const char *path = strGamesPath.c_str();
368 globalOutputStream() << "Scanning for game description files: " << path << '\n';
372 do we put game description files below AppPath, or in ~/.radiant
373 i.e. read only or read/write?
374 my guess .. readonly cause it's an install
375 we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
376 (if that's really needed)
379 Directory_forEach(path, [&](const char *name) {
380 if (!extension_equal(path_get_extension(name), "game")) {
383 StringOutputStream strPath(256);
384 strPath << path << name;
385 globalOutputStream() << strPath.c_str() << '\n';
387 xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
389 mGames.push_front(new CGameDescription(pDoc, name));
392 globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
397 CGameDescription *CGameDialog::GameDescriptionForComboItem()
399 std::list<CGameDescription *>::iterator iGame;
401 for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame, i++) {
402 if (i == m_nComboSelect) {
406 return 0; // not found
409 void CGameDialog::InitGlobalPrefPath()
411 g_Preferences.m_global_rc_path = g_string_new(SettingsPath_get());
414 void CGameDialog::Reset()
416 if (!g_Preferences.m_global_rc_path) {
417 InitGlobalPrefPath();
419 StringOutputStream strGlobalPref(256);
420 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
421 file_remove(strGlobalPref.c_str());
424 void CGameDialog::Init()
426 InitGlobalPrefPath();
429 if (mGames.empty()) {
430 Error("Didn't find any valid game file descriptions, aborting\n");
432 std::list<CGameDescription *>::iterator iGame, iPrevGame;
433 for (iGame = mGames.begin(), iPrevGame = mGames.end(); iGame != mGames.end(); iPrevGame = iGame, ++iGame) {
434 if (iPrevGame != mGames.end()) {
435 if (strcmp((*iGame)->getRequiredKeyValue("name"), (*iPrevGame)->getRequiredKeyValue("name")) < 0) {
436 CGameDescription *h = *iGame;
444 CGameDescription *currentGameDescription = 0;
446 if (!m_bGamePrompt) {
447 // search by .game name
448 std::list<CGameDescription *>::iterator iGame;
449 for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame) {
450 if ((*iGame)->mGameFile == m_sGameFile) {
451 currentGameDescription = (*iGame);
456 if (m_bGamePrompt || !currentGameDescription) {
459 // use m_nComboSelect to identify the game to run as and set the globals
460 currentGameDescription = GameDescriptionForComboItem();
461 ASSERT_NOTNULL(currentGameDescription);
463 g_pGameDescription = currentGameDescription;
465 g_pGameDescription->Dump();
468 CGameDialog::~CGameDialog()
470 // free all the game descriptions
471 std::list<CGameDescription *>::iterator iGame;
472 for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame) {
481 inline const char *GameDescription_getIdentifier(const CGameDescription &gameDescription)
483 const char *identifier = gameDescription.getKeyValue("index");
484 if (string_empty(identifier)) {
491 CGameDialog g_GamesDialog;
494 // =============================================================================
495 // Widget callbacks for PrefsDlg
497 static void OnButtonClean(ui::Widget widget, gpointer data)
499 // make sure this is what the user wants
500 if (ui::alert(g_Preferences.GetWidget(), "This will close Radiant and clean the corresponding registry entries.\n"
501 "Next time you start Radiant it will be good as new. Do you wish to continue?",
502 "Reset Registry", ui::alert_type::YESNO, ui::alert_icon::Asterisk) == ui::alert_response::YES) {
503 PrefsDlg *dlg = (PrefsDlg *) data;
504 dlg->EndModal(eIDCANCEL);
506 g_preferences_globals.disable_ini = true;
512 // =============================================================================
518 very first prefs init deals with selecting the game and the game tools path
519 then we can load .ini stuff
521 using prefs / ini settings:
524 look in ~/.radiant/<version>/gamename
528 const char *PREFS_LOCAL_FILENAME = "local.pref";
530 void PrefsDlg::Init()
532 // m_global_rc_path has been set above
533 // m_rc_path is for game specific preferences
534 // takes the form: global-pref-path/gamename/prefs-file
536 // this is common to win32 and Linux init now
537 m_rc_path = g_string_new(m_global_rc_path->str);
540 g_string_append(m_rc_path, g_pGameDescription->mGameFile.c_str());
541 g_string_append(m_rc_path, "/");
542 Q_mkdir(m_rc_path->str);
545 m_inipath = g_string_new(m_rc_path->str);
546 g_string_append(m_inipath, PREFS_LOCAL_FILENAME);
549 void notebook_set_page(ui::Widget notebook, ui::Widget page)
551 int pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), page);
552 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != pagenum) {
553 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), pagenum);
557 void PrefsDlg::showPrefPage(ui::Widget prefpage)
559 notebook_set_page(m_notebook, prefpage);
563 static void treeSelection(ui::TreeSelection selection, gpointer data)
565 PrefsDlg *dlg = (PrefsDlg *) data;
568 GtkTreeIter selected;
569 if (gtk_tree_selection_get_selected(selection, &model, &selected)) {
570 ui::Widget prefpage{ui::null};
571 gtk_tree_model_get(model, &selected, 1, (gpointer *) &prefpage, -1);
572 dlg->showPrefPage(prefpage);
576 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
578 inline void PreferenceGroupCallbacks_constructGroup(const PreferenceGroupCallbacks &callbacks, PreferenceGroup &group)
580 for (PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i) {
587 PreferenceGroupCallbacks_pushBack(PreferenceGroupCallbacks &callbacks, const PreferenceGroupCallback &callback)
589 callbacks.push_back(callback);
592 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
594 inline void PreferencesPageCallbacks_constructPage(const PreferencesPageCallbacks &callbacks, PreferencesPage &page)
596 for (PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i) {
602 PreferencesPageCallbacks_pushBack(PreferencesPageCallbacks &callbacks, const PreferencesPageCallback &callback)
604 callbacks.push_back(callback);
607 PreferencesPageCallbacks g_interfacePreferences;
609 void PreferencesDialog_addInterfacePreferences(const PreferencesPageCallback &callback)
611 PreferencesPageCallbacks_pushBack(g_interfacePreferences, callback);
614 PreferenceGroupCallbacks g_interfaceCallbacks;
616 void PreferencesDialog_addInterfacePage(const PreferenceGroupCallback &callback)
618 PreferenceGroupCallbacks_pushBack(g_interfaceCallbacks, callback);
621 PreferencesPageCallbacks g_displayPreferences;
623 void PreferencesDialog_addDisplayPreferences(const PreferencesPageCallback &callback)
625 PreferencesPageCallbacks_pushBack(g_displayPreferences, callback);
628 PreferenceGroupCallbacks g_displayCallbacks;
630 void PreferencesDialog_addDisplayPage(const PreferenceGroupCallback &callback)
632 PreferenceGroupCallbacks_pushBack(g_displayCallbacks, callback);
635 PreferencesPageCallbacks g_settingsPreferences;
637 void PreferencesDialog_addSettingsPreferences(const PreferencesPageCallback &callback)
639 PreferencesPageCallbacks_pushBack(g_settingsPreferences, callback);
642 PreferenceGroupCallbacks g_settingsCallbacks;
644 void PreferencesDialog_addSettingsPage(const PreferenceGroupCallback &callback)
646 PreferenceGroupCallbacks_pushBack(g_settingsCallbacks, callback);
649 void Widget_updateDependency(ui::Widget self, ui::Widget toggleButton)
651 gtk_widget_set_sensitive(self, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggleButton)) &&
652 gtk_widget_is_sensitive(toggleButton));
655 void ToggleButton_toggled_Widget_updateDependency(ui::Widget toggleButton, ui::Widget self)
657 Widget_updateDependency(self, toggleButton);
660 void ToggleButton_state_changed_Widget_updateDependency(ui::Widget toggleButton, GtkStateType state, ui::Widget self)
662 if (state == GTK_STATE_INSENSITIVE) {
663 Widget_updateDependency(self, toggleButton);
667 void Widget_connectToggleDependency(ui::Widget self, ui::Widget toggleButton)
669 toggleButton.connect("state_changed", G_CALLBACK(ToggleButton_state_changed_Widget_updateDependency), self);
670 toggleButton.connect("toggled", G_CALLBACK(ToggleButton_toggled_Widget_updateDependency), self);
671 Widget_updateDependency(self, toggleButton);
675 inline ui::VBox getVBox(ui::Bin page)
677 return ui::VBox::from(gtk_bin_get_child(page));
680 GtkTreeIter PreferenceTree_appendPage(ui::TreeStore store, GtkTreeIter *parent, const char *name, ui::Widget page)
683 gtk_tree_store_append(store, &group, parent);
684 gtk_tree_store_set(store, &group, 0, name, 1, page, -1);
688 ui::Bin PreferencePages_addPage(ui::Widget notebook, const char *name)
690 ui::Widget preflabel = ui::Label(name);
693 auto pageframe = ui::Frame(name);
694 gtk_container_set_border_width(GTK_CONTAINER(pageframe), 4);
697 ui::Widget vbox = ui::VBox(FALSE, 4);
699 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
702 // Add the page to the notebook
703 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel);
708 class PreferenceTreeGroup : public PreferenceGroup {
710 ui::Widget m_notebook;
711 ui::TreeStore m_store;
714 PreferenceTreeGroup(Dialog &dialog, ui::Widget notebook, ui::TreeStore store, GtkTreeIter group) :
716 m_notebook(notebook),
722 PreferencesPage createPage(const char *treeName, const char *frameName)
724 auto page = PreferencePages_addPage(m_notebook, frameName);
725 PreferenceTree_appendPage(m_store, &m_group, treeName, page);
726 return PreferencesPage(m_dialog, getVBox(page));
730 ui::Window PrefsDlg::BuildDialog()
732 PreferencesDialog_addInterfacePreferences(makeCallbackF(Interface_constructPreferences));
733 Mouse_registerPreferencesPage();
735 ui::Window dialog = ui::Window(create_floating_window("NetRadiant Preferences", m_parent));
738 auto mainvbox = ui::VBox(FALSE, 5);
739 dialog.add(mainvbox);
740 gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5);
744 auto hbox = ui::HBox(FALSE, 5);
746 mainvbox.pack_end(hbox, FALSE, TRUE, 0);
749 auto button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &m_modal);
750 hbox.pack_end(button, FALSE, FALSE, 0);
753 auto button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &m_modal);
754 hbox.pack_end(button, FALSE, FALSE, 0);
757 auto button = create_dialog_button("Clean", G_CALLBACK(OnButtonClean), this);
758 hbox.pack_end(button, FALSE, FALSE, 0);
763 auto hbox = ui::HBox(FALSE, 5);
764 mainvbox.pack_start(hbox, TRUE, TRUE, 0);
768 auto sc_win = ui::ScrolledWindow(ui::New);
769 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
770 hbox.pack_start(sc_win, FALSE, FALSE, 0);
772 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN);
774 // prefs pages notebook
775 m_notebook = ui::Widget::from(gtk_notebook_new());
776 // hide the notebook tabs since its not supposed to look like a notebook
777 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_notebook), FALSE);
778 hbox.pack_start(m_notebook, TRUE, TRUE, 0);
783 auto store = ui::TreeStore::from(gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER));
785 auto view = ui::TreeView(ui::TreeModel::from(store._handle));
786 gtk_tree_view_set_headers_visible(view, FALSE);
789 auto renderer = ui::CellRendererText(ui::New);
790 auto column = ui::TreeViewColumn("Preferences", renderer, {{"text", 0}});
791 gtk_tree_view_append_column(view, column);
795 auto selection = ui::TreeSelection::from(gtk_tree_view_get_selection(view));
796 selection.connect("changed", G_CALLBACK(treeSelection), this);
804 /********************************************************************/
805 /* Add preference tree options */
806 /********************************************************************/
809 PreferencePages_addPage(m_notebook, "Front Page");
812 auto global = PreferencePages_addPage(m_notebook, "Global Preferences");
814 PreferencesPage preferencesPage(*this, getVBox(global));
815 Global_constructPreferences(preferencesPage);
817 auto group = PreferenceTree_appendPage(store, 0, "Global", global);
819 auto game = PreferencePages_addPage(m_notebook, "Game");
820 PreferencesPage preferencesPage(*this, getVBox(game));
821 g_GamesDialog.CreateGlobalFrame(preferencesPage);
823 PreferenceTree_appendPage(store, &group, "Game", game);
828 auto interfacePage = PreferencePages_addPage(m_notebook, "Interface Preferences");
830 PreferencesPage preferencesPage(*this, getVBox(interfacePage));
831 PreferencesPageCallbacks_constructPage(g_interfacePreferences, preferencesPage);
834 auto group = PreferenceTree_appendPage(store, 0, "Interface", interfacePage);
835 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
837 PreferenceGroupCallbacks_constructGroup(g_interfaceCallbacks, preferenceGroup);
841 auto display = PreferencePages_addPage(m_notebook, "Display Preferences");
843 PreferencesPage preferencesPage(*this, getVBox(display));
844 PreferencesPageCallbacks_constructPage(g_displayPreferences, preferencesPage);
846 auto group = PreferenceTree_appendPage(store, 0, "Display", display);
847 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
849 PreferenceGroupCallbacks_constructGroup(g_displayCallbacks, preferenceGroup);
853 auto settings = PreferencePages_addPage(m_notebook, "General Settings");
855 PreferencesPage preferencesPage(*this, getVBox(settings));
856 PreferencesPageCallbacks_constructPage(g_settingsPreferences, preferencesPage);
859 auto group = PreferenceTree_appendPage(store, 0, "Settings", settings);
860 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
862 PreferenceGroupCallbacks_constructGroup(g_settingsCallbacks, preferenceGroup);
866 gtk_tree_view_expand_all(view);
868 g_object_unref(G_OBJECT(store));
874 gtk_notebook_set_current_page(GTK_NOTEBOOK(m_notebook), 0);
879 preferences_globals_t g_preferences_globals;
881 PrefsDlg g_Preferences; // global prefs instance
884 void PreferencesDialog_constructWindow(ui::Window main_window)
886 g_Preferences.m_parent = main_window;
887 g_Preferences.Create();
890 void PreferencesDialog_destroyWindow()
892 g_Preferences.Destroy();
896 PreferenceDictionary g_preferences;
898 PreferenceSystem &GetPreferenceSystem()
900 return g_preferences;
903 class PreferenceSystemAPI {
904 PreferenceSystem *m_preferencesystem;
906 typedef PreferenceSystem Type;
908 STRING_CONSTANT(Name, "*");
910 PreferenceSystemAPI()
912 m_preferencesystem = &GetPreferenceSystem();
915 PreferenceSystem *getTable()
917 return m_preferencesystem;
921 #include "modulesystem/singletonmodule.h"
922 #include "modulesystem/moduleregistry.h"
924 typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
925 typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
926 StaticRegisterModule staticRegisterPreferenceSystem(StaticPreferenceSystemModule::instance());
928 void Preferences_Load()
930 g_GamesDialog.LoadPrefs();
932 globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
934 if (!Preferences_Load(g_preferences, g_Preferences.m_inipath->str, g_GamesDialog.m_sGameFile.c_str())) {
935 globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
939 void Preferences_Save()
941 if (g_preferences_globals.disable_ini) {
945 g_GamesDialog.SavePrefs();
947 globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
949 if (!Preferences_Save_Safe(g_preferences, g_Preferences.m_inipath->str)) {
950 globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
954 void Preferences_Reset()
956 file_remove(g_Preferences.m_inipath->str);
960 void PrefsDlg::PostModal(EMessageBoxReturn code)
968 std::vector<const char *> g_restart_required;
970 void PreferencesDialog_restartRequired(const char *staticName)
972 g_restart_required.push_back(staticName);
975 void PreferencesDialog_showDialog()
977 if (ConfirmModified("Edit Preferences") && g_Preferences.DoModal() == eIDOK) {
978 if (!g_restart_required.empty()) {
979 StringOutputStream message(256);
980 message << "Preference changes require a restart:\n";
981 for (std::vector<const char *>::iterator i = g_restart_required.begin();
982 i != g_restart_required.end(); ++i) {
983 message << (*i) << '\n';
985 ui::alert(MainFrame_getWindow(), message.c_str());
986 g_restart_required.clear();
992 static void Export(const Callback<void(const char *)> &returnz)
994 returnz(gamename_get());
997 static void Import(const char *value)
1004 static void Export(const Callback<void(const char *)> &returnz)
1006 returnz(gamemode_get());
1009 static void Import(const char *value)
1011 gamemode_set(value);
1015 void RegisterPreferences(PreferenceSystem &preferences)
1018 preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useWin32Editor ) );
1020 preferences.registerPreference("UseCustomShaderEditor", make_property_string(g_TextEditor_useCustomEditor));
1021 preferences.registerPreference("CustomShaderEditorCommand", make_property_string(g_TextEditor_editorCommand));
1024 preferences.registerPreference("GameName", make_property<GameName>());
1025 preferences.registerPreference("GameMode", make_property<GameMode>());
1028 void Preferences_Init()
1030 RegisterPreferences(GetPreferenceSystem());