From 1b0f94547120435cbda18387ff4d936ed84d9276 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Fri, 2 Jan 2009 20:03:45 +0000 Subject: - Added support selection of themes via a basename again (This should fix bugs #2473213 "GUI: Theme selection oddities and regressions" and #2219605 "GUI: theme detection") - Changed default value to "scummmodern" instead of "scummmodern.zip" for "gui_theme" - Moved theme listing code from ThemeBrowser to GuiManager svn-id: r35680 --- gui/GuiManager.cpp | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++- gui/GuiManager.h | 16 +++++ gui/themebrowser.cpp | 103 ++++---------------------------- gui/themebrowser.h | 16 ++--- 4 files changed, 194 insertions(+), 104 deletions(-) (limited to 'gui') diff --git a/gui/GuiManager.cpp b/gui/GuiManager.cpp index 00babbea17..fc2b2c1a4b 100644 --- a/gui/GuiManager.cpp +++ b/gui/GuiManager.cpp @@ -26,6 +26,7 @@ #include "common/system.h" #include "common/util.h" #include "common/config-manager.h" +#include "common/algorithm.h" #include "gui/GuiManager.h" #include "gui/dialog.h" @@ -34,6 +35,10 @@ #include "graphics/cursorman.h" +#ifdef MACOSX +#include +#endif + DECLARE_SINGLETON(GUI::GuiManager); namespace GUI { @@ -56,10 +61,8 @@ GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled), memset(_cursor, 0xFF, sizeof(_cursor)); - ConfMan.registerDefault("gui_theme", "scummmodern.zip"); + ConfMan.registerDefault("gui_theme", "scummmodern"); Common::String themefile(ConfMan.get("gui_theme")); - if (themefile.compareToIgnoreCase("default") == 0) - themefile = "builtin"; ConfMan.registerDefault("gui_renderer", ThemeEngine::findModeConfigName(ThemeEngine::_defaultRendererMode)); ThemeEngine::GraphicsMode gfxMode = (ThemeEngine::GraphicsMode)ThemeEngine::findMode(ConfMan.get("gui_renderer")); @@ -80,6 +83,13 @@ GuiManager::~GuiManager() { } bool GuiManager::loadNewTheme(Common::String filename, ThemeEngine::GraphicsMode gfx) { + // We currently allow two different ways of theme selection in our config file: + // 1) Via full path + // 2) Via a basename, which will need to be translated into a full path + // This function assures we have a correct path to pass to the ThemeEngine + // constructor. + filename = findThemeFile(filename); + // If we are asked to reload the currently active theme, just do nothing // FIXME: Actually, why? It might be desirable at times to force a theme reload... if (_theme && filename == _theme->getThemeId() && gfx == _theme->getGraphicsMode()) @@ -130,6 +140,153 @@ bool GuiManager::loadNewTheme(Common::String filename, ThemeEngine::GraphicsMode return true; } +namespace { + +struct TDComparator { + const Common::String _id; + TDComparator(const Common::String &id) : _id(id) {} + + bool operator()(const GuiManager::ThemeDescriptor &r) { return _id == r.id; } +}; + +} // end of anonymous namespace + +void GuiManager::listUseableThemes(Common::List &list) { + ThemeDescriptor th; + th.name = "ScummVM Classic Theme (Builtin Version)"; + th.id = "builtin"; + th.filename = "builtin"; + list.push_back(th); + + if (ConfMan.hasKey("themepath")) + listUseableThemes(Common::FSNode(ConfMan.get("themepath")), list); + +#ifdef DATA_PATH + listUseableThemes(Common::FSNode(DATA_PATH), list); +#endif + +#ifdef MACOSX + CFURLRef resourceUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (resourceUrl) { + char buf[256]; + if (CFURLGetFileSystemRepresentation(resourceUrl, true, (UInt8 *)buf, 256)) { + Common::FSNode resourcePath(buf); + listUseableThemes(resourcePath, list); + } + CFRelease(resourceUrl); + } +#endif + + if (ConfMan.hasKey("extrapath")) + listUseableThemes(Common::FSNode(ConfMan.get("extrapath")), list); + + listUseableThemes(Common::FSNode("."), list); + + // Now we need to strip all duplicates + // TODO: It might not be the best idea to strip duplicates. The user might + // have different versions of a specific theme in his paths, thus this code + // might show him the wrong version. The problem is we have no ways of checking + // a theme version currently. Also since we want to avoid saving the full path + // in the config file we can not do any better currently. + Common::List output; + + for (Common::List::const_iterator i = list.begin(); i != list.end(); ++i) { + if (find_if(output.begin(), output.end(), TDComparator(i->id)) == output.end()) + output.push_back(*i); + } + + list = output; + output.clear(); +} + +void GuiManager::listUseableThemes(Common::FSNode node, Common::List &list) { + if (!node.exists() || !node.isReadable() || !node.isDirectory()) + return; + + ThemeDescriptor td; + + // Check whether we point to a valid theme directory. + if (ThemeEngine::themeConfigUseable(node, td.name)) { + td.filename = node.getPath(); + td.id = node.getName(); + + list.push_back(td); + + // A theme directory should never contain any other themes + // thus we just return to the caller here. + return; + } + + Common::FSList fileList; +#ifdef USE_ZLIB + // Check all files. We need this to find all themes inside ZIP archives. + if (!node.getChildren(fileList, Common::FSNode::kListFilesOnly)) + return; + + for (Common::FSList::iterator i = fileList.begin(); i != fileList.end(); ++i) { + // We will only process zip files for now + if (!i->getPath().hasSuffix(".zip")) + continue; + + td.name.clear(); + if (ThemeEngine::themeConfigUseable(*i, td.name)) { + td.filename = i->getPath(); + td.id = i->getName(); + + // If the name of the node object also contains + // the ".zip" suffix, we will strip it. + if (td.id.hasSuffix(".zip")) { + for (int j = 0; j < 4; ++j) + td.id.deleteLastChar(); + } + + list.push_back(td); + } + } + + fileList.clear(); +#endif + + // As next step we will search all subdirectories + if (!node.getChildren(fileList, Common::FSNode::kListDirectoriesOnly)) + return; + + for (Common::FSList::iterator i = fileList.begin(); i != fileList.end(); ++i) + listUseableThemes(*i, list); +} + +Common::String GuiManager::findThemeFile(const Common::String &id) { + // FIXME: Actually "default" rather sounds like it should use + // our default theme which would me "scummmodern" instead + // of the builtin one. + if (id.equalsIgnoreCase("default")) + return "builtin"; + + Common::FSNode node(id); + + // If the given id is a full path we'll just use it + if (node.exists() && (node.isDirectory() || (node.getName().hasSuffix(".zip") && !node.isDirectory()))) + return id; + + // FIXME: + // A very ugly hack to map a id to a filename, this will generate + // a complete theme list, thus it is slower than it could be. + // But it is the easiest solution for now. + Common::List list; + listUseableThemes(list); + + for (Common::List::const_iterator i = list.begin(); i != list.end(); ++i) { + if (id.equalsIgnoreCase(i->id)) + return i->filename; + } + + warning("Could not find theme '%s' falling back to builtin", id.c_str()); + + // If no matching id has been found we will + // just fall back to the builtin theme + return "builtin"; +} + void GuiManager::redraw() { int i; diff --git a/gui/GuiManager.h b/gui/GuiManager.h index c2ec61dd34..5e97fd82a2 100644 --- a/gui/GuiManager.h +++ b/gui/GuiManager.h @@ -29,6 +29,9 @@ #include "common/singleton.h" #include "common/stack.h" #include "common/str.h" +#include "common/list.h" +#include "common/fs.h" + #include "graphics/fontman.h" #include "gui/widget.h" @@ -90,6 +93,16 @@ public: */ bool checkScreenChange(); + struct ThemeDescriptor { + Common::String name; + Common::String id; + Common::String filename; + }; + + /** + * Lists all theme files useable. + */ + void listUseableThemes(Common::List &list); protected: enum RedrawStatus { kRedrawDisabled = 0, @@ -144,6 +157,9 @@ protected: Dialog *getTopDialog() const; void screenChange(); + + Common::String findThemeFile(const Common::String &id); + void listUseableThemes(Common::FSNode node, Common::List &list); }; } // End of namespace GUI diff --git a/gui/themebrowser.cpp b/gui/themebrowser.cpp index be79f300ed..7fc35e9bf0 100644 --- a/gui/themebrowser.cpp +++ b/gui/themebrowser.cpp @@ -25,13 +25,6 @@ #include "gui/themebrowser.h" #include "gui/ListWidget.h" #include "gui/widget.h" -#include "common/config-manager.h" - -#include "common/fs.h" - -#ifdef MACOSX -#include "CoreFoundation/CoreFoundation.h" -#endif namespace GUI { @@ -78,7 +71,18 @@ void ThemeBrowser::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) int selection = _fileList->getSelected(); if (selection < 0) break; - _select = _themes[selection].file; + + // TODO: + // Currently GuiManager::listUseableThemes uses a + // list. Thus we can not use operator[] here but + // need to iterate through the list. We might want + // to think of changing it, but it should not be + // of high importance anyway. + ThemeDescList::const_iterator sel = _themes.begin(); + for (int i = 0; i < selection; ++i) + ++sel; + + _select = sel->id; setResult(1); close(); break; @@ -91,43 +95,9 @@ void ThemeBrowser::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) void ThemeBrowser::updateListing() { _themes.clear(); - // classic is always built-in - ThemeDescriptor th; - th.name = "ScummVM Classic Theme (Builtin Version)"; - th.file = "builtin"; - _themes.push_back(th); - - // we are using only the paths 'themepath', 'extrapath', DATA_PATH and '.' - // since these are the default locations for the theme files - // files in other places are ignored in this dialog - // TODO: let the user browse the complete FS too/only the FS? - if (ConfMan.hasKey("themepath")) - addDir(_themes, Common::FSNode(ConfMan.get("themepath"))); - -#ifdef DATA_PATH - addDir(_themes, Common::FSNode(DATA_PATH)); -#endif - -#ifdef MACOSX - CFURLRef resourceUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); - if (resourceUrl) { - char buf[256]; - if (CFURLGetFileSystemRepresentation(resourceUrl, true, (UInt8 *)buf, 256)) { - Common::FSNode resourcePath(buf); - addDir(_themes, resourcePath); - } - CFRelease(resourceUrl); - } -#endif - - if (ConfMan.hasKey("extrapath")) - addDir(_themes, Common::FSNode(ConfMan.get("extrapath"))); - - addDir(_themes, Common::FSNode(".")); + g_gui.listUseableThemes(_themes); - // Populate the ListWidget Common::StringList list; - for (ThemeDescList::const_iterator i = _themes.begin(); i != _themes.end(); ++i) list.push_back(i->name); @@ -138,52 +108,5 @@ void ThemeBrowser::updateListing() { draw(); } - -void ThemeBrowser::addDir(ThemeDescList &list, const Common::FSNode &node) { - if (!node.exists() || !node.isReadable()) - return; - - // Scan this dir, all files and all subdirs in it for themes - Common::FSList fslist; - if (!node.getChildren(fslist, Common::FSNode::kListAll)) - return; - fslist.push_back(node); // Yup, also scan the dir itself - - for (Common::FSList::const_iterator i = fslist.begin(); i != fslist.end(); ++i) { - - ThemeDescriptor th; - if (isTheme(*i, th)) { - bool add = true; - - for (ThemeDescList::const_iterator p = list.begin(); p != list.end(); ++p) { - if (p->name == th.name || p->file == th.file) { - add = false; - break; - } - } - - if (add) - list.push_back(th); - } - } -} - -bool ThemeBrowser::isTheme(const Common::FSNode &node, ThemeDescriptor &out) { - out.file = node.getPath(); - -#ifdef USE_ZLIB - if (!out.file.hasSuffix(".zip") && !node.isDirectory()) - return false; -#else - if (!node.isDirectory()) - return false; -#endif - - if (!ThemeEngine::themeConfigUseable(node, out.name)) - return false; - - return true; -} - } // end of namespace GUI diff --git a/gui/themebrowser.h b/gui/themebrowser.h index 477034d5be..b6327253ca 100644 --- a/gui/themebrowser.h +++ b/gui/themebrowser.h @@ -26,9 +26,10 @@ #define GUI_THEMEBROWSER_H #include "gui/dialog.h" +#include "gui/GuiManager.h" + #include "common/str.h" -#include "common/fs.h" -#include "common/array.h" +#include "common/list.h" namespace GUI { @@ -44,20 +45,13 @@ public: const Common::String &getSelected() const { return _select; } private: - struct ThemeDescriptor { - Common::String name; - Common::String file; - }; - ListWidget *_fileList; Common::String _select; - typedef Common::Array ThemeDescList; + + typedef Common::List ThemeDescList; ThemeDescList _themes; void updateListing(); - - void addDir(ThemeDescList &list, const Common::FSNode &node); - bool isTheme(const Common::FSNode &node, ThemeDescriptor &out); }; } // end of namespace GUI -- cgit v1.2.3