/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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_THEME_ENGINE_H #define GUI_THEME_ENGINE_H #include "common/scummsys.h" #include "common/system.h" #include "common/fs.h" #include "graphics/surface.h" #include "graphics/fontman.h" #define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.4" namespace Graphics { struct DrawStep; class VectorRenderer; } namespace GUI { struct WidgetDrawData; struct DrawDataInfo; struct TextDataInfo; struct TextDrawData; class Dialog; class GuiObject; class ThemeEval; class ThemeItem; class ThemeParser; /** * DrawData sets enumeration. * Each DD set corresponds to the actual looks * of a widget in a given state. */ enum DrawData { kDDMainDialogBackground, kDDSpecialColorBackground, kDDPlainColorBackground, kDDDefaultBackground, kDDTextSelectionBackground, kDDWidgetBackgroundDefault, kDDWidgetBackgroundSmall, kDDWidgetBackgroundEditText, kDDWidgetBackgroundSlider, kDDButtonIdle, kDDButtonHover, kDDButtonDisabled, kDDSliderFull, kDDSliderHover, kDDSliderDisabled, kDDCheckboxDefault, kDDCheckboxDisabled, kDDCheckboxSelected, kDDTabActive, kDDTabInactive, kDDTabBackground, kDDScrollbarBase, kDDScrollbarButtonIdle, kDDScrollbarButtonHover, kDDScrollbarHandleIdle, kDDScrollbarHandleHover, kDDPopUpIdle, kDDPopUpHover, kDDPopUpDisabled, kDDCaret, kDDSeparator, kDrawDataMAX, kDDNone = -1 }; // FIXME: TextData is really a bad name, not conveying what this enum is about. enum TextData { kTextDataNone = -1, kTextDataDefault = 0, kTextDataHover, kTextDataDisabled, kTextDataInverted, kTextDataButton, kTextDataButtonHover, kTextDataNormalFont, kTextDataMAX }; class ThemeEngine { protected: typedef Common::HashMap ImagesMap; friend class GUI::Dialog; friend class GUI::GuiObject; public: //! Vertical alignment of the text. enum TextAlignVertical { kTextAlignVBottom, kTextAlignVCenter, kTextAlignVTop }; //! Widget background type enum WidgetBackground { kWidgetBackgroundNo, //!< No background at all kWidgetBackgroundPlain, //!< Simple background, this may not include borders kWidgetBackgroundBorder, //!< Same as kWidgetBackgroundPlain just with a border kWidgetBackgroundBorderSmall, //!< Same as kWidgetBackgroundPlain just with a small border kWidgetBackgroundEditText, //!< Background used for edit text fields kWidgetBackgroundSlider //!< Background used for sliders }; //! Dialog background type enum DialogBackground { kDialogBackgroundMain, kDialogBackgroundSpecial, kDialogBackgroundPlain, kDialogBackgroundDefault }; //! State of the widget to be drawn enum State { kStateDisabled, //!< Indicates that the widget is disabled, that does NOT include that it is invisible kStateEnabled, //!< Indicates that the widget is enabled kStateHighlight //!< Indicates that the widget is highlighted by the user }; typedef State WidgetStateInfo; enum ScrollbarState { kScrollbarStateNo, kScrollbarStateUp, kScrollbarStateDown, kScrollbarStateSlider, kScrollbarStateSinglePage }; //! Font style selector enum FontStyle { kFontStyleBold = 0, //!< A bold font. This is also the default font. kFontStyleNormal = 1, //!< A normal font. kFontStyleItalic = 2, //!< Italic styled font. kFontStyleFixedNormal = 3, //!< Fixed size font. kFontStyleFixedBold = 4, //!< Fixed size bold font. kFontStyleFixedItalic = 5, //!< Fixed size italic font. kFontStyleMax }; //! Function used to process areas other than the current dialog enum ShadingStyle { kShadingNone, //!< No special post processing kShadingDim, //!< Dimming unused areas kShadingLuminance //!< Converting colors to luminance for unused areas }; //! Special image ids for images used in the GUI enum kThemeImages { kImageLogo = 0, //!< ScummVM Logo used in the launcher kImageLogoSmall //!< ScummVM logo used in the GMM }; /** * Graphics mode enumeration. * Each item represents a set of BPP and Renderer modes for a given * surface. */ enum GraphicsMode { kGfxDisabled = 0, //!< No GFX kGfxStandard16bit, //!< 2BPP with the standard (aliased) renderer. kGfxAntialias16bit //!< 2BPP with the optimized AA renderer. }; /** Constant value to expand dirty rectangles, to make sure they are fully copied */ static const int kDirtyRectangleThreshold = 1; struct Renderer { const char *name; const char *cfg; GraphicsMode mode; }; static const Renderer _rendererModes[]; static const uint _rendererModesSize; static const GraphicsMode _defaultRendererMode; static GraphicsMode findMode(const Common::String &cfg); static const char *findModeConfigName(GraphicsMode mode); /** Default constructor */ ThemeEngine(Common::String id, GraphicsMode mode); /** Default destructor */ ~ThemeEngine(); bool init(); void clearAll(); void refresh(); void enable(); void disable(); /** * Implementation of the GUI::Theme API. Called when a * new dialog is opened. Note that the boolean parameter * meaning has been changed. * * @param enableBuffering If set to true, buffering is enabled for * drawing this dialog, and will continue enabled * until disabled. */ void openDialog(bool enableBuffering, ShadingStyle shading = kShadingNone); /** * The updateScreen() method is called every frame. * It processes all the drawing queues and then copies dirty rects * in the current Screen surface to the overlay. */ void updateScreen(); /** @name FONT MANAGEMENT METHODS */ //@{ TextData fontStyleToData(FontStyle font) const { if (font == kFontStyleNormal) return kTextDataNormalFont; return kTextDataDefault; } const Graphics::Font *getFont(FontStyle font = kFontStyleBold) const; int getFontHeight(FontStyle font = kFontStyleBold) const; int getStringWidth(const Common::String &str, FontStyle font = kFontStyleBold) const; int getCharWidth(byte c, FontStyle font = kFontStyleBold) const; //@} /** @name WIDGET DRAWING METHODS */ //@{ void drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background = kWidgetBackgroundPlain, WidgetStateInfo state = kStateEnabled); void drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, uint16 hints = 0); void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state = kStateEnabled, int alpha = 256, bool themeTrans = false); void drawSlider(const Common::Rect &r, int width, WidgetStateInfo state = kStateEnabled); void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state = kStateEnabled); void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state = kStateEnabled); void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState, WidgetStateInfo state = kStateEnabled); void drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignLeft); void drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state = kStateEnabled); void drawLineSeparator(const Common::Rect &r, WidgetStateInfo state = kStateEnabled); void drawDialogBackground(const Common::Rect &r, DialogBackground type, WidgetStateInfo state = kStateEnabled); void drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignCenter, bool inverted = false, int deltax = 0, bool useEllipsis = true, FontStyle font = kFontStyleBold); void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state = kStateEnabled); //@} /** * Actual implementation of a dirty rect handling. * Dirty rectangles are queued on a list and are later used for the * actual drawing. * * @param r Area of the dirty rect. */ void addDirtyRect(Common::Rect r); /** * Returns the DrawData enumeration value that represents the given string * in the DrawDataDefaults enumeration. * It's slow, but called sparsely. * * @returns The drawdata enum value, or -1 if not found. * @param name The representing name, as found on Theme Description XML files. * @see kDrawDataDefaults[] */ DrawData parseDrawDataId(const Common::String &name) const; TextData getTextData(DrawData ddId) const; /** * Interface for ThemeParser class: Parsed DrawSteps are added via this function. * There is no return type because DrawSteps can always be added, unless something * goes horribly wrong. * The specified step will be added to the Steps list of the given DrawData id. * * @param drawDataId The representing DrawData name, as found on Theme Description XML files. * @param step The actual DrawStep struct to be added. */ void addDrawStep(const Common::String &drawDataId, const Graphics::DrawStep &step); /** * Interfacefor the ThemeParser class: Parsed DrawData sets are added via this function. * The goal of the function is to initialize each DrawData set before their DrawSteps can * be added, hence this must be called for each DD set before addDrawStep() can be called * for that given set. * * @param data The representing DrawData name, as found on Theme Description XML files. * @param cached Whether this DD set will be cached beforehand. */ bool addDrawData(const Common::String &data, bool cached); /** * Interface for the ThemeParser class: Loads a font to use on the GUI from the given * filename. * * @param fontName Identifier name for the font. * @param file Name of the font file. * @param r, g, b Color of the font. */ bool addFont(TextData textId, const Common::String &file, int r, int g, int b); /** * Interface for the ThemeParser class: Loads a bitmap file to use on the GUI. * The filename is also used as its identifier. * * @param filename Name of the bitmap file. */ bool addBitmap(const Common::String &filename); /** * Adds a new TextStep from the ThemeParser. This will be deprecated/removed once the * new Font API is in place. FIXME: Is that so ??? */ bool addTextData(const Common::String &drawDataId, TextData textId, Graphics::TextAlign alignH, TextAlignVertical alignV); protected: /** * Returns if the Theme is ready to draw stuff on screen. * Must be called instead of just checking _initOk, because * this checks if the renderer is initialized AND if the theme * is loaded. */ bool ready() const { return _initOk && _themeOk; } /** Load the them from the file with the specified name. */ void loadTheme(const Common::String &themeid); /** * Changes the active graphics mode of the GUI; may be used to either * initialize the GUI or to change the mode while the GUI is already running. */ void setGraphicsMode(GraphicsMode mode); public: /** * Finishes buffering: widgets from then on will be drawn straight on the screen * without drawing queues. */ inline void finishBuffering() { _buffering = false; } inline void startBuffering() { _buffering = true; } inline ThemeEval *getEvaluator() { return _themeEval; } inline Graphics::VectorRenderer *renderer() { return _vectorRenderer; } inline bool supportsImages() const { return true; } inline bool ownCursor() const { return _useCursor; } Graphics::Surface *getBitmap(const Common::String &name) { return _bitmaps.contains(name) ? _bitmaps[name] : 0; } const Graphics::Surface *getImageSurface(const kThemeImages n) const { if (n == kImageLogo) return _bitmaps.contains("logo.bmp") ? _bitmaps["logo.bmp"] : 0; else if (n == kImageLogoSmall) return _bitmaps.contains("logo_small.bmp") ? _bitmaps["logo_small.bmp"] : 0; return 0; } /** * Interface for the Theme Parser: Creates a new cursor by loading the given * bitmap and sets it as the active cursor. * * @param filename File name of the bitmap to load. * @param hotspotX X Coordinate of the bitmap which does the cursor click. * @param hotspotY Y Coordinate of the bitmap which does the cursor click. * @param scale Scale at which the bitmap is supposed to be used. */ bool createCursor(const Common::String &filename, int hotspotX, int hotspotY, int scale); /** * Wrapper for restoring data from the Back Buffer to the screen. * The actual processing is done in the VectorRenderer. * * @param r Area to restore. */ void restoreBackground(Common::Rect r); const Common::String &getThemeName() const { return _themeName; } const Common::String &getThemeId() const { return _themeId; } int getGraphicsMode() const { return _graphicsMode; } protected: /** * Initializes the drawing screen surfaces, _screen and _backBuffer. * If the surfaces already exist, they are cleared and re-initialized. * * @param backBuffer Sets whether the _backBuffer surface should be initialized. * @template PixelType C type which specifies the size of each pixel. * Defaults to uint16 (2 BPP for the surfaces) */ template void screenInit(bool backBuffer = true); /** * Loads the given theme into the ThemeEngine. * * @param themeId Theme identifier. * @returns true if the theme was successfully loaded. */ bool loadThemeXML(const Common::String &themeId); /** * Loads the default theme file (the embedded XML file found * in ThemeDefaultXML.cpp). * Called only when no other themes are available. */ bool loadDefaultXML(); /** * Unloads the currently loaded theme so another one can * be loaded. */ void unloadTheme(); const Graphics::Font *loadFont(const Common::String &filename); const Graphics::Font *loadFontFromArchive(const Common::String &filename); Common::String genCacheFilename(const char *filename); /** * Actual Dirty Screen handling function. * Handles all the dirty squares in the list, merges and optimizes * them when possible and draws them to the screen. * Called from updateScreen() */ void renderDirtyScreen(); /** * Generates a DrawQueue item and enqueues it so it's drawn to the screen * when the drawing queue is processed. * * If Buffering is enabled, the DrawQueue item will be automatically placed * on its corresponding queue. * If Buffering is disabled, the DrawQueue item will be processed immediately * and drawn to the screen. * * This function is called from all the Widget Drawing methods. */ void queueDD(DrawData type, const Common::Rect &r, uint32 dynamic = 0, bool restore = false); void queueDDText(TextData type, const Common::Rect &r, const Common::String &text, bool restoreBg, bool elipsis, Graphics::TextAlign alignH = Graphics::kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0); void queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha); /** * DEBUG: Draws a white square and writes some text next to it. */ void debugWidgetPosition(const char *name, const Common::Rect &r); public: struct ThemeDescriptor { Common::String name; Common::String id; Common::String filename; }; /** * Lists all theme files useable. */ static void listUsableThemes(Common::List &list); private: static bool themeConfigUsable(const Common::FSNode &node, Common::String &themeName); static bool themeConfigParseHeader(Common::String header, Common::String &themeName); static Common::String getThemeFile(const Common::String &id); static Common::String getThemeId(const Common::String &filename); static void listUsableThemes(Common::FSNode node, Common::List &list, int depth=-1); protected: OSystem *_system; /** Global system object. */ /** Vector Renderer object, does the actual drawing on screen */ Graphics::VectorRenderer *_vectorRenderer; /** XML Parser, does the Theme parsing instead of the default parser */ GUI::ThemeParser *_parser; /** Theme getEvaluator (changed from GUI::Eval to add functionality) */ GUI::ThemeEval *_themeEval; /** Main screen surface. This is blitted straight into the overlay. */ Graphics::Surface _screen; /** Backbuffer surface. Stores previous states of the screen to blit back */ Graphics::Surface _backBuffer; /** Sets whether the current drawing is being buffered (stored for later processing) or drawn directly to the screen. */ bool _buffering; /** Bytes per pixel of the Active Drawing Surface (i.e. the screen) */ int _bytesPerPixel; /** Current graphics mode */ GraphicsMode _graphicsMode; /** Font info. */ Common::String _fontName; const Graphics::Font *_font; /** * Array of all the DrawData elements than can be drawn to the screen. * Must be full so the renderer can work. */ WidgetDrawData *_widgets[kDrawDataMAX]; /** Array of all the text fonts that can be drawn. */ TextDrawData *_texts[kTextDataMAX]; ImagesMap _bitmaps; Graphics::PixelFormat _overlayFormat; #ifdef ENABLE_16BIT Graphics::PixelFormat _cursorFormat; #endif /** List of all the dirty screens that must be blitted to the overlay. */ Common::List _dirtyScreen; /** Queue with all the drawing that must be done to the Back Buffer */ Common::List _bufferQueue; /** Queue with all the drawing that must be done to the screen */ Common::List _screenQueue; bool _initOk; //!< Class and renderer properly initialized bool _themeOk; //!< Theme data successfully loaded. bool _enabled; //!< Whether the Theme is currently shown on the overlay Common::String _themeName; //!< Name of the currently loaded theme Common::String _themeId; Common::String _themeFile; Common::Archive *_themeArchive; bool _useCursor; int _cursorHotspotX, _cursorHotspotY; int _cursorTargetScale; enum { MAX_CURS_COLORS = 255 }; byte *_cursor; bool _needPaletteUpdates; uint _cursorWidth, _cursorHeight; byte _cursorPal[4*MAX_CURS_COLORS]; byte _cursorPalSize; }; } // end of namespace GUI. #endif