Index: llvfs/lldir.cpp =================================================================== --- llvfs/lldir.cpp (revision 493) +++ llvfs/lldir.cpp (working copy) @@ -337,6 +337,12 @@ prefix += mDirDelimiter; prefix += "browser_profile"; break; + + case LL_PATH_THEMES: + prefix = getAppRODataDir(); + prefix += mDirDelimiter; + prefix += "themes"; + break; default: llassert(0); Index: llvfs/lldir.h =================================================================== --- llvfs/lldir.h (revision 493) +++ llvfs/lldir.h (working copy) @@ -50,7 +50,8 @@ LL_PATH_PER_ACCOUNT_CHAT_LOGS = 13, LL_PATH_MOZILLA_PROFILE = 14, LL_PATH_HTML = 15, - LL_PATH_COUNT = 16 + LL_PATH_THEMES = 16, + LL_PATH_COUNT = 17 } ELLPath; Index: newview/app_settings/settings.xml =================================================================== --- newview/app_settings/settings.xml (revision 493) +++ newview/app_settings/settings.xml (working copy) @@ -1467,6 +1467,17 @@ 1 + ColorTheme + + Comment + Color theme + Persist + 1 + Type + String + Value + Dazzle + ColumnHeaderDropDownDelay Comment Index: newview/llappviewer.cpp =================================================================== --- newview/llappviewer.cpp (revision 493) +++ newview/llappviewer.cpp (working copy) @@ -685,7 +685,14 @@ gColors.loadFromFileLegacy(colors_base_filename.c_str(), FALSE, TYPE_COL4U); // Load overrides from user colors file - LLString user_colors_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "colors.xml"); + gColorTheme = gSavedSettings.getString("ColorTheme"); + std::string delem = gDirUtilp->getDirDelimiter(); + LLString user_colors_filename = gDirUtilp->getExpandedFilename(LL_PATH_THEMES, gColorTheme + delem + "colors.xml"); + if (!gDirUtilp->fileExists(user_colors_filename)) { + user_colors_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "colors.xml"); + } + + llinfos << "Loading user colors from " << user_colors_filename << llendl; if (gColors.loadFromFileLegacy(user_colors_filename.c_str(), FALSE, TYPE_COL4U) == 0) { Index: newview/llfloaterpreference.cpp =================================================================== --- newview/llfloaterpreference.cpp (revision 493) +++ newview/llfloaterpreference.cpp (working copy) @@ -55,6 +55,7 @@ #include "llpaneldisplay.h" #include "llpaneldebug.h" #include "llpanelgeneral.h" +#include "llpanelskins.h" #include "llpanelinput.h" #include "llpanellogin.h" #include "llpanelLCD.h" @@ -131,6 +132,7 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * default_btn) : mTabContainer(tab_container), mGeneralPanel(NULL), + mSkinsPanel(NULL), mInputPanel(NULL), mNetworkPanel(NULL), mDisplayPanel(NULL), @@ -142,6 +144,10 @@ mTabContainer->addTabPanel(mGeneralPanel, mGeneralPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mGeneralPanel->setDefaultBtn(default_btn); + mSkinsPanel = new LLPanelSkins(); + mTabContainer->addTabPanel(mSkinsPanel, mSkinsPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mSkinsPanel->setDefaultBtn(default_btn); + mInputPanel = new LLPanelInput(); mTabContainer->addTabPanel(mInputPanel, mInputPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mInputPanel->setDefaultBtn(default_btn); @@ -205,6 +211,11 @@ delete mGeneralPanel; mGeneralPanel = NULL; } + if (mSkinsPanel) + { + delete mSkinsPanel; + mSkinsPanel = NULL; + } if (mInputPanel) { delete mInputPanel; @@ -252,6 +263,7 @@ void LLPreferenceCore::apply() { mGeneralPanel->apply(); + mSkinsPanel->apply(); mInputPanel->apply(); mNetworkPanel->apply(); mDisplayPanel->apply(); @@ -278,6 +290,7 @@ void LLPreferenceCore::cancel() { mGeneralPanel->cancel(); + mSkinsPanel->cancel(); mInputPanel->cancel(); mNetworkPanel->cancel(); mDisplayPanel->cancel(); Index: newview/llfloaterpreference.h =================================================================== --- newview/llfloaterpreference.h (revision 493) +++ newview/llfloaterpreference.h (working copy) @@ -42,6 +42,7 @@ #include "lltabcontainervertical.h" class LLPanelGeneral; +class LLPanelSkins; class LLPanelInput; class LLPanelLCD; class LLPanelDisplay; @@ -81,6 +82,7 @@ private: LLTabContainer *mTabContainer; LLPanelGeneral *mGeneralPanel; + LLPanelSkins *mSkinsPanel; LLPanelInput *mInputPanel; LLPanelNetwork *mNetworkPanel; LLPanelDisplay *mDisplayPanel; Index: newview/llpanelskins.cpp =================================================================== --- newview/llpanelskins.cpp (revision 0) +++ newview/llpanelskins.cpp (revision 0) @@ -0,0 +1,166 @@ +/** + * @file llpanellskins.cpp + * @brief skinning panel + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelskins.h" + +// linden library includes +#include "lluictrlfactory.h" +#include "llxmltree.h" +#include "llxmlnode.h" + +// project includes +#include "llviewerwindow.h" +#include "llcombobox.h" +#include "llviewercontrol.h" + +// +// Globals +// + +// +// Static functions +// + + +LLPanelSkins::LLPanelSkins() +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_skins.xml"); +} + +BOOL LLPanelSkins::postBuild() +{ + requires("ThemeCombobox"); + + if (!checkRequirements()) + { + return FALSE; + } + + childSetCommitCallback("ThemeCombobox", LLPanelSkins::ThemeComboboxChanged, this); + + refresh(); + + return TRUE; +} + + +LLPanelSkins::~LLPanelSkins() +{ + // Children all cleaned up by default view destructor. +} + +void LLPanelSkins::UpdateDesc(LLPanelSkins *panel, LLComboBox *combo) +{ + LLString selected = (LLString)combo->getValue(); + LLString empty = ""; + + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_THEMES, selected, "theme.xml"); + if (gDirUtilp->fileExists(filename)) { + LLXmlTree xml_controls; + + if (!xml_controls.parseFile(filename)) + { + llwarns << "Unable to open theme file " << filename << llendl; + panel->childSetText("ThemeDesc", empty); + panel->childSetText("ThemeAuthor", empty); + return; + } + + LLXmlTreeNode* rootp = xml_controls.getRoot(); + LLXmlTreeNode* descp = rootp->getChildByName("description"); + if (descp) { + panel->childSetText("ThemeDesc", descp->getContents()); + } else { + panel->childSetText("ThemeDesc", empty); + } + LLXmlTreeNode* authorp = rootp->getChildByName("author"); + if (authorp) { + panel->childSetText("ThemeAuthor", authorp->getContents()); + } else { + panel->childSetText("ThemeAuthor", empty); + } + } else { + panel->childSetText("ThemeDesc", empty); + panel->childSetText("ThemeAuthor", empty); + } +} + +void LLPanelSkins::ThemeComboboxChanged(LLUICtrl *ctrl, void *data) +{ + UpdateDesc((LLPanelSkins*)data, (LLComboBox*)ctrl); +} + +void LLPanelSkins::refresh() +{ + mThemeCombobox = gSavedSettings.getString("ColorTheme"); + + LLCtrlListInterface* listInterface = childGetListInterface("ThemeCombobox"); + + listInterface->clearRows(); + + std::string delem = gDirUtilp->getDirDelimiter(); + std::string path = gDirUtilp->getExpandedFilename(LL_PATH_THEMES, delem); + std::string subpath; + + while(gDirUtilp->getNextFileInDir(path, "*", subpath, FALSE)) { + if (gDirUtilp->fileExists(gDirUtilp->getExpandedFilename(LL_PATH_THEMES, subpath, "theme.xml"))) { + listInterface->addSimpleElement(subpath); + } + } + + this->childSetValue("ThemeCombobox", mThemeCombobox); + + UpdateDesc(this, getChild("ThemeCombobox")); + LLPanel::refresh(); +} + +void LLPanelSkins::apply() +{ + mThemeCombobox = (LLString)this->childGetValue("ThemeCombobox"); + + if (mThemeCombobox != gColorTheme && gSavedSettings.getString("ColorTheme") != mThemeCombobox) + { + gViewerWindow->alertXml("ThemeChanged"); + } + + gSavedSettings.setString("ColorTheme", mThemeCombobox); + + // nothing really to do here. +} + + +void LLPanelSkins::cancel() +{ + // doing this to restore situation when we entered this function + gSavedSettings.setString("ColorTheme", mThemeCombobox); +} \ No newline at end of file Index: newview/llpanelskins.h =================================================================== --- newview/llpanelskins.h (revision 0) +++ newview/llpanelskins.h (revision 0) @@ -0,0 +1,52 @@ +/** + * @file llpanellskins.h + * @brief skinning panel + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llpanel.h" + +#include "llcombobox.h" + +class LLPanelSkins : public LLPanel +{ +public: + LLPanelSkins(); + virtual ~LLPanelSkins(); + + virtual BOOL postBuild(); + virtual void refresh(); + void apply(); + void cancel(); + + static void ThemeComboboxChanged(LLUICtrl *ctrl, void *data); + +protected: + static void UpdateDesc(LLPanelSkins *panel, LLComboBox *combo); + LLString mThemeCombobox; +}; Index: newview/llviewercontrol.cpp =================================================================== --- newview/llviewercontrol.cpp (revision 493) +++ newview/llviewercontrol.cpp (working copy) @@ -81,7 +81,9 @@ LLControlGroup gSavedPerAccountSettings; // saved at end of session LLControlGroup gColors; // read-only LLControlGroup gCrashSettings; // saved at end of session +LLString gColorTheme; + LLString gLastRunVersion; LLString gCurrentVersion; Index: newview/llviewercontrol.h =================================================================== --- newview/llviewercontrol.h (revision 493) +++ newview/llviewercontrol.h (working copy) @@ -57,7 +57,9 @@ // Read-only extern LLControlGroup gColors; +extern LLString gColorTheme; + // Saved at end of session extern LLControlGroup gCrashSettings; Index: newview/llviewerimage.cpp =================================================================== --- newview/llviewerimage.cpp (revision 493) +++ newview/llviewerimage.cpp (working copy) @@ -210,7 +210,11 @@ : LLImageGL(usemipmaps), mID(id) { - mLocalFileName = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", filename); + std::string delem = gDirUtilp->getDirDelimiter(); + mLocalFileName = gDirUtilp->getExpandedFilename(LL_PATH_THEMES, gColorTheme + delem + "textures", filename); + if (!gDirUtilp->fileExists(mLocalFileName)) { + mLocalFileName = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", filename); + } init(true); sImageCount++; } Index: newview/llviewerimagelist.cpp =================================================================== --- newview/llviewerimagelist.cpp (revision 493) +++ newview/llviewerimagelist.cpp (working copy) @@ -124,7 +124,12 @@ LLUIImageList* image_list = LLUIImageList::getInstance(); - image_list->initFromFile(gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", "textures.xml")); + std::string delem = gDirUtilp->getDirDelimiter(); + std::string mLocalFileName = gDirUtilp->getExpandedFilename(LL_PATH_THEMES, gColorTheme + delem + "textures", "textures.xml"); + if (!gDirUtilp->fileExists(mLocalFileName)) { + mLocalFileName = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", "textures.xml"); + } + image_list->initFromFile(mLocalFileName); // prefetch specific UUIDs getImage(IMG_SHOT, TRUE); Index: newview/llviewermenu.cpp =================================================================== --- newview/llviewermenu.cpp (revision 493) +++ newview/llviewermenu.cpp (working copy) @@ -4900,7 +4900,12 @@ gSavedSettings.loadFromFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); llinfos << "Loading colors from colors.xml" << llendl; - std::string color_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"colors.xml"); + std::string delem = gDirUtilp->getDirDelimiter(); + std::string color_file = gDirUtilp->getExpandedFilename(LL_PATH_THEMES, gColorTheme + delem + "colors.xml"); + if (!gDirUtilp->fileExists(color_file)) { + color_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"colors.xml"); + } + gColors.resetToDefaults(); gColors.loadFromFile(color_file, FALSE, TYPE_COL4U); } Index: newview/skins/xui/en-us/alerts.xml =================================================================== --- newview/skins/xui/en-us/alerts.xml (revision 493) +++ newview/skins/xui/en-us/alerts.xml (working copy) @@ -874,7 +874,12 @@ Cache will be cleared after you restart [SECOND_LIFE]. - + + + New theme will be adopted after you restart [SECOND_LIFE]. + + + Cache will be moved after you restart [SECOND_LIFE]. Note: This will clear the cache. Index: newview/skins/xui/en-us/panel_preferences_skins.xml =================================================================== --- newview/skins/xui/en-us/panel_preferences_skins.xml (revision 0) +++ newview/skins/xui/en-us/panel_preferences_skins.xml (revision 0) @@ -0,0 +1,23 @@ + + + + Theme: + + + + + + + + \ No newline at end of file