1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef THEME_LAYOUT_H 24 #define THEME_LAYOUT_H 25 26 #include "common/array.h" 27 #include "common/rect.h" 28 #include "graphics/font.h" 29 30 #ifdef LAYOUT_DEBUG_DIALOG 31 namespace Graphics { 32 struct Surface; 33 } 34 #endif 35 36 namespace GUI { 37 38 class Widget; 39 40 class ThemeLayout { 41 friend class ThemeLayoutMain; 42 friend class ThemeLayoutStacked; 43 friend class ThemeLayoutSpacing; 44 friend class ThemeLayoutWidget; 45 public: 46 enum LayoutType { 47 kLayoutMain, 48 kLayoutVertical, 49 kLayoutHorizontal, 50 kLayoutWidget, 51 kLayoutTabWidget, 52 kLayoutSpace 53 }; 54 55 /// Cross-direction alignment of layout children. 56 enum ItemAlign { 57 kItemAlignStart, ///< Items are aligned to the left for vertical layouts or to the top for horizontal layouts 58 kItemAlignCenter, ///< Items are centered in the container 59 kItemAlignEnd, ///< Items are aligned to the right for vertical layouts or to the bottom for horizontal layouts 60 kItemAlignStretch ///< Items are resized to match the size of the layout in the cross-direction 61 }; 62 ThemeLayout(ThemeLayout * p)63 ThemeLayout(ThemeLayout *p) : 64 _parent(p), _x(0), _y(0), _w(-1), _h(-1), 65 _defaultW(-1), _defaultH(-1), 66 _textHAlign(Graphics::kTextAlignInvalid), _useRTL(true) {} 67 ~ThemeLayout()68 virtual ~ThemeLayout() { 69 for (uint i = 0; i < _children.size(); ++i) 70 delete _children[i]; 71 } 72 73 virtual void reflowLayout(Widget *widgetChain) = 0; 74 virtual void resetLayout(); 75 addChild(ThemeLayout * child)76 void addChild(ThemeLayout *child) { _children.push_back(child); } 77 setPadding(int8 left,int8 right,int8 top,int8 bottom)78 void setPadding(int8 left, int8 right, int8 top, int8 bottom) { 79 _padding.left = left; 80 _padding.right = right; 81 _padding.top = top; 82 _padding.bottom = bottom; 83 } 84 85 protected: getWidth()86 int16 getWidth() { return _w; } getHeight()87 int16 getHeight() { return _h; } 88 offsetX(int newX)89 void offsetX(int newX) { 90 _x += newX; 91 for (uint i = 0; i < _children.size(); ++i) 92 _children[i]->offsetX(newX); 93 } 94 offsetY(int newY)95 void offsetY(int newY) { 96 _y += newY; 97 for (uint i = 0; i < _children.size(); ++i) 98 _children[i]->offsetY(newY); 99 } 100 setWidth(int16 width)101 void setWidth(int16 width) { _w = width; } setHeight(int16 height)102 void setHeight(int16 height) { _h = height; } setTextHAlign(Graphics::TextAlign align)103 void setTextHAlign(Graphics::TextAlign align) { _textHAlign = align; } 104 105 /** 106 * Checks if the layout element is attached to a GUI widget 107 * 108 * Layout elements that are not bound do not take space. 109 */ isBound(Widget * widgetChain)110 virtual bool isBound(Widget *widgetChain) const { return true; } 111 112 virtual LayoutType getLayoutType() const = 0; 113 114 virtual ThemeLayout *makeClone(ThemeLayout *newParent) = 0; 115 116 public: 117 virtual bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL); getUseRTL()118 bool getUseRTL() { return _useRTL; } 119 120 virtual Graphics::TextAlign getWidgetTextHAlign(const Common::String &name); 121 122 void importLayout(ThemeLayout *layout); 123 getTextHAlign()124 Graphics::TextAlign getTextHAlign() { return _textHAlign; } 125 126 #ifdef LAYOUT_DEBUG_DIALOG 127 void debugDraw(Graphics::Surface *screen, const Graphics::Font *font); 128 129 virtual const char *getName() const = 0; 130 #endif 131 132 protected: 133 ThemeLayout *_parent; 134 int16 _x, _y, _w, _h; 135 bool _useRTL; 136 Common::Rect _padding; 137 Common::Array<ThemeLayout *> _children; 138 int16 _defaultW, _defaultH; 139 Graphics::TextAlign _textHAlign; 140 }; 141 142 class ThemeLayoutMain : public ThemeLayout { 143 public: ThemeLayoutMain(const Common::String & name,const Common::String & overlays,int16 width,int16 height,int inset)144 ThemeLayoutMain(const Common::String &name, const Common::String &overlays, int16 width, int16 height, int inset) : 145 ThemeLayout(nullptr), 146 _name(name), 147 _overlays(overlays), 148 _inset(inset) { 149 _w = _defaultW = width; 150 _h = _defaultH = height; 151 _x = _defaultX = -1; 152 _y = _defaultY = -1; 153 } 154 void reflowLayout(Widget *widgetChain) override; 155 resetLayout()156 void resetLayout() override { 157 ThemeLayout::resetLayout(); 158 _x = _defaultX; 159 _y = _defaultY; 160 } 161 getName()162 const char *getName() const { return _name.c_str(); } 163 164 protected: getLayoutType()165 LayoutType getLayoutType() const override { return kLayoutMain; } makeClone(ThemeLayout * newParent)166 ThemeLayout *makeClone(ThemeLayout *newParent) override { assert(!"Do not copy Main Layouts!"); return nullptr; } 167 168 int16 _defaultX; 169 int16 _defaultY; 170 171 Common::String _name; 172 Common::String _overlays; 173 int _inset; 174 }; 175 176 class ThemeLayoutStacked : public ThemeLayout { 177 public: ThemeLayoutStacked(ThemeLayout * p,LayoutType type,int spacing,ItemAlign itemAlign)178 ThemeLayoutStacked(ThemeLayout *p, LayoutType type, int spacing, ItemAlign itemAlign) : 179 ThemeLayout(p), _type(type), _itemAlign(itemAlign) { 180 assert((type == kLayoutVertical) || (type == kLayoutHorizontal)); 181 _spacing = spacing; 182 } 183 reflowLayout(Widget * widgetChain)184 void reflowLayout(Widget *widgetChain) override { 185 if (_type == kLayoutVertical) 186 reflowLayoutVertical(widgetChain); 187 else 188 reflowLayoutHorizontal(widgetChain); 189 } 190 191 void reflowLayoutHorizontal(Widget *widgetChain); 192 void reflowLayoutVertical(Widget *widgetChain); 193 194 #ifdef LAYOUT_DEBUG_DIALOG getName()195 const char *getName() const { 196 return (_type == kLayoutVertical) 197 ? "Vertical Layout" : "Horizontal Layout"; 198 } 199 #endif 200 201 protected: 202 int16 getParentWidth(); 203 int16 getParentHeight(); 204 getLayoutType()205 LayoutType getLayoutType() const override { return _type; } 206 makeClone(ThemeLayout * newParent)207 ThemeLayout *makeClone(ThemeLayout *newParent) override { 208 ThemeLayoutStacked *n = new ThemeLayoutStacked(*this); 209 n->_parent = newParent; 210 211 for (uint i = 0; i < n->_children.size(); ++i) 212 n->_children[i] = n->_children[i]->makeClone(n); 213 214 return n; 215 } 216 217 const LayoutType _type; 218 ItemAlign _itemAlign; 219 int8 _spacing; 220 }; 221 222 class ThemeLayoutWidget : public ThemeLayout { 223 public: ThemeLayoutWidget(ThemeLayout * p,const Common::String & name,int16 w,int16 h,Graphics::TextAlign align,bool useRTL)224 ThemeLayoutWidget(ThemeLayout *p, const Common::String &name, int16 w, int16 h, Graphics::TextAlign align, bool useRTL) : ThemeLayout(p), _name(name) { 225 _w = _defaultW = w; 226 _h = _defaultH = h; 227 _useRTL = useRTL; 228 229 setTextHAlign(align); 230 } 231 232 bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL) override; 233 Graphics::TextAlign getWidgetTextHAlign(const Common::String &name) override; 234 235 void reflowLayout(Widget *widgetChain) override; 236 getName()237 virtual const char *getName() const { return _name.c_str(); } 238 239 protected: getLayoutType()240 LayoutType getLayoutType() const override { return kLayoutWidget; } 241 242 bool isBound(Widget *widgetChain) const override; 243 Widget *getWidget(Widget *widgetChain) const; 244 makeClone(ThemeLayout * newParent)245 ThemeLayout *makeClone(ThemeLayout *newParent) override { 246 ThemeLayout *n = new ThemeLayoutWidget(*this); 247 n->_parent = newParent; 248 return n; 249 } 250 251 Common::String _name; 252 }; 253 254 class ThemeLayoutTabWidget : public ThemeLayoutWidget { 255 int _tabHeight; 256 257 public: ThemeLayoutTabWidget(ThemeLayout * p,const Common::String & name,int16 w,int16 h,Graphics::TextAlign align,int tabHeight)258 ThemeLayoutTabWidget(ThemeLayout *p, const Common::String &name, int16 w, int16 h, Graphics::TextAlign align, int tabHeight): 259 ThemeLayoutWidget(p, name, w, h, align, p->getUseRTL()) { 260 _tabHeight = tabHeight; 261 } 262 reflowLayout(Widget * widgetChain)263 void reflowLayout(Widget *widgetChain) override { 264 for (uint i = 0; i < _children.size(); ++i) { 265 _children[i]->reflowLayout(widgetChain); 266 } 267 } 268 getWidgetData(const Common::String & name,int16 & x,int16 & y,int16 & w,int16 & h,bool & useRTL)269 bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL) override { 270 if (ThemeLayoutWidget::getWidgetData(name, x, y, w, h, useRTL)) { 271 h -= _tabHeight; 272 return true; 273 } 274 275 return false; 276 } 277 278 protected: getLayoutType()279 LayoutType getLayoutType() const override { return kLayoutTabWidget; } 280 makeClone(ThemeLayout * newParent)281 ThemeLayout *makeClone(ThemeLayout *newParent) override { 282 ThemeLayoutTabWidget *n = new ThemeLayoutTabWidget(*this); 283 n->_parent = newParent; 284 return n; 285 } 286 }; 287 288 class ThemeLayoutSpacing : public ThemeLayout { 289 public: ThemeLayoutSpacing(ThemeLayout * p,int size)290 ThemeLayoutSpacing(ThemeLayout *p, int size) : ThemeLayout(p) { 291 if (p->getLayoutType() == kLayoutHorizontal) { 292 _w = _defaultW = size; 293 _h = _defaultH = 1; 294 } else if (p->getLayoutType() == kLayoutVertical) { 295 _w = _defaultW = 1; 296 _h = _defaultH = size; 297 } 298 } 299 getWidgetData(const Common::String & name,int16 & x,int16 & y,int16 & w,int16 & h,bool & useRTL)300 bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL) override { return false; } reflowLayout(Widget * widgetChain)301 void reflowLayout(Widget *widgetChain) override {} 302 #ifdef LAYOUT_DEBUG_DIALOG getName()303 const char *getName() const { return "SPACE"; } 304 #endif 305 306 protected: getLayoutType()307 LayoutType getLayoutType() const override { return kLayoutSpace; } 308 makeClone(ThemeLayout * newParent)309 ThemeLayout *makeClone(ThemeLayout *newParent) override { 310 ThemeLayout *n = new ThemeLayoutSpacing(*this); 311 n->_parent = newParent; 312 return n; 313 } 314 }; 315 316 } 317 318 #endif 319