gtkradiant/radiant/preferences.cpp

1056 lines
31 KiB
C++

/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
//
// User preferences
//
// Leonardo Zide (leo@lokigames.com)
//
#include "preferences.h"
#include "debugging/debugging.h"
#include <gtk/gtkmain.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkframe.h>
#include <gtk/gtklabel.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtkspinbutton.h>
#include <gtk/gtkscrolledwindow.h>
#include <gtk/gtktreemodel.h>
#include <gtk/gtktreeview.h>
#include <gtk/gtktreestore.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtknotebook.h>
#include "generic/callback.h"
#include "math/vector.h"
#include "string/string.h"
#include "stream/stringstream.h"
#include "os/file.h"
#include "os/path.h"
#include "os/dir.h"
#include "gtkutil/filechooser.h"
#include "gtkutil/messagebox.h"
#include "cmdlib.h"
#include "error.h"
#include "console.h"
#include "xywindow.h"
#include "mainframe.h"
#include "qe3.h"
#include "gtkdlgs.h"
void Global_constructPreferences(PreferencesPage& page)
{
page.appendCheckBox("Console", "Enable Logging", g_Console_enableLogging);
}
void Interface_constructPreferences(PreferencesPage& page)
{
#ifdef WIN32
page.appendCheckBox("", "Default Text Editor", g_TextEditor_useWin32Editor);
#else
{
GtkWidget* use_custom = page.appendCheckBox("Text Editor", "Custom", g_TextEditor_useCustomEditor);
GtkWidget* custom_editor = page.appendPathEntry("Text Editor Command", g_TextEditor_editorCommand, true);
Widget_connectToggleDependency(custom_editor, use_custom);
}
#endif
}
void Mouse_constructPreferences(PreferencesPage& page)
{
{
const char* buttons[] = { "2 button", "3 button", };
page.appendRadio("Mouse Type", g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE(buttons));
}
page.appendCheckBox("Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick);
}
void Mouse_constructPage(PreferenceGroup& group)
{
PreferencesPage page(group.createPage("Mouse", "Mouse Preferences"));
Mouse_constructPreferences(page);
}
void Mouse_registerPreferencesPage()
{
PreferencesDialog_addInterfacePage(FreeCaller1<PreferenceGroup&, Mouse_constructPage>());
}
/*!
=========================================================
Games selection dialog
=========================================================
*/
#include <map>
inline const char* xmlAttr_getName(xmlAttrPtr attr)
{
return reinterpret_cast<const char*>(attr->name);
}
inline const char* xmlAttr_getValue(xmlAttrPtr attr)
{
return reinterpret_cast<const char*>(attr->children->content);
}
CGameDescription::CGameDescription(xmlDocPtr pDoc, const CopiedString& gameFile)
{
// read the user-friendly game name
xmlNodePtr pNode = pDoc->children;
while (strcmp((const char*)pNode->name, "game") && pNode != 0)
{
pNode=pNode->next;
}
if (!pNode)
{
Error("Didn't find 'game' node in the game description file '%s'\n", pDoc->URL);
}
for(xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next)
{
m_gameDescription.insert(GameDescription::value_type(xmlAttr_getName(attr), xmlAttr_getValue(attr)));
}
{
StringOutputStream path(256);
path << AppPath_get() << gameFile.c_str() << "/";
mGameToolsPath = path.c_str();
}
ASSERT_MESSAGE(file_exists(mGameToolsPath.c_str()), "game directory not found: " << makeQuoted(mGameToolsPath.c_str()));
mGameFile = gameFile;
{
GameDescription::iterator i = m_gameDescription.find("type");
if(i == m_gameDescription.end())
{
globalErrorStream() << "Warning, 'type' attribute not found in '" << reinterpret_cast<const char*>(pDoc->URL) << "'\n";
// default
mGameType = "q3";
}
else
{
mGameType = (*i).second.c_str();
}
}
}
void CGameDescription::Dump()
{
globalOutputStream() << "game description file: " << makeQuoted(mGameFile.c_str()) << "\n";
for(GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i)
{
globalOutputStream() << (*i).first.c_str() << " = " << makeQuoted((*i).second.c_str()) << "\n";
}
}
CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentDescription
#include "warnings.h"
#include "stream/textfilestream.h"
#include "container/array.h"
#include "xml/ixml.h"
#include "xml/xmlparser.h"
#include "xml/xmlwriter.h"
#include "preferencedictionary.h"
#include "stringio.h"
const char* const PREFERENCES_VERSION = "1.0";
bool Preferences_Load(PreferenceDictionary& preferences, const char* filename)
{
TextFileInputStream file(filename);
if(!file.failed())
{
XMLStreamParser parser(file);
XMLPreferenceDictionaryImporter importer(preferences, PREFERENCES_VERSION);
parser.exportXML(importer);
return true;
}
return false;
}
bool Preferences_Save(PreferenceDictionary& preferences, const char* filename)
{
TextFileOutputStream file(filename);
if(!file.failed())
{
XMLStreamWriter writer(file);
XMLPreferenceDictionaryExporter exporter(preferences, PREFERENCES_VERSION);
exporter.exportXML(writer);
return true;
}
return false;
}
bool Preferences_Save_Safe(PreferenceDictionary& preferences, const char* filename)
{
Array<char> tmpName(filename, filename + strlen(filename) + 1 + 3);
*(tmpName.end() - 4) = 'T';
*(tmpName.end() - 3) = 'M';
*(tmpName.end() - 2) = 'P';
*(tmpName.end() - 1) = '\0';
return Preferences_Save(preferences, tmpName.data())
&& (!file_exists(filename) || file_remove(filename))
&& file_move(tmpName.data(), filename);
}
void LogConsole_importString(const char* string)
{
g_Console_enableLogging = string_equal(string, "true");
Sys_LogFile(g_Console_enableLogging);
}
typedef FreeCaller1<const char*, LogConsole_importString> LogConsoleImportStringCaller;
void RegisterGlobalPreferences(PreferenceSystem& preferences)
{
preferences.registerPreference("gamefile", CopiedStringImportStringCaller(g_GamesDialog.m_sGameFile), CopiedStringExportStringCaller(g_GamesDialog.m_sGameFile));
preferences.registerPreference("gamePrompt", BoolImportStringCaller(g_GamesDialog.m_bGamePrompt), BoolExportStringCaller(g_GamesDialog.m_bGamePrompt));
preferences.registerPreference("log console", LogConsoleImportStringCaller(), BoolExportStringCaller(g_Console_enableLogging));
}
PreferenceDictionary g_global_preferences;
void GlobalPreferences_Init()
{
RegisterGlobalPreferences(g_global_preferences);
}
void CGameDialog::LoadPrefs()
{
// load global .pref file
StringOutputStream strGlobalPref(256);
strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
globalOutputStream() << "loading global preferences from " << makeQuoted(strGlobalPref.c_str()) << "\n";
if(!Preferences_Load(g_global_preferences, strGlobalPref.c_str()))
{
globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
}
}
void CGameDialog::SavePrefs()
{
StringOutputStream strGlobalPref(256);
strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
if(!Preferences_Save_Safe(g_global_preferences, strGlobalPref.c_str()))
{
globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
}
}
void CGameDialog::DoGameDialog()
{
// show the UI
DoModal();
// we save the prefs file
SavePrefs();
}
void CGameDialog::GameFileImport(int value)
{
m_nComboSelect = value;
// use value to set m_sGameFile
std::list<CGameDescription *>::iterator iGame = mGames.begin();
int i;
for(i=0; i<value; i++)
{
++iGame;
}
m_sGameFile = (*iGame)->mGameFile;
}
void CGameDialog::GameFileExport(const IntImportCallback& importCallback) const
{
// use m_sGameFile to set value
std::list<CGameDescription *>::const_iterator iGame;
int i = 0;
for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
{
if ((*iGame)->mGameFile == m_sGameFile)
{
m_nComboSelect = i;
break;
}
i++;
}
importCallback(m_nComboSelect);
}
void CGameDialog_GameFileImport(CGameDialog& self, int value)
{
self.GameFileImport(value);
}
void CGameDialog_GameFileExport(CGameDialog& self, const IntImportCallback& importCallback)
{
self.GameFileExport(importCallback);
}
void CGameDialog::CreateGlobalFrame(PreferencesPage& page)
{
std::vector<const char*> games;
games.reserve(mGames.size());
for(std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i)
{
games.push_back((*i)->getRequiredKeyValue("name"));
}
page.appendCombo(
"Select the game",
StringArrayRange(&(*games.begin()), &(*games.end())),
ReferenceCaller1<CGameDialog, int, CGameDialog_GameFileImport>(*this),
ReferenceCaller1<CGameDialog, const IntImportCallback&, CGameDialog_GameFileExport>(*this)
);
page.appendCheckBox("Startup", "Show Global Preferences", m_bGamePrompt);
}
GtkWindow* CGameDialog::BuildDialog()
{
GtkFrame* frame = create_dialog_frame("Game settings", GTK_SHADOW_ETCHED_IN);
GtkVBox* vbox2 = create_dialog_vbox(0, 4);
gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox2));
{
PreferencesPage preferencesPage(*this, GTK_WIDGET(vbox2));
Global_constructPreferences(preferencesPage);
CreateGlobalFrame(preferencesPage);
}
return create_simple_modal_dialog_window("Global Preferences", m_modal, GTK_WIDGET(frame));
}
class LoadGameFile
{
std::list<CGameDescription*>& mGames;
const char* mPath;
public:
LoadGameFile(std::list<CGameDescription*>& games, const char* path) : mGames(games), mPath(path)
{
}
void operator()(const char* name) const
{
if(!extension_equal(path_get_extension(name), "game"))
{
return;
}
StringOutputStream strPath(256);
strPath << mPath << name;
globalOutputStream() << strPath.c_str() << '\n';
xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
if(pDoc)
{
mGames.push_front(new CGameDescription(pDoc, name));
xmlFreeDoc(pDoc);
}
else
{
globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
}
}
};
void CGameDialog::ScanForGames()
{
StringOutputStream strGamesPath(256);
strGamesPath << AppPath_get() << "games/";
const char *path = strGamesPath.c_str();
globalOutputStream() << "Scanning for game description files: " << path << '\n';
/*!
\todo FIXME LINUX:
do we put game description files below AppPath, or in ~/.radiant
i.e. read only or read/write?
my guess .. readonly cause it's an install
we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
(if that's really needed)
*/
Directory_forEach(path, LoadGameFile(mGames, path));
}
CGameDescription* CGameDialog::GameDescriptionForComboItem()
{
std::list<CGameDescription *>::iterator iGame;
int i=0;
for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame,i++)
{
if (i == m_nComboSelect)
{
return (*iGame);
}
}
return 0; // not found
}
void CGameDialog::InitGlobalPrefPath()
{
g_Preferences.m_global_rc_path = g_string_new(SettingsPath_get());
}
void CGameDialog::Reset()
{
if (!g_Preferences.m_global_rc_path)
InitGlobalPrefPath();
StringOutputStream strGlobalPref(256);
strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
file_remove(strGlobalPref.c_str());
}
void CGameDialog::Init()
{
InitGlobalPrefPath();
LoadPrefs();
ScanForGames();
if (mGames.empty())
{
Error("Didn't find any valid game file descriptions, aborting\n");
}
CGameDescription* currentGameDescription = 0;
if (!m_bGamePrompt)
{
// search by .game name
std::list<CGameDescription *>::iterator iGame;
for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
{
if ((*iGame)->mGameFile == m_sGameFile)
{
currentGameDescription = (*iGame);
break;
}
}
}
if (m_bGamePrompt || !currentGameDescription)
{
Create();
DoGameDialog();
// use m_nComboSelect to identify the game to run as and set the globals
currentGameDescription = GameDescriptionForComboItem();
ASSERT_NOTNULL(currentGameDescription);
}
g_pGameDescription = currentGameDescription;
g_pGameDescription->Dump();
}
CGameDialog::~CGameDialog()
{
// free all the game descriptions
std::list<CGameDescription *>::iterator iGame;
for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
{
delete (*iGame);
*iGame = 0;
}
if(GetWidget() != 0)
{
Destroy();
}
}
inline const char* GameDescription_getIdentifier(const CGameDescription& gameDescription)
{
const char* identifier = gameDescription.getKeyValue("index");
if(string_empty(identifier))
{
identifier = "1";
}
return identifier;
}
void CGameDialog::AddPacksURL(StringOutputStream &URL)
{
// add the URLs for the list of game packs installed
// FIXME: this is kinda hardcoded for now..
std::list<CGameDescription *>::iterator iGame;
for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
{
URL << "&Games_dlup%5B%5D=" << GameDescription_getIdentifier(*(*iGame));
}
}
CGameDialog g_GamesDialog;
// =============================================================================
// Widget callbacks for PrefsDlg
static void OnButtonClean (GtkWidget *widget, gpointer data)
{
// make sure this is what the user wants
if (gtk_MessageBox(GTK_WIDGET(g_Preferences.GetWidget()), "This will close Radiant and clean the corresponding registry entries.\n"
"Next time you start Radiant it will be good as new. Do you wish to continue?",
"Reset Registry", eMB_YESNO, eMB_ICONASTERISK) == eIDYES)
{
PrefsDlg *dlg = (PrefsDlg*)data;
dlg->EndModal (eIDCANCEL);
g_preferences_globals.disable_ini = true;
Preferences_Reset();
gtk_main_quit();
}
}
// =============================================================================
// PrefsDlg class
/*
========
very first prefs init deals with selecting the game and the game tools path
then we can load .ini stuff
using prefs / ini settings:
those are per-game
look in ~/.radiant/<version>/gamename
========
*/
#define PREFS_LOCAL_FILENAME "local.pref"
void PrefsDlg::Init()
{
// m_global_rc_path has been set above
// m_rc_path is for game specific preferences
// takes the form: global-pref-path/gamename/prefs-file
// this is common to win32 and Linux init now
m_rc_path = g_string_new (m_global_rc_path->str);
// game sub-dir
g_string_append (m_rc_path, g_pGameDescription->mGameFile.c_str());
g_string_append (m_rc_path, "/");
Q_mkdir (m_rc_path->str);
// then the ini file
m_inipath = g_string_new (m_rc_path->str);
g_string_append (m_inipath, PREFS_LOCAL_FILENAME);
}
void notebook_set_page(GtkWidget* notebook, GtkWidget* page)
{
int pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), page);
if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != pagenum)
{
gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), pagenum);
}
}
void PrefsDlg::showPrefPage(GtkWidget* prefpage)
{
notebook_set_page(m_notebook, prefpage);
return;
}
static void treeSelection(GtkTreeSelection* selection, gpointer data)
{
PrefsDlg *dlg = (PrefsDlg*)data;
GtkTreeModel* model;
GtkTreeIter selected;
if(gtk_tree_selection_get_selected(selection, &model, &selected))
{
GtkWidget* prefpage;
gtk_tree_model_get(model, &selected, 1, (gpointer*)&prefpage, -1);
dlg->showPrefPage(prefpage);
}
}
typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
inline void PreferenceGroupCallbacks_constructGroup(const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group)
{
for(PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
{
(*i)(group);
}
}
inline void PreferenceGroupCallbacks_pushBack(PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback)
{
callbacks.push_back(callback);
}
typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
inline void PreferencesPageCallbacks_constructPage(const PreferencesPageCallbacks& callbacks, PreferencesPage& page)
{
for(PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
{
(*i)(page);
}
}
inline void PreferencesPageCallbacks_pushBack(PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback)
{
callbacks.push_back(callback);
}
PreferencesPageCallbacks g_interfacePreferences;
void PreferencesDialog_addInterfacePreferences(const PreferencesPageCallback& callback)
{
PreferencesPageCallbacks_pushBack(g_interfacePreferences, callback);
}
PreferenceGroupCallbacks g_interfaceCallbacks;
void PreferencesDialog_addInterfacePage(const PreferenceGroupCallback& callback)
{
PreferenceGroupCallbacks_pushBack(g_interfaceCallbacks, callback);
}
PreferencesPageCallbacks g_displayPreferences;
void PreferencesDialog_addDisplayPreferences(const PreferencesPageCallback& callback)
{
PreferencesPageCallbacks_pushBack(g_displayPreferences, callback);
}
PreferenceGroupCallbacks g_displayCallbacks;
void PreferencesDialog_addDisplayPage(const PreferenceGroupCallback& callback)
{
PreferenceGroupCallbacks_pushBack(g_displayCallbacks, callback);
}
PreferencesPageCallbacks g_settingsPreferences;
void PreferencesDialog_addSettingsPreferences(const PreferencesPageCallback& callback)
{
PreferencesPageCallbacks_pushBack(g_settingsPreferences, callback);
}
PreferenceGroupCallbacks g_settingsCallbacks;
void PreferencesDialog_addSettingsPage(const PreferenceGroupCallback& callback)
{
PreferenceGroupCallbacks_pushBack(g_settingsCallbacks, callback);
}
void Widget_updateDependency(GtkWidget* self, GtkWidget* toggleButton)
{
gtk_widget_set_sensitive(self, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggleButton)) && GTK_WIDGET_IS_SENSITIVE(toggleButton));
}
void ToggleButton_toggled_Widget_updateDependency(GtkWidget *toggleButton, GtkWidget* self)
{
Widget_updateDependency(self, toggleButton);
}
void ToggleButton_state_changed_Widget_updateDependency(GtkWidget* toggleButton, GtkStateType state, GtkWidget* self)
{
if(state == GTK_STATE_INSENSITIVE)
{
Widget_updateDependency(self, toggleButton);
}
}
void Widget_connectToggleDependency(GtkWidget* self, GtkWidget* toggleButton)
{
g_signal_connect(G_OBJECT(toggleButton), "state_changed", G_CALLBACK(ToggleButton_state_changed_Widget_updateDependency), self);
g_signal_connect(G_OBJECT(toggleButton), "toggled", G_CALLBACK(ToggleButton_toggled_Widget_updateDependency), self);
Widget_updateDependency(self, toggleButton);
}
inline GtkWidget* getVBox(GtkWidget* page)
{
return gtk_bin_get_child(GTK_BIN(page));
}
GtkTreeIter PreferenceTree_appendPage(GtkTreeStore* store, GtkTreeIter* parent, const char* name, GtkWidget* page)
{
GtkTreeIter group;
gtk_tree_store_append(store, &group, parent);
gtk_tree_store_set(store, &group, 0, name, 1, page, -1);
return group;
}
GtkWidget* PreferencePages_addPage(GtkWidget* notebook, const char* name)
{
GtkWidget* preflabel = gtk_label_new(name);
gtk_widget_show(preflabel);
GtkWidget* pageframe = gtk_frame_new(name);
gtk_container_set_border_width(GTK_CONTAINER(pageframe), 4);
gtk_widget_show(pageframe);
GtkWidget* vbox = gtk_vbox_new(FALSE, 4);
gtk_widget_show(vbox);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
gtk_container_add(GTK_CONTAINER(pageframe), vbox);
// Add the page to the notebook
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel);
return pageframe;
}
class PreferenceTreeGroup : public PreferenceGroup
{
Dialog& m_dialog;
GtkWidget* m_notebook;
GtkTreeStore* m_store;
GtkTreeIter m_group;
public:
PreferenceTreeGroup(Dialog& dialog, GtkWidget* notebook, GtkTreeStore* store, GtkTreeIter group) :
m_dialog(dialog),
m_notebook(notebook),
m_store(store),
m_group(group)
{
}
PreferencesPage createPage(const char* treeName, const char* frameName)
{
GtkWidget* page = PreferencePages_addPage(m_notebook, frameName);
PreferenceTree_appendPage(m_store, &m_group, treeName, page);
return PreferencesPage(m_dialog, getVBox(page));
}
};
GtkWindow* PrefsDlg::BuildDialog()
{
PreferencesDialog_addInterfacePreferences(FreeCaller1<PreferencesPage&, Interface_constructPreferences>());
Mouse_registerPreferencesPage();
GtkWindow* dialog = create_floating_window("GtkRadiant Preferences", m_parent);
{
GtkWidget* mainvbox = gtk_vbox_new(FALSE, 5);
gtk_container_add(GTK_CONTAINER(dialog), mainvbox);
gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5);
gtk_widget_show(mainvbox);
{
GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
gtk_widget_show(hbox);
gtk_box_pack_end(GTK_BOX(mainvbox), hbox, FALSE, TRUE, 0);
{
GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &m_modal);
gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
}
{
GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &m_modal);
gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
}
{
GtkButton* button = create_dialog_button("Clean", G_CALLBACK(OnButtonClean), this);
gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
}
}
{
GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
gtk_box_pack_start(GTK_BOX(mainvbox), hbox, TRUE, TRUE, 0);
gtk_widget_show(hbox);
{
GtkWidget* sc_win = gtk_scrolled_window_new(0, 0);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_box_pack_start(GTK_BOX(hbox), sc_win, FALSE, FALSE, 0);
gtk_widget_show(sc_win);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN);
// prefs pages notebook
m_notebook = gtk_notebook_new();
// hide the notebook tabs since its not supposed to look like a notebook
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_notebook), FALSE);
gtk_box_pack_start(GTK_BOX(hbox), m_notebook, TRUE, TRUE, 0);
gtk_widget_show(m_notebook);
{
GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
{
GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Preferences", renderer, "text", 0, 0);
gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
}
{
GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(treeSelection), this);
}
gtk_widget_show(view);
gtk_container_add(GTK_CONTAINER (sc_win), view);
{
/********************************************************************/
/* Add preference tree options */
/********************************************************************/
// Front page...
//GtkWidget* front =
PreferencePages_addPage(m_notebook, "Front Page");
{
GtkWidget* global = PreferencePages_addPage(m_notebook, "Global Preferences");
{
PreferencesPage preferencesPage(*this, getVBox(global));
Global_constructPreferences(preferencesPage);
}
GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Global", global);
{
GtkWidget* game = PreferencePages_addPage(m_notebook, "Game");
PreferencesPage preferencesPage(*this, getVBox(game));
g_GamesDialog.CreateGlobalFrame(preferencesPage);
PreferenceTree_appendPage(store, &group, "Game", game);
}
}
{
GtkWidget* interfacePage = PreferencePages_addPage(m_notebook, "Interface Preferences");
{
PreferencesPage preferencesPage(*this, getVBox(interfacePage));
PreferencesPageCallbacks_constructPage(g_interfacePreferences, preferencesPage);
}
GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Interface", interfacePage);
PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
PreferenceGroupCallbacks_constructGroup(g_interfaceCallbacks, preferenceGroup);
}
{
GtkWidget* display = PreferencePages_addPage(m_notebook, "Display Preferences");
{
PreferencesPage preferencesPage(*this, getVBox(display));
PreferencesPageCallbacks_constructPage(g_displayPreferences, preferencesPage);
}
GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Display", display);
PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
PreferenceGroupCallbacks_constructGroup(g_displayCallbacks, preferenceGroup);
}
{
GtkWidget* settings = PreferencePages_addPage(m_notebook, "General Settings");
{
PreferencesPage preferencesPage(*this, getVBox(settings));
PreferencesPageCallbacks_constructPage(g_settingsPreferences, preferencesPage);
}
GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Settings", settings);
PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
PreferenceGroupCallbacks_constructGroup(g_settingsCallbacks, preferenceGroup);
}
}
gtk_tree_view_expand_all(GTK_TREE_VIEW(view));
g_object_unref(G_OBJECT(store));
}
}
}
}
gtk_notebook_set_page(GTK_NOTEBOOK(m_notebook), 0);
return dialog;
}
preferences_globals_t g_preferences_globals;
PrefsDlg g_Preferences; // global prefs instance
void PreferencesDialog_constructWindow(GtkWindow* main_window)
{
g_Preferences.m_parent = main_window;
g_Preferences.Create();
}
void PreferencesDialog_destroyWindow()
{
g_Preferences.Destroy();
}
PreferenceDictionary g_preferences;
PreferenceSystem& GetPreferenceSystem()
{
return g_preferences;
}
class PreferenceSystemAPI
{
PreferenceSystem* m_preferencesystem;
public:
typedef PreferenceSystem Type;
STRING_CONSTANT(Name, "*");
PreferenceSystemAPI()
{
m_preferencesystem = &GetPreferenceSystem();
}
PreferenceSystem* getTable()
{
return m_preferencesystem;
}
};
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
StaticRegisterModule staticRegisterPreferenceSystem(StaticPreferenceSystemModule::instance());
void Preferences_Load()
{
g_GamesDialog.LoadPrefs();
globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
if(!Preferences_Load(g_preferences, g_Preferences.m_inipath->str))
{
globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
}
}
void Preferences_Save()
{
if (g_preferences_globals.disable_ini)
return;
g_GamesDialog.SavePrefs();
globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
if(!Preferences_Save_Safe(g_preferences, g_Preferences.m_inipath->str))
{
globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
}
}
void Preferences_Reset()
{
file_remove(g_Preferences.m_inipath->str);
}
void PrefsDlg::PostModal (EMessageBoxReturn code)
{
if (code == eIDOK)
{
Preferences_Save();
UpdateAllWindows();
}
}
std::vector<const char*> g_restart_required;
void PreferencesDialog_restartRequired(const char* staticName)
{
g_restart_required.push_back(staticName);
}
void PreferencesDialog_showDialog()
{
if(ConfirmModified("Edit Preferences") && g_Preferences.DoModal() == eIDOK)
{
if(!g_restart_required.empty())
{
StringOutputStream message(256);
message << "Preference changes require a restart:\n";
for(std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i)
{
message << (*i) << '\n';
}
gtk_MessageBox(GTK_WIDGET(MainFrame_getWindow()), message.c_str());
g_restart_required.clear();
}
}
}
void GameName_importString(const char* value)
{
gamename_set(value);
}
typedef FreeCaller1<const char*, GameName_importString> GameNameImportStringCaller;
void GameName_exportString(const StringImportCallback& importer)
{
importer(gamename_get());
}
typedef FreeCaller1<const StringImportCallback&, GameName_exportString> GameNameExportStringCaller;
void GameMode_importString(const char* value)
{
gamemode_set(value);
}
typedef FreeCaller1<const char*, GameMode_importString> GameModeImportStringCaller;
void GameMode_exportString(const StringImportCallback& importer)
{
importer(gamemode_get());
}
typedef FreeCaller1<const StringImportCallback&, GameMode_exportString> GameModeExportStringCaller;
void RegisterPreferences(PreferenceSystem& preferences)
{
#ifdef WIN32
preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useWin32Editor), BoolExportStringCaller(g_TextEditor_useWin32Editor));
#else
preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useCustomEditor), BoolExportStringCaller(g_TextEditor_useCustomEditor));
preferences.registerPreference("CustomShaderEditorCommand", CopiedStringImportStringCaller(g_TextEditor_editorCommand), CopiedStringExportStringCaller(g_TextEditor_editorCommand));
#endif
preferences.registerPreference("GameName", GameNameImportStringCaller(), GameNameExportStringCaller());
preferences.registerPreference("GameMode", GameModeImportStringCaller(), GameModeExportStringCaller());
}
void Preferences_Init()
{
RegisterPreferences(GetPreferenceSystem());
}