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());
334 for (std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i) {
335 games.push_back((*i)->getRequiredKeyValue("name"));
339 StringArrayRange(&(*games.begin()), &(*games.end())),
340 make_property<CGameDialog_GameFile>(*this)
342 page.appendCheckBox("Startup", "Show Global Preferences", m_bGamePrompt);
345 ui::Window CGameDialog::BuildDialog()
347 auto frame = create_dialog_frame("Game settings", ui::Shadow::ETCHED_IN);
349 auto vbox2 = create_dialog_vbox(0, 4);
353 PreferencesPage preferencesPage(*this, vbox2);
354 Global_constructPreferences(preferencesPage);
355 CreateGlobalFrame(preferencesPage);
358 return create_simple_modal_dialog_window("Global Preferences", m_modal, frame);
361 void CGameDialog::ScanForGames()
363 StringOutputStream strGamesPath(256);
364 strGamesPath << AppPath_get() << "games/";
365 const char *path = strGamesPath.c_str();
367 globalOutputStream() << "Scanning for game description files: " << path << '\n';
371 do we put game description files below AppPath, or in ~/.radiant
372 i.e. read only or read/write?
373 my guess .. readonly cause it's an install
374 we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
375 (if that's really needed)
378 Directory_forEach(path, [&](const char *name) {
379 if (!extension_equal(path_get_extension(name), "game")) {
382 StringOutputStream strPath(256);
383 strPath << path << name;
384 globalOutputStream() << strPath.c_str() << '\n';
386 xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
388 mGames.push_front(new CGameDescription(pDoc, name));
391 globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
396 CGameDescription *CGameDialog::GameDescriptionForComboItem()
398 std::list<CGameDescription *>::iterator iGame;
400 for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame, i++) {
401 if (i == m_nComboSelect) {
405 return 0; // not found
408 void CGameDialog::InitGlobalPrefPath()
410 g_Preferences.m_global_rc_path = g_string_new(SettingsPath_get());
413 void CGameDialog::Reset()
415 if (!g_Preferences.m_global_rc_path) {
416 InitGlobalPrefPath();
418 StringOutputStream strGlobalPref(256);
419 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
420 file_remove(strGlobalPref.c_str());
423 void CGameDialog::Init()
425 InitGlobalPrefPath();
428 if (mGames.empty()) {
429 Error("Didn't find any valid game file descriptions, aborting\n");
431 std::list<CGameDescription *>::iterator iGame, iPrevGame;
432 for (iGame = mGames.begin(), iPrevGame = mGames.end(); iGame != mGames.end(); iPrevGame = iGame, ++iGame) {
433 if (iPrevGame != mGames.end()) {
434 if (strcmp((*iGame)->getRequiredKeyValue("name"), (*iPrevGame)->getRequiredKeyValue("name")) < 0) {
435 CGameDescription *h = *iGame;
443 CGameDescription *currentGameDescription = 0;
445 if (!m_bGamePrompt) {
446 // search by .game name
447 std::list<CGameDescription *>::iterator iGame;
448 for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame) {
449 if ((*iGame)->mGameFile == m_sGameFile) {
450 currentGameDescription = (*iGame);
455 if (m_bGamePrompt || !currentGameDescription) {
458 // use m_nComboSelect to identify the game to run as and set the globals
459 currentGameDescription = GameDescriptionForComboItem();
460 ASSERT_NOTNULL(currentGameDescription);
462 g_pGameDescription = currentGameDescription;
464 g_pGameDescription->Dump();
467 CGameDialog::~CGameDialog()
469 // free all the game descriptions
470 std::list<CGameDescription *>::iterator iGame;
471 for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame) {
480 inline const char *GameDescription_getIdentifier(const CGameDescription &gameDescription)
482 const char *identifier = gameDescription.getKeyValue("index");
483 if (string_empty(identifier)) {
490 CGameDialog g_GamesDialog;
493 // =============================================================================
494 // Widget callbacks for PrefsDlg
496 static void OnButtonClean(ui::Widget widget, gpointer data)
498 // make sure this is what the user wants
499 if (ui::alert(g_Preferences.GetWidget(), "This will close Radiant and clean the corresponding registry entries.\n"
500 "Next time you start Radiant it will be good as new. Do you wish to continue?",
501 "Reset Registry", ui::alert_type::YESNO, ui::alert_icon::Asterisk) == ui::alert_response::YES) {
502 PrefsDlg *dlg = (PrefsDlg *) data;
503 dlg->EndModal(eIDCANCEL);
505 g_preferences_globals.disable_ini = true;
511 // =============================================================================
517 very first prefs init deals with selecting the game and the game tools path
518 then we can load .ini stuff
520 using prefs / ini settings:
523 look in ~/.radiant/<version>/gamename
527 const char *PREFS_LOCAL_FILENAME = "local.pref";
529 void PrefsDlg::Init()
531 // m_global_rc_path has been set above
532 // m_rc_path is for game specific preferences
533 // takes the form: global-pref-path/gamename/prefs-file
535 // this is common to win32 and Linux init now
536 m_rc_path = g_string_new(m_global_rc_path->str);
539 g_string_append(m_rc_path, g_pGameDescription->mGameFile.c_str());
540 g_string_append(m_rc_path, "/");
541 Q_mkdir(m_rc_path->str);
544 m_inipath = g_string_new(m_rc_path->str);
545 g_string_append(m_inipath, PREFS_LOCAL_FILENAME);
548 void notebook_set_page(ui::Widget notebook, ui::Widget page)
550 int pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), page);
551 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != pagenum) {
552 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), pagenum);
556 void PrefsDlg::showPrefPage(ui::Widget prefpage)
558 notebook_set_page(m_notebook, prefpage);
562 static void treeSelection(ui::TreeSelection selection, gpointer data)
564 PrefsDlg *dlg = (PrefsDlg *) data;
567 GtkTreeIter selected;
568 if (gtk_tree_selection_get_selected(selection, &model, &selected)) {
569 ui::Widget prefpage{ui::null};
570 gtk_tree_model_get(model, &selected, 1, (gpointer *) &prefpage, -1);
571 dlg->showPrefPage(prefpage);
575 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
577 inline void PreferenceGroupCallbacks_constructGroup(const PreferenceGroupCallbacks &callbacks, PreferenceGroup &group)
579 for (PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i) {
586 PreferenceGroupCallbacks_pushBack(PreferenceGroupCallbacks &callbacks, const PreferenceGroupCallback &callback)
588 callbacks.push_back(callback);
591 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
593 inline void PreferencesPageCallbacks_constructPage(const PreferencesPageCallbacks &callbacks, PreferencesPage &page)
595 for (PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i) {
601 PreferencesPageCallbacks_pushBack(PreferencesPageCallbacks &callbacks, const PreferencesPageCallback &callback)
603 callbacks.push_back(callback);
606 PreferencesPageCallbacks g_interfacePreferences;
608 void PreferencesDialog_addInterfacePreferences(const PreferencesPageCallback &callback)
610 PreferencesPageCallbacks_pushBack(g_interfacePreferences, callback);
613 PreferenceGroupCallbacks g_interfaceCallbacks;
615 void PreferencesDialog_addInterfacePage(const PreferenceGroupCallback &callback)
617 PreferenceGroupCallbacks_pushBack(g_interfaceCallbacks, callback);
620 PreferencesPageCallbacks g_displayPreferences;
622 void PreferencesDialog_addDisplayPreferences(const PreferencesPageCallback &callback)
624 PreferencesPageCallbacks_pushBack(g_displayPreferences, callback);
627 PreferenceGroupCallbacks g_displayCallbacks;
629 void PreferencesDialog_addDisplayPage(const PreferenceGroupCallback &callback)
631 PreferenceGroupCallbacks_pushBack(g_displayCallbacks, callback);
634 PreferencesPageCallbacks g_settingsPreferences;
636 void PreferencesDialog_addSettingsPreferences(const PreferencesPageCallback &callback)
638 PreferencesPageCallbacks_pushBack(g_settingsPreferences, callback);
641 PreferenceGroupCallbacks g_settingsCallbacks;
643 void PreferencesDialog_addSettingsPage(const PreferenceGroupCallback &callback)
645 PreferenceGroupCallbacks_pushBack(g_settingsCallbacks, callback);
648 void Widget_updateDependency(ui::Widget self, ui::Widget toggleButton)
650 gtk_widget_set_sensitive(self, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggleButton)) &&
651 gtk_widget_is_sensitive(toggleButton));
654 void ToggleButton_toggled_Widget_updateDependency(ui::Widget toggleButton, ui::Widget self)
656 Widget_updateDependency(self, toggleButton);
659 void ToggleButton_state_changed_Widget_updateDependency(ui::Widget toggleButton, GtkStateType state, ui::Widget self)
661 if (state == GTK_STATE_INSENSITIVE) {
662 Widget_updateDependency(self, toggleButton);
666 void Widget_connectToggleDependency(ui::Widget self, ui::Widget toggleButton)
668 toggleButton.connect("state_changed", G_CALLBACK(ToggleButton_state_changed_Widget_updateDependency), self);
669 toggleButton.connect("toggled", G_CALLBACK(ToggleButton_toggled_Widget_updateDependency), self);
670 Widget_updateDependency(self, toggleButton);
674 inline ui::VBox getVBox(ui::Bin page)
676 return ui::VBox::from(gtk_bin_get_child(page));
679 GtkTreeIter PreferenceTree_appendPage(ui::TreeStore store, GtkTreeIter *parent, const char *name, ui::Widget page)
682 gtk_tree_store_append(store, &group, parent);
683 gtk_tree_store_set(store, &group, 0, name, 1, page, -1);
687 ui::Bin PreferencePages_addPage(ui::Widget notebook, const char *name)
689 ui::Widget preflabel = ui::Label(name);
692 auto pageframe = ui::Frame(name);
693 gtk_container_set_border_width(GTK_CONTAINER(pageframe), 4);
696 ui::Widget vbox = ui::VBox(FALSE, 4);
698 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
701 // Add the page to the notebook
702 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel);
707 class PreferenceTreeGroup : public PreferenceGroup {
709 ui::Widget m_notebook;
710 ui::TreeStore m_store;
713 PreferenceTreeGroup(Dialog &dialog, ui::Widget notebook, ui::TreeStore store, GtkTreeIter group) :
715 m_notebook(notebook),
721 PreferencesPage createPage(const char *treeName, const char *frameName)
723 auto page = PreferencePages_addPage(m_notebook, frameName);
724 PreferenceTree_appendPage(m_store, &m_group, treeName, page);
725 return PreferencesPage(m_dialog, getVBox(page));
729 ui::Window PrefsDlg::BuildDialog()
731 PreferencesDialog_addInterfacePreferences(makeCallbackF(Interface_constructPreferences));
732 Mouse_registerPreferencesPage();
734 ui::Window dialog = ui::Window(create_floating_window("NetRadiant Preferences", m_parent));
737 auto mainvbox = ui::VBox(FALSE, 5);
738 dialog.add(mainvbox);
739 gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5);
743 auto hbox = ui::HBox(FALSE, 5);
745 mainvbox.pack_end(hbox, FALSE, TRUE, 0);
748 auto button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &m_modal);
749 hbox.pack_end(button, FALSE, FALSE, 0);
752 auto button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &m_modal);
753 hbox.pack_end(button, FALSE, FALSE, 0);
756 auto button = create_dialog_button("Clean", G_CALLBACK(OnButtonClean), this);
757 hbox.pack_end(button, FALSE, FALSE, 0);
762 auto hbox = ui::HBox(FALSE, 5);
763 mainvbox.pack_start(hbox, TRUE, TRUE, 0);
767 auto sc_win = ui::ScrolledWindow(ui::New);
768 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
769 hbox.pack_start(sc_win, FALSE, FALSE, 0);
771 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN);
773 // prefs pages notebook
774 m_notebook = ui::Widget::from(gtk_notebook_new());
775 // hide the notebook tabs since its not supposed to look like a notebook
776 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_notebook), FALSE);
777 hbox.pack_start(m_notebook, TRUE, TRUE, 0);
782 auto store = ui::TreeStore::from(gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER));
784 auto view = ui::TreeView(ui::TreeModel::from(store._handle));
785 gtk_tree_view_set_headers_visible(view, FALSE);
788 auto renderer = ui::CellRendererText(ui::New);
789 auto column = ui::TreeViewColumn("Preferences", renderer, {{"text", 0}});
790 gtk_tree_view_append_column(view, column);
794 auto selection = ui::TreeSelection::from(gtk_tree_view_get_selection(view));
795 selection.connect("changed", G_CALLBACK(treeSelection), this);
803 /********************************************************************/
804 /* Add preference tree options */
805 /********************************************************************/
808 PreferencePages_addPage(m_notebook, "Front Page");
811 auto global = PreferencePages_addPage(m_notebook, "Global Preferences");
813 PreferencesPage preferencesPage(*this, getVBox(global));
814 Global_constructPreferences(preferencesPage);
816 auto group = PreferenceTree_appendPage(store, 0, "Global", global);
818 auto game = PreferencePages_addPage(m_notebook, "Game");
819 PreferencesPage preferencesPage(*this, getVBox(game));
820 g_GamesDialog.CreateGlobalFrame(preferencesPage);
822 PreferenceTree_appendPage(store, &group, "Game", game);
827 auto interfacePage = PreferencePages_addPage(m_notebook, "Interface Preferences");
829 PreferencesPage preferencesPage(*this, getVBox(interfacePage));
830 PreferencesPageCallbacks_constructPage(g_interfacePreferences, preferencesPage);
833 auto group = PreferenceTree_appendPage(store, 0, "Interface", interfacePage);
834 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
836 PreferenceGroupCallbacks_constructGroup(g_interfaceCallbacks, preferenceGroup);
840 auto display = PreferencePages_addPage(m_notebook, "Display Preferences");
842 PreferencesPage preferencesPage(*this, getVBox(display));
843 PreferencesPageCallbacks_constructPage(g_displayPreferences, preferencesPage);
845 auto group = PreferenceTree_appendPage(store, 0, "Display", display);
846 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
848 PreferenceGroupCallbacks_constructGroup(g_displayCallbacks, preferenceGroup);
852 auto settings = PreferencePages_addPage(m_notebook, "General Settings");
854 PreferencesPage preferencesPage(*this, getVBox(settings));
855 PreferencesPageCallbacks_constructPage(g_settingsPreferences, preferencesPage);
858 auto group = PreferenceTree_appendPage(store, 0, "Settings", settings);
859 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
861 PreferenceGroupCallbacks_constructGroup(g_settingsCallbacks, preferenceGroup);
865 gtk_tree_view_expand_all(view);
867 g_object_unref(G_OBJECT(store));
873 gtk_notebook_set_current_page(GTK_NOTEBOOK(m_notebook), 0);
878 preferences_globals_t g_preferences_globals;
880 PrefsDlg g_Preferences; // global prefs instance
883 void PreferencesDialog_constructWindow(ui::Window main_window)
885 g_Preferences.m_parent = main_window;
886 g_Preferences.Create();
889 void PreferencesDialog_destroyWindow()
891 g_Preferences.Destroy();
895 PreferenceDictionary g_preferences;
897 PreferenceSystem &GetPreferenceSystem()
899 return g_preferences;
902 class PreferenceSystemAPI {
903 PreferenceSystem *m_preferencesystem;
905 typedef PreferenceSystem Type;
907 STRING_CONSTANT(Name, "*");
909 PreferenceSystemAPI()
911 m_preferencesystem = &GetPreferenceSystem();
914 PreferenceSystem *getTable()
916 return m_preferencesystem;
920 #include "modulesystem/singletonmodule.h"
921 #include "modulesystem/moduleregistry.h"
923 typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
924 typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
925 StaticRegisterModule staticRegisterPreferenceSystem(StaticPreferenceSystemModule::instance());
927 void Preferences_Load()
929 g_GamesDialog.LoadPrefs();
931 globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
933 if (!Preferences_Load(g_preferences, g_Preferences.m_inipath->str, g_GamesDialog.m_sGameFile.c_str())) {
934 globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
938 void Preferences_Save()
940 if (g_preferences_globals.disable_ini) {
944 g_GamesDialog.SavePrefs();
946 globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
948 if (!Preferences_Save_Safe(g_preferences, g_Preferences.m_inipath->str)) {
949 globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
953 void Preferences_Reset()
955 file_remove(g_Preferences.m_inipath->str);
959 void PrefsDlg::PostModal(EMessageBoxReturn code)
967 std::vector<const char *> g_restart_required;
969 void PreferencesDialog_restartRequired(const char *staticName)
971 g_restart_required.push_back(staticName);
974 void PreferencesDialog_showDialog()
976 if (ConfirmModified("Edit Preferences") && g_Preferences.DoModal() == eIDOK) {
977 if (!g_restart_required.empty()) {
978 StringOutputStream message(256);
979 message << "Preference changes require a restart:\n";
980 for (std::vector<const char *>::iterator i = g_restart_required.begin();
981 i != g_restart_required.end(); ++i) {
982 message << (*i) << '\n';
984 ui::alert(MainFrame_getWindow(), message.c_str());
985 g_restart_required.clear();
991 static void Export(const Callback<void(const char *)> &returnz)
993 returnz(gamename_get());
996 static void Import(const char *value)
1003 static void Export(const Callback<void(const char *)> &returnz)
1005 returnz(gamemode_get());
1008 static void Import(const char *value)
1010 gamemode_set(value);
1014 void RegisterPreferences(PreferenceSystem &preferences)
1017 preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useWin32Editor ) );
1019 preferences.registerPreference("UseCustomShaderEditor", make_property_string(g_TextEditor_useCustomEditor));
1020 preferences.registerPreference("CustomShaderEditorCommand", make_property_string(g_TextEditor_editorCommand));
1023 preferences.registerPreference("GameName", make_property<GameName>());
1024 preferences.registerPreference("GameMode", make_property<GameMode>());
1027 void Preferences_Init()
1029 RegisterPreferences(GetPreferenceSystem());