1 /***************************************************************************
2  *      Mechanized Assault and Exploration Reloaded Projectfile            *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19 
20 #include "ui/graphical/menu/widgets/pushbutton.h"
21 
22 #include "ui/graphical/application.h"
23 
24 #include "settings.h"
25 #include "video.h"
26 #include "unifonts.h"
27 #include "main.h"
28 #include "input/mouse/mouse.h"
29 #include "output/sound/sounddevice.h"
30 #include "output/sound/soundchannel.h"
31 #include "utility/drawing.h"
32 
33 //------------------------------------------------------------------------------
cPushButton(const cBox<cPosition> & area)34 cPushButton::cPushButton (const cBox<cPosition>& area) :
35 	cClickableWidget (area),
36 	buttonType (ePushButtonType::Invisible),
37 	fontType (FONT_LATIN_BIG),
38 	text (""),
39 	clickSound (&SoundData.SNDHudButton),
40 	isLocked (false)
41 
42 {
43 	if (buttonType >= ePushButtonType::HudNext && buttonType <= ePushButtonType::HudFiles)
44 		fontType = FONT_LATIN_SMALL_WHITE;
45 	renewSurface();
46 }
47 
48 //------------------------------------------------------------------------------
cPushButton(const cPosition & position,ePushButtonType buttonType_)49 cPushButton::cPushButton (const cPosition& position, ePushButtonType buttonType_) :
50 	cClickableWidget (position),
51 	buttonType (buttonType_),
52 	fontType (FONT_LATIN_BIG),
53 	text (""),
54 	clickSound (&SoundData.SNDHudButton),
55 	isLocked (false)
56 {
57 	if (buttonType >= ePushButtonType::HudNext && buttonType <= ePushButtonType::HudFiles)
58 		fontType = FONT_LATIN_SMALL_WHITE;
59 	renewSurface();
60 }
61 
62 //------------------------------------------------------------------------------
cPushButton(const cPosition & position,ePushButtonType buttonType_,cSoundChunk * clickSound_)63 cPushButton::cPushButton (const cPosition& position, ePushButtonType buttonType_, cSoundChunk* clickSound_) :
64 	cClickableWidget (position),
65 	buttonType (buttonType_),
66 	fontType (FONT_LATIN_BIG),
67 	text (""),
68 	clickSound (clickSound_),
69 	isLocked (false)
70 {
71 	if (buttonType >= ePushButtonType::HudNext && buttonType <= ePushButtonType::HudFiles)
72 		fontType = FONT_LATIN_SMALL_WHITE;
73 	renewSurface();
74 }
75 
76 //------------------------------------------------------------------------------
cPushButton(const cPosition & position,ePushButtonType buttonType_,const std::string & text_,eUnicodeFontType fontType_)77 cPushButton::cPushButton (const cPosition& position, ePushButtonType buttonType_, const std::string& text_, eUnicodeFontType fontType_) :
78 	cClickableWidget (position),
79 	buttonType (buttonType_),
80 	fontType (fontType_),
81 	text (text_),
82 	clickSound (&SoundData.SNDHudButton),
83 	isLocked (false)
84 {
85 	if (buttonType >= ePushButtonType::HudNext && buttonType <= ePushButtonType::HudFiles)
86 		fontType = FONT_LATIN_SMALL_WHITE;
87 	renewSurface();
88 }
89 
90 //------------------------------------------------------------------------------
cPushButton(const cPosition & position,ePushButtonType buttonType_,cSoundChunk * clickSound_,const std::string & text_,eUnicodeFontType fontType_)91 cPushButton::cPushButton (const cPosition& position, ePushButtonType buttonType_, cSoundChunk* clickSound_, const std::string& text_, eUnicodeFontType fontType_) :
92 	cClickableWidget (position),
93 	buttonType (buttonType_),
94 	fontType (fontType_),
95 	text (text_),
96 	clickSound (clickSound_),
97 	isLocked (false)
98 {
99 	if (buttonType >= ePushButtonType::HudNext && buttonType <= ePushButtonType::HudFiles)
100 		fontType = FONT_LATIN_SMALL_WHITE;
101 	renewSurface();
102 }
103 
104 //------------------------------------------------------------------------------
draw(SDL_Surface & destination,const cBox<cPosition> & clipRect)105 void cPushButton::draw (SDL_Surface& destination, const cBox<cPosition>& clipRect)
106 {
107 	SDL_Rect position = getArea().toSdlRect();
108 	if (surface != nullptr) SDL_BlitSurface (surface.get(), nullptr, &destination, &position);
109 
110 	if (!text.empty())
111 	{
112 		if (buttonType >= ePushButtonType::HudNext && buttonType <= ePushButtonType::HudFiles)
113 		{
114 			if (isPressed || isLocked) font->showTextCentered (position.x + position.w / 2, position.y + getTextYOffset(), text, FONT_LATIN_SMALL_GREEN);
115 			else font->showTextCentered (position.x + position.w / 2, position.y + getTextYOffset() - 1, text, FONT_LATIN_SMALL_RED);
116 			font->showTextCentered (position.x + position.w / 2 - 1, position.y + getTextYOffset() - 1 + (isPressed || isLocked ? 1 : 0), text, FONT_LATIN_SMALL_WHITE);
117 		}
118 		else font->showTextCentered (position.x + position.w / 2, position.y + getTextYOffset(), text, fontType);
119 	}
120 
121 	cWidget::draw (destination, clipRect);
122 }
123 
124 //------------------------------------------------------------------------------
handleMousePressed(cApplication & application,cMouse & mouse,eMouseButtonType button)125 bool cPushButton::handleMousePressed (cApplication& application, cMouse& mouse, eMouseButtonType button)
126 {
127 	if (isLocked) return false;
128 	return cClickableWidget::handleMousePressed (application, mouse, button);
129 }
130 
131 //------------------------------------------------------------------------------
handleMouseReleased(cApplication & application,cMouse & mouse,eMouseButtonType button)132 bool cPushButton::handleMouseReleased (cApplication& application, cMouse& mouse, eMouseButtonType button)
133 {
134 	if (isLocked)
135 	{
136 		cClickableWidget::finishMousePressed (application, mouse, button);
137 		return false;
138 	}
139 	return cClickableWidget::handleMouseReleased (application, mouse, button);
140 }
141 
142 //------------------------------------------------------------------------------
handleClicked(cApplication & application,cMouse & mouse,eMouseButtonType button)143 bool cPushButton::handleClicked (cApplication& application, cMouse& mouse, eMouseButtonType button)
144 {
145 	if (button == eMouseButtonType::Left)
146 	{
147 		if (clickSound) cSoundDevice::getInstance().playSoundEffect (*clickSound);
148 		clicked();
149 		return true;
150 	}
151 	return false;
152 }
153 
154 //------------------------------------------------------------------------------
setPressed(bool pressed)155 void cPushButton::setPressed (bool pressed)
156 {
157 	cClickableWidget::setPressed (pressed);
158 	renewSurface();
159 }
160 
161 //------------------------------------------------------------------------------
lock()162 void cPushButton::lock()
163 {
164 	isLocked = true;
165 	renewSurface();
166 }
167 
168 //------------------------------------------------------------------------------
unlock()169 void cPushButton::unlock()
170 {
171 	isLocked = false;
172 	renewSurface();
173 }
174 
175 //------------------------------------------------------------------------------
renewSurface()176 void cPushButton::renewSurface()
177 {
178 	if (buttonType == ePushButtonType::Invisible)
179 	{
180 		surface = nullptr;
181 		return;
182 	}
183 
184 	cPosition size;
185 	SDL_Rect src;
186 	switch (buttonType)
187 	{
188 		default:
189 		case ePushButtonType::StandardBig:
190 			src.x = 0;
191 			src.y = (isPressed || isLocked) ? 29 : 0;
192 			size = cPosition (200, 29);
193 			break;
194 		case ePushButtonType::StandardSmall:
195 			src.x = 0;
196 			src.y = (isPressed || isLocked) ? 87 : 58;
197 			size = cPosition (150, 29);
198 			break;
199 		case ePushButtonType::Huge:
200 			src.x = (isPressed || isLocked) ? 109 : 0;
201 			src.y = 116;
202 			size = cPosition (109, 40);
203 			break;
204 		case ePushButtonType::ArrowUpBig:
205 			src.x = (isPressed || isLocked) ? 125 : 97;
206 			src.y = 157;
207 			size = cPosition (28, 29);
208 			break;
209 		case ePushButtonType::ArrowDownBig:
210 			src.x = (isPressed || isLocked) ? 181 : 153;
211 			src.y = 157;
212 			size = cPosition (28, 29);
213 			break;
214 		case ePushButtonType::ArrowLeftBig:
215 			src.x = (isPressed || isLocked) ? 293 : 265;
216 			src.y = 157;
217 			size = cPosition (28, 29);
218 			break;
219 		case ePushButtonType::ArrowRightBig:
220 			src.x = (isPressed || isLocked) ? 237 : 209;
221 			src.y = 157;
222 			size = cPosition (28, 29);
223 			break;
224 		case ePushButtonType::ArrowUpSmall:
225 			size = cPosition (18, 17);
226 			src.x = (isPressed || isLocked) ? 151 + size.x() : 151;
227 			src.y = 59;
228 			break;
229 		case ePushButtonType::ArrowDownSmall:
230 			size = cPosition (18, 17);
231 			src.x = (isPressed || isLocked) ? 187 + size.x() : 187;
232 			src.y = 59;
233 			break;
234 		case ePushButtonType::ArrowLeftSmall:
235 			size = cPosition (18, 17);
236 			src.x = (isPressed || isLocked) ? 151 + size.x() : 151;
237 			src.y = 76;
238 			break;
239 		case ePushButtonType::ArrowRightSmall:
240 			size = cPosition (18, 17);
241 			src.x = (isPressed || isLocked) ? 187 + size.x() : 187;
242 			src.y = 76;
243 			break;
244 		case ePushButtonType::ArrowUpBar:
245 			size = cPosition (17, 17);
246 			src.x = (isPressed || isLocked) ? 201 + size.x() : 201;
247 			src.y = 1;
248 			break;
249 		case ePushButtonType::ArrowDownBar:
250 			size = cPosition (17, 17);
251 			src.x = (isPressed || isLocked) ? 201 + size.x() : 201;
252 			src.y = 18;
253 			break;
254 		case ePushButtonType::Angular:
255 			size = cPosition (78, 23);
256 			src.x = (isPressed || isLocked) ? size.x() : 0;
257 			src.y = 196;
258 			break;
259 		case ePushButtonType::HudHelp:
260 			src.x = (isPressed || isLocked) ? 366 : 268;
261 			src.y = (isPressed || isLocked) ? 0 : 151;
262 			size = cPosition (26, 24);
263 			break;
264 		case ePushButtonType::HudCenter:
265 			src.x = (isPressed || isLocked) ? 0 : 139;
266 			src.y = (isPressed || isLocked) ? 21 : 149;
267 			size = cPosition (21, 22);
268 			break;
269 		case ePushButtonType::HudReport:
270 			src.x = (isPressed || isLocked) ? 210 : 245;
271 			src.y = (isPressed || isLocked) ? 21 : 130;
272 			size = cPosition (49, 20);
273 			break;
274 		case ePushButtonType::HudChat:
275 			src.x = (isPressed || isLocked) ? 160 : 196;
276 			src.y = (isPressed || isLocked) ? 21 : 129;
277 			size = cPosition (49, 20);
278 			break;
279 		case ePushButtonType::HudNext:
280 			src.x = (isPressed || isLocked) ? 288 : 158;
281 			src.y = (isPressed || isLocked) ? 0 : 172;
282 			size = cPosition (39, 23);
283 			break;
284 		case ePushButtonType::HudPrev:
285 			src.x = (isPressed || isLocked) ? 327 : 198;
286 			src.y = (isPressed || isLocked) ? 0 : 172;
287 			size = cPosition (38, 23);
288 			break;
289 		case ePushButtonType::HudDone:
290 			src.x = (isPressed || isLocked) ? 262 : 132;
291 			src.y = (isPressed || isLocked) ? 0 : 172;
292 			size = cPosition (26, 24);
293 			break;
294 		case ePushButtonType::HudEnd:
295 			src.x = (isPressed || isLocked) ? 22 : 0;
296 			src.y = (isPressed || isLocked) ? 21 : 151;
297 			size = cPosition (70, 17);
298 			break;
299 		case ePushButtonType::HudPreferences:
300 			src.x = (isPressed || isLocked) ? 195 : 0;
301 			src.y = (isPressed || isLocked) ? 0 : 169;
302 			size = cPosition (67, 20);
303 			break;
304 		case ePushButtonType::HudFiles:
305 			src.x = (isPressed || isLocked) ? 93 : 71;
306 			src.y = (isPressed || isLocked) ? 21 : 151;
307 			size = cPosition (67, 20);
308 			break;
309 		case ePushButtonType::HudPlay:
310 			src.x = (isPressed || isLocked) ? 157 : 0;
311 			src.y = (isPressed || isLocked) ? 0 : 132;
312 			size = cPosition (19, 18);
313 			break;
314 		case ePushButtonType::HudStop:
315 			src.x = (isPressed || isLocked) ? 176 : 19;
316 			src.y = (isPressed || isLocked) ? 0 : 132;
317 			size = cPosition (19, 19);
318 			break;
319 		case ePushButtonType::UnitContextMenu:
320 			src.x = 0;
321 			src.y = (isPressed || isLocked) ? 21 : 0;
322 			size = cPosition (42, 21);
323 			break;
324 		case ePushButtonType::Destroy:
325 			src.x = (isPressed || isLocked) ? 6 : 15;
326 			src.y = (isPressed || isLocked) ? 269 : 13;
327 			size = cPosition (59, 56);
328 			break;
329 		case ePushButtonType::ArrowUpSmallModern:
330 			src.x = 224;
331 			src.y = (isPressed || isLocked) ? 75 : 83;
332 			size = cPosition (16, 8);
333 			break;
334 		case ePushButtonType::ArrowDownSmallModern:
335 			src.x = 224;
336 			src.y = (isPressed || isLocked) ? 59 : 67;
337 			size = cPosition (16, 8);
338 			break;
339 		case ePushButtonType::ArrowLeftSmallModern:
340 			src.x = (isPressed || isLocked) ? 272 : 264;
341 			src.y = 59;
342 			size = cPosition (8, 16);
343 			break;
344 		case ePushButtonType::ArrowRightSmallModern:
345 			src.x = (isPressed || isLocked) ? 256 : 248;
346 			src.y = 59;
347 			size = cPosition (8, 16);
348 			break;
349 	}
350 	resize (size);
351 
352 	src.w = size.x();
353 	src.h = size.y();
354 
355 	surface = AutoSurface (SDL_CreateRGBSurface (0, src.w, src.h, Video.getColDepth(), 0, 0, 0, 0));
356 	SDL_SetColorKey (surface.get(), SDL_TRUE, 0xFF00FF);
357 	SDL_FillRect (surface.get(), nullptr, 0xFF00FF);
358 
359 	SDL_Surface* srcSurface = nullptr;
360 
361 	if (buttonType >= ePushButtonType::HudHelp && buttonType <= ePushButtonType::HudStop) srcSurface = GraphicsData.gfx_hud_stuff.get();
362 	else if (buttonType == ePushButtonType::UnitContextMenu) srcSurface = GraphicsData.gfx_context_menu.get();
363 	else if (buttonType == ePushButtonType::Destroy) srcSurface = (isPressed || isLocked) ? GraphicsData.gfx_hud_stuff.get() : GraphicsData.gfx_destruction.get();
364 	else srcSurface = GraphicsData.gfx_menu_stuff.get();
365 
366 	assert (srcSurface != nullptr);
367 
368 	SDL_BlitSurface (srcSurface, &src, surface.get(), nullptr);
369 
370 	text = font->shortenStringToSize (text, size.x() - getBordersSize(), fontType);
371 }
372 
373 //------------------------------------------------------------------------------
getTextYOffset() const374 int cPushButton::getTextYOffset() const
375 {
376 	switch (buttonType)
377 	{
378 		default:
379 		case ePushButtonType::StandardBig:
380 		case ePushButtonType::StandardSmall:
381 			return 7;
382 		case ePushButtonType::Huge:
383 			return 11;
384 		case ePushButtonType::ArrowUpBig:
385 		case ePushButtonType::ArrowDownBig:
386 		case ePushButtonType::ArrowLeftBig:
387 		case ePushButtonType::ArrowRightBig:
388 		case ePushButtonType::ArrowUpSmall:
389 		case ePushButtonType::ArrowDownSmall:
390 		case ePushButtonType::ArrowLeftSmall:
391 		case ePushButtonType::ArrowRightSmall:
392 		case ePushButtonType::ArrowUpBar:
393 		case ePushButtonType::ArrowDownBar:
394 			return -1;
395 		case ePushButtonType::Angular:
396 			if (isPressed || isLocked) return 5;
397 			else return 4;
398 		case ePushButtonType::HudNext:
399 		case ePushButtonType::HudPrev:
400 		case ePushButtonType::HudDone:
401 			return 9;
402 		case ePushButtonType::HudEnd:
403 			if (isPressed || isLocked) return 3;
404 			else return 2;
405 		case ePushButtonType::HudReport:
406 		case ePushButtonType::HudChat:
407 		case ePushButtonType::HudPreferences:
408 		case ePushButtonType::HudFiles:
409 			return 6;
410 		case ePushButtonType::UnitContextMenu:
411 			return 7;
412 	}
413 }
414 
415 //------------------------------------------------------------------------------
getBordersSize() const416 int cPushButton::getBordersSize() const
417 {
418 	switch (buttonType)
419 	{
420 		case ePushButtonType::UnitContextMenu:
421 		case ePushButtonType::HudDone:
422 			return 0;
423 		default:
424 			return 12;
425 	}
426 }
427