| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- // ================================================================================
- // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
- // == See tb_core.h for more information. ==
- // ================================================================================
- #ifndef TB_SKIN_H
- #define TB_SKIN_H
- #include "tb_core.h"
- #include "tb_renderer.h"
- #include "tb_bitmap_fragment.h"
- #include "tb_hashtable.h"
- #include "tb_linklist.h"
- #include "tb_dimension.h"
- #include "tb_value.h"
- namespace tb {
- class TBNode;
- class TBSkinConditionContext;
- /** Used for some values in TBSkinElement if they has not been specified in the skin. */
- #define SKIN_VALUE_NOT_SPECIFIED TB_INVALID_DIMENSION
- /** Skin state types (may be combined).
- NOTE: This should exactly match WIDGET_STATE in tb_widgets.h! */
- enum SKIN_STATE {
- SKIN_STATE_NONE = 0,
- SKIN_STATE_DISABLED = 1,
- SKIN_STATE_FOCUSED = 2,
- SKIN_STATE_PRESSED = 4,
- SKIN_STATE_SELECTED = 8,
- SKIN_STATE_HOVERED = 16,
- SKIN_STATE_ALL = SKIN_STATE_DISABLED |
- SKIN_STATE_FOCUSED |
- SKIN_STATE_PRESSED |
- SKIN_STATE_SELECTED |
- SKIN_STATE_HOVERED
- };
- MAKE_ENUM_FLAG_COMBO(SKIN_STATE);
- /** Type of painting that should be done for a TBSkinElement. */
- enum SKIN_ELEMENT_TYPE {
- SKIN_ELEMENT_TYPE_STRETCH_BOX,
- SKIN_ELEMENT_TYPE_STRETCH_BORDER,
- SKIN_ELEMENT_TYPE_STRETCH_IMAGE,
- SKIN_ELEMENT_TYPE_TILE,
- SKIN_ELEMENT_TYPE_IMAGE
- };
- /** TBSkinCondition checks if a condition is true for a given TBSkinConditionContext.
- This is used to apply different state elements depending on what is currently
- painting the skin. */
- class TBSkinCondition : public TBLinkOf<TBSkinCondition>
- {
- public:
- /** Defines which target(s) relative to the context that should be tested for the condition. */
- enum TARGET {
- TARGET_THIS, ///< The object painting the skin.
- TARGET_PARENT, ///< The parent of the object painting the skin.
- TARGET_ANCESTORS, ///< All ancestors of the object painting the skin.
- TARGET_PREV_SIBLING, ///< The previous sibling of the object painting the skin.
- TARGET_NEXT_SIBLING ///< The next sibling of the object painting the skin.
- };
- /** Defines which property in the context that should be checked. */
- enum PROPERTY {
- PROPERTY_SKIN, ///< The background skin id.
- PROPERTY_WINDOW_ACTIVE, ///< The window is active (no value required).
- PROPERTY_AXIS, ///< The axis of the content (x or y)
- PROPERTY_ALIGN, ///< The alignment.
- PROPERTY_ID, ///< The id.
- PROPERTY_STATE, ///< The state is set.
- PROPERTY_VALUE, ///< The current value (integer).
- PROPERTY_HOVER, ///< Focus is on the target or any child (no value required).
- PROPERTY_CAPTURE, ///< Capture is on the target or any child (no value required).
- PROPERTY_FOCUS, ///< Focus is on the target or any child (no value required).
- PROPERTY_CUSTOM ///< It's a property unknown to skin, that the TBSkinConditionContext might know about.
- };
- /** Defines if the condition tested should be equal or not for the condition to be true. */
- enum TEST {
- TEST_EQUAL, ///< Value should be equal for condition to be true.
- TEST_NOT_EQUAL ///< Value should not be equal for condition to be true.
- };
- /** Stores the information needed for checking a condition. */
- struct CONDITION_INFO {
- PROPERTY prop; ///< Which property.
- TBID custom_prop; ///< Which property (only if prop is PROPERTY_CUSTOM).
- TBID value; ///< The value to compare.
- };
- TBSkinCondition(TARGET target, PROPERTY prop, const TBID &custom_prop, const TBID &value, TEST test);
- /** Return true if the condition is true for the given context. */
- bool GetCondition(TBSkinConditionContext &context) const;
- private:
- TARGET m_target;
- CONDITION_INFO m_info;
- TEST m_test;
- };
- /** TBSkinConditionContext checks if a condition is true. It is passed to skin painting functions
- so different state elements can be applied depending on the current situation of the context.
- F.ex a widget may change appearance if it's under a parent with a certain skin. */
- class TBSkinConditionContext
- {
- public:
- /** Return true if the given target and property equals the given value. */
- virtual bool GetCondition(TBSkinCondition::TARGET target, const TBSkinCondition::CONDITION_INFO &info) = 0;
- };
- /** TBSkinElementState has a skin element id that should be used if its state and condition
- matches that which is being painted.
- */
- class TBSkinElementState : public TBLinkOf<TBSkinElementState>
- {
- public:
- /** Defines how to match states. */
- enum MATCH_RULE {
- /** States with "all" (SKIN_STATE_ALL) will also be considered a match. */
- MATCH_RULE_DEFAULT,
- /** States with "all" will not be considered a match. */
- MATCH_RULE_ONLY_SPECIFIC_STATE
- };
- bool IsMatch(SKIN_STATE state, TBSkinConditionContext &context,
- MATCH_RULE rule = MATCH_RULE_DEFAULT) const;
- bool IsExactMatch(SKIN_STATE state, TBSkinConditionContext &context,
- MATCH_RULE rule = MATCH_RULE_DEFAULT) const;
- TBID element_id;
- SKIN_STATE state;
- TBLinkListAutoDeleteOf<TBSkinCondition> conditions;
- };
- /** List of state elements in a TBSkinElement. */
- class TBSkinElementStateList
- {
- public:
- ~TBSkinElementStateList();
- TBSkinElementState *GetStateElement(SKIN_STATE state, TBSkinConditionContext &context,
- TBSkinElementState::MATCH_RULE rule = TBSkinElementState::MATCH_RULE_DEFAULT) const;
- TBSkinElementState *GetStateElementExactMatch(SKIN_STATE state, TBSkinConditionContext &context,
- TBSkinElementState::MATCH_RULE rule = TBSkinElementState::MATCH_RULE_DEFAULT) const;
- bool HasStateElements() const { return m_state_elements.HasLinks(); }
- const TBSkinElementState *GetFirstElement() const { return m_state_elements.GetFirst(); }
- void Load(TBNode *n);
- private:
- TBLinkListOf<TBSkinElementState> m_state_elements;
- };
- /** Skin element.
- Contains a bitmap fragment (or nullptr) and info specifying how it should be painted.
- Also contains padding and other look-specific widget properties. */
- class TBSkinElement
- {
- public:
- TBSkinElement();
- ~TBSkinElement();
- // Skin properties
- TBID id; ///< ID of the skin element
- TBStr name; ///< Name of the skin element, f.ex "TBSelectDropdown.arrow"
- TBStr bitmap_file; ///< File name of the bitmap (might be empty)
- TBBitmapFragment *bitmap;///< Bitmap fragment containing the graphics, or nullptr.
- uint8 cut; ///< How the bitmap should be sliced using StretchBox.
- int16 expand; ///< How much the skin should expand outside the widgets rect.
- SKIN_ELEMENT_TYPE type;///< Skin element type
- bool is_painting; ///< If the skin is being painted (avoiding eternal recursing)
- bool is_getting; ///< If the skin is being got (avoiding eternal recursion)
- int16 padding_left; ///< Left padding for any content in the element
- int16 padding_top; ///< Top padding for any content in the element
- int16 padding_right; ///< Right padding for any content in the element
- int16 padding_bottom; ///< Bottom padding for any content in the element
- int16 width; ///< Intrinsic width or SKIN_VALUE_NOT_SPECIFIED
- int16 height; ///< Intrinsic height or SKIN_VALUE_NOT_SPECIFIED
- int16 pref_width; ///< Preferred width or SKIN_VALUE_NOT_SPECIFIED
- int16 pref_height; ///< Preferred height or SKIN_VALUE_NOT_SPECIFIED
- int16 min_width; ///< Minimum width or SKIN_VALUE_NOT_SPECIFIED
- int16 min_height; ///< Minimum height or SKIN_VALUE_NOT_SPECIFIED
- int16 max_width; ///< Maximum width or SKIN_VALUE_NOT_SPECIFIED
- int16 max_height; ///< Maximum height or SKIN_VALUE_NOT_SPECIFIED
- int16 spacing; ///< Spacing used on layout or SKIN_VALUE_NOT_SPECIFIED.
- int16 content_ofs_x; ///< X offset of the content in the widget.
- int16 content_ofs_y; ///< Y offset of the content in the widget.
- int16 img_ofs_x; ///< X offset for type image. Relative to image position (img_position_x).
- int16 img_ofs_y; ///< Y offset for type image. Relative to image position (img_position_y).
- int8 img_position_x; ///< Horizontal position for type image. 0-100 (left to
- ///< right in available space). Default 50.
- int8 img_position_y; ///< Vertical position for type image. 0-100 (top to bottom
- ///< in available space). Default 50.
- int8 flip_x; ///< The skin is flipped horizontally
- int8 flip_y; ///< The skin is flipped vertically
- float opacity; ///< Opacity that should be used for the whole widget (0.f - 1.f).
- TBColor text_color; ///< Color of the text in the widget.
- TBColor bg_color; ///< Color of the background in the widget.
- int16 bitmap_dpi; ///< The DPI of the bitmap that was loaded.
- TBValue tag; ///< This value is free to use for anything. It's not used internally.
- /** Get the minimum width, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
- int GetMinWidth() const { return min_width; }
- /** Get the minimum height, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
- int GetMinHeight() const { return min_height; }
- /** Get the intrinsic minimum width. It will be calculated based on the skin properties. */
- int GetIntrinsicMinWidth() const;
- /** Get the intrinsic minimum height. It will be calculated based on the skin properties. */
- int GetIntrinsicMinHeight() const;
- /** Get the maximum width, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
- int GetMaxWidth() const { return max_width; }
- /** Get the maximum height, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
- int GetMaxHeight() const { return max_height; }
- /** Get the preferred width, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
- int GetPrefWidth() const { return pref_width; }
- /** Get the preferred height, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
- int GetPrefHeight() const { return pref_height; }
- /** Get the intrinsic width. If not specified using the "width" attribute, it will be
- calculated based on the skin properties. If it can't be calculated it will return
- SKIN_VALUE_NOT_SPECIFIED. */
- int GetIntrinsicWidth() const;
- /** Get the intrinsic height. If not specified using the "height" attribute, it will be
- calculated based on the skin properties. If it can't be calculated it will return
- SKIN_VALUE_NOT_SPECIFIED. */
- int GetIntrinsicHeight() const;
- /** Set the DPI that the bitmap was loaded in. This may modify properties
- to compensate for the bitmap resolution. */
- void SetBitmapDPI(const TBDimensionConverter &dim_conv, int bitmap_dpi);
- /** List of override elements (See TBSkin::PaintSkin) */
- TBSkinElementStateList m_override_elements;
- /** List of strong-override elements (See TBSkin::PaintSkin) */
- TBSkinElementStateList m_strong_override_elements;
- /** List of child elements (See TBSkin::PaintSkin) */
- TBSkinElementStateList m_child_elements;
- /** List of overlay elements (See TBSkin::PaintSkin) */
- TBSkinElementStateList m_overlay_elements;
- /** Check if there's a exact or partial match for the given state in either
- override, child or overlay element list.
- State elements with state "all" will be ignored. */
- bool HasState(SKIN_STATE state, TBSkinConditionContext &context);
- /** Return true if this element has overlay elements. */
- bool HasOverlayElements() const { return m_overlay_elements.HasStateElements(); }
- void Load(TBNode *n, TBSkin *skin, const char *skin_path);
- };
- class TBSkinListener
- {
- public:
- /** Called when a skin element has been loaded from the given TBNode.
- NOTE: This may be called multiple times on elements that occur multiple times
- in the skin or is overridden in an override skin.
- This method can be used to f.ex feed custom properties into element->tag. */
- virtual void OnSkinElementLoaded(TBSkin *skin, TBSkinElement *element, TBNode *node) = 0;
- };
- /** TBSkin contains a list of TBSkinElement. */
- class TBSkin : private TBRendererListener
- {
- public:
- TBSkin();
- virtual ~TBSkin();
- /** Set the listener for this skin. */
- void SetListener(TBSkinListener *listener) { m_listener = listener; }
- TBSkinListener *GetListener() const { return m_listener; }
- /** Load the skin file and the bitmaps it refers to.
- If override_skin_file is specified, it will also be loaded into this skin after
- loading skin_file. Elements using the same name will override any previosly
- read data for the same element. Known limitation: Clone can currently only
- clone elements in the same file!
- Returns true on success, and all bitmaps referred to also loaded successfully. */
- bool Load(const char *skin_file, const char *override_skin_file = nullptr);
- /** Unload all bitmaps used in this skin. */
- void UnloadBitmaps();
- /** Reload all bitmaps used in this skin. Calls UnloadBitmaps first to ensure no bitmaps
- are loaded before loading new ones. */
- bool ReloadBitmaps();
- /** Get the dimension converter used for the current skin. This dimension converter
- converts to px by the same factor as the skin (based on the skin DPI settings). */
- const TBDimensionConverter *GetDimensionConverter() const { return &m_dim_conv; }
- /** Get the skin element with the given id.
- Returns nullptr if there's no match. */
- TBSkinElement *GetSkinElement(const TBID &skin_id) const;
- /** Get the skin element with the given id and state.
- This is like calling GetSkinElement and also following any strong overrides that
- match the current state (if any). See details about strong overrides in PaintSkin.
- Returns nullptr if there's no match. */
- TBSkinElement *GetSkinElementStrongOverride(const TBID &skin_id, SKIN_STATE state, TBSkinConditionContext &context) const;
- /** Get the default text color for all skin elements */
- TBColor GetDefaultTextColor() const { return m_default_text_color; }
- /** Get the default disabled opacity for all skin elements */
- float GetDefaultDisabledOpacity() const { return m_default_disabled_opacity; }
- /** Get the default placeholder opacity for all skin elements */
- float GetDefaultPlaceholderOpacity() const { return m_default_placeholder_opacity; }
- /** Get the default layout spacing in pixels. */
- int GetDefaultSpacing() const { return m_default_spacing; }
- /** Paint the skin at dst_rect.
- Strong override elements:
- -Strong override elements are like override elements, but they don't only apply
- when painting. They also override padding and other things that might affect
- the layout of the widget having the skin set.
- Override elements:
- -If there is a override element with the exact matching state, it will paint
- the override *instead* if the base skin. If no exact match was found, it will
- check for a partial match and paint that *instead* of the base skin.
- Child elements:
- -It will paint *all* child elements that match the current state ("all" can be specified
- as state so it will always be painted). The elements are painted in the order they are
- specified in the skin.
- Special elements:
- -There's some special generic skin elements used by TBWidget (see TBWidget::SetSkinBg)
- Overlay elements:
- -Overlay elements are painted separately, from PaintSkinOverlay (when all sibling
- widgets has been painted). As with child elements, all overlay elements that match
- the current state will be painted in the order they are specified in the skin.
- Return the skin element used (after following override elements),
- or nullptr if no skin element was found matching the skin_id. */
- TBSkinElement *PaintSkin(const TBRect &dst_rect, const TBID &skin_id, SKIN_STATE state, TBSkinConditionContext &context);
- /** Paint the skin at dst_rect. Just like the PaintSkin above, but takes a specific
- skin element instead of looking it up from the id. */
- TBSkinElement *PaintSkin(const TBRect &dst_rect, TBSkinElement *element, SKIN_STATE state, TBSkinConditionContext &context);
- /** Paint the overlay elements for the given skin element and state. */
- void PaintSkinOverlay(const TBRect &dst_rect, TBSkinElement *element, SKIN_STATE state, TBSkinConditionContext &context);
- #ifdef TB_RUNTIME_DEBUG_INFO
- /** Render the skin bitmaps on screen, to analyze fragment positioning. */
- void Debug();
- #endif
- // Implementing TBRendererListener
- virtual void OnContextLost();
- virtual void OnContextRestored();
- private:
- friend class TBSkinElement;
- TBSkinListener *m_listener;
- TBHashTableAutoDeleteOf<TBSkinElement> m_elements; ///< All skin elements for this skin.
- TBBitmapFragmentManager m_frag_manager; ///< Fragment manager
- TBDimensionConverter m_dim_conv; ///< Dimension converter
- TBColor m_default_text_color; ///< Default text color for all skin elements
- float m_default_disabled_opacity; ///< Disabled opacity
- float m_default_placeholder_opacity; ///< Placeholder opacity
- int16 m_default_spacing; ///< Default layout spacing
- bool LoadInternal(const char *skin_file);
- bool ReloadBitmapsInternal();
- void PaintElement(const TBRect &dst_rect, TBSkinElement *element);
- void PaintElementBGColor(const TBRect &dst_rect, TBSkinElement *element);
- void PaintElementImage(const TBRect &dst_rect, TBSkinElement *element);
- void PaintElementTile(const TBRect &dst_rect, TBSkinElement *element);
- void PaintElementStretchImage(const TBRect &dst_rect, TBSkinElement *element);
- void PaintElementStretchBox(const TBRect &dst_rect, TBSkinElement *element, bool fill_center);
- TBRect GetFlippedRect(const TBRect &src_rect, TBSkinElement *element) const;
- int GetPxFromNode(TBNode *node, int def_value) const;
- };
- }; // namespace tb
- #endif // TB_SKIN_H
|