From 3a81941981a6ca5fab229ff9aeb6b05b94a444bc Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 8 Oct 2006 18:22:28 +0000 Subject: - Added dialog for selecting the theme to use - Added runtime theme switching svn-id: r24213 --- graphics/imageman.cpp | 29 ++++++--- graphics/imageman.h | 18 +++++- gui/ThemeNew.cpp | 1 + gui/module.mk | 1 + gui/newgui.cpp | 122 ++++++++++++++++++++++++----------- gui/newgui.h | 5 ++ gui/options.cpp | 21 ++++++- gui/options.h | 3 + gui/theme-config.cpp | 6 ++ gui/theme.h | 2 + gui/themebrowser.cpp | 168 +++++++++++++++++++++++++++++++++++++++++++++++++ gui/themebrowser.h | 64 +++++++++++++++++++ gui/themes/classic.ini | 6 ++ gui/themes/modern.ini | 6 ++ 14 files changed, 405 insertions(+), 47 deletions(-) create mode 100644 gui/themebrowser.cpp create mode 100644 gui/themebrowser.h diff --git a/graphics/imageman.cpp b/graphics/imageman.cpp index 6139159c56..d4fc9da72d 100644 --- a/graphics/imageman.cpp +++ b/graphics/imageman.cpp @@ -43,7 +43,7 @@ ImageManager::~ImageManager() { _surfaces.clear(); #ifdef USE_ZLIB for (ZipIterator pos2 = _archives.begin(); pos2 != _archives.end(); ++pos2) { - unzClose(*pos2); + unzClose(pos2->file); } _archives.clear(); #endif @@ -54,11 +54,26 @@ bool ImageManager::addArchive(const Common::String &name) { unzFile newFile = unzOpen(name.c_str()); if (!newFile) return false; - _archives.push_back(newFile); + Archive arch; + arch.file = newFile; + arch.filename = name; + _archives.push_back(arch); #endif return true; } +void ImageManager::remArchive(const Common::String &name) { +#ifdef USE_ZLIB + for (ZipIterator pos = _archives.begin(); pos != _archives.end(); ++pos) { + if (pos->filename.compareToIgnoreCase(name) == 0) { + unzClose(pos->file); + _archives.erase(pos); + break; + } + } +#endif +} + bool ImageManager::registerSurface(const Common::String &name, Surface *surf) { if (getSurface(name)) { return false; @@ -74,7 +89,7 @@ bool ImageManager::registerSurface(const Common::String &name, Surface *surf) { #ifdef USE_ZLIB ZipIterator file = _archives.end(); for (ZipIterator pos = _archives.begin(); pos != _archives.end(); ++pos) { - if (unzLocateFile(*pos, name.c_str(), 2) == UNZ_OK) { + if (unzLocateFile(pos->file, name.c_str(), 2) == UNZ_OK) { file = pos; break; } @@ -84,12 +99,12 @@ bool ImageManager::registerSurface(const Common::String &name, Surface *surf) { return false; unz_file_info fileInfo; - unzOpenCurrentFile(*file); - unzGetCurrentFileInfo(*file, &fileInfo, NULL, 0, NULL, 0, NULL, 0); + unzOpenCurrentFile(file->file); + unzGetCurrentFileInfo(file->file, &fileInfo, NULL, 0, NULL, 0, NULL, 0); uint8 *buffer = new uint8[fileInfo.uncompressed_size]; assert(buffer); - unzReadCurrentFile(*file, buffer, fileInfo.uncompressed_size); - unzCloseCurrentFile(*file); + unzReadCurrentFile(file->file, buffer, fileInfo.uncompressed_size); + unzCloseCurrentFile(file->file); Common::MemoryReadStream stream(buffer, fileInfo.uncompressed_size); surf = ImageDecoder::loadFile(stream); delete [] buffer; diff --git a/graphics/imageman.h b/graphics/imageman.h index 6f682c1646..a5fe8f131d 100644 --- a/graphics/imageman.h +++ b/graphics/imageman.h @@ -37,7 +37,7 @@ public: ~ImageManager(); /** - * adds an .zip archive to the pool there the ImagaManager searches + * adds an .zip archive to the pool where the ImageManager searches * for image files * * @param name the name of the archive @@ -45,6 +45,14 @@ public: */ bool addArchive(const Common::String &name); + /** + * deletes an .zip archive from the pool where the Image Manager searches + * for image files + * + * @param name the name of the archive + */ + void remArchive(const Common::String &name); + /** * registers a surface to the ImageManager. * surf->free(), also delete surf, will be called when the ImageManager will @@ -84,14 +92,18 @@ private: }; typedef Common::List::iterator Iterator; #ifdef USE_ZLIB - typedef Common::List::iterator ZipIterator; + struct Archive { + unzFile file; + Common::String filename; + }; + typedef Common::List::iterator ZipIterator; #endif Iterator searchHandle(const Common::String &name); Common::List _surfaces; #ifdef USE_ZLIB - Common::List _archives; + Common::List _archives; #endif }; diff --git a/gui/ThemeNew.cpp b/gui/ThemeNew.cpp index fc8aadcd51..78afbb487a 100644 --- a/gui/ThemeNew.cpp +++ b/gui/ThemeNew.cpp @@ -114,6 +114,7 @@ ThemeNew::~ThemeNew() { ImageMan.unregisterSurface(_imageHandles[i]); } } + ImageMan.remArchive(_stylefile + ".zip"); } bool ThemeNew::init() { diff --git a/gui/module.mk b/gui/module.mk index bab4b31c94..9df80d5cbc 100644 --- a/gui/module.mk +++ b/gui/module.mk @@ -18,6 +18,7 @@ MODULE_OBJS := \ PopUpWidget.o \ ScrollBarWidget.o \ TabWidget.o \ + themebrowser.o \ widget.o \ theme.o \ ThemeClassic.o \ diff --git a/gui/newgui.cpp b/gui/newgui.cpp index 94924f1e84..211068c30f 100644 --- a/gui/newgui.cpp +++ b/gui/newgui.cpp @@ -106,35 +106,61 @@ NewGui::NewGui() : _needRedraw(false), Common::String styleType; Common::ConfigFile cfg; +#endif + + if (!loadNewTheme(style)) { + warning("falling back to classic style"); + _theme = new ThemeClassic(_system); + assert(_theme); + if (!_theme->init()) { + error("Couldn't initialize classic theme"); + } + } + + _theme->resetDrawArea(); + _themeChange = false; +} + +bool NewGui::loadNewTheme(const Common::String &style) { + Common::String styleType; + Common::ConfigFile cfg; + + Common::String oldTheme = (_theme != 0) ? _theme->getStylefileName() : ""; + delete _theme; + if (Theme::themeConfigUseable(style, "", &styleType, &cfg)) { if (0 == styleType.compareToIgnoreCase("classic")) _theme = new ThemeClassic(_system, style, &cfg); +#ifndef DISABLE_FANCY_THEMES else if (0 == styleType.compareToIgnoreCase("modern")) _theme = new ThemeNew(_system, style, &cfg); +#endif else warning("Unsupported theme type '%s'", styleType.c_str()); } else { warning("Config '%s' is NOT usable for themes or not found", style.c_str()); } cfg.clear(); -#endif - - if (!_theme) - _theme = new ThemeClassic(_system); - assert(_theme); + if (!_theme) + return (!oldTheme.empty() ? loadNewTheme(oldTheme) : false); - // Init the theme if (!_theme->init()) { - warning("Could not initialize your preferred theme, falling back to classic style"); + warning("Could not initialize your preferred theme"); delete _theme; - _theme = new ThemeClassic(_system); - assert(_theme); - if (!_theme->init()) { - error("Couldn't initialize classic theme"); - } + _theme = 0; + loadNewTheme(oldTheme); + return false; } _theme->resetDrawArea(); + + _theme->enable(); + if (!oldTheme.empty()) + screenChange(); + + _themeChange = true; + + return true; } void NewGui::redraw() { @@ -180,18 +206,8 @@ void NewGui::runLoop() { bool useStandardCurs = !_theme->ownCursor(); - if (useStandardCurs) { - const byte palette[] = { - 255, 255, 255, 0, - 255, 255, 255, 0, - 171, 171, 171, 0, - 87, 87, 87, 0 - }; - - PaletteMan.pushCursorPalette(palette, 0, 4); - CursorMan.pushCursor(NULL, 0, 0, 0, 0); - CursorMan.showMouse(true); - } + if (useStandardCurs) + setupCursor(); while (!_dialogStack.empty() && activeDialog == _dialogStack.top()) { if (_needRedraw) { @@ -217,6 +233,23 @@ void NewGui::runLoop() { continue; Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y); + + // HACK to change the cursor to the new themes one + if (_themeChange) { + if (useStandardCurs) + PaletteMan.popCursorPalette(); + + CursorMan.popCursor(); + + useStandardCurs = !_theme->ownCursor(); + if (useStandardCurs) + setupCursor(); + + _theme->refresh(); + + _themeChange = false; + redraw(); + } switch (event.type) { case OSystem::EVENT_KEYDOWN: @@ -270,18 +303,7 @@ void NewGui::runLoop() { _system->quit(); return; case OSystem::EVENT_SCREEN_CHANGED: - _lastScreenChangeID = _system->getScreenChangeID(); - - // reinit the whole theme - _theme->refresh(); - // refresh all dialogs - for (int i = 0; i < _dialogStack.size(); ++i) { - _dialogStack[i]->reflowLayout(); - } - // We need to redraw immediately. Otherwise - // some other event may cause a widget to be - // redrawn before redraw() has been called. - redraw(); + screenChange(); break; } } @@ -361,6 +383,19 @@ void NewGui::closeTopDialog() { _needRedraw = true; } +void NewGui::setupCursor() { + const byte palette[] = { + 255, 255, 255, 0, + 255, 255, 255, 0, + 171, 171, 171, 0, + 87, 87, 87, 0 + }; + + PaletteMan.pushCursorPalette(palette, 0, 4); + CursorMan.pushCursor(NULL, 0, 0, 0, 0); + CursorMan.showMouse(true); +} + // Draw the mouse cursor (animated). This is pretty much the same as in old // SCUMM games, but the code no longer resembles what we have in cursor.cpp // very much. We could plug in a different cursor here if we like to. @@ -390,4 +425,19 @@ void NewGui::clearDragWidget() { _dialogStack.top()->_dragWidget = 0; } +void NewGui::screenChange() { + _lastScreenChangeID = _system->getScreenChangeID(); + + // reinit the whole theme + _theme->refresh(); + // refresh all dialogs + for (int i = 0; i < _dialogStack.size(); ++i) { + _dialogStack[i]->reflowLayout(); + } + // We need to redraw immediately. Otherwise + // some other event may cause a widget to be + // redrawn before redraw() has been called. + redraw(); +} + } // End of namespace GUI diff --git a/gui/newgui.h b/gui/newgui.h index 54815a2d51..f40a33ebd2 100644 --- a/gui/newgui.h +++ b/gui/newgui.h @@ -70,6 +70,7 @@ public: bool isActive() const { return ! _dialogStack.empty(); } + bool loadNewTheme(const Common::String &file); Theme *theme() { return _theme; } Eval *evaluator() { return _theme->_evaluator; } @@ -113,16 +114,20 @@ protected: int _cursorAnimateTimer; byte _cursor[2048]; + bool _themeChange; + void saveState(); void restoreState(); void openDialog(Dialog *dialog); void closeTopDialog(); + void screenChange(); void redraw(); void loop(); + void setupCursor(); void animateCursor(); }; diff --git a/gui/options.cpp b/gui/options.cpp index ee04fb31a5..007ef48f07 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -21,6 +21,7 @@ #include "common/stdafx.h" #include "gui/browser.h" +#include "gui/themebrowser.h" #include "gui/chooser.h" #include "gui/eval.h" #include "gui/newgui.h" @@ -69,7 +70,8 @@ enum { kChooseSoundFontCmd = 'chsf', kChooseSaveDirCmd = 'chos', kChooseThemeDirCmd = 'chth', - kChooseExtraDirCmd = 'chex' + kChooseExtraDirCmd = 'chex', + kChooseThemeCmd = 'chtf' }; #ifdef SMALL_SCREEN_DEVICE @@ -685,6 +687,11 @@ GlobalOptionsDialog::GlobalOptionsDialog() new ButtonWidget(tab, "globaloptions_keysbutton", "Keys", kChooseKeyMappingCmd, 0); #endif + tab->addTab("Misc"); + + new ButtonWidget(tab, "globaloptions_themebutton2", "Theme:", kChooseThemeCmd, 0); + _curTheme = new StaticTextWidget(tab, "globaloptions_curtheme", ConfMan.get("gui_theme", _domain)); + // TODO: joystick setting @@ -797,6 +804,18 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3 } break; } + case kChooseThemeCmd: { + ThemeBrowser browser; + if (browser.runModal() > 0) { + // User made his choice... + Common::String theme = browser.selected(); + if (0 != theme.compareToIgnoreCase(g_gui.theme()->getStylefileName())) + if (g_gui.loadNewTheme(theme)) + _curTheme->setLabel(theme); + draw(); + } + break; + } #ifdef SMALL_SCREEN_DEVICE case kChooseKeyMappingCmd: _keysDialog->runModal(); diff --git a/gui/options.h b/gui/options.h index 136b73b0e9..34ced65376 100644 --- a/gui/options.h +++ b/gui/options.h @@ -36,6 +36,7 @@ class CheckboxWidget; class PopUpWidget; class SliderWidget; class StaticTextWidget; +class ListWidget; class OptionsDialog : public Dialog { typedef Common::String String; @@ -152,6 +153,8 @@ protected: StaticTextWidget *_savePath; StaticTextWidget *_themePath; StaticTextWidget *_extraPath; + + StaticTextWidget *_curTheme; }; } // End of namespace GUI diff --git a/gui/theme-config.cpp b/gui/theme-config.cpp index e0d2af458c..253def8f60 100644 --- a/gui/theme-config.cpp +++ b/gui/theme-config.cpp @@ -185,6 +185,12 @@ const char *Theme::_defaultConfigINI = "yoffset=(yoffset + buttonHeight + 4)\n" "globaloptions_keysbutton=10 yoffset (buttonWidth + 5) buttonHeight\n" "\n" +"# Misc options\n" +"yoffset=vBorder\n" +"glOff=((buttonHeight - kLineHeight) / 2 + 2)\n" +"globaloptions_themebutton2=10 yoffset buttonWidth buttonHeight\n" +"globaloptions_curtheme=(prev.x2 + 20) (yoffset + glOff) (parent.w - (prev.w + 20) - 10) kLineHeight\n" +"\n" "globaloptions_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight\n" "globaloptions_ok=(prev.x2 + 10) prev.y prev.w prev.h\n" "\n" diff --git a/gui/theme.h b/gui/theme.h index 4cf3358e30..1c783d8166 100644 --- a/gui/theme.h +++ b/gui/theme.h @@ -213,6 +213,8 @@ public: Eval *_evaluator; static bool themeConfigUseable(const String &file, const String &style="", String *cStyle=0, Common::ConfigFile *cfg=0); + + const String &getStylefileName() const { return _stylefile; } protected: bool loadConfigFile(const String &file); void getColorFromConfig(const String &name, OverlayColor &col); diff --git a/gui/themebrowser.cpp b/gui/themebrowser.cpp new file mode 100644 index 0000000000..5bda962db1 --- /dev/null +++ b/gui/themebrowser.cpp @@ -0,0 +1,168 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "common/stdafx.h" +#include "gui/themebrowser.h" +#include "gui/ListWidget.h" +#include "gui/widget.h" +#include "gui/theme.h" +#include "common/fs.h" + +namespace GUI { + +enum { + kChooseCmd = 'Chos' +}; + +// TODO: this is a rip off of GUI::Browser right now +// it will get some more output like theme name, +// theme style, theme preview(?) in the future +// but for now this simple browser works, +// also it will get its own theme config values +// and not use 'browser_' anymore +ThemeBrowser::ThemeBrowser() : Dialog("browser") { + _fileList = 0; + + new StaticTextWidget(this, "browser_headline", "Select a Theme"); + + // Add file list + _fileList = new ListWidget(this, "browser_list"); + _fileList->setNumberingMode(kListNumberingOff); + _fileList->setEditable(false); + + _fileList->setHints(THEME_HINT_PLAIN_COLOR); + + // Buttons + new ButtonWidget(this, "browser_cancel", "Cancel", kCloseCmd, 0); + new ButtonWidget(this, "browser_choose", "Choose", kChooseCmd, 0); +} + +void ThemeBrowser::open() { + // Alway refresh file list + updateListing(); + + // Call super implementation + Dialog::open(); +} + +void ThemeBrowser::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { + switch (cmd) { + case kChooseCmd: + case kListItemActivatedCmd: + case kListItemDoubleClickedCmd: + int selection = _fileList->getSelected(); + if (selection < 0) + break; + _select = _themes[selection].file; + setResult(1); + close(); + break; + default: + Dialog::handleCommand(sender, cmd, data); + } +} + +void ThemeBrowser::updateListing() { + _themes.clear(); + + if (ConfMan.hasKey("themepath")) + addDir(_themes, ConfMan.get("themepath"), 0); + +#ifdef DATA_PATH + addDir(_themes, DATA_PATH); +#endif + + if (ConfMan.hasKey("extrapath")) + addDir(_themes, ConfMan.get("extrapath")); + + addDir(_themes, ".", 0); + + // Populate the ListWidget + Common::StringList list; + + for (ThList::const_iterator i = _themes.begin(); i != _themes.end(); ++i) + list.push_back(i->name); + + _fileList->setList(list); + _fileList->scrollTo(0); + + // Finally, redraw + draw(); +} + +void ThemeBrowser::addDir(ThList &list, const Common::String &dir, int level) { + if (level < 0) + return; + + FilesystemNode node(dir); + + if (!node.isValid()) + return; + + FSList fslist; + if (!node.listDir(fslist, FilesystemNode::kListAll)) + return; + + for (FSList::const_iterator i = fslist.begin(); i != fslist.end(); ++i) { + if (i->isDirectory()) { + addDir(list, i->path(), level-1); + } else { + Entry th; + if (isTheme(*i, th)) { + bool add = true; + for (ThList::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 FilesystemNode &node, Entry &out) { + Common::ConfigFile cfg; + Common::String type; + + out.file = node.name(); + for (int i = out.file.size()-1; out.file[i] != '.' && i > 0; --i) { + out.file.deleteLastChar(); + } + out.file.deleteLastChar(); + + if (out.file.empty()) + return false; + + if (!Theme::themeConfigUseable(out.file, "", &type, &cfg)) + return false; + + out.type = type; + out.name = out.file; + + return true; +} + +} // end of namespace GUI + diff --git a/gui/themebrowser.h b/gui/themebrowser.h new file mode 100644 index 0000000000..ce38bead9d --- /dev/null +++ b/gui/themebrowser.h @@ -0,0 +1,64 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#ifndef GUI_THEMEBROWSER_H +#define GUI_THEMEBROWSER_H + +#include "gui/dialog.h" +#include "common/str.h" +#include "common/fs.h" +#include "common/array.h" + +namespace GUI { + +class ListWidget; +class StaticTextWidget; + +class ThemeBrowser : public Dialog { +public: + ThemeBrowser(); + + void open(); + void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); + + const Common::String &selected() const { return _select; } +private: + struct Entry { + Common::String name; + Common::String type; + Common::String file; + }; + + ListWidget *_fileList; + Common::String _select; + typedef Common::Array ThList; + ThList _themes; + + void updateListing(); + + void addDir(ThList &list, const Common::String &dir, int level = 4); + bool isTheme(const FilesystemNode &node, Entry &out); +}; + +} // end of namespace GUI + +#endif + diff --git a/gui/themes/classic.ini b/gui/themes/classic.ini index c26715343d..91f91b1e80 100644 --- a/gui/themes/classic.ini +++ b/gui/themes/classic.ini @@ -178,6 +178,12 @@ globaloptions_themepath=(prev.x2 + 20) (yoffset + glOff) (parent.w - (prev.w + 2 yoffset=(yoffset + buttonHeight + 4) globaloptions_keysbutton=10 yoffset (buttonWidth + 5) buttonHeight +# Misc options +yoffset=vBorder +glOff=((buttonHeight - kLineHeight) / 2 + 2) +globaloptions_themebutton2=10 yoffset buttonWidth buttonHeight +globaloptions_curtheme=(prev.x2 + 20) (yoffset + glOff) (parent.w - (prev.w + 20) - 10) kLineHeight + globaloptions_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight globaloptions_ok=(prev.x2 + 10) prev.y prev.w prev.h diff --git a/gui/themes/modern.ini b/gui/themes/modern.ini index 43aee8d33e..f656ee96fd 100644 --- a/gui/themes/modern.ini +++ b/gui/themes/modern.ini @@ -298,6 +298,12 @@ globaloptions_themepath=(prev.x2 + 20) (yoffset + glOff) (parent.w - (prev.w + 2 yoffset=(yoffset + buttonHeight + 12) globaloptions_keysbutton=5 yoffset buttonWidth buttonHeight +# Misc options +yoffset=vBorder +glOff=((buttonHeight - kLineHeight) / 2 + 2) +globaloptions_themebutton2=10 yoffset buttonWidth buttonHeight +globaloptions_curtheme=(prev.x2 + 20) (yoffset + glOff) (parent.w - (prev.w + 20) - 10) kLineHeight + globaloptions_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight globaloptions_ok=(prev.x2 + 10) prev.y prev.w prev.h -- cgit v1.2.3