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 ThemeLayout {
39 	friend class ThemeLayoutMain;
40 	friend class ThemeLayoutStacked;
41 	friend class ThemeLayoutSpacing;
42 	friend class ThemeLayoutWidget;
43 public:
44 	enum LayoutType {
45 		kLayoutMain,
46 		kLayoutVertical,
47 		kLayoutHorizontal,
48 		kLayoutWidget,
49 		kLayoutTabWidget
50 	};
51 
ThemeLayout(ThemeLayout * p)52 	ThemeLayout(ThemeLayout *p) :
53 		_parent(p), _x(0), _y(0), _w(-1), _h(-1),
54 		_centered(false), _defaultW(-1), _defaultH(-1),
55 		_textHAlign(Graphics::kTextAlignInvalid) {}
56 
~ThemeLayout()57 	virtual ~ThemeLayout() {
58 		for (uint i = 0; i < _children.size(); ++i)
59 			delete _children[i];
60 	}
61 
62 	virtual void reflowLayout() = 0;
63 
resetLayout()64 	virtual void resetLayout() { _x = 0; _y = 0; _w = _defaultW; _h = _defaultH; }
65 
addChild(ThemeLayout * child)66 	void addChild(ThemeLayout *child) { _children.push_back(child); }
67 
setPadding(int8 left,int8 right,int8 top,int8 bottom)68 	void setPadding(int8 left, int8 right, int8 top, int8 bottom) {
69 		_padding.left = left;
70 		_padding.right = right;
71 		_padding.top = top;
72 		_padding.bottom = bottom;
73 	}
74 
75 protected:
getWidth()76 	int16 getWidth() { return _w; }
getHeight()77 	int16 getHeight() { return _h; }
78 
offsetX(int newX)79 	void offsetX(int newX) {
80 		_x += newX;
81 		for (uint i = 0; i < _children.size(); ++i)
82 			_children[i]->offsetX(newX);
83 	}
84 
offsetY(int newY)85 	void offsetY(int newY) {
86 		_y += newY;
87 		for (uint i = 0; i < _children.size(); ++i)
88 			_children[i]->offsetY(newY);
89 	}
90 
setWidth(int16 width)91 	void setWidth(int16 width) { _w = width; }
setHeight(int16 height)92 	void setHeight(int16 height) { _h = height; }
setTextHAlign(Graphics::TextAlign align)93 	void setTextHAlign(Graphics::TextAlign align) { _textHAlign = align; }
94 
95 	virtual LayoutType getLayoutType() = 0;
96 
97 	virtual ThemeLayout *makeClone(ThemeLayout *newParent) = 0;
98 
99 public:
100 	virtual bool getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h);
101 
102 	virtual Graphics::TextAlign getWidgetTextHAlign(const Common::String &name);
103 
104 	void importLayout(ThemeLayout *layout);
105 
getTextHAlign()106 	Graphics::TextAlign getTextHAlign() { return _textHAlign; }
107 
108 #ifdef LAYOUT_DEBUG_DIALOG
109 	void debugDraw(Graphics::Surface *screen, const Graphics::Font *font);
110 
111 	virtual const char *getName() const = 0;
112 #endif
113 
114 protected:
115 	ThemeLayout *_parent;
116 	int16 _x, _y, _w, _h;
117 	Common::Rect _padding;
118 	Common::Array<ThemeLayout *> _children;
119 	bool _centered;
120 	int16 _defaultW, _defaultH;
121 	Graphics::TextAlign _textHAlign;
122 };
123 
124 class ThemeLayoutMain : public ThemeLayout {
125 public:
ThemeLayoutMain(int16 x,int16 y,int16 w,int16 h)126 	ThemeLayoutMain(int16 x, int16 y, int16 w, int16 h) : ThemeLayout(0) {
127 		_w = _defaultW = w;
128 		_h = _defaultH = h;
129 		_x = _defaultX = x;
130 		_y = _defaultY = y;
131 	}
132 	void reflowLayout();
133 
resetLayout()134 	void resetLayout() {
135 		ThemeLayout::resetLayout();
136 		_x = _defaultX;
137 		_y = _defaultY;
138 	}
139 
140 #ifdef LAYOUT_DEBUG_DIALOG
getName()141 	const char *getName() const { return "Global Layout"; }
142 #endif
143 
144 protected:
getLayoutType()145 	LayoutType getLayoutType() { return kLayoutMain; }
makeClone(ThemeLayout * newParent)146 	ThemeLayout *makeClone(ThemeLayout *newParent) { assert(!"Do not copy Main Layouts!"); return 0; }
147 
148 	int16 _defaultX;
149 	int16 _defaultY;
150 };
151 
152 class ThemeLayoutStacked : public ThemeLayout {
153 public:
ThemeLayoutStacked(ThemeLayout * p,LayoutType type,int spacing,bool center)154 	ThemeLayoutStacked(ThemeLayout *p, LayoutType type, int spacing, bool center) :
155 		ThemeLayout(p), _type(type) {
156 		assert((type == kLayoutVertical) || (type == kLayoutHorizontal));
157 		_spacing = spacing;
158 		_centered = center;
159 	}
160 
reflowLayout()161 	void reflowLayout() {
162 		if (_type == kLayoutVertical)
163 			reflowLayoutVertical();
164 		else
165 			reflowLayoutHorizontal();
166 	}
167 	void reflowLayoutHorizontal();
168 	void reflowLayoutVertical();
169 
170 #ifdef LAYOUT_DEBUG_DIALOG
getName()171 	const char *getName() const {
172 		return (_type == kLayoutVertical)
173 			? "Vertical Layout" : "Horizontal Layout";
174 	}
175 #endif
176 
177 protected:
178 	int16 getParentWidth();
179 	int16 getParentHeight();
180 
getLayoutType()181 	LayoutType getLayoutType() { return _type; }
182 
makeClone(ThemeLayout * newParent)183 	ThemeLayout *makeClone(ThemeLayout *newParent) {
184 		ThemeLayoutStacked *n = new ThemeLayoutStacked(*this);
185 		n->_parent = newParent;
186 
187 		for (uint i = 0; i < n->_children.size(); ++i)
188 			n->_children[i] = n->_children[i]->makeClone(n);
189 
190 		return n;
191 	}
192 
193 	const LayoutType _type;
194 	int8 _spacing;
195 };
196 
197 class ThemeLayoutWidget : public ThemeLayout {
198 public:
ThemeLayoutWidget(ThemeLayout * p,const Common::String & name,int16 w,int16 h,Graphics::TextAlign align)199 	ThemeLayoutWidget(ThemeLayout *p, const Common::String &name, int16 w, int16 h, Graphics::TextAlign align) : ThemeLayout(p), _name(name) {
200 		_w = _defaultW = w;
201 		_h = _defaultH = h;
202 
203 		setTextHAlign(align);
204 	}
205 
206 	bool getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h);
207 	Graphics::TextAlign getWidgetTextHAlign(const Common::String &name);
208 
reflowLayout()209 	void reflowLayout() {}
210 
211 #ifdef LAYOUT_DEBUG_DIALOG
getName()212 	virtual const char *getName() const { return _name.c_str(); }
213 #endif
214 
215 protected:
getLayoutType()216 	LayoutType getLayoutType() { return kLayoutWidget; }
217 
makeClone(ThemeLayout * newParent)218 	ThemeLayout *makeClone(ThemeLayout *newParent) {
219 		ThemeLayout *n = new ThemeLayoutWidget(*this);
220 		n->_parent = newParent;
221 		return n;
222 	}
223 
224 	Common::String _name;
225 };
226 
227 class ThemeLayoutTabWidget : public ThemeLayoutWidget {
228 	int _tabHeight;
229 
230 public:
ThemeLayoutTabWidget(ThemeLayout * p,const Common::String & name,int16 w,int16 h,Graphics::TextAlign align,int tabHeight)231 	ThemeLayoutTabWidget(ThemeLayout *p, const Common::String &name, int16 w, int16 h, Graphics::TextAlign align, int tabHeight):
232 		ThemeLayoutWidget(p, name, w, h, align) {
233 		_tabHeight = tabHeight;
234 	}
235 
reflowLayout()236 	void reflowLayout() {
237 		for (uint i = 0; i < _children.size(); ++i) {
238 			_children[i]->resetLayout();
239 			_children[i]->reflowLayout();
240 		}
241 	}
242 
getWidgetData(const Common::String & name,int16 & x,int16 & y,uint16 & w,uint16 & h)243 	virtual bool getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h) {
244 		if (ThemeLayoutWidget::getWidgetData(name, x, y, w, h)) {
245 			h -= _tabHeight;
246 			return true;
247 		}
248 
249 		return false;
250 	}
251 
252 protected:
getLayoutType()253 	LayoutType getLayoutType() { return kLayoutTabWidget; }
254 
makeClone(ThemeLayout * newParent)255 	ThemeLayout *makeClone(ThemeLayout *newParent) {
256 		ThemeLayoutTabWidget *n = new ThemeLayoutTabWidget(*this);
257 		n->_parent = newParent;
258 		return n;
259 	}
260 };
261 
262 class ThemeLayoutSpacing : public ThemeLayout {
263 public:
ThemeLayoutSpacing(ThemeLayout * p,int size)264 	ThemeLayoutSpacing(ThemeLayout *p, int size) : ThemeLayout(p) {
265 		if (p->getLayoutType() == kLayoutHorizontal) {
266 			_w = _defaultW = size;
267 			_h = _defaultH = 1;
268 		} else if (p->getLayoutType() == kLayoutVertical) {
269 			_w = _defaultW = 1;
270 			_h = _defaultH = size;
271 		}
272 	}
273 
getWidgetData(const Common::String & name,int16 & x,int16 & y,uint16 & w,uint16 & h)274 	bool getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h) { return false; }
reflowLayout()275 	void reflowLayout() {}
276 #ifdef LAYOUT_DEBUG_DIALOG
getName()277 	const char *getName() const { return "SPACE"; }
278 #endif
279 
280 protected:
getLayoutType()281 	LayoutType getLayoutType() { return kLayoutWidget; }
282 
makeClone(ThemeLayout * newParent)283 	ThemeLayout *makeClone(ThemeLayout *newParent) {
284 		ThemeLayout *n = new ThemeLayoutSpacing(*this);
285 		n->_parent = newParent;
286 		return n;
287 	}
288 };
289 
290 }
291 
292 #endif
293