1 //       _________ __                 __
2 //      /   _____//  |_____________ _/  |______     ____  __ __  ______
3 //      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
4 //      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
5 //     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
6 //             \/                  \/          \//_____/            \/
7 //  ______________________                           ______________________
8 //                        T H E   W A R   B E G I N S
9 //         Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name popup.cpp - The popup globals. */
12 //
13 //      (c) Copyright 2012-2015 by cybermind and Joris Dauphin
14 //
15 //      This program is free software; you can redistribute it and/or modify
16 //      it under the terms of the GNU General Public License as published by
17 //      the Free Software Foundation; only version 2 of the License.
18 //
19 //      This program is distributed in the hope that it will be useful,
20 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //      GNU General Public License for more details.
23 //
24 //      You should have received a copy of the GNU General Public License
25 //      along with this program; if not, write to the Free Software
26 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 //      02111-1307, USA.
28 //
29 
30 //@{
31 
32 /*----------------------------------------------------------------------------
33 --  Includes
34 ----------------------------------------------------------------------------*/
35 
36 #include "stratagus.h"
37 
38 #include "ui/popup.h"
39 
40 #include "depend.h"
41 #include "font.h"
42 #include "player.h"
43 #include "spells.h"
44 #include "trigger.h"
45 #include "ui.h"
46 #include "unittype.h"
47 #include "video.h"
48 
GetWidth(const ButtonAction & button,int *) const49 /* virtual */ int CPopupContentTypeButtonInfo::GetWidth(const ButtonAction &button, int *) const
50 {
51 	const CFont &font = this->Font ? *this->Font : GetSmallFont();
52 	std::string draw("");
53 	switch (this->InfoType) {
54 		case PopupButtonInfo_Hint:
55 			draw = button.Hint;
56 			break;
57 		case PopupButtonInfo_Description:
58 			draw = button.Description;
59 			break;
60 		case PopupButtonInfo_Dependencies:
61 			draw = PrintDependencies(*ThisPlayer, button);
62 			break;
63 	}
64 	int width = 0;
65 	std::string sub;
66 	if (draw.length()) {
67 		if (this->MaxWidth) {
68 			return std::min((unsigned int)font.getWidth(draw), this->MaxWidth);
69 		}
70 		int i = 1;
71 		while (!(sub = GetLineFont(i++, draw, 0, &font)).empty()) {
72 			width = std::max(width, font.getWidth(sub));
73 		}
74 	}
75 	return width;
76 }
77 
GetHeight(const ButtonAction & button,int *) const78 /* virtual */ int CPopupContentTypeButtonInfo::GetHeight(const ButtonAction &button, int *) const
79 {
80 	const CFont &font = this->Font ? *this->Font : GetSmallFont();
81 	std::string draw;
82 
83 	switch (this->InfoType) {
84 		case PopupButtonInfo_Hint:
85 			draw = button.Hint;
86 			break;
87 		case PopupButtonInfo_Description:
88 			draw = button.Description;
89 			break;
90 		case PopupButtonInfo_Dependencies:
91 			draw = PrintDependencies(*ThisPlayer, button);
92 			break;
93 	}
94 	int height = 0;
95 	if (draw.length()) {
96 		int i = 1;
97 		while ((GetLineFont(i++, draw, this->MaxWidth, &font)).length()) {
98 			height += font.Height() + 2;
99 		}
100 	}
101 	return height;
102 }
103 
Draw(int x,int y,const CPopup & popup,const unsigned int popupWidth,const ButtonAction & button,int *) const104 /* virtual */ void CPopupContentTypeButtonInfo::Draw(int x, int y, const CPopup &popup, const unsigned int popupWidth, const ButtonAction &button, int *) const
105 {
106 	const CFont &font = this->Font ? *this->Font : GetSmallFont();
107 	CLabel label(font, this->TextColor, this->HighlightColor);
108 	std::string draw("");
109 	switch (this->InfoType) {
110 		case PopupButtonInfo_Hint:
111 			draw = button.Hint;
112 			break;
113 		case PopupButtonInfo_Description:
114 			draw = button.Description;
115 			break;
116 		case PopupButtonInfo_Dependencies:
117 			draw = PrintDependencies(*ThisPlayer, button);
118 			break;
119 	}
120 	std::string sub(draw);
121 	if (draw.length()) {
122 		int i = 0;
123 		int y_off = y;
124 		unsigned int width = this->MaxWidth
125 							 ? std::min(this->MaxWidth, popupWidth - 2 * popup.MarginX)
126 							 : 0;
127 		while ((sub = GetLineFont(++i, draw, width, &font)).length()) {
128 			label.Draw(x, y_off, sub);
129 			y_off += font.Height() + 2;
130 		}
131 		return;
132 	}
133 }
134 
Parse(lua_State * l)135 /* virtual */ void CPopupContentTypeButtonInfo::Parse(lua_State *l)
136 {
137 	Assert(lua_istable(l, -1));
138 
139 	for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
140 		const char *key = LuaToString(l, -2);
141 		if (!strcmp(key, "InfoType")) {
142 			std::string temp(LuaToString(l, -1));
143 			if (temp == "Hint") {
144 				this->InfoType = PopupButtonInfo_Hint;
145 			} else if (temp == "Description") {
146 				this->InfoType = PopupButtonInfo_Description;
147 			} else if (temp == "Dependencies") {
148 				this->InfoType = PopupButtonInfo_Dependencies;
149 			}
150 		} else if (!strcmp(key, "MaxWidth")) {
151 			this->MaxWidth = LuaToNumber(l, -1);
152 		} else if (!strcmp(key, "Font")) {
153 			this->Font = CFont::Get(LuaToString(l, -1));
154 		} else {
155 			LuaError(l, "'%s' invalid for method 'Name' in DefinePopups" _C_ key);
156 		}
157 	}
158 }
159 
GetWidth(const ButtonAction & button,int *) const160 /* virtual */ int CPopupContentTypeText::GetWidth(const ButtonAction &button, int *) const
161 {
162 	const CFont &font = this->Font ? *this->Font : GetSmallFont();
163 
164 	if (this->MaxWidth) {
165 		return std::min((unsigned int)font.getWidth(this->Text), this->MaxWidth);
166 	}
167 	int width = 0;
168 	std::string sub;
169 	int i = 1;
170 	while (!(sub = GetLineFont(i++, this->Text, 0, &font)).empty()) {
171 		width = std::max(width, font.getWidth(sub));
172 	}
173 	return width;
174 }
175 
GetHeight(const ButtonAction & button,int *) const176 /* virtual */ int CPopupContentTypeText::GetHeight(const ButtonAction &button, int *) const
177 {
178 	CFont &font = this->Font ? *this->Font : GetSmallFont();
179 	int height = 0;
180 	int i = 1;
181 	while ((GetLineFont(i++, this->Text, this->MaxWidth, &font)).length()) {
182 		height += font.Height() + 2;
183 	}
184 	return height;
185 }
186 
Draw(int x,int y,const CPopup & popup,const unsigned int popupWidth,const ButtonAction & button,int *) const187 /* virtual */ void CPopupContentTypeText::Draw(int x, int y, const CPopup &popup, const unsigned int popupWidth, const ButtonAction &button, int *) const
188 {
189 	const CFont &font = this->Font ? *this->Font : GetSmallFont();
190 	CLabel label(font, this->TextColor, this->HighlightColor);
191 	std::string sub;
192 	int i = 0;
193 	int y_off = y;
194 	unsigned int width = this->MaxWidth
195 						 ? std::min(this->MaxWidth, popupWidth - 2 * popup.MarginX)
196 						 : 0;
197 	while ((sub = GetLineFont(++i, this->Text, width, &font)).length()) {
198 		label.Draw(x, y_off, sub);
199 		y_off += font.Height() + 2;
200 	}
201 }
202 
Parse(lua_State * l)203 /* virtual */ void CPopupContentTypeText::Parse(lua_State *l)
204 {
205 	Assert(lua_istable(l, -1));
206 
207 	for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
208 		const char *key = LuaToString(l, -2);
209 		if (!strcmp(key, "Text")) {
210 			this->Text = LuaToString(l, -1);
211 		} else if (!strcmp(key, "MaxWidth")) {
212 			this->MaxWidth = LuaToNumber(l, -1);
213 		} else if (!strcmp(key, "Font")) {
214 			this->Font = CFont::Get(LuaToString(l, -1));
215 		} else {
216 			LuaError(l, "'%s' invalid for method 'Text' in DefinePopups" _C_ key);
217 		}
218 	}
219 }
220 
GetWidth(const ButtonAction & button,int * Costs) const221 /* virtual */ int CPopupContentTypeCosts::GetWidth(const ButtonAction &button, int *Costs) const
222 {
223 	int popupWidth = 0;
224 	const CFont &font = this->Font ? *this->Font : GetSmallFont();
225 
226 	for (unsigned int i = 1; i <= MaxCosts; ++i) {
227 		if (Costs[i]) {
228 			if (UI.Resources[i].IconWidth != -1)	{
229 				popupWidth += (UI.Resources[i].IconWidth + 5);
230 			} else {
231 				const CGraphic *G = UI.Resources[i].G;
232 				if (G) {
233 					popupWidth += (G->Width + 5);
234 				}
235 			}
236 			popupWidth += (font.Width(Costs[i]) + 5);
237 		}
238 	}
239 	if (Costs[ManaResCost]) {
240 		const CGraphic *G = UI.Resources[ManaResCost].G;
241 		const SpellType *spell = SpellTypeTable[button.Value];
242 
243 		if (spell->ManaCost) {
244 			popupWidth = 10;
245 			if (UI.Resources[ManaResCost].IconWidth != -1) {
246 				popupWidth += (UI.Resources[ManaResCost].IconWidth + 5);
247 			} else {
248 				if (G) {
249 					popupWidth += (G->Width + 5);
250 				}
251 			}
252 			popupWidth += font.Width(spell->ManaCost);
253 			popupWidth = std::max<int>(popupWidth, font.Width(spell->Name) + 10);
254 		} else {
255 			popupWidth = font.Width(button.Hint) + 10;
256 		}
257 		popupWidth = std::max<int>(popupWidth, 100);
258 	}
259 	return popupWidth;
260 }
261 
GetHeight(const ButtonAction & button,int * Costs) const262 /* virtual */ int CPopupContentTypeCosts::GetHeight(const ButtonAction &button, int *Costs) const
263 {
264 	int popupHeight = 0;
265 	const CFont &font = this->Font ? *this->Font : GetSmallFont();
266 
267 	for (unsigned int i = 1; i <= ManaResCost; ++i) {
268 		if (Costs[i] && UI.Resources[i].G) {
269 			popupHeight = std::max(UI.Resources[i].G->Height, popupHeight);
270 		}
271 	}
272 	return std::max(popupHeight, font.Height());
273 }
274 
Draw(int x,int y,const CPopup &,const unsigned int,const ButtonAction & button,int * Costs) const275 /* virtual */ void CPopupContentTypeCosts::Draw(int x, int y, const CPopup &, const unsigned int, const ButtonAction &button, int *Costs) const
276 {
277 	const CFont &font = this->Font ? *this->Font : GetSmallFont();
278 	CLabel label(font, this->TextColor, this->HighlightColor);
279 
280 	for (unsigned int i = 1; i <= MaxCosts; ++i) {
281 		if (Costs[i]) {
282 			int y_offset = 0;
283 			const CGraphic *G = UI.Resources[i].G;
284 			if (G) {
285 				int x_offset = UI.Resources[i].IconWidth;
286 				G->DrawFrameClip(UI.Resources[i].IconFrame,	x , y);
287 				x += ((x_offset != -1 ? x_offset : G->Width) + 5);
288 				y_offset = G->Height;
289 				y_offset -= label.Height();
290 				y_offset /= 2;
291 			}
292 			x += label.Draw(x, y + y_offset, Costs[i]);
293 			x += 5;
294 		}
295 	}
296 	if (Costs[ManaResCost]) {
297 		const SpellType &spell = *SpellTypeTable[button.Value];
298 		const CGraphic *G = UI.Resources[ManaResCost].G;
299 		if (spell.ManaCost) {
300 			int y_offset = 0;
301 			if (G) {
302 				int x_offset =  UI.Resources[ManaResCost].IconWidth;
303 				x += 5;
304 				G->DrawFrameClip(UI.Resources[ManaResCost].IconFrame, x, y);
305 				x += ((x_offset != -1 ? x_offset : G->Width) + 5);
306 				y_offset = G->Height;
307 				y_offset -= font.Height();
308 				y_offset /= 2;
309 			}
310 			label.Draw(x, y + y_offset, spell.ManaCost);
311 		}
312 	}
313 }
314 
Parse(lua_State * l)315 /* virtual */ void CPopupContentTypeCosts::Parse(lua_State *l)
316 {
317 	Assert(lua_istable(l, -1) || lua_isnil(l, -1));
318 
319 	if (!lua_isnil(l, -1)) {
320 		for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
321 			const char *key = LuaToString(l, -2);
322 			if (!strcmp(key, "Font")) {
323 				this->Font = CFont::Get(LuaToString(l, -1));
324 			} else if (!strcmp(key, "Centered")) {
325 				this->Centered = LuaToBoolean(l, -1);
326 			} else {
327 				LuaError(l, "'%s' invalid for method 'Costs' in DefinePopups" _C_ key);
328 			}
329 		}
330 	}
331 }
332 
CPopupContentTypeLine()333 CPopupContentTypeLine::CPopupContentTypeLine() : Color(ColorWhite), Width(0), Height(1)
334 {
335 
336 }
337 
GetWidth(const ButtonAction & button,int * Costs) const338 /* virtual */ int CPopupContentTypeLine::GetWidth(const ButtonAction &button, int *Costs) const
339 {
340 	return this->Width;
341 }
342 
GetHeight(const ButtonAction & button,int * Costs) const343 /* virtual */ int CPopupContentTypeLine::GetHeight(const ButtonAction &button, int *Costs) const
344 {
345 	return this->Height;
346 }
347 
Draw(int x,int y,const CPopup & popup,const unsigned int popupWidth,const ButtonAction & button,int * Costs) const348 /* virtual */ void CPopupContentTypeLine::Draw(int x, int y, const CPopup &popup, const unsigned int popupWidth, const ButtonAction &button, int *Costs) const
349 {
350 	Video.FillRectangle(this->Color, x - popup.MarginX - this->MarginX + 1,
351 						y, this->Width && Width < popupWidth ? Width : popupWidth - 2, Height);
352 }
353 
Parse(lua_State * l)354 /* virtual */ void CPopupContentTypeLine::Parse(lua_State *l)
355 {
356 	Assert(lua_istable(l, -1) || lua_isnil(l, -1));
357 
358 	if (!lua_isnil(l, -1)) {
359 		for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
360 			const char *key = LuaToString(l, -2);
361 			if (!strcmp(key, "Width")) {
362 				this->Width = LuaToNumber(l, -1);
363 			} else if (!strcmp(key, "Height")) {
364 				this->Height = LuaToNumber(l, -1);
365 			} else if (!strcmp(key, "Color")) {
366 				this->Color = LuaToUnsignedNumber(l, -1);
367 			} else {
368 				LuaError(l, "'%s' invalid for method 'Costs' in DefinePopups" _C_ key);
369 			}
370 		}
371 	}
372 }
373 
GetWidth(const ButtonAction & button,int *) const374 /* virtual */ int CPopupContentTypeVariable::GetWidth(const ButtonAction &button, int *) const
375 {
376 	CFont &font = this->Font ? *this->Font : GetSmallFont();
377 	TriggerData.Type = UnitTypes[button.Value];
378 	std::string text = EvalString(this->Text);
379 	TriggerData.Type = NULL;
380 	return font.getWidth(text);
381 }
382 
GetHeight(const ButtonAction &,int *) const383 /* virtual */ int CPopupContentTypeVariable::GetHeight(const ButtonAction &, int *) const
384 {
385 	CFont &font = this->Font ? *this->Font : GetSmallFont();
386 	return font.Height();
387 }
388 
Draw(int x,int y,const CPopup &,const unsigned int,const ButtonAction & button,int *) const389 /* virtual */ void CPopupContentTypeVariable::Draw(int x, int y, const CPopup &, const unsigned int, const ButtonAction &button, int *) const
390 {
391 	std::string text;										// Optional text to display.
392 	CFont &font = this->Font ? *this->Font : GetSmallFont(); // Font to use.
393 
394 	Assert(this->Index == -1 || ((unsigned int) this->Index < UnitTypeVar.GetNumberVariable()));
395 
396 	CLabel label(font, this->TextColor, this->HighlightColor);
397 
398 	if (this->Text) {
399 		TriggerData.Type = UnitTypes[button.Value];
400 		text = EvalString(this->Text);
401 		TriggerData.Type = NULL;
402 		if (this->Centered) {
403 			x += (label.DrawCentered(x, y, text) * 2);
404 		} else {
405 			x += label.Draw(x, y, text);
406 		}
407 	}
408 
409 	if (this->Index != -1) {
410 		CUnitType &type = *UnitTypes[button.Value];
411 		int value = type.DefaultStat.Variables[this->Index].Value;
412 		int diff = type.Stats[ThisPlayer->Index].Variables[this->Index].Value - value;
413 
414 		if (!diff) {
415 			label.Draw(x, y, value);
416 		} else {
417 			char buf[64];
418 			snprintf(buf, sizeof(buf), diff > 0 ? "%d~<+%d~>" : "%d~<-%d~>", value, diff);
419 			label.Draw(x, y, buf);
420 		}
421 	}
422 }
423 
Parse(lua_State * l)424 /* virtual */ void CPopupContentTypeVariable::Parse(lua_State *l)
425 {
426 	Assert(lua_istable(l, -1) || lua_isstring(l, -1));
427 
428 	if (lua_isstring(l, -1)) {
429 		this->Text = CclParseStringDesc(l);
430 		lua_pushnil(l); // ParseStringDesc eat token
431 	} else {
432 		for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
433 			const char *key = LuaToString(l, -2);
434 			if (!strcmp(key, "Text")) {
435 				this->Text = CclParseStringDesc(l);
436 				lua_pushnil(l); // ParseStringDesc eat token
437 			} else if (!strcmp(key, "Font")) {
438 				this->Font = CFont::Get(LuaToString(l, -1));
439 			} else if (!strcmp(key, "Centered")) {
440 				this->Centered = LuaToBoolean(l, -1);
441 			} else if (!strcmp(key, "Variable")) {
442 				const char *const name = LuaToString(l, -1);
443 				this->Index = UnitTypeVar.VariableNameLookup[name];
444 				if (this->Index == -1) {
445 					LuaError(l, "unknown variable '%s'" _C_ LuaToString(l, -1));
446 				}
447 			} else {
448 				LuaError(l, "'%s' invalid for method 'Text' in DefinePopups" _C_ key);
449 			}
450 		}
451 	}
452 }
453 
454 /**
455 **  Parse the popup conditions.
456 **
457 **  @param l   Lua State.
458 */
ParsePopupConditions(lua_State * l)459 static PopupConditionPanel *ParsePopupConditions(lua_State *l)
460 {
461 	Assert(lua_istable(l, -1));
462 
463 	PopupConditionPanel *condition = new PopupConditionPanel;
464 	for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
465 		const char *key = LuaToString(l, -2);
466 
467 		if (!strcmp(key, "HasHint")) {
468 			condition->HasHint = LuaToBoolean(l, -1);
469 		} else if (!strcmp(key, "HasDescription")) {
470 			condition->HasDescription = LuaToBoolean(l, -1);
471 		} else if (!strcmp(key, "HasDependencies")) {
472 			condition->HasDependencies = LuaToBoolean(l, -1);
473 		} else if (!strcmp(key, "ButtonValue")) {
474 			condition->ButtonValue = LuaToString(l, -1);
475 		} else if (!strcmp(key, "ButtonAction")) {
476 			const char *value = LuaToString(l, -1);
477 			if (!strcmp(value, "move")) {
478 				condition->ButtonAction = ButtonMove;
479 			} else if (!strcmp(value, "stop")) {
480 				condition->ButtonAction = ButtonStop;
481 			} else if (!strcmp(value, "attack")) {
482 				condition->ButtonAction = ButtonAttack;
483 			} else if (!strcmp(value, "repair")) {
484 				condition->ButtonAction = ButtonRepair;
485 			} else if (!strcmp(value, "harvest")) {
486 				condition->ButtonAction = ButtonHarvest;
487 			} else if (!strcmp(value, "button")) {
488 				condition->ButtonAction = ButtonButton;
489 			} else if (!strcmp(value, "build")) {
490 				condition->ButtonAction = ButtonBuild;
491 			} else if (!strcmp(value, "train-unit")) {
492 				condition->ButtonAction = ButtonTrain;
493 			} else if (!strcmp(value, "patrol")) {
494 				condition->ButtonAction = ButtonPatrol;
495 			} else if (!strcmp(value, "explore")) {
496 				condition->ButtonAction = ButtonExplore;
497 			} else if (!strcmp(value, "stand-ground")) {
498 				condition->ButtonAction = ButtonStandGround;
499 			} else if (!strcmp(value, "attack-ground")) {
500 				condition->ButtonAction = ButtonAttackGround;
501 			} else if (!strcmp(value, "return-goods")) {
502 				condition->ButtonAction = ButtonReturn;
503 			} else if (!strcmp(value, "cast-spell")) {
504 				condition->ButtonAction = ButtonSpellCast;
505 			} else if (!strcmp(value, "research")) {
506 				condition->ButtonAction = ButtonResearch;
507 			} else if (!strcmp(value, "upgrade-to")) {
508 				condition->ButtonAction = ButtonUpgradeTo;
509 			} else if (!strcmp(value, "unload")) {
510 				condition->ButtonAction = ButtonUnload;
511 			} else if (!strcmp(value, "cancel")) {
512 				condition->ButtonAction = ButtonCancel;
513 			} else if (!strcmp(value, "cancel-upgrade")) {
514 				condition->ButtonAction = ButtonCancelUpgrade;
515 			} else if (!strcmp(value, "cancel-train-unit")) {
516 				condition->ButtonAction = ButtonCancelTrain;
517 			} else if (!strcmp(value, "cancel-build")) {
518 				condition->ButtonAction = ButtonCancelBuild;
519 			} else {
520 				LuaError(l, "Unsupported button action: %s" _C_ value);
521 			}
522 		} else {
523 			int index = UnitTypeVar.BoolFlagNameLookup[key];
524 			if (index != -1) {
525 				if (!condition->BoolFlags) {
526 					size_t new_bool_size = UnitTypeVar.GetNumberBoolFlag();
527 					condition->BoolFlags = new char[new_bool_size];
528 					memset(condition->BoolFlags, 0, new_bool_size * sizeof(char));
529 				}
530 				condition->BoolFlags[index] = Ccl2Condition(l, LuaToString(l, -1));
531 				continue;
532 			}
533 			index = UnitTypeVar.VariableNameLookup[key];
534 			if (index != -1) {
535 				if (!condition->Variables) {
536 					size_t new_variables_size = UnitTypeVar.GetNumberVariable();
537 					condition->Variables = new char[new_variables_size];
538 					memset(condition->Variables, 0, new_variables_size * sizeof(char));
539 				}
540 				condition->Variables[index] = Ccl2Condition(l, LuaToString(l, -1));
541 				continue;
542 			}
543 			LuaError(l, "'%s' invalid for Condition in DefinePopups" _C_ key);
544 		}
545 	}
546 	return condition;
547 }
548 
ParsePopupContent(lua_State * l)549 /* static */ CPopupContentType *CPopupContentType::ParsePopupContent(lua_State *l)
550 {
551 	Assert(lua_istable(l, -1));
552 
553 	bool wrap = true;
554 	int marginX = MARGIN_X;
555 	int marginY = MARGIN_Y;
556 	int minWidth = 0;
557 	int minHeight = 0;
558 	std::string textColor("white");
559 	std::string highColor("red");
560 	CPopupContentType *content = NULL;
561 	PopupConditionPanel *condition = NULL;
562 
563 	for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
564 		const char *key = LuaToString(l, -2);
565 
566 		if (!strcmp(key, "Wrap")) {
567 			wrap = LuaToBoolean(l, -1);
568 		} else if (!strcmp(key, "TextColor")) {
569 			textColor = LuaToString(l, -1);
570 		} else if (!strcmp(key, "HighlightColor")) {
571 			highColor = LuaToString(l, -1);
572 		} else if (!strcmp(key, "Margin")) {
573 			CclGetPos(l, &marginX, &marginY);
574 		} else if (!strcmp(key, "MinWidth")) {
575 			minWidth = LuaToNumber(l, -1);
576 		} else if (!strcmp(key, "MinHeight")) {
577 			minHeight = LuaToNumber(l, -1);
578 		} else if (!strcmp(key, "More")) {
579 			Assert(lua_istable(l, -1));
580 			key = LuaToString(l, -1, 1); // Method name
581 			lua_rawgeti(l, -1, 2); // Method data
582 			if (!strcmp(key, "ButtonInfo")) {
583 				content = new CPopupContentTypeButtonInfo;
584 			} else if (!strcmp(key, "Text")) {
585 				content = new CPopupContentTypeText;
586 			} else if (!strcmp(key, "Costs")) {
587 				content = new CPopupContentTypeCosts;
588 			} else if (!strcmp(key, "Line")) {
589 				content = new CPopupContentTypeLine;
590 			} else if (!strcmp(key, "Variable")) {
591 				content = new CPopupContentTypeVariable;
592 			} else {
593 				LuaError(l, "Invalid drawing method '%s' in DefinePopups" _C_ key);
594 			}
595 			content->Parse(l);
596 			lua_pop(l, 1); // Pop Variable Method data
597 		} else if (!strcmp(key, "Condition")) {
598 			condition = ParsePopupConditions(l);
599 		} else {
600 			LuaError(l, "'%s' invalid for Contents in DefinePopups" _C_ key);
601 		}
602 	}
603 	content->Wrap = wrap;
604 	content->MarginX = marginX;
605 	content->MarginY = marginY;
606 	content->minSize.x = minWidth;
607 	content->minSize.y = minHeight;
608 	content->Condition = condition;
609 	content->TextColor = textColor;
610 	content->HighlightColor = highColor;
611 	return content;
612 }
613 
CPopup()614 CPopup::CPopup() :
615 	Contents(), MarginX(MARGIN_X), MarginY(MARGIN_Y), MinWidth(0), MinHeight(0),
616 	DefaultFont(NULL), BackgroundColor(ColorBlue), BorderColor(ColorWhite)
617 {}
618 
~CPopup()619 CPopup::~CPopup()
620 {
621 	for (std::vector<CPopupContentType *>::iterator content = Contents.begin();
622 		 content != Contents.end(); ++content) {
623 		delete *content;
624 	}
625 }
626 
627 //@}
628