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 icons.cpp - The icons. */
12 //
13 //      (c) Copyright 1998-2012 by Lutz Sammer and Jimmy Salmon
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 "icons.h"
39 
40 #include "config.h"
41 #include "menus.h"
42 #include "mod.h"
43 #include "player.h"
44 #include "translate.h"
45 #include "ui/ui.h"
46 #include "unit/unit.h"
47 #include "video.h"
48 
49 #include <map>
50 
51 /*----------------------------------------------------------------------------
52 --  Variables
53 ----------------------------------------------------------------------------*/
54 
55 //Wyrmgus start
56 //typedef std::map<std::string, CIcon *> IconMap;
57 //static IconMap Icons;   /// Map of ident to icon.
58 IconMap Icons;   /// Map of ident to icon.
59 //Wyrmgus end
60 
61 
62 /*----------------------------------------------------------------------------
63 --  Functions
64 ----------------------------------------------------------------------------*/
65 
66 /**
67 **  CIcon constructor
68 */
69 //Wyrmgus start
70 //CIcon::CIcon(const std::string &ident) : G(nullptr), GScale(nullptr), Frame(0), Ident(ident)
CIcon(const std::string & ident)71 CIcon::CIcon(const std::string &ident) : G(nullptr), GScale(nullptr), Frame(0), Ident(ident), Loaded(false)
72 //Wyrmgus end
73 {
74 }
75 
76 /**
77 **  CIcon destructor
78 */
~CIcon()79 CIcon::~CIcon()
80 {
81 	CPlayerColorGraphic::Free(this->G);
82 	CPlayerColorGraphic::Free(this->GScale);
83 }
84 
85 /**
86 **  Create a new icon
87 **
88 **  @param ident  Icon identifier
89 **
90 **  @return       New icon
91 */
New(const std::string & ident)92 CIcon *CIcon::New(const std::string &ident)
93 {
94 	CIcon *&icon = Icons[ident];
95 
96 	if (icon == nullptr) {
97 		icon = new CIcon(ident);
98 	}
99 	return icon;
100 }
101 
102 /**
103 **  Get an icon
104 **
105 **  @param ident  Icon identifier
106 **
107 **  @return       The icon
108 */
Get(const std::string & ident)109 CIcon *CIcon::Get(const std::string &ident)
110 {
111 	IconMap::iterator it = Icons.find(ident);
112 	if (it == Icons.end()) {
113 		DebugPrint("icon not found: %s\n" _C_ ident.c_str());
114 	}
115 	return it->second;
116 }
117 
ProcessConfigData(const CConfigData * config_data)118 void CIcon::ProcessConfigData(const CConfigData *config_data)
119 {
120 	for (size_t i = 0; i < config_data->Properties.size(); ++i) {
121 		std::string key = config_data->Properties[i].first;
122 		std::string value = config_data->Properties[i].second;
123 
124 		if (key == "frame") {
125 			this->Frame = std::stoi(value);
126 		} else {
127 			fprintf(stderr, "Invalid icon property: \"%s\".\n", key.c_str());
128 		}
129 	}
130 
131 	for (const CConfigData *child_config_data : config_data->Children) {
132 		if (child_config_data->Tag == "image") {
133 			std::string file;
134 			Vec2i size(0, 0);
135 
136 			for (size_t j = 0; j < child_config_data->Properties.size(); ++j) {
137 				std::string key = child_config_data->Properties[j].first;
138 				std::string value = child_config_data->Properties[j].second;
139 
140 				if (key == "file") {
141 					file = CMod::GetCurrentModPath() + value;
142 				} else if (key == "width") {
143 					size.x = std::stoi(value);
144 				} else if (key == "height") {
145 					size.y = std::stoi(value);
146 				} else {
147 					fprintf(stderr, "Invalid image property: \"%s\".\n", key.c_str());
148 				}
149 			}
150 
151 			if (file.empty()) {
152 				fprintf(stderr, "Image has no file.\n");
153 				continue;
154 			}
155 
156 			if (size.x == 0) {
157 				fprintf(stderr, "Image has no width.\n");
158 				continue;
159 			}
160 
161 			if (size.y == 0) {
162 				fprintf(stderr, "Image has no height.\n");
163 				continue;
164 			}
165 
166 			this->G = CPlayerColorGraphic::New(file, size.x, size.y);
167 		} else {
168 			fprintf(stderr, "Invalid icon property: \"%s\".\n", child_config_data->Tag.c_str());
169 		}
170 	}
171 }
172 
Load()173 void CIcon::Load()
174 {
175 	//Wyrmgus start
176 	if (this->Loaded) {
177 		return;
178 	}
179 	//Wyrmgus end
180 	Assert(G);
181 	G->Load();
182 	if (Preference.GrayscaleIcons) {
183 		GScale = G->Clone(true);
184 	}
185 	if (Frame >= G->NumFrames) {
186 		DebugPrint("Invalid icon frame: %s - %d\n" _C_ Ident.c_str() _C_ Frame);
187 		Frame = 0;
188 	}
189 	//Wyrmgus start
190 	this->Loaded = true;
191 	//Wyrmgus end
192 }
193 
194 /**
195 **  Draw icon at pos.
196 **
197 **  @param player  Player pointer used for icon colors
198 **  @param pos     display pixel position
199 */
DrawIcon(const PixelPos & pos,const int player) const200 void CIcon::DrawIcon(const PixelPos &pos, const int player) const
201 {
202 	if (player != -1 ) {
203 		//Wyrmgus start
204 //		this->G->DrawPlayerColorFrameClip(player, this->Frame, pos.x, pos.y);
205 		this->G->DrawPlayerColorFrameClip(player, this->Frame, pos.x, pos.y, true);
206 		//Wyrmgus end
207 	} else {
208 		this->G->DrawFrameClip(this->Frame, pos.x, pos.y);
209 	}
210 }
211 
212 /**
213 **  Draw grayscale icon at pos.
214 **
215 **  @param pos     display pixel position
216 */
DrawGrayscaleIcon(const PixelPos & pos,const int player) const217 void CIcon::DrawGrayscaleIcon(const PixelPos &pos, const int player) const
218 {
219 	if (this->GScale) {
220 		if (player != -1) {
221 			this->GScale->DrawPlayerColorFrameClip(player, this->Frame, pos.x, pos.y);
222 		} else {
223 			this->GScale->DrawFrameClip(this->Frame, pos.x, pos.y);
224 		}
225 	}
226 }
227 
228 /**
229 **  Draw cooldown spell effect on icon at pos.
230 **
231 **  @param pos       display pixel position
232 **  @param percent   cooldown percent
233 */
DrawCooldownSpellIcon(const PixelPos & pos,const int percent) const234 void CIcon::DrawCooldownSpellIcon(const PixelPos &pos, const int percent) const
235 {
236 	// TO-DO: implement more effect types (clock-like)
237 	if (this->GScale) {
238 		this->GScale->DrawFrameClip(this->Frame, pos.x, pos.y);
239 		const int height = (G->Height * (100 - percent)) / 100;
240 		this->G->DrawSubClip(G->frame_map[Frame].x, G->frame_map[Frame].y + G->Height - height,
241 							 G->Width, height, pos.x, pos.y + G->Height - height);
242 	} else {
243 		DebugPrint("Enable grayscale icon drawing in your game to achieve special effects for cooldown spell icons");
244 		this->DrawIcon(pos);
245 	}
246 }
247 
248 /**
249 **  Draw unit icon 'icon' with border on x,y
250 **
251 **  @param style   Button style
252 **  @param flags   State of icon (clicked, mouse over...)
253 **  @param pos     display pixel position
254 **  @param text    Optional text to display
255 */
DrawUnitIcon(const ButtonStyle & style,unsigned flags,const PixelPos & pos,const std::string & text,int player,bool transparent,bool grayscale,int show_percent) const256 void CIcon::DrawUnitIcon(const ButtonStyle &style, unsigned flags,
257 						 //Wyrmgus start
258 //						 const PixelPos &pos, const std::string &text, int player) const
259 						 const PixelPos &pos, const std::string &text, int player, bool transparent, bool grayscale, int show_percent) const
260 						 //Wyrmgus end
261 {
262 	ButtonStyle s(style);
263 
264 	//Wyrmgus start
265 //	s.Default.Sprite = s.Hover.Sprite = s.Clicked.Sprite = this->G;
266 	if (grayscale) {
267 		s.Default.Sprite = s.Hover.Sprite = s.Clicked.Sprite = this->GScale;
268 	} else {
269 		s.Default.Sprite = s.Hover.Sprite = s.Clicked.Sprite = this->G;
270 	}
271 	//Wyrmgus end
272 	s.Default.Frame = s.Hover.Frame = s.Clicked.Frame = this->Frame;
273 	if (!(flags & IconSelected) && (flags & IconAutoCast)) {
274 		s.Default.BorderColorRGB = UI.ButtonPanel.AutoCastBorderColorRGB;
275 		s.Default.BorderColor = 0;
276 		//Wyrmgus start
277 //		s.Default.BorderSize = 2;
278 		//Wyrmgus end
279 	}
280 	//Wyrmgus start
281 	if (!(flags & IconAutoCast)) {
282 		s.Default.BorderSize = 0;
283 	}
284 	//Wyrmgus end
285 	//Wyrmgus start
286 	if (Preference.IconsShift && Preference.IconFrameG && Preference.PressedIconFrameG) {
287 		Video.FillRectangle(ColorBlack, pos.x, pos.y, 46, 38);
288 		if (flags & IconActive) { // Code to make a border appear around the icon when the mouse hovers over it.
289 //			Video.DrawRectangle(ColorGray, pos.x - 4, pos.y - 4, 54, 46);
290 //			DrawUIButton(&s, flags, pos.x, pos.y, text, player, transparent);
291 		}
292 
293 		if (flags & IconClicked) { // Shift the icon a bit to make it look like it's been pressed.
294 			if (show_percent < 100) {
295 				DrawUIButton(&s, flags, pos.x + 1, pos.y + 1, text, player, true);
296 			}
297 			DrawUIButton(&s, flags, pos.x + 1, pos.y + 1, text, player, transparent, show_percent);
298 			if (flags & IconSelected) {
299 				Video.DrawRectangle(ColorGreen, pos.x, pos.y, 48, 40);
300 			} else if (flags & IconAutoCast) {
301 				Video.DrawRectangle(Video.MapRGB(TheScreen->format, UI.ButtonPanel.AutoCastBorderColorRGB), pos.x, pos.y, 48, 40);
302 			}
303 			if (!Preference.CommandButtonFrameG || !(flags & IconCommandButton)) {
304 				Preference.PressedIconFrameG->DrawClip(pos.x - 4, pos.y - 4);
305 			} else {
306 				Preference.CommandButtonFrameG->DrawClip(pos.x - 5, pos.y - 4);
307 			}
308 //			Video.DrawRectangle(ColorGray, pos.x - 4, pos.y - 4, 54, 46);
309 		} else {
310 			if (show_percent < 100) {
311 				DrawUIButton(&s, flags, pos.x, pos.y, text, player, true);
312 			}
313 			DrawUIButton(&s, flags, pos.x, pos.y, text, player, transparent, show_percent);
314 			if (flags & IconSelected) {
315 				Video.DrawRectangle(ColorGreen, pos.x, pos.y, 46, 38);
316 			} else if (flags & IconAutoCast) {
317 				Video.DrawRectangle(Video.MapRGB(TheScreen->format, UI.ButtonPanel.AutoCastBorderColorRGB), pos.x, pos.y, 46, 38);
318 			}
319 			if (Preference.CommandButtonFrameG && (flags & IconCommandButton)) {
320 				Preference.CommandButtonFrameG->DrawClip(pos.x - 5, pos.y - 4);
321 			} else {
322 				Preference.IconFrameG->DrawClip(pos.x - 4, pos.y - 4);
323 			}
324 		}
325 	//Wyrmgus end
326 	//Wyrmgus start
327 //	if (Preference.IconsShift) {
328 	} else if (Preference.IconsShift) {
329 	//Wyrmgus end
330 		// Left and top edge of Icon
331 		Video.DrawHLine(ColorWhite, pos.x - 1, pos.y - 1, 49);
332 		Video.DrawVLine(ColorWhite, pos.x - 1, pos.y, 40);
333 		Video.DrawVLine(ColorWhite, pos.x, pos.y + 38, 2);
334 		Video.DrawHLine(ColorWhite, pos.x + 46, pos.y, 2);
335 
336 		// Bottom and Right edge of Icon
337 		Video.DrawHLine(ColorGray, pos.x + 1, pos.y + 38, 47);
338 		Video.DrawHLine(ColorGray, pos.x + 1, pos.y + 39, 47);
339 		Video.DrawVLine(ColorGray, pos.x + 46, pos.y + 1, 37);
340 		Video.DrawVLine(ColorGray, pos.x + 47, pos.y + 1, 37);
341 
342 		Video.DrawRectangle(ColorBlack, pos.x - 3, pos.y - 3, 52, 44);
343 		Video.DrawRectangle(ColorBlack, pos.x - 4, pos.y - 4, 54, 46);
344 
345 		if (flags & IconActive) { // Code to make a border appear around the icon when the mouse hovers over it.
346 			Video.DrawRectangle(ColorGray, pos.x - 4, pos.y - 4, 54, 46);
347 			//Wyrmgus start
348 //			DrawUIButton(&s, flags, pos.x, pos.y, text, player);
349 			if (show_percent < 100) {
350 				DrawUIButton(&s, flags, pos.x, pos.y, text, player, true);
351 			}
352 			DrawUIButton(&s, flags, pos.x, pos.y, text, player, transparent, show_percent);
353 			//Wyrmgus end
354 		}
355 
356 		if (flags & IconClicked) { // Shift the icon a bit to make it look like it's been pressed.
357 			//Wyrmgus start
358 //			DrawUIButton(&s, flags, pos.x + 1, pos.y + 1, text, player);
359 			if (show_percent < 100) {
360 				DrawUIButton(&s, flags, pos.x + 1, pos.y + 1, text, player, true);
361 			}
362 			DrawUIButton(&s, flags, pos.x + 1, pos.y + 1, text, player, transparent, show_percent);
363 			//Wyrmgus end
364 			if (flags & IconSelected) {
365 				Video.DrawRectangle(ColorGreen, pos.x + 1, pos.y + 1, 46, 38);
366 			}
367 			Video.DrawRectangle(ColorGray, pos.x, pos.y, 48, 40);
368 			Video.DrawVLine(ColorDarkGray, pos.x - 1, pos.y - 1, 40);
369 			Video.DrawHLine(ColorDarkGray, pos.x - 1, pos.y - 1, 49);
370 			Video.DrawHLine(ColorDarkGray, pos.x - 1, pos.y + 39, 2);
371 
372 			Video.DrawRectangle(ColorGray, pos.x - 4, pos.y - 4, 54, 46);
373 		} else {
374 			//Wyrmgus start
375 //			DrawUIButton(&s, flags, pos.x, pos.y, text, player);
376 			if (show_percent < 100) {
377 				DrawUIButton(&s, flags, pos.x, pos.y, text, player, true);
378 			}
379 			DrawUIButton(&s, flags, pos.x, pos.y, text, player, transparent, show_percent);
380 			//Wyrmgus end
381 			if (flags & IconSelected) {
382 				Video.DrawRectangle(ColorGreen, pos.x, pos.y, 46, 38);
383 			}
384 		}
385 	} else {
386 		//Wyrmgus start
387 //		DrawUIButton(&s, flags, pos.x, pos.y, text, player);
388 		if (show_percent < 100) {
389 			DrawUIButton(&s, flags, pos.x, pos.y, text, player, true);
390 		}
391 		DrawUIButton(&s, flags, pos.x, pos.y, text, player, transparent, show_percent);
392 		//Wyrmgus end
393 	}
394 }
395 
396 /**
397 **  Load the Icon
398 */
LoadNoLog()399 bool IconConfig::LoadNoLog()
400 {
401 	Assert(!Name.empty());
402 
403 	Icon = CIcon::Get(Name);
404 	return Icon != nullptr;
405 }
406 
407 /**
408 **  Load the Icon
409 */
Load()410 bool IconConfig::Load()
411 {
412 	bool res = LoadNoLog();
413 	if (res == true) {
414 		UpdateLoadProgress();
415 	} else {
416 		fprintf(stderr, _("Can't find icon %s\n"), this->Name.c_str());
417 	}
418 	return res;
419 }
420 
421 /**
422 **  Get the numbers of icons.
423 */
GetIconsCount()424 int GetIconsCount()
425 {
426 	return Icons.size();
427 }
428 
429 /**
430 **  Load the graphics for the icons.
431 */
LoadIcons()432 void LoadIcons()
433 {
434 	ShowLoadProgress("%s", _("Loading Icons"));
435 
436 	for (IconMap::iterator it = Icons.begin(); it != Icons.end(); ++it) {
437 		CIcon &icon = *(*it).second;
438 
439 		UpdateLoadProgress();
440 		icon.Load();
441 
442 		IncItemsLoaded();
443 	}
444 }
445 
446 /**
447 **  Clean up memory used by the icons.
448 */
CleanIcons()449 void CleanIcons()
450 {
451 	for (IconMap::iterator it = Icons.begin(); it != Icons.end(); ++it) {
452 		CIcon *icon = (*it).second;
453 		delete icon;
454 	}
455 	Icons.clear();
456 }
457 
458 //@}
459