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("", "Native File-Chooser", g_FileChooser_nativeGUI);
76 page.appendCheckBox("", "Default Text Editor", g_TextEditor_useWin32Editor);
79 GtkWidget* use_custom = page.appendCheckBox("Text Editor", "Custom", g_TextEditor_useCustomEditor);
80 GtkWidget* custom_editor = page.appendPathEntry("Text Editor Command", g_TextEditor_editorCommand, true);
81 Widget_connectToggleDependency(custom_editor, use_custom);
86 void Mouse_constructPreferences(PreferencesPage& page)
89 const char* buttons[] = { "2 button", "3 button", };
90 page.appendRadio("Mouse Type", g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE(buttons));
92 page.appendCheckBox("Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick);
94 void Mouse_constructPage(PreferenceGroup& group)
96 PreferencesPage page(group.createPage("Mouse", "Mouse Preferences"));
97 Mouse_constructPreferences(page);
99 void Mouse_registerPreferencesPage()
101 PreferencesDialog_addInterfacePage(FreeCaller1<PreferenceGroup&, Mouse_constructPage>());
106 =========================================================
107 Games selection dialog
108 =========================================================
113 inline const char* xmlAttr_getName(xmlAttrPtr attr)
115 return reinterpret_cast<const char*>(attr->name);
118 inline const char* xmlAttr_getValue(xmlAttrPtr attr)
120 return reinterpret_cast<const char*>(attr->children->content);
123 CGameDescription::CGameDescription(xmlDocPtr pDoc, const CopiedString& gameFile)
125 // read the user-friendly game name
126 xmlNodePtr pNode = pDoc->children;
128 while (strcmp((const char*)pNode->name, "game") && pNode != 0)
134 Error("Didn't find 'game' node in the game description file '%s'\n", pDoc->URL);
137 for(xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next)
139 m_gameDescription.insert(GameDescription::value_type(xmlAttr_getName(attr), xmlAttr_getValue(attr)));
143 StringOutputStream path(256);
144 path << AppPath_get() << gameFile.c_str() << "/";
145 mGameToolsPath = path.c_str();
148 ASSERT_MESSAGE(file_exists(mGameToolsPath.c_str()), "game directory not found: " << makeQuoted(mGameToolsPath.c_str()));
150 mGameFile = gameFile;
153 GameDescription::iterator i = m_gameDescription.find("type");
154 if(i == m_gameDescription.end())
156 globalErrorStream() << "Warning, 'type' attribute not found in '" << reinterpret_cast<const char*>(pDoc->URL) << "'\n";
162 mGameType = (*i).second.c_str();
167 void CGameDescription::Dump()
169 globalOutputStream() << "game description file: " << makeQuoted(mGameFile.c_str()) << "\n";
170 for(GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i)
172 globalOutputStream() << (*i).first.c_str() << " = " << makeQuoted((*i).second.c_str()) << "\n";
176 CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentDescription
179 #include "warnings.h"
180 #include "stream/textfilestream.h"
181 #include "container/array.h"
182 #include "xml/ixml.h"
183 #include "xml/xmlparser.h"
184 #include "xml/xmlwriter.h"
186 #include "preferencedictionary.h"
187 #include "stringio.h"
189 const char* const PREFERENCES_VERSION = "1.0";
191 bool Preferences_Load(PreferenceDictionary& preferences, const char* filename)
193 TextFileInputStream file(filename);
196 XMLStreamParser parser(file);
197 XMLPreferenceDictionaryImporter importer(preferences, PREFERENCES_VERSION);
198 parser.exportXML(importer);
204 bool Preferences_Save(PreferenceDictionary& preferences, const char* filename)
206 TextFileOutputStream file(filename);
209 XMLStreamWriter writer(file);
210 XMLPreferenceDictionaryExporter exporter(preferences, PREFERENCES_VERSION);
211 exporter.exportXML(writer);
217 bool Preferences_Save_Safe(PreferenceDictionary& preferences, const char* filename)
219 Array<char> tmpName(filename, filename + strlen(filename) + 1 + 3);
220 *(tmpName.end() - 4) = 'T';
221 *(tmpName.end() - 3) = 'M';
222 *(tmpName.end() - 2) = 'P';
223 *(tmpName.end() - 1) = '\0';
225 return Preferences_Save(preferences, tmpName.data())
226 && (!file_exists(filename) || file_remove(filename))
227 && file_move(tmpName.data(), filename);
232 void LogConsole_importString(const char* string)
234 g_Console_enableLogging = string_equal(string, "true");
235 Sys_LogFile(g_Console_enableLogging);
237 typedef FreeCaller1<const char*, LogConsole_importString> LogConsoleImportStringCaller;
240 void RegisterGlobalPreferences(PreferenceSystem& preferences)
242 preferences.registerPreference("gamefile", CopiedStringImportStringCaller(g_GamesDialog.m_sGameFile), CopiedStringExportStringCaller(g_GamesDialog.m_sGameFile));
243 preferences.registerPreference("gamePrompt", BoolImportStringCaller(g_GamesDialog.m_bGamePrompt), BoolExportStringCaller(g_GamesDialog.m_bGamePrompt));
244 preferences.registerPreference("log console", LogConsoleImportStringCaller(), BoolExportStringCaller(g_Console_enableLogging));
248 PreferenceDictionary g_global_preferences;
250 void GlobalPreferences_Init()
252 RegisterGlobalPreferences(g_global_preferences);
255 void CGameDialog::LoadPrefs()
257 // load global .pref file
258 StringOutputStream strGlobalPref(256);
259 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
261 globalOutputStream() << "loading global preferences from " << makeQuoted(strGlobalPref.c_str()) << "\n";
263 if(!Preferences_Load(g_global_preferences, strGlobalPref.c_str()))
265 globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
269 void CGameDialog::SavePrefs()
271 StringOutputStream strGlobalPref(256);
272 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
274 globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
276 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++)
301 m_sGameFile = (*iGame)->mGameFile;
304 void CGameDialog::GameFileExport(const IntImportCallback& importCallback) const
306 // use m_sGameFile to set value
307 std::list<CGameDescription *>::const_iterator iGame;
309 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
311 if ((*iGame)->mGameFile == m_sGameFile)
318 importCallback(m_nComboSelect);
321 void CGameDialog_GameFileImport(CGameDialog& self, int value)
323 self.GameFileImport(value);
326 void CGameDialog_GameFileExport(CGameDialog& self, const IntImportCallback& importCallback)
328 self.GameFileExport(importCallback);
331 void CGameDialog::CreateGlobalFrame(PreferencesPage& page)
333 std::vector<const char*> games;
334 games.reserve(mGames.size());
335 for(std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i)
337 games.push_back((*i)->getRequiredKeyValue("name"));
341 StringArrayRange(&(*games.begin()), &(*games.end())),
342 ReferenceCaller1<CGameDialog, int, CGameDialog_GameFileImport>(*this),
343 ReferenceCaller1<CGameDialog, const IntImportCallback&, CGameDialog_GameFileExport>(*this)
345 page.appendCheckBox("Startup", "Show Global Preferences", m_bGamePrompt);
348 GtkWindow* CGameDialog::BuildDialog()
350 GtkFrame* frame = create_dialog_frame("Game settings", GTK_SHADOW_ETCHED_IN);
352 GtkVBox* vbox2 = create_dialog_vbox(0, 4);
353 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox2));
356 PreferencesPage preferencesPage(*this, GTK_WIDGET(vbox2));
357 Global_constructPreferences(preferencesPage);
358 CreateGlobalFrame(preferencesPage);
361 return create_simple_modal_dialog_window("Global Preferences", m_modal, GTK_WIDGET(frame));
366 std::list<CGameDescription*>& mGames;
369 LoadGameFile(std::list<CGameDescription*>& games, const char* path) : mGames(games), mPath(path)
372 void operator()(const char* name) const
374 if(!extension_equal(path_get_extension(name), "game"))
378 StringOutputStream strPath(256);
379 strPath << mPath << name;
380 globalOutputStream() << strPath.c_str() << '\n';
382 xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
385 mGames.push_front(new CGameDescription(pDoc, name));
390 globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
395 void CGameDialog::ScanForGames()
397 StringOutputStream strGamesPath(256);
398 strGamesPath << AppPath_get() << "games/";
399 const char *path = strGamesPath.c_str();
401 globalOutputStream() << "Scanning for game description files: " << path << '\n';
405 do we put game description files below AppPath, or in ~/.radiant
406 i.e. read only or read/write?
407 my guess .. readonly cause it's an install
408 we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
409 (if that's really needed)
412 Directory_forEach(path, LoadGameFile(mGames, path));
415 CGameDescription* CGameDialog::GameDescriptionForComboItem()
417 std::list<CGameDescription *>::iterator iGame;
419 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame,i++)
421 if (i == m_nComboSelect)
426 return 0; // not found
429 void CGameDialog::InitGlobalPrefPath()
431 g_Preferences.m_global_rc_path = g_string_new(SettingsPath_get());
434 void CGameDialog::Reset()
436 if (!g_Preferences.m_global_rc_path)
437 InitGlobalPrefPath();
438 StringOutputStream strGlobalPref(256);
439 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
440 file_remove(strGlobalPref.c_str());
443 void CGameDialog::Init()
445 InitGlobalPrefPath();
450 Error("Didn't find any valid game file descriptions, aborting\n");
453 CGameDescription* currentGameDescription = 0;
457 // search by .game name
458 std::list<CGameDescription *>::iterator iGame;
459 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
461 if ((*iGame)->mGameFile == m_sGameFile)
463 currentGameDescription = (*iGame);
468 if (m_bGamePrompt || !currentGameDescription)
472 // use m_nComboSelect to identify the game to run as and set the globals
473 currentGameDescription = GameDescriptionForComboItem();
474 ASSERT_NOTNULL(currentGameDescription);
476 g_pGameDescription = currentGameDescription;
478 g_pGameDescription->Dump();
481 CGameDialog::~CGameDialog()
483 // free all the game descriptions
484 std::list<CGameDescription *>::iterator iGame;
485 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
496 inline const char* GameDescription_getIdentifier(const CGameDescription& gameDescription)
498 const char* identifier = gameDescription.getKeyValue("index");
499 if(string_empty(identifier))
506 void CGameDialog::AddPacksURL(StringOutputStream &URL)
508 // add the URLs for the list of game packs installed
509 // FIXME: this is kinda hardcoded for now..
510 std::list<CGameDescription *>::iterator iGame;
511 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
513 URL << "&Games_dlup%5B%5D=" << GameDescription_getIdentifier(*(*iGame));
517 CGameDialog g_GamesDialog;
520 // =============================================================================
521 // Widget callbacks for PrefsDlg
523 static void OnButtonClean (GtkWidget *widget, gpointer data)
525 // make sure this is what the user wants
526 if (gtk_MessageBox(GTK_WIDGET(g_Preferences.GetWidget()), "This will close Radiant and clean the corresponding registry entries.\n"
527 "Next time you start Radiant it will be good as new. Do you wish to continue?",
528 "Reset Registry", eMB_YESNO, eMB_ICONASTERISK) == eIDYES)
530 PrefsDlg *dlg = (PrefsDlg*)data;
531 dlg->EndModal (eIDCANCEL);
533 g_preferences_globals.disable_ini = true;
539 // =============================================================================
545 very first prefs init deals with selecting the game and the game tools path
546 then we can load .ini stuff
548 using prefs / ini settings:
551 look in ~/.radiant/<version>/gamename
555 #define PREFS_LOCAL_FILENAME "local.pref"
557 void PrefsDlg::Init()
559 // m_global_rc_path has been set above
560 // m_rc_path is for game specific preferences
561 // takes the form: global-pref-path/gamename/prefs-file
563 // this is common to win32 and Linux init now
564 m_rc_path = g_string_new (m_global_rc_path->str);
567 g_string_append (m_rc_path, g_pGameDescription->mGameFile.c_str());
568 g_string_append (m_rc_path, "/");
569 Q_mkdir (m_rc_path->str);
572 m_inipath = g_string_new (m_rc_path->str);
573 g_string_append (m_inipath, PREFS_LOCAL_FILENAME);
576 void notebook_set_page(GtkWidget* notebook, GtkWidget* page)
578 int pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), page);
579 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != pagenum)
581 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), pagenum);
585 void PrefsDlg::showPrefPage(GtkWidget* prefpage)
587 notebook_set_page(m_notebook, prefpage);
591 static void treeSelection(GtkTreeSelection* selection, gpointer data)
593 PrefsDlg *dlg = (PrefsDlg*)data;
596 GtkTreeIter selected;
597 if(gtk_tree_selection_get_selected(selection, &model, &selected))
600 gtk_tree_model_get(model, &selected, 1, (gpointer*)&prefpage, -1);
601 dlg->showPrefPage(prefpage);
605 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
607 inline void PreferenceGroupCallbacks_constructGroup(const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group)
609 for(PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
616 inline void PreferenceGroupCallbacks_pushBack(PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback)
618 callbacks.push_back(callback);
621 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
623 inline void PreferencesPageCallbacks_constructPage(const PreferencesPageCallbacks& callbacks, PreferencesPage& page)
625 for(PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
631 inline void PreferencesPageCallbacks_pushBack(PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback)
633 callbacks.push_back(callback);
636 PreferencesPageCallbacks g_interfacePreferences;
637 void PreferencesDialog_addInterfacePreferences(const PreferencesPageCallback& callback)
639 PreferencesPageCallbacks_pushBack(g_interfacePreferences, callback);
641 PreferenceGroupCallbacks g_interfaceCallbacks;
642 void PreferencesDialog_addInterfacePage(const PreferenceGroupCallback& callback)
644 PreferenceGroupCallbacks_pushBack(g_interfaceCallbacks, callback);
647 PreferencesPageCallbacks g_displayPreferences;
648 void PreferencesDialog_addDisplayPreferences(const PreferencesPageCallback& callback)
650 PreferencesPageCallbacks_pushBack(g_displayPreferences, callback);
652 PreferenceGroupCallbacks g_displayCallbacks;
653 void PreferencesDialog_addDisplayPage(const PreferenceGroupCallback& callback)
655 PreferenceGroupCallbacks_pushBack(g_displayCallbacks, callback);
658 PreferencesPageCallbacks g_settingsPreferences;
659 void PreferencesDialog_addSettingsPreferences(const PreferencesPageCallback& callback)
661 PreferencesPageCallbacks_pushBack(g_settingsPreferences, callback);
663 PreferenceGroupCallbacks g_settingsCallbacks;
664 void PreferencesDialog_addSettingsPage(const PreferenceGroupCallback& callback)
666 PreferenceGroupCallbacks_pushBack(g_settingsCallbacks, callback);
669 void Widget_updateDependency(GtkWidget* self, GtkWidget* toggleButton)
671 gtk_widget_set_sensitive(self, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggleButton)) && GTK_WIDGET_IS_SENSITIVE(toggleButton));
674 void ToggleButton_toggled_Widget_updateDependency(GtkWidget *toggleButton, GtkWidget* self)
676 Widget_updateDependency(self, toggleButton);
679 void ToggleButton_state_changed_Widget_updateDependency(GtkWidget* toggleButton, GtkStateType state, GtkWidget* self)
681 if(state == GTK_STATE_INSENSITIVE)
683 Widget_updateDependency(self, toggleButton);
687 void Widget_connectToggleDependency(GtkWidget* self, GtkWidget* toggleButton)
689 g_signal_connect(G_OBJECT(toggleButton), "state_changed", G_CALLBACK(ToggleButton_state_changed_Widget_updateDependency), self);
690 g_signal_connect(G_OBJECT(toggleButton), "toggled", G_CALLBACK(ToggleButton_toggled_Widget_updateDependency), self);
691 Widget_updateDependency(self, toggleButton);
695 inline GtkWidget* getVBox(GtkWidget* page)
697 return gtk_bin_get_child(GTK_BIN(page));
700 GtkTreeIter PreferenceTree_appendPage(GtkTreeStore* store, GtkTreeIter* parent, const char* name, GtkWidget* page)
703 gtk_tree_store_append(store, &group, parent);
704 gtk_tree_store_set(store, &group, 0, name, 1, page, -1);
708 GtkWidget* PreferencePages_addPage(GtkWidget* notebook, const char* name)
710 GtkWidget* preflabel = gtk_label_new(name);
711 gtk_widget_show(preflabel);
713 GtkWidget* pageframe = gtk_frame_new(name);
714 gtk_container_set_border_width(GTK_CONTAINER(pageframe), 4);
715 gtk_widget_show(pageframe);
717 GtkWidget* vbox = gtk_vbox_new(FALSE, 4);
718 gtk_widget_show(vbox);
719 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
720 gtk_container_add(GTK_CONTAINER(pageframe), vbox);
722 // Add the page to the notebook
723 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel);
728 class PreferenceTreeGroup : public PreferenceGroup
731 GtkWidget* m_notebook;
732 GtkTreeStore* m_store;
735 PreferenceTreeGroup(Dialog& dialog, GtkWidget* notebook, GtkTreeStore* store, GtkTreeIter group) :
737 m_notebook(notebook),
742 PreferencesPage createPage(const char* treeName, const char* frameName)
744 GtkWidget* page = PreferencePages_addPage(m_notebook, frameName);
745 PreferenceTree_appendPage(m_store, &m_group, treeName, page);
746 return PreferencesPage(m_dialog, getVBox(page));
750 GtkWindow* PrefsDlg::BuildDialog()
752 PreferencesDialog_addInterfacePreferences(FreeCaller1<PreferencesPage&, Interface_constructPreferences>());
753 Mouse_registerPreferencesPage();
755 GtkWindow* dialog = create_floating_window("GtkRadiant Preferences", m_parent);
758 GtkWidget* mainvbox = gtk_vbox_new(FALSE, 5);
759 gtk_container_add(GTK_CONTAINER(dialog), mainvbox);
760 gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5);
761 gtk_widget_show(mainvbox);
764 GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
765 gtk_widget_show(hbox);
766 gtk_box_pack_end(GTK_BOX(mainvbox), hbox, FALSE, TRUE, 0);
769 GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &m_modal);
770 gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
773 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &m_modal);
774 gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
777 GtkButton* button = create_dialog_button("Clean", G_CALLBACK(OnButtonClean), this);
778 gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
783 GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
784 gtk_box_pack_start(GTK_BOX(mainvbox), hbox, TRUE, TRUE, 0);
785 gtk_widget_show(hbox);
788 GtkWidget* sc_win = gtk_scrolled_window_new(0, 0);
789 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
790 gtk_box_pack_start(GTK_BOX(hbox), sc_win, FALSE, FALSE, 0);
791 gtk_widget_show(sc_win);
792 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN);
794 // prefs pages notebook
795 m_notebook = gtk_notebook_new();
796 // hide the notebook tabs since its not supposed to look like a notebook
797 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_notebook), FALSE);
798 gtk_box_pack_start(GTK_BOX(hbox), m_notebook, TRUE, TRUE, 0);
799 gtk_widget_show(m_notebook);
803 GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
805 GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
806 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
809 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
810 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Preferences", renderer, "text", 0, 0);
811 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
815 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
816 g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(treeSelection), this);
819 gtk_widget_show(view);
821 gtk_container_add(GTK_CONTAINER (sc_win), view);
824 /********************************************************************/
825 /* Add preference tree options */
826 /********************************************************************/
829 PreferencePages_addPage(m_notebook, "Front Page");
832 GtkWidget* global = PreferencePages_addPage(m_notebook, "Global Preferences");
834 PreferencesPage preferencesPage(*this, getVBox(global));
835 Global_constructPreferences(preferencesPage);
837 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Global", global);
839 GtkWidget* game = PreferencePages_addPage(m_notebook, "Game");
840 PreferencesPage preferencesPage(*this, getVBox(game));
841 g_GamesDialog.CreateGlobalFrame(preferencesPage);
843 PreferenceTree_appendPage(store, &group, "Game", game);
848 GtkWidget* interfacePage = PreferencePages_addPage(m_notebook, "Interface Preferences");
850 PreferencesPage preferencesPage(*this, getVBox(interfacePage));
851 PreferencesPageCallbacks_constructPage(g_interfacePreferences, preferencesPage);
854 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Interface", interfacePage);
855 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
857 PreferenceGroupCallbacks_constructGroup(g_interfaceCallbacks, preferenceGroup);
861 GtkWidget* display = PreferencePages_addPage(m_notebook, "Display Preferences");
863 PreferencesPage preferencesPage(*this, getVBox(display));
864 PreferencesPageCallbacks_constructPage(g_displayPreferences, preferencesPage);
866 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Display", display);
867 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
869 PreferenceGroupCallbacks_constructGroup(g_displayCallbacks, preferenceGroup);
873 GtkWidget* settings = PreferencePages_addPage(m_notebook, "General Settings");
875 PreferencesPage preferencesPage(*this, getVBox(settings));
876 PreferencesPageCallbacks_constructPage(g_settingsPreferences, preferencesPage);
879 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Settings", settings);
880 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
882 PreferenceGroupCallbacks_constructGroup(g_settingsCallbacks, preferenceGroup);
886 gtk_tree_view_expand_all(GTK_TREE_VIEW(view));
888 g_object_unref(G_OBJECT(store));
894 gtk_notebook_set_page(GTK_NOTEBOOK(m_notebook), 0);
899 preferences_globals_t g_preferences_globals;
901 PrefsDlg g_Preferences; // global prefs instance
904 void PreferencesDialog_constructWindow(GtkWindow* main_window)
906 g_Preferences.m_parent = main_window;
907 g_Preferences.Create();
909 void PreferencesDialog_destroyWindow()
911 g_Preferences.Destroy();
915 PreferenceDictionary g_preferences;
917 PreferenceSystem& GetPreferenceSystem()
919 return g_preferences;
922 class PreferenceSystemAPI
924 PreferenceSystem* m_preferencesystem;
926 typedef PreferenceSystem Type;
927 STRING_CONSTANT(Name, "*");
929 PreferenceSystemAPI()
931 m_preferencesystem = &GetPreferenceSystem();
933 PreferenceSystem* getTable()
935 return m_preferencesystem;
939 #include "modulesystem/singletonmodule.h"
940 #include "modulesystem/moduleregistry.h"
942 typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
943 typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
944 StaticRegisterModule staticRegisterPreferenceSystem(StaticPreferenceSystemModule::instance());
946 void Preferences_Load()
948 g_GamesDialog.LoadPrefs();
950 globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
952 if(!Preferences_Load(g_preferences, g_Preferences.m_inipath->str))
954 globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
958 void Preferences_Save()
960 if (g_preferences_globals.disable_ini)
963 g_GamesDialog.SavePrefs();
965 globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
967 if(!Preferences_Save_Safe(g_preferences, g_Preferences.m_inipath->str))
969 globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
973 void Preferences_Reset()
975 file_remove(g_Preferences.m_inipath->str);
979 void PrefsDlg::PostModal (EMessageBoxReturn code)
988 std::vector<const char*> g_restart_required;
990 void PreferencesDialog_restartRequired(const char* staticName)
992 g_restart_required.push_back(staticName);
995 void PreferencesDialog_showDialog()
997 if(ConfirmModified("Edit Preferences") && g_Preferences.DoModal() == eIDOK)
999 if(!g_restart_required.empty())
1001 StringOutputStream message(256);
1002 message << "Preference changes require a restart:\n";
1003 for(std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i)
1005 message << (*i) << '\n';
1007 gtk_MessageBox(GTK_WIDGET(MainFrame_getWindow()), message.c_str());
1008 g_restart_required.clear();
1017 void GameName_importString(const char* value)
1019 gamename_set(value);
1021 typedef FreeCaller1<const char*, GameName_importString> GameNameImportStringCaller;
1022 void GameName_exportString(const StringImportCallback& importer)
1024 importer(gamename_get());
1026 typedef FreeCaller1<const StringImportCallback&, GameName_exportString> GameNameExportStringCaller;
1028 void GameMode_importString(const char* value)
1030 gamemode_set(value);
1032 typedef FreeCaller1<const char*, GameMode_importString> GameModeImportStringCaller;
1033 void GameMode_exportString(const StringImportCallback& importer)
1035 importer(gamemode_get());
1037 typedef FreeCaller1<const StringImportCallback&, GameMode_exportString> GameModeExportStringCaller;
1040 void RegisterPreferences(PreferenceSystem& preferences)
1044 preferences.registerPreference("NativeGUI", BoolImportStringCaller(g_FileChooser_nativeGUI), BoolExportStringCaller(g_FileChooser_nativeGUI));
1049 preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useWin32Editor), BoolExportStringCaller(g_TextEditor_useWin32Editor));
1051 preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useCustomEditor), BoolExportStringCaller(g_TextEditor_useCustomEditor));
1052 preferences.registerPreference("CustomShaderEditorCommand", CopiedStringImportStringCaller(g_TextEditor_editorCommand), CopiedStringExportStringCaller(g_TextEditor_editorCommand));
1055 preferences.registerPreference("GameName", GameNameImportStringCaller(), GameNameExportStringCaller());
1056 preferences.registerPreference("GameMode", GameModeImportStringCaller(), GameModeExportStringCaller());
1059 void Preferences_Init()
1061 RegisterPreferences(GetPreferenceSystem());