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 #include "gui/ThemeEval.h"
24 
25 #include "graphics/scaler.h"
26 
27 #include "common/system.h"
28 #include "common/tokenizer.h"
29 
30 namespace GUI {
31 
~ThemeEval()32 ThemeEval::~ThemeEval() {
33 	reset();
34 }
35 
buildBuiltinVars()36 void ThemeEval::buildBuiltinVars() {
37 	_builtin["kThumbnailWidth"] = kThumbnailWidth;
38 	_builtin["kThumbnailHeight"] = kThumbnailHeight1;
39 	_builtin["kThumbnailHeight2"] = kThumbnailHeight2;
40 }
41 
reset()42 void ThemeEval::reset() {
43 	_vars.clear();
44 	_curDialog.clear();
45 	_curLayout.clear();
46 
47 	for (LayoutsMap::iterator i = _layouts.begin(); i != _layouts.end(); ++i)
48 		delete i->_value;
49 
50 	_layouts.clear();
51 }
52 
getWidgetData(const Common::String & widget,int16 & x,int16 & y,int16 & w,int16 & h)53 bool ThemeEval::getWidgetData(const Common::String &widget, int16 &x, int16 &y, int16 &w, int16 &h) {
54 	bool useRTL;
55 
56 	return getWidgetData(widget, x, y, w, h, useRTL);
57 }
58 
getWidgetData(const Common::String & widget,int16 & x,int16 & y,int16 & w,int16 & h,bool & useRTL)59 bool ThemeEval::getWidgetData(const Common::String &widget, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL) {
60 	Common::StringTokenizer tokenizer(widget, ".");
61 
62 	if (widget.hasPrefix("Dialog."))
63 		tokenizer.nextToken();
64 
65 	Common::String dialogName = "Dialog." + tokenizer.nextToken();
66 	Common::String widgetName = tokenizer.nextToken();
67 
68 	if (!_layouts.contains(dialogName))
69 		return false;
70 
71 	return _layouts[dialogName]->getWidgetData(widgetName, x, y, w, h, useRTL);
72 }
73 
getWidgetTextHAlign(const Common::String & widget)74 Graphics::TextAlign ThemeEval::getWidgetTextHAlign(const Common::String &widget) {
75 	Common::StringTokenizer tokenizer(widget, ".");
76 
77 	if (widget.hasPrefix("Dialog."))
78 		tokenizer.nextToken();
79 
80 	Common::String dialogName = "Dialog." + tokenizer.nextToken();
81 	Common::String widgetName = tokenizer.nextToken();
82 
83 	if (!_layouts.contains(dialogName))
84 		return Graphics::kTextAlignInvalid;
85 
86 	return _layouts[dialogName]->getWidgetTextHAlign(widgetName);
87 }
88 
addWidget(const Common::String & name,const Common::String & type,int w,int h,Graphics::TextAlign align,bool useRTL)89 ThemeEval &ThemeEval::addWidget(const Common::String &name, const Common::String &type, int w, int h, Graphics::TextAlign align, bool useRTL) {
90 	int typeW = -1;
91 	int typeH = -1;
92 	Graphics::TextAlign typeAlign = Graphics::kTextAlignInvalid;
93 
94 	if (!type.empty()) {
95 		typeW = getVar("Globals." + type + ".Width", -1);
96 		typeH = getVar("Globals." + type + ".Height", -1);
97 		typeAlign = (Graphics::TextAlign)getVar("Globals." + type + ".Align", Graphics::kTextAlignInvalid);
98 	}
99 
100 	ThemeLayoutWidget *widget;
101 	if (type == "TabWidget")
102 		widget = new ThemeLayoutTabWidget(_curLayout.top(), name,
103 									typeW == -1 ? w : typeW,
104 									typeH == -1 ? h : typeH,
105 									typeAlign == Graphics::kTextAlignInvalid ? align : typeAlign,
106 									getVar("Globals.TabWidget.Tab.Height", 0));
107 	else
108 		widget = new ThemeLayoutWidget(_curLayout.top(), name,
109 									typeW == -1 ? w : typeW,
110 									typeH == -1 ? h : typeH,
111 									typeAlign == Graphics::kTextAlignInvalid ? align : typeAlign,
112 									useRTL);
113 
114 	_curLayout.top()->addChild(widget);
115 
116 	return *this;
117 }
118 
addDialog(const Common::String & name,const Common::String & overlays,int16 width,int16 height,int inset)119 ThemeEval &ThemeEval::addDialog(const Common::String &name, const Common::String &overlays, int16 width, int16 height, int inset) {
120 	Common::String var = "Dialog." + name;
121 
122 	ThemeLayout *layout = new ThemeLayoutMain(name, overlays, width, height, inset);
123 
124 	if (_layouts.contains(var))
125 		delete _layouts[var];
126 
127 	_layouts[var] = layout;
128 
129 	layout->setPadding(
130 		getVar("Globals.Padding.Left", 0),
131 		getVar("Globals.Padding.Right", 0),
132 		getVar("Globals.Padding.Top", 0),
133 		getVar("Globals.Padding.Bottom", 0)
134 		);
135 
136 	_curLayout.push(layout);
137 	_curDialog = name;
138 
139 	return *this;
140 }
141 
addLayout(ThemeLayout::LayoutType type,int spacing,ThemeLayout::ItemAlign itemAlign)142 ThemeEval &ThemeEval::addLayout(ThemeLayout::LayoutType type, int spacing, ThemeLayout::ItemAlign itemAlign) {
143 	ThemeLayout *layout = nullptr;
144 
145 	if (spacing == -1)
146 		spacing = getVar("Globals.Layout.Spacing");
147 
148 	layout = new ThemeLayoutStacked(_curLayout.top(), type, spacing, itemAlign);
149 
150 	assert(layout);
151 
152 	layout->setPadding(
153 		getVar("Globals.Padding.Left", 0),
154 		getVar("Globals.Padding.Right", 0),
155 		getVar("Globals.Padding.Top", 0),
156 		getVar("Globals.Padding.Bottom", 0)
157 		);
158 
159 	_curLayout.top()->addChild(layout);
160 	_curLayout.push(layout);
161 
162 	return *this;
163 }
164 
addSpace(int size)165 ThemeEval &ThemeEval::addSpace(int size) {
166 	ThemeLayout *space = new ThemeLayoutSpacing(_curLayout.top(), size);
167 	_curLayout.top()->addChild(space);
168 
169 	return *this;
170 }
171 
172 #define SCALEVALUE(val) (val > 0 ? val * _scaleFactor : val)
173 
addPadding(int16 l,int16 r,int16 t,int16 b)174 ThemeEval &ThemeEval::addPadding(int16 l, int16 r, int16 t, int16 b) {
175 	_curLayout.top()->setPadding(SCALEVALUE(l), SCALEVALUE(r), SCALEVALUE(t), SCALEVALUE(b));
176 
177 	return *this;
178 }
179 
hasDialog(const Common::String & name)180 bool ThemeEval::hasDialog(const Common::String &name) {
181 	Common::StringTokenizer tokenizer(name, ".");
182 
183 	if (name.hasPrefix("Dialog."))
184 		tokenizer.nextToken();
185 
186 	Common::String dialogName = "Dialog." + tokenizer.nextToken();
187 	return _layouts.contains(dialogName);
188 }
189 
reflowDialogLayout(const Common::String & name,Widget * widgetChain)190 void ThemeEval::reflowDialogLayout(const Common::String &name, Widget *widgetChain) {
191 	if (!_layouts.contains("Dialog." + name)) {
192 		warning("No layout found for dialog '%s'", name.c_str());
193 		return;
194 	}
195 
196 	_layouts["Dialog." + name]->reflowLayout(widgetChain);
197 }
198 
addImportedLayout(const Common::String & name)199 ThemeEval &ThemeEval::addImportedLayout(const Common::String &name) {
200 	ThemeLayout *importedLayout = _layouts[name];
201 	assert(importedLayout);
202 
203 	_curLayout.top()->importLayout(importedLayout);
204 
205 	return *this;
206 }
207 
208 } // End of namespace GUI
209