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 "menus.h"
41 #include "player.h"
42 #include "translate.h"
43 #include "ui.h"
44 #include "unit.h"
45 #include "video.h"
46 
47 #include <map>
48 
49 /*----------------------------------------------------------------------------
50 --  Variables
51 ----------------------------------------------------------------------------*/
52 
53 typedef std::map<std::string, CIcon *> IconMap;
54 static IconMap Icons;   /// Map of ident to icon.
55 
56 
57 /*----------------------------------------------------------------------------
58 --  Functions
59 ----------------------------------------------------------------------------*/
60 
61 /**
62 **  CIcon constructor
63 */
CIcon(const std::string & ident)64 CIcon::CIcon(const std::string &ident) : G(NULL), GScale(NULL), Frame(0), Ident(ident)
65 {
66 }
67 
68 /**
69 **  CIcon destructor
70 */
~CIcon()71 CIcon::~CIcon()
72 {
73 	CPlayerColorGraphic::Free(this->G);
74 	CPlayerColorGraphic::Free(this->GScale);
75 }
76 
77 /**
78 **  Create a new icon
79 **
80 **  @param ident  Icon identifier
81 **
82 **  @return       New icon
83 */
New(const std::string & ident)84 /* static */ CIcon *CIcon::New(const std::string &ident)
85 {
86 	CIcon *&icon = Icons[ident];
87 
88 	if (icon == NULL) {
89 		icon = new CIcon(ident);
90 	}
91 	return icon;
92 }
93 
94 /**
95 **  Get an icon
96 **
97 **  @param ident  Icon identifier
98 **
99 **  @return       The icon
100 */
Get(const std::string & ident)101 /* static */ CIcon *CIcon::Get(const std::string &ident)
102 {
103 	IconMap::iterator it = Icons.find(ident);
104 	if (it == Icons.end()) {
105 		DebugPrint("icon not found: %s\n" _C_ ident.c_str());
106 	}
107 	return it->second;
108 }
109 
Load()110 void CIcon::Load()
111 {
112 	Assert(G);
113 	G->Load();
114 	if (Preference.GrayscaleIcons) {
115 		GScale = G->Clone(true);
116 	}
117 	if (Frame >= G->NumFrames) {
118 		DebugPrint("Invalid icon frame: %s - %d\n" _C_ Ident.c_str() _C_ Frame);
119 		Frame = 0;
120 	}
121 }
122 
123 /**
124 **  Draw icon at pos.
125 **
126 **  @param player  Player pointer used for icon colors
127 **  @param pos     display pixel position
128 */
DrawIcon(const PixelPos & pos,const int player) const129 void CIcon::DrawIcon(const PixelPos &pos, const int player) const
130 {
131 	if (player != -1 ) {
132 		this->G->DrawPlayerColorFrameClip(player, this->Frame, pos.x, pos.y);
133 	} else {
134 		this->G->DrawFrameClip(this->Frame, pos.x, pos.y);
135 	}
136 }
137 
138 /**
139 **  Draw grayscale icon at pos.
140 **
141 **  @param pos     display pixel position
142 */
DrawGrayscaleIcon(const PixelPos & pos,const int player) const143 void CIcon::DrawGrayscaleIcon(const PixelPos &pos, const int player) const
144 {
145 	if (this->GScale) {
146 		if (player != -1) {
147 			this->GScale->DrawPlayerColorFrameClip(player, this->Frame, pos.x, pos.y);
148 		} else {
149 			this->GScale->DrawFrameClip(this->Frame, pos.x, pos.y);
150 		}
151 	}
152 }
153 
154 /**
155 **  Draw cooldown spell effect on icon at pos.
156 **
157 **  @param pos       display pixel position
158 **  @param percent   cooldown percent
159 */
DrawCooldownSpellIcon(const PixelPos & pos,const int percent) const160 void CIcon::DrawCooldownSpellIcon(const PixelPos &pos, const int percent) const
161 {
162 	// TO-DO: implement more effect types (clock-like)
163 	if (this->GScale) {
164 		this->GScale->DrawFrameClip(this->Frame, pos.x, pos.y);
165 		const int height = (G->Height * (100 - percent)) / 100;
166 		this->G->DrawSubClip(G->frame_map[Frame].x, G->frame_map[Frame].y + G->Height - height,
167 							 G->Width, height, pos.x, pos.y + G->Height - height);
168 	} else {
169 		DebugPrint("Enable grayscale icon drawing in your game to achieve special effects for cooldown spell icons");
170 		this->DrawIcon(pos);
171 	}
172 }
173 
174 /**
175 **  Draw unit icon 'icon' with border on x,y
176 **
177 **  @param style   Button style
178 **  @param flags   State of icon (clicked, mouse over...)
179 **  @param pos     display pixel position
180 **  @param text    Optional text to display
181 */
DrawUnitIcon(const ButtonStyle & style,unsigned flags,const PixelPos & pos,const std::string & text,int player) const182 void CIcon::DrawUnitIcon(const ButtonStyle &style, unsigned flags,
183 						 const PixelPos &pos, const std::string &text, int player) const
184 {
185 	ButtonStyle s(style);
186 
187 	s.Default.Sprite = s.Hover.Sprite = s.Clicked.Sprite = this->G;
188 	s.Default.Frame = s.Hover.Frame = s.Clicked.Frame = this->Frame;
189 	if (!(flags & IconSelected) && (flags & IconAutoCast)) {
190 		s.Default.BorderColorRGB = UI.ButtonPanel.AutoCastBorderColorRGB;
191 		s.Default.BorderColor = 0;
192 		s.Default.BorderSize = 2;
193 	}
194 	if (Preference.IconsShift && Preference.IconFrameG && Preference.PressedIconFrameG) {
195 		int shift = 0;
196 		if (!(flags & IconClicked)) {
197 			int xoffset = (s.Width - Preference.IconFrameG->Width) / 2;
198 			int yoffset = (s.Height - Preference.IconFrameG->Height) / 2;
199 			Preference.IconFrameG->DrawClip(pos.x + xoffset, pos.y + yoffset);
200 		} else { // Shift the icon a bit to make it look like it's been pressed.
201 			shift = 1;
202 			int xoffset = (s.Width - Preference.PressedIconFrameG->Width) / 2 + shift;
203 			int yoffset = (s.Height - Preference.PressedIconFrameG->Height) / 2 + shift;
204 			Preference.PressedIconFrameG->DrawClip(pos.x + xoffset, pos.y + yoffset);
205 		}
206 		DrawUIButton(&s, flags, pos.x + shift, pos.y + shift, text, player);
207 		if (flags & IconSelected) {
208 			Video.DrawRectangle(ColorGreen, pos.x + shift, pos.y + shift, s.Width, s.Height);
209 		}
210 	} else if (Preference.IconsShift) {
211 		// Left and top edge of Icon
212 		Video.DrawHLine(ColorWhite, pos.x - 1, pos.y - 1, 49);
213 		Video.DrawVLine(ColorWhite, pos.x - 1, pos.y, 40);
214 		Video.DrawVLine(ColorWhite, pos.x, pos.y + 38, 2);
215 		Video.DrawHLine(ColorWhite, pos.x + 46, pos.y, 2);
216 
217 		// Bottom and Right edge of Icon
218 		Video.DrawHLine(ColorGray, pos.x + 1, pos.y + 38, 47);
219 		Video.DrawHLine(ColorGray, pos.x + 1, pos.y + 39, 47);
220 		Video.DrawVLine(ColorGray, pos.x + 46, pos.y + 1, 37);
221 		Video.DrawVLine(ColorGray, pos.x + 47, pos.y + 1, 37);
222 
223 		Video.DrawRectangle(ColorBlack, pos.x - 3, pos.y - 3, 52, 44);
224 		Video.DrawRectangle(ColorBlack, pos.x - 4, pos.y - 4, 54, 46);
225 
226 		if (flags & IconActive) { // Code to make a border appear around the icon when the mouse hovers over it.
227 			Video.DrawRectangle(ColorGray, pos.x - 4, pos.y - 4, 54, 46);
228 			DrawUIButton(&s, flags, pos.x, pos.y, text, player);
229 		}
230 
231 		if (flags & IconClicked) { // Shift the icon a bit to make it look like it's been pressed.
232 			DrawUIButton(&s, flags, pos.x + 1, pos.y + 1, text, player);
233 			if (flags & IconSelected) {
234 				Video.DrawRectangle(ColorGreen, pos.x + 1, pos.y + 1, 46, 38);
235 			}
236 			Video.DrawRectangle(ColorGray, pos.x, pos.y, 48, 40);
237 			Video.DrawVLine(ColorDarkGray, pos.x - 1, pos.y - 1, 40);
238 			Video.DrawHLine(ColorDarkGray, pos.x - 1, pos.y - 1, 49);
239 			Video.DrawHLine(ColorDarkGray, pos.x - 1, pos.y + 39, 2);
240 
241 			Video.DrawRectangle(ColorGray, pos.x - 4, pos.y - 4, 54, 46);
242 		} else {
243 			DrawUIButton(&s, flags, pos.x, pos.y, text, player);
244 			if (flags & IconSelected) {
245 				Video.DrawRectangle(ColorGreen, pos.x, pos.y, 46, 38);
246 			}
247 		}
248 	} else {
249 		DrawUIButton(&s, flags, pos.x, pos.y, text, player);
250 	}
251 }
252 
253 /**
254 **  Load the Icon
255 */
LoadNoLog()256 bool IconConfig::LoadNoLog()
257 {
258 	if (Name.empty()) {
259 		return false;
260 	}
261 
262 	Icon = CIcon::Get(Name);
263 	return Icon != NULL;
264 }
265 
266 /**
267 **  Load the Icon
268 */
Load()269 bool IconConfig::Load()
270 {
271 	if (LoadNoLog() == true) {
272 		ShowLoadProgress(_("Icon %s"), this->Name.c_str());
273 		return true;
274 	} else {
275 		fprintf(stderr, _("Can't find icon %s\n"), this->Name.c_str());
276 		return false;
277 	}
278 }
279 
280 /**
281 **  Load the graphics for the icons.
282 */
LoadIcons()283 void LoadIcons()
284 {
285 	for (IconMap::iterator it = Icons.begin(); it != Icons.end(); ++it) {
286 		CIcon &icon = *(*it).second;
287 
288 		ShowLoadProgress(_("Icons %s"), icon.G->File.c_str());
289 		icon.Load();
290 	}
291 }
292 
293 /**
294 **  Clean up memory used by the icons.
295 */
CleanIcons()296 void CleanIcons()
297 {
298 	for (IconMap::iterator it = Icons.begin(); it != Icons.end(); ++it) {
299 		CIcon *icon = (*it).second;
300 		delete icon;
301 	}
302 	Icons.clear();
303 }
304 
305 //@}
306