tb_skin.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #ifndef TB_SKIN_H
  6. #define TB_SKIN_H
  7. #include "tb_core.h"
  8. #include "tb_renderer.h"
  9. #include "tb_bitmap_fragment.h"
  10. #include "tb_hashtable.h"
  11. #include "tb_linklist.h"
  12. #include "tb_dimension.h"
  13. #include "tb_value.h"
  14. namespace tb {
  15. class TBNode;
  16. class TBSkinConditionContext;
  17. /** Used for some values in TBSkinElement if they has not been specified in the skin. */
  18. #define SKIN_VALUE_NOT_SPECIFIED TB_INVALID_DIMENSION
  19. /** Skin state types (may be combined).
  20. NOTE: This should exactly match WIDGET_STATE in tb_widgets.h! */
  21. enum SKIN_STATE {
  22. SKIN_STATE_NONE = 0,
  23. SKIN_STATE_DISABLED = 1,
  24. SKIN_STATE_FOCUSED = 2,
  25. SKIN_STATE_PRESSED = 4,
  26. SKIN_STATE_SELECTED = 8,
  27. SKIN_STATE_HOVERED = 16,
  28. SKIN_STATE_ALL = SKIN_STATE_DISABLED |
  29. SKIN_STATE_FOCUSED |
  30. SKIN_STATE_PRESSED |
  31. SKIN_STATE_SELECTED |
  32. SKIN_STATE_HOVERED
  33. };
  34. MAKE_ENUM_FLAG_COMBO(SKIN_STATE);
  35. /** Type of painting that should be done for a TBSkinElement. */
  36. enum SKIN_ELEMENT_TYPE {
  37. SKIN_ELEMENT_TYPE_STRETCH_BOX,
  38. SKIN_ELEMENT_TYPE_STRETCH_BORDER,
  39. SKIN_ELEMENT_TYPE_STRETCH_IMAGE,
  40. SKIN_ELEMENT_TYPE_TILE,
  41. SKIN_ELEMENT_TYPE_IMAGE
  42. };
  43. /** TBSkinCondition checks if a condition is true for a given TBSkinConditionContext.
  44. This is used to apply different state elements depending on what is currently
  45. painting the skin. */
  46. class TBSkinCondition : public TBLinkOf<TBSkinCondition>
  47. {
  48. public:
  49. /** Defines which target(s) relative to the context that should be tested for the condition. */
  50. enum TARGET {
  51. TARGET_THIS, ///< The object painting the skin.
  52. TARGET_PARENT, ///< The parent of the object painting the skin.
  53. TARGET_ANCESTORS, ///< All ancestors of the object painting the skin.
  54. TARGET_PREV_SIBLING, ///< The previous sibling of the object painting the skin.
  55. TARGET_NEXT_SIBLING ///< The next sibling of the object painting the skin.
  56. };
  57. /** Defines which property in the context that should be checked. */
  58. enum PROPERTY {
  59. PROPERTY_SKIN, ///< The background skin id.
  60. PROPERTY_WINDOW_ACTIVE, ///< The window is active (no value required).
  61. PROPERTY_AXIS, ///< The axis of the content (x or y)
  62. PROPERTY_ALIGN, ///< The alignment.
  63. PROPERTY_ID, ///< The id.
  64. PROPERTY_STATE, ///< The state is set.
  65. PROPERTY_VALUE, ///< The current value (integer).
  66. PROPERTY_HOVER, ///< Focus is on the target or any child (no value required).
  67. PROPERTY_CAPTURE, ///< Capture is on the target or any child (no value required).
  68. PROPERTY_FOCUS, ///< Focus is on the target or any child (no value required).
  69. PROPERTY_CUSTOM ///< It's a property unknown to skin, that the TBSkinConditionContext might know about.
  70. };
  71. /** Defines if the condition tested should be equal or not for the condition to be true. */
  72. enum TEST {
  73. TEST_EQUAL, ///< Value should be equal for condition to be true.
  74. TEST_NOT_EQUAL ///< Value should not be equal for condition to be true.
  75. };
  76. /** Stores the information needed for checking a condition. */
  77. struct CONDITION_INFO {
  78. PROPERTY prop; ///< Which property.
  79. TBID custom_prop; ///< Which property (only if prop is PROPERTY_CUSTOM).
  80. TBID value; ///< The value to compare.
  81. };
  82. TBSkinCondition(TARGET target, PROPERTY prop, const TBID &custom_prop, const TBID &value, TEST test);
  83. /** Return true if the condition is true for the given context. */
  84. bool GetCondition(TBSkinConditionContext &context) const;
  85. private:
  86. TARGET m_target;
  87. CONDITION_INFO m_info;
  88. TEST m_test;
  89. };
  90. /** TBSkinConditionContext checks if a condition is true. It is passed to skin painting functions
  91. so different state elements can be applied depending on the current situation of the context.
  92. F.ex a widget may change appearance if it's under a parent with a certain skin. */
  93. class TBSkinConditionContext
  94. {
  95. public:
  96. /** Return true if the given target and property equals the given value. */
  97. virtual bool GetCondition(TBSkinCondition::TARGET target, const TBSkinCondition::CONDITION_INFO &info) = 0;
  98. };
  99. /** TBSkinElementState has a skin element id that should be used if its state and condition
  100. matches that which is being painted.
  101. */
  102. class TBSkinElementState : public TBLinkOf<TBSkinElementState>
  103. {
  104. public:
  105. /** Defines how to match states. */
  106. enum MATCH_RULE {
  107. /** States with "all" (SKIN_STATE_ALL) will also be considered a match. */
  108. MATCH_RULE_DEFAULT,
  109. /** States with "all" will not be considered a match. */
  110. MATCH_RULE_ONLY_SPECIFIC_STATE
  111. };
  112. bool IsMatch(SKIN_STATE state, TBSkinConditionContext &context,
  113. MATCH_RULE rule = MATCH_RULE_DEFAULT) const;
  114. bool IsExactMatch(SKIN_STATE state, TBSkinConditionContext &context,
  115. MATCH_RULE rule = MATCH_RULE_DEFAULT) const;
  116. TBID element_id;
  117. SKIN_STATE state;
  118. TBLinkListAutoDeleteOf<TBSkinCondition> conditions;
  119. };
  120. /** List of state elements in a TBSkinElement. */
  121. class TBSkinElementStateList
  122. {
  123. public:
  124. ~TBSkinElementStateList();
  125. TBSkinElementState *GetStateElement(SKIN_STATE state, TBSkinConditionContext &context,
  126. TBSkinElementState::MATCH_RULE rule = TBSkinElementState::MATCH_RULE_DEFAULT) const;
  127. TBSkinElementState *GetStateElementExactMatch(SKIN_STATE state, TBSkinConditionContext &context,
  128. TBSkinElementState::MATCH_RULE rule = TBSkinElementState::MATCH_RULE_DEFAULT) const;
  129. bool HasStateElements() const { return m_state_elements.HasLinks(); }
  130. const TBSkinElementState *GetFirstElement() const { return m_state_elements.GetFirst(); }
  131. void Load(TBNode *n);
  132. private:
  133. TBLinkListOf<TBSkinElementState> m_state_elements;
  134. };
  135. /** Skin element.
  136. Contains a bitmap fragment (or nullptr) and info specifying how it should be painted.
  137. Also contains padding and other look-specific widget properties. */
  138. class TBSkinElement
  139. {
  140. public:
  141. TBSkinElement();
  142. ~TBSkinElement();
  143. // Skin properties
  144. TBID id; ///< ID of the skin element
  145. TBStr name; ///< Name of the skin element, f.ex "TBSelectDropdown.arrow"
  146. TBStr bitmap_file; ///< File name of the bitmap (might be empty)
  147. TBBitmapFragment *bitmap;///< Bitmap fragment containing the graphics, or nullptr.
  148. uint8 cut; ///< How the bitmap should be sliced using StretchBox.
  149. int16 expand; ///< How much the skin should expand outside the widgets rect.
  150. SKIN_ELEMENT_TYPE type;///< Skin element type
  151. bool is_painting; ///< If the skin is being painted (avoiding eternal recursing)
  152. bool is_getting; ///< If the skin is being got (avoiding eternal recursion)
  153. int16 padding_left; ///< Left padding for any content in the element
  154. int16 padding_top; ///< Top padding for any content in the element
  155. int16 padding_right; ///< Right padding for any content in the element
  156. int16 padding_bottom; ///< Bottom padding for any content in the element
  157. int16 width; ///< Intrinsic width or SKIN_VALUE_NOT_SPECIFIED
  158. int16 height; ///< Intrinsic height or SKIN_VALUE_NOT_SPECIFIED
  159. int16 pref_width; ///< Preferred width or SKIN_VALUE_NOT_SPECIFIED
  160. int16 pref_height; ///< Preferred height or SKIN_VALUE_NOT_SPECIFIED
  161. int16 min_width; ///< Minimum width or SKIN_VALUE_NOT_SPECIFIED
  162. int16 min_height; ///< Minimum height or SKIN_VALUE_NOT_SPECIFIED
  163. int16 max_width; ///< Maximum width or SKIN_VALUE_NOT_SPECIFIED
  164. int16 max_height; ///< Maximum height or SKIN_VALUE_NOT_SPECIFIED
  165. int16 spacing; ///< Spacing used on layout or SKIN_VALUE_NOT_SPECIFIED.
  166. int16 content_ofs_x; ///< X offset of the content in the widget.
  167. int16 content_ofs_y; ///< Y offset of the content in the widget.
  168. int16 img_ofs_x; ///< X offset for type image. Relative to image position (img_position_x).
  169. int16 img_ofs_y; ///< Y offset for type image. Relative to image position (img_position_y).
  170. int8 img_position_x; ///< Horizontal position for type image. 0-100 (left to
  171. ///< right in available space). Default 50.
  172. int8 img_position_y; ///< Vertical position for type image. 0-100 (top to bottom
  173. ///< in available space). Default 50.
  174. int8 flip_x; ///< The skin is flipped horizontally
  175. int8 flip_y; ///< The skin is flipped vertically
  176. float opacity; ///< Opacity that should be used for the whole widget (0.f - 1.f).
  177. TBColor text_color; ///< Color of the text in the widget.
  178. TBColor bg_color; ///< Color of the background in the widget.
  179. int16 bitmap_dpi; ///< The DPI of the bitmap that was loaded.
  180. TBValue tag; ///< This value is free to use for anything. It's not used internally.
  181. /** Get the minimum width, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
  182. int GetMinWidth() const { return min_width; }
  183. /** Get the minimum height, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
  184. int GetMinHeight() const { return min_height; }
  185. /** Get the intrinsic minimum width. It will be calculated based on the skin properties. */
  186. int GetIntrinsicMinWidth() const;
  187. /** Get the intrinsic minimum height. It will be calculated based on the skin properties. */
  188. int GetIntrinsicMinHeight() const;
  189. /** Get the maximum width, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
  190. int GetMaxWidth() const { return max_width; }
  191. /** Get the maximum height, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
  192. int GetMaxHeight() const { return max_height; }
  193. /** Get the preferred width, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
  194. int GetPrefWidth() const { return pref_width; }
  195. /** Get the preferred height, or SKIN_VALUE_NOT_SPECIFIED if not specified. */
  196. int GetPrefHeight() const { return pref_height; }
  197. /** Get the intrinsic width. If not specified using the "width" attribute, it will be
  198. calculated based on the skin properties. If it can't be calculated it will return
  199. SKIN_VALUE_NOT_SPECIFIED. */
  200. int GetIntrinsicWidth() const;
  201. /** Get the intrinsic height. If not specified using the "height" attribute, it will be
  202. calculated based on the skin properties. If it can't be calculated it will return
  203. SKIN_VALUE_NOT_SPECIFIED. */
  204. int GetIntrinsicHeight() const;
  205. /** Set the DPI that the bitmap was loaded in. This may modify properties
  206. to compensate for the bitmap resolution. */
  207. void SetBitmapDPI(const TBDimensionConverter &dim_conv, int bitmap_dpi);
  208. /** List of override elements (See TBSkin::PaintSkin) */
  209. TBSkinElementStateList m_override_elements;
  210. /** List of strong-override elements (See TBSkin::PaintSkin) */
  211. TBSkinElementStateList m_strong_override_elements;
  212. /** List of child elements (See TBSkin::PaintSkin) */
  213. TBSkinElementStateList m_child_elements;
  214. /** List of overlay elements (See TBSkin::PaintSkin) */
  215. TBSkinElementStateList m_overlay_elements;
  216. /** Check if there's a exact or partial match for the given state in either
  217. override, child or overlay element list.
  218. State elements with state "all" will be ignored. */
  219. bool HasState(SKIN_STATE state, TBSkinConditionContext &context);
  220. /** Return true if this element has overlay elements. */
  221. bool HasOverlayElements() const { return m_overlay_elements.HasStateElements(); }
  222. void Load(TBNode *n, TBSkin *skin, const char *skin_path);
  223. };
  224. class TBSkinListener
  225. {
  226. public:
  227. /** Called when a skin element has been loaded from the given TBNode.
  228. NOTE: This may be called multiple times on elements that occur multiple times
  229. in the skin or is overridden in an override skin.
  230. This method can be used to f.ex feed custom properties into element->tag. */
  231. virtual void OnSkinElementLoaded(TBSkin *skin, TBSkinElement *element, TBNode *node) = 0;
  232. };
  233. /** TBSkin contains a list of TBSkinElement. */
  234. class TBSkin : private TBRendererListener
  235. {
  236. public:
  237. TBSkin();
  238. virtual ~TBSkin();
  239. /** Set the listener for this skin. */
  240. void SetListener(TBSkinListener *listener) { m_listener = listener; }
  241. TBSkinListener *GetListener() const { return m_listener; }
  242. /** Load the skin file and the bitmaps it refers to.
  243. If override_skin_file is specified, it will also be loaded into this skin after
  244. loading skin_file. Elements using the same name will override any previosly
  245. read data for the same element. Known limitation: Clone can currently only
  246. clone elements in the same file!
  247. Returns true on success, and all bitmaps referred to also loaded successfully. */
  248. bool Load(const char *skin_file, const char *override_skin_file = nullptr);
  249. /** Unload all bitmaps used in this skin. */
  250. void UnloadBitmaps();
  251. /** Reload all bitmaps used in this skin. Calls UnloadBitmaps first to ensure no bitmaps
  252. are loaded before loading new ones. */
  253. bool ReloadBitmaps();
  254. /** Get the dimension converter used for the current skin. This dimension converter
  255. converts to px by the same factor as the skin (based on the skin DPI settings). */
  256. const TBDimensionConverter *GetDimensionConverter() const { return &m_dim_conv; }
  257. /** Get the skin element with the given id.
  258. Returns nullptr if there's no match. */
  259. TBSkinElement *GetSkinElement(const TBID &skin_id) const;
  260. /** Get the skin element with the given id and state.
  261. This is like calling GetSkinElement and also following any strong overrides that
  262. match the current state (if any). See details about strong overrides in PaintSkin.
  263. Returns nullptr if there's no match. */
  264. TBSkinElement *GetSkinElementStrongOverride(const TBID &skin_id, SKIN_STATE state, TBSkinConditionContext &context) const;
  265. /** Get the default text color for all skin elements */
  266. TBColor GetDefaultTextColor() const { return m_default_text_color; }
  267. /** Get the default disabled opacity for all skin elements */
  268. float GetDefaultDisabledOpacity() const { return m_default_disabled_opacity; }
  269. /** Get the default placeholder opacity for all skin elements */
  270. float GetDefaultPlaceholderOpacity() const { return m_default_placeholder_opacity; }
  271. /** Get the default layout spacing in pixels. */
  272. int GetDefaultSpacing() const { return m_default_spacing; }
  273. /** Paint the skin at dst_rect.
  274. Strong override elements:
  275. -Strong override elements are like override elements, but they don't only apply
  276. when painting. They also override padding and other things that might affect
  277. the layout of the widget having the skin set.
  278. Override elements:
  279. -If there is a override element with the exact matching state, it will paint
  280. the override *instead* if the base skin. If no exact match was found, it will
  281. check for a partial match and paint that *instead* of the base skin.
  282. Child elements:
  283. -It will paint *all* child elements that match the current state ("all" can be specified
  284. as state so it will always be painted). The elements are painted in the order they are
  285. specified in the skin.
  286. Special elements:
  287. -There's some special generic skin elements used by TBWidget (see TBWidget::SetSkinBg)
  288. Overlay elements:
  289. -Overlay elements are painted separately, from PaintSkinOverlay (when all sibling
  290. widgets has been painted). As with child elements, all overlay elements that match
  291. the current state will be painted in the order they are specified in the skin.
  292. Return the skin element used (after following override elements),
  293. or nullptr if no skin element was found matching the skin_id. */
  294. TBSkinElement *PaintSkin(const TBRect &dst_rect, const TBID &skin_id, SKIN_STATE state, TBSkinConditionContext &context);
  295. /** Paint the skin at dst_rect. Just like the PaintSkin above, but takes a specific
  296. skin element instead of looking it up from the id. */
  297. TBSkinElement *PaintSkin(const TBRect &dst_rect, TBSkinElement *element, SKIN_STATE state, TBSkinConditionContext &context);
  298. /** Paint the overlay elements for the given skin element and state. */
  299. void PaintSkinOverlay(const TBRect &dst_rect, TBSkinElement *element, SKIN_STATE state, TBSkinConditionContext &context);
  300. #ifdef TB_RUNTIME_DEBUG_INFO
  301. /** Render the skin bitmaps on screen, to analyze fragment positioning. */
  302. void Debug();
  303. #endif
  304. // Implementing TBRendererListener
  305. virtual void OnContextLost();
  306. virtual void OnContextRestored();
  307. private:
  308. friend class TBSkinElement;
  309. TBSkinListener *m_listener;
  310. TBHashTableAutoDeleteOf<TBSkinElement> m_elements; ///< All skin elements for this skin.
  311. TBBitmapFragmentManager m_frag_manager; ///< Fragment manager
  312. TBDimensionConverter m_dim_conv; ///< Dimension converter
  313. TBColor m_default_text_color; ///< Default text color for all skin elements
  314. float m_default_disabled_opacity; ///< Disabled opacity
  315. float m_default_placeholder_opacity; ///< Placeholder opacity
  316. int16 m_default_spacing; ///< Default layout spacing
  317. bool LoadInternal(const char *skin_file);
  318. bool ReloadBitmapsInternal();
  319. void PaintElement(const TBRect &dst_rect, TBSkinElement *element);
  320. void PaintElementBGColor(const TBRect &dst_rect, TBSkinElement *element);
  321. void PaintElementImage(const TBRect &dst_rect, TBSkinElement *element);
  322. void PaintElementTile(const TBRect &dst_rect, TBSkinElement *element);
  323. void PaintElementStretchImage(const TBRect &dst_rect, TBSkinElement *element);
  324. void PaintElementStretchBox(const TBRect &dst_rect, TBSkinElement *element, bool fill_center);
  325. TBRect GetFlippedRect(const TBRect &src_rect, TBSkinElement *element) const;
  326. int GetPxFromNode(TBNode *node, int def_value) const;
  327. };
  328. }; // namespace tb
  329. #endif // TB_SKIN_H