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 "environment.h"
31 #include "debugging/debugging.h"
33 #include <gtk/gtkmain.h>
34 #include <gtk/gtkvbox.h>
35 #include <gtk/gtkhbox.h>
36 #include <gtk/gtkframe.h>
37 #include <gtk/gtklabel.h>
38 #include <gtk/gtktogglebutton.h>
39 #include <gtk/gtkspinbutton.h>
40 #include <gtk/gtkscrolledwindow.h>
41 #include <gtk/gtktreemodel.h>
42 #include <gtk/gtktreeview.h>
43 #include <gtk/gtktreestore.h>
44 #include <gtk/gtktreeselection.h>
45 #include <gtk/gtkcellrenderertext.h>
46 #include <gtk/gtknotebook.h>
48 #include "generic/callback.h"
49 #include "math/vector.h"
50 #include "string/string.h"
51 #include "stream/stringstream.h"
55 #include "gtkutil/filechooser.h"
56 #include "gtkutil/messagebox.h"
62 #include "mainframe.h"
68 void Global_constructPreferences(PreferencesPage& page)
70 page.appendCheckBox("Console", "Enable Logging", g_Console_enableLogging);
73 void Interface_constructPreferences(PreferencesPage& page)
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, const char *cmdline_prefix)
194 TextFileInputStream file(filename);
197 XMLStreamParser parser(file);
198 XMLPreferenceDictionaryImporter importer(preferences, PREFERENCES_VERSION);
199 parser.exportXML(importer);
203 int l = strlen(cmdline_prefix);
204 for(int i = 1; i < g_argc - 1; ++i)
206 if(g_argv[i][0] == '-')
208 if(!strncmp(g_argv[i]+1, cmdline_prefix, l))
209 if(g_argv[i][l+1] == '-')
210 preferences.importPref(g_argv[i]+l+2, g_argv[i+1]);
218 bool Preferences_Save(PreferenceDictionary& preferences, const char* filename)
220 TextFileOutputStream file(filename);
223 XMLStreamWriter writer(file);
224 XMLPreferenceDictionaryExporter exporter(preferences, PREFERENCES_VERSION);
225 exporter.exportXML(writer);
231 bool Preferences_Save_Safe(PreferenceDictionary& preferences, const char* filename)
233 Array<char> tmpName(filename, filename + strlen(filename) + 1 + 3);
234 *(tmpName.end() - 4) = 'T';
235 *(tmpName.end() - 3) = 'M';
236 *(tmpName.end() - 2) = 'P';
237 *(tmpName.end() - 1) = '\0';
239 return Preferences_Save(preferences, tmpName.data())
240 && (!file_exists(filename) || file_remove(filename))
241 && file_move(tmpName.data(), filename);
246 void LogConsole_importString(const char* string)
248 g_Console_enableLogging = string_equal(string, "true");
249 Sys_LogFile(g_Console_enableLogging);
251 typedef FreeCaller1<const char*, LogConsole_importString> LogConsoleImportStringCaller;
254 void RegisterGlobalPreferences(PreferenceSystem& preferences)
256 preferences.registerPreference("gamefile", CopiedStringImportStringCaller(g_GamesDialog.m_sGameFile), CopiedStringExportStringCaller(g_GamesDialog.m_sGameFile));
257 preferences.registerPreference("gamePrompt", BoolImportStringCaller(g_GamesDialog.m_bGamePrompt), BoolExportStringCaller(g_GamesDialog.m_bGamePrompt));
258 preferences.registerPreference("log console", LogConsoleImportStringCaller(), BoolExportStringCaller(g_Console_enableLogging));
262 PreferenceDictionary g_global_preferences;
264 void GlobalPreferences_Init()
266 RegisterGlobalPreferences(g_global_preferences);
269 void CGameDialog::LoadPrefs()
271 // load global .pref file
272 StringOutputStream strGlobalPref(256);
273 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
275 globalOutputStream() << "loading global preferences from " << makeQuoted(strGlobalPref.c_str()) << "\n";
277 if(!Preferences_Load(g_global_preferences, strGlobalPref.c_str(), "global"))
279 globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
283 void CGameDialog::SavePrefs()
285 StringOutputStream strGlobalPref(256);
286 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
288 globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
290 if(!Preferences_Save_Safe(g_global_preferences, strGlobalPref.c_str()))
292 globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
296 void CGameDialog::DoGameDialog()
301 // we save the prefs file
305 void CGameDialog::GameFileImport(int value)
307 m_nComboSelect = value;
308 // use value to set m_sGameFile
309 std::list<CGameDescription *>::iterator iGame = mGames.begin();
311 for(i=0; i<value; i++)
315 m_sGameFile = (*iGame)->mGameFile;
318 void CGameDialog::GameFileExport(const IntImportCallback& importCallback) const
320 // use m_sGameFile to set value
321 std::list<CGameDescription *>::const_iterator iGame;
323 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
325 if ((*iGame)->mGameFile == m_sGameFile)
332 importCallback(m_nComboSelect);
335 void CGameDialog_GameFileImport(CGameDialog& self, int value)
337 self.GameFileImport(value);
340 void CGameDialog_GameFileExport(CGameDialog& self, const IntImportCallback& importCallback)
342 self.GameFileExport(importCallback);
345 void CGameDialog::CreateGlobalFrame(PreferencesPage& page)
347 std::vector<const char*> games;
348 games.reserve(mGames.size());
349 for(std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i)
351 games.push_back((*i)->getRequiredKeyValue("name"));
355 StringArrayRange(&(*games.begin()), &(*games.end())),
356 ReferenceCaller1<CGameDialog, int, CGameDialog_GameFileImport>(*this),
357 ReferenceCaller1<CGameDialog, const IntImportCallback&, CGameDialog_GameFileExport>(*this)
359 page.appendCheckBox("Startup", "Show Global Preferences", m_bGamePrompt);
362 GtkWindow* CGameDialog::BuildDialog()
364 GtkFrame* frame = create_dialog_frame("Game settings", GTK_SHADOW_ETCHED_IN);
366 GtkVBox* vbox2 = create_dialog_vbox(0, 4);
367 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox2));
370 PreferencesPage preferencesPage(*this, GTK_WIDGET(vbox2));
371 Global_constructPreferences(preferencesPage);
372 CreateGlobalFrame(preferencesPage);
375 return create_simple_modal_dialog_window("Global Preferences", m_modal, GTK_WIDGET(frame));
380 std::list<CGameDescription*>& mGames;
383 LoadGameFile(std::list<CGameDescription*>& games, const char* path) : mGames(games), mPath(path)
386 void operator()(const char* name) const
388 if(!extension_equal(path_get_extension(name), "game"))
392 StringOutputStream strPath(256);
393 strPath << mPath << name;
394 globalOutputStream() << strPath.c_str() << '\n';
396 xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
399 mGames.push_front(new CGameDescription(pDoc, name));
404 globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
409 void CGameDialog::ScanForGames()
411 StringOutputStream strGamesPath(256);
412 strGamesPath << AppPath_get() << "games/";
413 const char *path = strGamesPath.c_str();
415 globalOutputStream() << "Scanning for game description files: " << path << '\n';
419 do we put game description files below AppPath, or in ~/.radiant
420 i.e. read only or read/write?
421 my guess .. readonly cause it's an install
422 we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
423 (if that's really needed)
426 Directory_forEach(path, LoadGameFile(mGames, path));
429 CGameDescription* CGameDialog::GameDescriptionForComboItem()
431 std::list<CGameDescription *>::iterator iGame;
433 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame,i++)
435 if (i == m_nComboSelect)
440 return 0; // not found
443 void CGameDialog::InitGlobalPrefPath()
445 g_Preferences.m_global_rc_path = g_string_new(SettingsPath_get());
448 void CGameDialog::Reset()
450 if (!g_Preferences.m_global_rc_path)
451 InitGlobalPrefPath();
452 StringOutputStream strGlobalPref(256);
453 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
454 file_remove(strGlobalPref.c_str());
457 void CGameDialog::Init()
459 InitGlobalPrefPath();
464 Error("Didn't find any valid game file descriptions, aborting\n");
467 CGameDescription* currentGameDescription = 0;
471 // search by .game name
472 std::list<CGameDescription *>::iterator iGame;
473 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
475 if ((*iGame)->mGameFile == m_sGameFile)
477 currentGameDescription = (*iGame);
482 if (m_bGamePrompt || !currentGameDescription)
486 // use m_nComboSelect to identify the game to run as and set the globals
487 currentGameDescription = GameDescriptionForComboItem();
488 ASSERT_NOTNULL(currentGameDescription);
490 g_pGameDescription = currentGameDescription;
492 g_pGameDescription->Dump();
495 CGameDialog::~CGameDialog()
497 // free all the game descriptions
498 std::list<CGameDescription *>::iterator iGame;
499 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
510 inline const char* GameDescription_getIdentifier(const CGameDescription& gameDescription)
512 const char* identifier = gameDescription.getKeyValue("index");
513 if(string_empty(identifier))
520 void CGameDialog::AddPacksURL(StringOutputStream &URL)
522 // add the URLs for the list of game packs installed
523 // FIXME: this is kinda hardcoded for now..
524 std::list<CGameDescription *>::iterator iGame;
525 for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
527 URL << "&Games_dlup%5B%5D=" << GameDescription_getIdentifier(*(*iGame));
531 CGameDialog g_GamesDialog;
534 // =============================================================================
535 // Widget callbacks for PrefsDlg
537 static void OnButtonClean (GtkWidget *widget, gpointer data)
539 // make sure this is what the user wants
540 if (gtk_MessageBox(GTK_WIDGET(g_Preferences.GetWidget()), "This will close Radiant and clean the corresponding registry entries.\n"
541 "Next time you start Radiant it will be good as new. Do you wish to continue?",
542 "Reset Registry", eMB_YESNO, eMB_ICONASTERISK) == eIDYES)
544 PrefsDlg *dlg = (PrefsDlg*)data;
545 dlg->EndModal (eIDCANCEL);
547 g_preferences_globals.disable_ini = true;
553 // =============================================================================
559 very first prefs init deals with selecting the game and the game tools path
560 then we can load .ini stuff
562 using prefs / ini settings:
565 look in ~/.radiant/<version>/gamename
569 #define PREFS_LOCAL_FILENAME "local.pref"
571 void PrefsDlg::Init()
573 // m_global_rc_path has been set above
574 // m_rc_path is for game specific preferences
575 // takes the form: global-pref-path/gamename/prefs-file
577 // this is common to win32 and Linux init now
578 m_rc_path = g_string_new (m_global_rc_path->str);
581 g_string_append (m_rc_path, g_pGameDescription->mGameFile.c_str());
582 g_string_append (m_rc_path, "/");
583 Q_mkdir (m_rc_path->str);
586 m_inipath = g_string_new (m_rc_path->str);
587 g_string_append (m_inipath, PREFS_LOCAL_FILENAME);
590 void notebook_set_page(GtkWidget* notebook, GtkWidget* page)
592 int pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), page);
593 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != pagenum)
595 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), pagenum);
599 void PrefsDlg::showPrefPage(GtkWidget* prefpage)
601 notebook_set_page(m_notebook, prefpage);
605 static void treeSelection(GtkTreeSelection* selection, gpointer data)
607 PrefsDlg *dlg = (PrefsDlg*)data;
610 GtkTreeIter selected;
611 if(gtk_tree_selection_get_selected(selection, &model, &selected))
614 gtk_tree_model_get(model, &selected, 1, (gpointer*)&prefpage, -1);
615 dlg->showPrefPage(prefpage);
619 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
621 inline void PreferenceGroupCallbacks_constructGroup(const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group)
623 for(PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
630 inline void PreferenceGroupCallbacks_pushBack(PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback)
632 callbacks.push_back(callback);
635 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
637 inline void PreferencesPageCallbacks_constructPage(const PreferencesPageCallbacks& callbacks, PreferencesPage& page)
639 for(PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
645 inline void PreferencesPageCallbacks_pushBack(PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback)
647 callbacks.push_back(callback);
650 PreferencesPageCallbacks g_interfacePreferences;
651 void PreferencesDialog_addInterfacePreferences(const PreferencesPageCallback& callback)
653 PreferencesPageCallbacks_pushBack(g_interfacePreferences, callback);
655 PreferenceGroupCallbacks g_interfaceCallbacks;
656 void PreferencesDialog_addInterfacePage(const PreferenceGroupCallback& callback)
658 PreferenceGroupCallbacks_pushBack(g_interfaceCallbacks, callback);
661 PreferencesPageCallbacks g_displayPreferences;
662 void PreferencesDialog_addDisplayPreferences(const PreferencesPageCallback& callback)
664 PreferencesPageCallbacks_pushBack(g_displayPreferences, callback);
666 PreferenceGroupCallbacks g_displayCallbacks;
667 void PreferencesDialog_addDisplayPage(const PreferenceGroupCallback& callback)
669 PreferenceGroupCallbacks_pushBack(g_displayCallbacks, callback);
672 PreferencesPageCallbacks g_settingsPreferences;
673 void PreferencesDialog_addSettingsPreferences(const PreferencesPageCallback& callback)
675 PreferencesPageCallbacks_pushBack(g_settingsPreferences, callback);
677 PreferenceGroupCallbacks g_settingsCallbacks;
678 void PreferencesDialog_addSettingsPage(const PreferenceGroupCallback& callback)
680 PreferenceGroupCallbacks_pushBack(g_settingsCallbacks, callback);
683 void Widget_updateDependency(GtkWidget* self, GtkWidget* toggleButton)
685 gtk_widget_set_sensitive(self, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggleButton)) && GTK_WIDGET_IS_SENSITIVE(toggleButton));
688 void ToggleButton_toggled_Widget_updateDependency(GtkWidget *toggleButton, GtkWidget* self)
690 Widget_updateDependency(self, toggleButton);
693 void ToggleButton_state_changed_Widget_updateDependency(GtkWidget* toggleButton, GtkStateType state, GtkWidget* self)
695 if(state == GTK_STATE_INSENSITIVE)
697 Widget_updateDependency(self, toggleButton);
701 void Widget_connectToggleDependency(GtkWidget* self, GtkWidget* toggleButton)
703 g_signal_connect(G_OBJECT(toggleButton), "state_changed", G_CALLBACK(ToggleButton_state_changed_Widget_updateDependency), self);
704 g_signal_connect(G_OBJECT(toggleButton), "toggled", G_CALLBACK(ToggleButton_toggled_Widget_updateDependency), self);
705 Widget_updateDependency(self, toggleButton);
709 inline GtkWidget* getVBox(GtkWidget* page)
711 return gtk_bin_get_child(GTK_BIN(page));
714 GtkTreeIter PreferenceTree_appendPage(GtkTreeStore* store, GtkTreeIter* parent, const char* name, GtkWidget* page)
717 gtk_tree_store_append(store, &group, parent);
718 gtk_tree_store_set(store, &group, 0, name, 1, page, -1);
722 GtkWidget* PreferencePages_addPage(GtkWidget* notebook, const char* name)
724 GtkWidget* preflabel = gtk_label_new(name);
725 gtk_widget_show(preflabel);
727 GtkWidget* pageframe = gtk_frame_new(name);
728 gtk_container_set_border_width(GTK_CONTAINER(pageframe), 4);
729 gtk_widget_show(pageframe);
731 GtkWidget* vbox = gtk_vbox_new(FALSE, 4);
732 gtk_widget_show(vbox);
733 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
734 gtk_container_add(GTK_CONTAINER(pageframe), vbox);
736 // Add the page to the notebook
737 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel);
742 class PreferenceTreeGroup : public PreferenceGroup
745 GtkWidget* m_notebook;
746 GtkTreeStore* m_store;
749 PreferenceTreeGroup(Dialog& dialog, GtkWidget* notebook, GtkTreeStore* store, GtkTreeIter group) :
751 m_notebook(notebook),
756 PreferencesPage createPage(const char* treeName, const char* frameName)
758 GtkWidget* page = PreferencePages_addPage(m_notebook, frameName);
759 PreferenceTree_appendPage(m_store, &m_group, treeName, page);
760 return PreferencesPage(m_dialog, getVBox(page));
764 GtkWindow* PrefsDlg::BuildDialog()
766 PreferencesDialog_addInterfacePreferences(FreeCaller1<PreferencesPage&, Interface_constructPreferences>());
767 Mouse_registerPreferencesPage();
769 GtkWindow* dialog = create_floating_window("NetRadiant Preferences", m_parent);
772 GtkWidget* mainvbox = gtk_vbox_new(FALSE, 5);
773 gtk_container_add(GTK_CONTAINER(dialog), mainvbox);
774 gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5);
775 gtk_widget_show(mainvbox);
778 GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
779 gtk_widget_show(hbox);
780 gtk_box_pack_end(GTK_BOX(mainvbox), hbox, FALSE, TRUE, 0);
783 GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &m_modal);
784 gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
787 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &m_modal);
788 gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
791 GtkButton* button = create_dialog_button("Clean", G_CALLBACK(OnButtonClean), this);
792 gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
797 GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
798 gtk_box_pack_start(GTK_BOX(mainvbox), hbox, TRUE, TRUE, 0);
799 gtk_widget_show(hbox);
802 GtkWidget* sc_win = gtk_scrolled_window_new(0, 0);
803 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
804 gtk_box_pack_start(GTK_BOX(hbox), sc_win, FALSE, FALSE, 0);
805 gtk_widget_show(sc_win);
806 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN);
808 // prefs pages notebook
809 m_notebook = gtk_notebook_new();
810 // hide the notebook tabs since its not supposed to look like a notebook
811 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_notebook), FALSE);
812 gtk_box_pack_start(GTK_BOX(hbox), m_notebook, TRUE, TRUE, 0);
813 gtk_widget_show(m_notebook);
817 GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
819 GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
820 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
823 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
824 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Preferences", renderer, "text", 0, NULL);
825 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
829 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
830 g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(treeSelection), this);
833 gtk_widget_show(view);
835 gtk_container_add(GTK_CONTAINER (sc_win), view);
838 /********************************************************************/
839 /* Add preference tree options */
840 /********************************************************************/
843 PreferencePages_addPage(m_notebook, "Front Page");
846 GtkWidget* global = PreferencePages_addPage(m_notebook, "Global Preferences");
848 PreferencesPage preferencesPage(*this, getVBox(global));
849 Global_constructPreferences(preferencesPage);
851 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Global", global);
853 GtkWidget* game = PreferencePages_addPage(m_notebook, "Game");
854 PreferencesPage preferencesPage(*this, getVBox(game));
855 g_GamesDialog.CreateGlobalFrame(preferencesPage);
857 PreferenceTree_appendPage(store, &group, "Game", game);
862 GtkWidget* interfacePage = PreferencePages_addPage(m_notebook, "Interface Preferences");
864 PreferencesPage preferencesPage(*this, getVBox(interfacePage));
865 PreferencesPageCallbacks_constructPage(g_interfacePreferences, preferencesPage);
868 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Interface", interfacePage);
869 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
871 PreferenceGroupCallbacks_constructGroup(g_interfaceCallbacks, preferenceGroup);
875 GtkWidget* display = PreferencePages_addPage(m_notebook, "Display Preferences");
877 PreferencesPage preferencesPage(*this, getVBox(display));
878 PreferencesPageCallbacks_constructPage(g_displayPreferences, preferencesPage);
880 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Display", display);
881 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
883 PreferenceGroupCallbacks_constructGroup(g_displayCallbacks, preferenceGroup);
887 GtkWidget* settings = PreferencePages_addPage(m_notebook, "General Settings");
889 PreferencesPage preferencesPage(*this, getVBox(settings));
890 PreferencesPageCallbacks_constructPage(g_settingsPreferences, preferencesPage);
893 GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Settings", settings);
894 PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
896 PreferenceGroupCallbacks_constructGroup(g_settingsCallbacks, preferenceGroup);
900 gtk_tree_view_expand_all(GTK_TREE_VIEW(view));
902 g_object_unref(G_OBJECT(store));
908 gtk_notebook_set_page(GTK_NOTEBOOK(m_notebook), 0);
913 preferences_globals_t g_preferences_globals;
915 PrefsDlg g_Preferences; // global prefs instance
918 void PreferencesDialog_constructWindow(GtkWindow* main_window)
920 g_Preferences.m_parent = main_window;
921 g_Preferences.Create();
923 void PreferencesDialog_destroyWindow()
925 g_Preferences.Destroy();
929 PreferenceDictionary g_preferences;
931 PreferenceSystem& GetPreferenceSystem()
933 return g_preferences;
936 class PreferenceSystemAPI
938 PreferenceSystem* m_preferencesystem;
940 typedef PreferenceSystem Type;
941 STRING_CONSTANT(Name, "*");
943 PreferenceSystemAPI()
945 m_preferencesystem = &GetPreferenceSystem();
947 PreferenceSystem* getTable()
949 return m_preferencesystem;
953 #include "modulesystem/singletonmodule.h"
954 #include "modulesystem/moduleregistry.h"
956 typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
957 typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
958 StaticRegisterModule staticRegisterPreferenceSystem(StaticPreferenceSystemModule::instance());
960 void Preferences_Load()
962 g_GamesDialog.LoadPrefs();
964 globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
966 if(!Preferences_Load(g_preferences, g_Preferences.m_inipath->str, g_GamesDialog.m_sGameFile.c_str()))
968 globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
972 void Preferences_Save()
974 if (g_preferences_globals.disable_ini)
977 g_GamesDialog.SavePrefs();
979 globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
981 if(!Preferences_Save_Safe(g_preferences, g_Preferences.m_inipath->str))
983 globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
987 void Preferences_Reset()
989 file_remove(g_Preferences.m_inipath->str);
993 void PrefsDlg::PostModal (EMessageBoxReturn code)
1002 std::vector<const char*> g_restart_required;
1004 void PreferencesDialog_restartRequired(const char* staticName)
1006 g_restart_required.push_back(staticName);
1009 void PreferencesDialog_showDialog()
1011 if(ConfirmModified("Edit Preferences") && g_Preferences.DoModal() == eIDOK)
1013 if(!g_restart_required.empty())
1015 StringOutputStream message(256);
1016 message << "Preference changes require a restart:\n";
1017 for(std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i)
1019 message << (*i) << '\n';
1021 gtk_MessageBox(GTK_WIDGET(MainFrame_getWindow()), message.c_str());
1022 g_restart_required.clear();
1031 void GameName_importString(const char* value)
1033 gamename_set(value);
1035 typedef FreeCaller1<const char*, GameName_importString> GameNameImportStringCaller;
1036 void GameName_exportString(const StringImportCallback& importer)
1038 importer(gamename_get());
1040 typedef FreeCaller1<const StringImportCallback&, GameName_exportString> GameNameExportStringCaller;
1042 void GameMode_importString(const char* value)
1044 gamemode_set(value);
1046 typedef FreeCaller1<const char*, GameMode_importString> GameModeImportStringCaller;
1047 void GameMode_exportString(const StringImportCallback& importer)
1049 importer(gamemode_get());
1051 typedef FreeCaller1<const StringImportCallback&, GameMode_exportString> GameModeExportStringCaller;
1054 void RegisterPreferences(PreferenceSystem& preferences)
1057 preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useWin32Editor), BoolExportStringCaller(g_TextEditor_useWin32Editor));
1059 preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useCustomEditor), BoolExportStringCaller(g_TextEditor_useCustomEditor));
1060 preferences.registerPreference("CustomShaderEditorCommand", CopiedStringImportStringCaller(g_TextEditor_editorCommand), CopiedStringExportStringCaller(g_TextEditor_editorCommand));
1063 preferences.registerPreference("GameName", GameNameImportStringCaller(), GameNameExportStringCaller());
1064 preferences.registerPreference("GameMode", GameModeImportStringCaller(), GameModeExportStringCaller());
1067 void Preferences_Init()
1069 RegisterPreferences(GetPreferenceSystem());