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"
30 #include "debugging/debugging.h"
32 #include <gtk/gtkmain.h>
33 #include <gtk/gtkvbox.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtkframe.h>
36 #include <gtk/gtklabel.h>
37 #include <gtk/gtktogglebutton.h>
38 #include <gtk/gtkspinbutton.h>
39 #include <gtk/gtkscrolledwindow.h>
40 #include <gtk/gtktreemodel.h>
41 #include <gtk/gtktreeview.h>
42 #include <gtk/gtktreestore.h>
43 #include <gtk/gtktreeselection.h>
44 #include <gtk/gtkcellrenderertext.h>
45 #include <gtk/gtknotebook.h>
47 #include "generic/callback.h"
48 #include "math/vector.h"
49 #include "string/string.h"
50 #include "stream/stringstream.h"
54 #include "gtkutil/filechooser.h"
55 #include "gtkutil/messagebox.h"
61 #include "mainframe.h"
67 void Global_constructPreferences(PreferencesPage& page)
69 page.appendCheckBox("Console", "Enable Logging", g_Console_enableLogging);
72 void Interface_constructPreferences(PreferencesPage& page)
75 page.appendCheckBox("", "Default Text Editor", g_TextEditor_useWin32Editor);
78 GtkWidget* use_custom = page.appendCheckBox("Text Editor", "Custom", g_TextEditor_useCustomEditor);
79 GtkWidget* custom_editor = page.appendPathEntry("Text Editor Command", g_TextEditor_editorCommand, true);
80 Widget_connectToggleDependency(custom_editor, use_custom);
85 void Mouse_constructPreferences(PreferencesPage& page)
88 const char* buttons[] = { "2 button", "3 button", };
89 page.appendRadio("Mouse Type", g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE(buttons));
91 page.appendCheckBox("Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick);
93 void Mouse_constructPage(PreferenceGroup& group)
95 PreferencesPage page(group.createPage("Mouse", "Mouse Preferences"));
96 Mouse_constructPreferences(page);
98 void Mouse_registerPreferencesPage()
100 PreferencesDialog_addInterfacePage(FreeCaller1<PreferenceGroup&, Mouse_constructPage>());
105 =========================================================
106 Games selection dialog
107 =========================================================
112 inline const char* xmlAttr_getName(xmlAttrPtr attr)
114 return reinterpret_cast<const char*>(attr->name);
117 inline const char* xmlAttr_getValue(xmlAttrPtr attr)
119 return reinterpret_cast<const char*>(attr->children->content);
122 CGameDescription::CGameDescription(xmlDocPtr pDoc, const CopiedString& gameFile)
124 // read the user-friendly game name
125 xmlNodePtr pNode = pDoc->children;
127 while (strcmp((const char*)pNode->name, "game") && pNode != 0)
133 Error("Didn't find 'game' node in the game description file '%s'\n", pDoc->URL);
136 for(xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next)
138 m_gameDescription.insert(GameDescription::value_type(xmlAttr_getName(attr), xmlAttr_getValue(attr)));
142 StringOutputStream path(256);
143 path << AppPath_get() << gameFile.c_str() << "/";
144 mGameToolsPath = path.c_str();
147 ASSERT_MESSAGE(file_exists(mGameToolsPath.c_str()), "game directory not found: " << makeQuoted(mGameToolsPath.c_str()));
149 mGameFile = gameFile;
152 GameDescription::iterator i = m_gameDescription.find("type");
153 if(i == m_gameDescription.end())
155 globalErrorStream() << "Warning, 'type' attribute not found in '" << reinterpret_cast<const char*>(pDoc->URL) << "'\n";
161 mGameType = (*i).second.c_str();
166 void CGameDescription::Dump()
168 globalOutputStream() << "game description file: " << makeQuoted(mGameFile.c_str()) << "\n";
169 for(GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i)
171 globalOutputStream() << (*i).first.c_str() << " = " << makeQuoted((*i).second.c_str()) << "\n";
175 CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentDescription
178 #include "warnings.h"
179 #include "stream/textfilestream.h"
180 #include "container/array.h"
181 #include "xml/ixml.h"
182 #include "xml/xmlparser.h"
183 #include "xml/xmlwriter.h"
185 #include "preferencedictionary.h"
186 #include "stringio.h"
188 const char* const PREFERENCES_VERSION = "1.0";
190 bool Preferences_Load(PreferenceDictionary& preferences, const char* filename)
192 TextFileInputStream file(filename);
195 XMLStreamParser parser(file);
196 XMLPreferenceDictionaryImporter importer(preferences, PREFERENCES_VERSION);
197 parser.exportXML(importer);
203 bool Preferences_Save(PreferenceDictionary& preferences, const char* filename)
205 TextFileOutputStream file(filename);
208 XMLStreamWriter writer(file);
209 XMLPreferenceDictionaryExporter exporter(preferences, PREFERENCES_VERSION);
210 exporter.exportXML(writer);
216 bool Preferences_Save_Safe(PreferenceDictionary& preferences, const char* filename)
218 Array<char> tmpName(filename, filename + strlen(filename) + 1 + 3);
219 *(tmpName.end() - 4) = 'T';
220 *(tmpName.end() - 3) = 'M';
221 *(tmpName.end() - 2) = 'P';
222 *(tmpName.end() - 1) = '\0';
224 return Preferences_Save(preferences, tmpName.data())
225 && (!file_exists(filename) || file_remove(filename))
226 && file_move(tmpName.data(), filename);
231 void LogConsole_importString(const char* string)
233 g_Console_enableLogging = string_equal(string, "true");
234 Sys_LogFile(g_Console_enableLogging);
236 typedef FreeCaller1<const char*, LogConsole_importString> LogConsoleImportStringCaller;
239 void RegisterGlobalPreferences(PreferenceSystem& preferences)
241 preferences.registerPreference("gamefile", CopiedStringImportStringCaller(g_GamesDialog.m_sGameFile), CopiedStringExportStringCaller(g_GamesDialog.m_sGameFile));
242 preferences.registerPreference("gamePrompt", BoolImportStringCaller(g_GamesDialog.m_bGamePrompt), BoolExportStringCaller(g_GamesDialog.m_bGamePrompt));
243 preferences.registerPreference("log console", LogConsoleImportStringCaller(), BoolExportStringCaller(g_Console_enableLogging));
247 PreferenceDictionary g_global_preferences;
249 void GlobalPreferences_Init()
251 RegisterGlobalPreferences(g_global_preferences);
254 void CGameDialog::LoadPrefs()
256 // load global .pref file
257 StringOutputStream strGlobalPref(256);
258 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
260 globalOutputStream() << "loading global preferences from " << makeQuoted(strGlobalPref.c_str()) << "\n";
262 if(!Preferences_Load(g_global_preferences, strGlobalPref.c_str()))
264 globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
268 void CGameDialog::SavePrefs()
270 StringOutputStream strGlobalPref(256);
271 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
273 globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
275 if(!Preferences_Save_Safe(g_global_preferences, strGlobalPref.c_str()))
277 globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
281 void CGameDialog::DoGameDialog()
286 // we save the prefs file
290 void CGameDialog::GameFileImport(int value)
292 m_nComboSelect = value;
293 // use value to set m_sGameFile
294 std::list<CGameDescription *>::iterator iGame = mGames.begin();
296 for(i=0; i<value; i++)
300 m_sGameFile = (*iGame)->mGameFile;
303 void CGameDialog::GameFileExport(const IntImportCallback& 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)
310 if ((*iGame)->mGameFile == m_sGameFile)
317 importCallback(m_nComboSelect);
320 void CGameDialog_GameFileImport(CGameDialog& self, int value)
322 self.GameFileImport(value);
325 void CGameDialog_GameFileExport(CGameDialog& self, const IntImportCallback& importCallback)
327 self.GameFileExport(importCallback);
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)
336 games.push_back((*i)->getRequiredKeyValue("name"));
340 StringArrayRange(&(*games.begin()), &(*games.end())),
341 ReferenceCaller1<CGameDialog, int, CGameDialog_GameFileImport>(*this),
342 ReferenceCaller1<CGameDialog, const IntImportCallback&, CGameDialog_GameFileExport>(*this)
344 page.appendCheckBox("Startup", "Show Global Preferences", m_bGamePrompt);
347 GtkWindow* CGameDialog::BuildDialog()
349 GtkFrame* frame = create_dialog_frame("Game settings", GTK_SHADOW_ETCHED_IN);
351 GtkVBox* vbox2 = create_dialog_vbox(0, 4);
352 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox2));
355 PreferencesPage preferencesPage(*this, GTK_WIDGET(vbox2));
356 Global_constructPreferences(preferencesPage);
357 CreateGlobalFrame(preferencesPage);
360 return create_simple_modal_dialog_window("Global Preferences", m_modal, GTK_WIDGET(frame));
365 std::list<CGameDescription*>& mGames;
368 LoadGameFile(std::list<CGameDescription*>& games, const char* path) : mGames(games), mPath(path)
371 void operator()(const char* name) const
373 if(!extension_equal(path_get_extension(name), "game"))
377 StringOutputStream strPath(256);
378 strPath << mPath << name;
379 globalOutputStream() << strPath.c_str() << '\n';
381 xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
384 mGames.push_front(new CGameDescription(pDoc, name));
389 globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
394 void CGameDialog::ScanForGames()
396 StringOutputStream strGamesPath(256);
397 strGamesPath << AppPath_get() << "games/";
398 const char *path = strGamesPath.c_str();
400 globalOutputStream() << "Scanning for game description files: " << path << '\n';
404 do we put game description files below AppPath, or in ~/.radiant
405 i.e. read only or read/write?
406 my guess .. readonly cause it's an install
407 we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
408 (if that's really needed)
411 Directory_forEach(path, LoadGameFile(mGames, path));
414 CGameDescription* CGameDialog::GameDescriptionForComboItem()
416 std::list<CGameDescription *>::iterator iGame;
418 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame,i++)
420 if (i == m_nComboSelect)
425 return 0; // not found
428 void CGameDialog::InitGlobalPrefPath()
430 g_Preferences.m_global_rc_path = g_string_new(SettingsPath_get());
433 void CGameDialog::Reset()
435 if (!g_Preferences.m_global_rc_path)
436 InitGlobalPrefPath();
437 StringOutputStream strGlobalPref(256);
438 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
439 file_remove(strGlobalPref.c_str());
442 void CGameDialog::Init()
444 InitGlobalPrefPath();
449 Error("Didn't find any valid game file descriptions, aborting\n");
452 CGameDescription* currentGameDescription = 0;
456 // search by .game name
457 std::list<CGameDescription *>::iterator iGame;
458 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
460 if ((*iGame)->mGameFile == m_sGameFile)
462 currentGameDescription = (*iGame);
467 if (m_bGamePrompt || !currentGameDescription)
471 // use m_nComboSelect to identify the game to run as and set the globals
472 currentGameDescription = GameDescriptionForComboItem();
473 ASSERT_NOTNULL(currentGameDescription);
475 g_pGameDescription = currentGameDescription;
477 g_pGameDescription->Dump();
480 CGameDialog::~CGameDialog()
482 // free all the game descriptions
483 std::list<CGameDescription *>::iterator iGame;
484 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
495 inline const char* GameDescription_getIdentifier(const CGameDescription& gameDescription)
497 const char* identifier = gameDescription.getKeyValue("index");
498 if(string_empty(identifier))
505 void CGameDialog::AddPacksURL(StringOutputStream &URL)
507 // add the URLs for the list of game packs installed
508 // FIXME: this is kinda hardcoded for now..
509 std::list<CGameDescription *>::iterator iGame;
510 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
512 URL << "&Games_dlup%5B%5D=" << GameDescription_getIdentifier(*(*iGame));
516 CGameDialog g_GamesDialog;
519 // =============================================================================
520 // Widget callbacks for PrefsDlg
522 static void OnButtonClean (GtkWidget *widget, gpointer data)
524 // make sure this is what the user wants
525 if (gtk_MessageBox(GTK_WIDGET(g_Preferences.GetWidget()), "This will close Radiant and clean the corresponding registry entries.\n"
526 "Next time you start Radiant it will be good as new. Do you wish to continue?",
527 "Reset Registry", eMB_YESNO, eMB_ICONASTERISK) == eIDYES)
529 PrefsDlg *dlg = (PrefsDlg*)data;
530 dlg->EndModal (eIDCANCEL);
532 g_preferences_globals.disable_ini = true;
538 // =============================================================================
544 very first prefs init deals with selecting the game and the game tools path
545 then we can load .ini stuff
547 using prefs / ini settings:
550 look in ~/.radiant/<version>/gamename
554 #define PREFS_LOCAL_FILENAME "local.pref"
556 void PrefsDlg::Init()
558 // m_global_rc_path has been set above
559 // m_rc_path is for game specific preferences
560 // takes the form: global-pref-path/gamename/prefs-file
562 // this is common to win32 and Linux init now
563 m_rc_path = g_string_new (m_global_rc_path->str);
566 g_string_append (m_rc_path, g_pGameDescription->mGameFile.c_str());
567 g_string_append (m_rc_path, "/");
568 Q_mkdir (m_rc_path->str);
571 m_inipath = g_string_new (m_rc_path->str);
572 g_string_append (m_inipath, PREFS_LOCAL_FILENAME);
575 void notebook_set_page(GtkWidget* notebook, GtkWidget* page)
577 int pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), page);
578 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != pagenum)
580 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), pagenum);
584 void PrefsDlg::showPrefPage(GtkWidget* prefpage)
586 notebook_set_page(m_notebook, prefpage);
590 static void treeSelection(GtkTreeSelection* selection, gpointer data)
592 PrefsDlg *dlg = (PrefsDlg*)data;
595 GtkTreeIter selected;
596 if(gtk_tree_selection_get_selected(selection, &model, &selected))
599 gtk_tree_model_get(model, &selected, 1, (gpointer*)&prefpage, -1);
600 dlg->showPrefPage(prefpage);
604 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
606 inline void PreferenceGroupCallbacks_constructGroup(const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group)
608 for(PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
615 inline void PreferenceGroupCallbacks_pushBack(PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback)
617 callbacks.push_back(callback);
620 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
622 inline void PreferencesPageCallbacks_constructPage(const PreferencesPageCallbacks& callbacks, PreferencesPage& page)
624 for(PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
630 inline void PreferencesPageCallbacks_pushBack(PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback)
632 callbacks.push_back(callback);
635 PreferencesPageCallbacks g_interfacePreferences;
636 void PreferencesDialog_addInterfacePreferences(const PreferencesPageCallback& callback)
638 PreferencesPageCallbacks_pushBack(g_interfacePreferences, callback);
640 PreferenceGroupCallbacks g_interfaceCallbacks;
641 void PreferencesDialog_addInterfacePage(const PreferenceGroupCallback& callback)
643 PreferenceGroupCallbacks_pushBack(g_interfaceCallbacks, callback);
646 PreferencesPageCallbacks g_displayPreferences;
647 void PreferencesDialog_addDisplayPreferences(const PreferencesPageCallback& callback)
649 PreferencesPageCallbacks_pushBack(g_displayPreferences, callback);
651 PreferenceGroupCallbacks g_displayCallbacks;
652 void PreferencesDialog_addDisplayPage(const PreferenceGroupCallback& callback)
654 PreferenceGroupCallbacks_pushBack(g_displayCallbacks, callback);
657 PreferencesPageCallbacks g_settingsPreferences;
658 void PreferencesDialog_addSettingsPreferences(const PreferencesPageCallback& callback)
660 PreferencesPageCallbacks_pushBack(g_settingsPreferences, callback);
662 PreferenceGroupCallbacks g_settingsCallbacks;
663 void PreferencesDialog_addSettingsPage(const PreferenceGroupCallback& callback)
665 PreferenceGroupCallbacks_pushBack(g_settingsCallbacks, callback);
668 void Widget_updateDependency(GtkWidget* self, GtkWidget* toggleButton)
670 gtk_widget_set_sensitive(self, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggleButton)) && GTK_WIDGET_IS_SENSITIVE(toggleButton));
673 void ToggleButton_toggled_Widget_updateDependency(GtkWidget *toggleButton, GtkWidget* self)
675 Widget_updateDependency(self, toggleButton);
678 void ToggleButton_state_changed_Widget_updateDependency(GtkWidget* toggleButton, GtkStateType state, GtkWidget* self)
680 if(state == GTK_STATE_INSENSITIVE)
682 Widget_updateDependency(self, toggleButton);
686 void Widget_connectToggleDependency(GtkWidget* self, GtkWidget* toggleButton)
688 g_signal_connect(G_OBJECT(toggleButton), "state_changed", G_CALLBACK(ToggleButton_state_changed_Widget_updateDependency), self);
689 g_signal_connect(G_OBJECT(toggleButton), "toggled", G_CALLBACK(ToggleButton_toggled_Widget_updateDependency), self);
690 Widget_updateDependency(self, toggleButton);
694 inline GtkWidget* getVBox(GtkWidget* page)
696 return gtk_bin_get_child(GTK_BIN(page));
699 GtkTreeIter PreferenceTree_appendPage(GtkTreeStore* store, GtkTreeIter* parent, const char* name, GtkWidget* page)
702 gtk_tree_store_append(store, &group, parent);
703 gtk_tree_store_set(store, &group, 0, name, 1, page, -1);
707 GtkWidget* PreferencePages_addPage(GtkWidget* notebook, const char* name)
709 GtkWidget* preflabel = gtk_label_new(name);
710 gtk_widget_show(preflabel);
712 GtkWidget* pageframe = gtk_frame_new(name);
713 gtk_container_set_border_width(GTK_CONTAINER(pageframe), 4);
714 gtk_widget_show(pageframe);
716 GtkWidget* vbox = gtk_vbox_new(FALSE, 4);
717 gtk_widget_show(vbox);
718 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
719 gtk_container_add(GTK_CONTAINER(pageframe), vbox);
721 // Add the page to the notebook
722 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel);
727 class PreferenceTreeGroup : public PreferenceGroup
730 GtkWidget* m_notebook;
731 GtkTreeStore* m_store;
734 PreferenceTreeGroup(Dialog& dialog, GtkWidget* notebook, GtkTreeStore* store, GtkTreeIter group) :
736 m_notebook(notebook),
741 PreferencesPage createPage(const char* treeName, const char* frameName)
743 GtkWidget* page = PreferencePages_addPage(m_notebook, frameName);
744 PreferenceTree_appendPage(m_store, &m_group, treeName, page);
745 return PreferencesPage(m_dialog, getVBox(page));
749 GtkWindow* PrefsDlg::BuildDialog()
751 PreferencesDialog_addInterfacePreferences(FreeCaller1<PreferencesPage&, Interface_constructPreferences>());
752 Mouse_registerPreferencesPage();
754 GtkWindow* dialog = create_floating_window("NetRadiant Preferences", m_parent);
757 GtkWidget* mainvbox = gtk_vbox_new(FALSE, 5);
758 gtk_container_add(GTK_CONTAINER(dialog), mainvbox);
759 gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5);
760 gtk_widget_show(mainvbox);
763 GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
764 gtk_widget_show(hbox);
765 gtk_box_pack_end(GTK_BOX(mainvbox), hbox, FALSE, TRUE, 0);
768 GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &m_modal);
769 gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
772 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &m_modal);
773 gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
776 GtkButton* button = create_dialog_button("Clean", G_CALLBACK(OnButtonClean), this);
777 gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
782 GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
783 gtk_box_pack_start(GTK_BOX(mainvbox), hbox, TRUE, TRUE, 0);
784 gtk_widget_show(hbox);
787 GtkWidget* sc_win = gtk_scrolled_window_new(0, 0);
788 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
789 gtk_box_pack_start(GTK_BOX(hbox), sc_win, FALSE, FALSE, 0);
790 gtk_widget_show(sc_win);
791 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN);
793 // prefs pages notebook
794 m_notebook = gtk_notebook_new();
795 // hide the notebook tabs since its not supposed to look like a notebook
796 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_notebook), FALSE);
797 gtk_box_pack_start(GTK_BOX(hbox), m_notebook, TRUE, TRUE, 0);
798 gtk_widget_show(m_notebook);
802 GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
804 GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
805 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
808 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
809 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Preferences", renderer, "text", 0, NULL);
810 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
814 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
815 g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(treeSelection), this);
818 gtk_widget_show(view);
820 gtk_container_add(GTK_CONTAINER (sc_win), view);
823 /********************************************************************/
824 /* Add preference tree options */
825 /********************************************************************/
828 PreferencePages_addPage(m_notebook, "Front Page");
831 GtkWidget* global = PreferencePages_addPage(m_notebook, "Global Preferences");
833 PreferencesPage preferencesPage(*this, getVBox(global));
834 Global_constructPreferences(preferencesPage);
836 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Global", global);
838 GtkWidget* game = PreferencePages_addPage(m_notebook, "Game");
839 PreferencesPage preferencesPage(*this, getVBox(game));
840 g_GamesDialog.CreateGlobalFrame(preferencesPage);
842 PreferenceTree_appendPage(store, &group, "Game", game);
847 GtkWidget* interfacePage = PreferencePages_addPage(m_notebook, "Interface Preferences");
849 PreferencesPage preferencesPage(*this, getVBox(interfacePage));
850 PreferencesPageCallbacks_constructPage(g_interfacePreferences, preferencesPage);
853 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Interface", interfacePage);
854 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
856 PreferenceGroupCallbacks_constructGroup(g_interfaceCallbacks, preferenceGroup);
860 GtkWidget* display = PreferencePages_addPage(m_notebook, "Display Preferences");
862 PreferencesPage preferencesPage(*this, getVBox(display));
863 PreferencesPageCallbacks_constructPage(g_displayPreferences, preferencesPage);
865 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Display", display);
866 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
868 PreferenceGroupCallbacks_constructGroup(g_displayCallbacks, preferenceGroup);
872 GtkWidget* settings = PreferencePages_addPage(m_notebook, "General Settings");
874 PreferencesPage preferencesPage(*this, getVBox(settings));
875 PreferencesPageCallbacks_constructPage(g_settingsPreferences, preferencesPage);
878 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Settings", settings);
879 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
881 PreferenceGroupCallbacks_constructGroup(g_settingsCallbacks, preferenceGroup);
885 gtk_tree_view_expand_all(GTK_TREE_VIEW(view));
887 g_object_unref(G_OBJECT(store));
893 gtk_notebook_set_page(GTK_NOTEBOOK(m_notebook), 0);
898 preferences_globals_t g_preferences_globals;
900 PrefsDlg g_Preferences; // global prefs instance
903 void PreferencesDialog_constructWindow(GtkWindow* main_window)
905 g_Preferences.m_parent = main_window;
906 g_Preferences.Create();
908 void PreferencesDialog_destroyWindow()
910 g_Preferences.Destroy();
914 PreferenceDictionary g_preferences;
916 PreferenceSystem& GetPreferenceSystem()
918 return g_preferences;
921 class PreferenceSystemAPI
923 PreferenceSystem* m_preferencesystem;
925 typedef PreferenceSystem Type;
926 STRING_CONSTANT(Name, "*");
928 PreferenceSystemAPI()
930 m_preferencesystem = &GetPreferenceSystem();
932 PreferenceSystem* getTable()
934 return m_preferencesystem;
938 #include "modulesystem/singletonmodule.h"
939 #include "modulesystem/moduleregistry.h"
941 typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
942 typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
943 StaticRegisterModule staticRegisterPreferenceSystem(StaticPreferenceSystemModule::instance());
945 void Preferences_Load()
947 g_GamesDialog.LoadPrefs();
949 globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
951 if(!Preferences_Load(g_preferences, g_Preferences.m_inipath->str))
953 globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
957 void Preferences_Save()
959 if (g_preferences_globals.disable_ini)
962 g_GamesDialog.SavePrefs();
964 globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
966 if(!Preferences_Save_Safe(g_preferences, g_Preferences.m_inipath->str))
968 globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
972 void Preferences_Reset()
974 file_remove(g_Preferences.m_inipath->str);
978 void PrefsDlg::PostModal (EMessageBoxReturn code)
987 std::vector<const char*> g_restart_required;
989 void PreferencesDialog_restartRequired(const char* staticName)
991 g_restart_required.push_back(staticName);
994 void PreferencesDialog_showDialog()
996 if(ConfirmModified("Edit Preferences") && g_Preferences.DoModal() == eIDOK)
998 if(!g_restart_required.empty())
1000 StringOutputStream message(256);
1001 message << "Preference changes require a restart:\n";
1002 for(std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i)
1004 message << (*i) << '\n';
1006 gtk_MessageBox(GTK_WIDGET(MainFrame_getWindow()), message.c_str());
1007 g_restart_required.clear();
1016 void GameName_importString(const char* value)
1018 gamename_set(value);
1020 typedef FreeCaller1<const char*, GameName_importString> GameNameImportStringCaller;
1021 void GameName_exportString(const StringImportCallback& importer)
1023 importer(gamename_get());
1025 typedef FreeCaller1<const StringImportCallback&, GameName_exportString> GameNameExportStringCaller;
1027 void GameMode_importString(const char* value)
1029 gamemode_set(value);
1031 typedef FreeCaller1<const char*, GameMode_importString> GameModeImportStringCaller;
1032 void GameMode_exportString(const StringImportCallback& importer)
1034 importer(gamemode_get());
1036 typedef FreeCaller1<const StringImportCallback&, GameMode_exportString> GameModeExportStringCaller;
1039 void RegisterPreferences(PreferenceSystem& preferences)
1042 preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useWin32Editor), BoolExportStringCaller(g_TextEditor_useWin32Editor));
1044 preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useCustomEditor), BoolExportStringCaller(g_TextEditor_useCustomEditor));
1045 preferences.registerPreference("CustomShaderEditorCommand", CopiedStringImportStringCaller(g_TextEditor_editorCommand), CopiedStringExportStringCaller(g_TextEditor_editorCommand));
1048 preferences.registerPreference("GameName", GameNameImportStringCaller(), GameNameExportStringCaller());
1049 preferences.registerPreference("GameMode", GameModeImportStringCaller(), GameModeExportStringCaller());
1052 void Preferences_Init()
1054 RegisterPreferences(GetPreferenceSystem());