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