1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3 
4 This file is part of Aquaria.
5 
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15 See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 */
21 #include "AquariaMenuItem.h"
22 #include "DSQ.h"
23 #include "Game.h"
24 
25 float AquariaGuiElement::guiMoveTimer = 0;
26 AquariaGuiElement::GuiElements AquariaGuiElement::guiElements;
27 bool AquariaGuiElement::canDirMoveGlobal = true;
28 
29 int AquariaGuiElement::currentGuiInputLevel = 0;
30 
31 AquariaGuiElement *AquariaGuiElement::currentFocus = 0;
32 
AquariaGuiElement()33 AquariaGuiElement::AquariaGuiElement()
34 {
35 	for (int i = 0; i < DIR_MAX; i++)
36 	{
37 		dirMove[i] = 0;
38 	}
39 	hasFocus = false;
40 
41 	guiMoveTimer = 0;
42 
43 	guiElements.push_back(this);
44 
45 	canDirMove = true;
46 
47 	guiInputLevel = 0;
48 }
49 
hasInput()50 bool AquariaGuiElement::hasInput()
51 {
52 	if (guiInputLevel >= AquariaGuiElement::currentGuiInputLevel)
53 	{
54 		return true;
55 	}
56 	return false;
57 }
58 
clean()59 void AquariaGuiElement::clean()
60 {
61 	guiElements.remove(this);
62 }
63 
setDirMove(int dir,AquariaGuiElement * item)64 void AquariaGuiElement::setDirMove(int dir, AquariaGuiElement *item)
65 {
66 	if (dir >= 0 && dir < DIR_MAX)
67 	{
68 		dirMove[dir] = item;
69 	}
70 }
71 
setCanDirMove(bool on)72 void AquariaGuiElement::setCanDirMove(bool on)
73 {
74 	canDirMove = on;
75 }
76 
setFocus(bool v)77 void AquariaGuiElement::setFocus(bool v)
78 {
79 	hasFocus = v;
80 
81 	if (v)
82 	{
83 		currentFocus = this;
84 		if (dsq->inputMode == INPUT_JOYSTICK)
85 			core->setMousePosition(getGuiPosition());
86 
87 		AquariaGuiElement *gui=0, *guiThis = (AquariaGuiElement*)this;
88 		for (GuiElements::iterator i = guiElements.begin(); i != guiElements.end(); i++)
89 		{
90 			gui = (*i);
91 			if (gui && gui != guiThis)
92 			{
93 				gui->setFocus(false);
94 			}
95 		}
96 	}
97 	else if(this == currentFocus)
98 		currentFocus = 0;
99 }
100 
updateMovement(float dt)101 void AquariaGuiElement::updateMovement(float dt)
102 {
103 	//debugLog("in update movement");
104 	if (hasFocus && isGuiVisible() && canDirMove && canDirMoveGlobal && hasInput())
105 	{
106 		//debugLog("has focus");
107 		/*
108 		if (alpha.x <= 0 || alphaMod <= 0)
109 		{
110 			setFocus(false);
111 			return;
112 		}
113 		*/
114 
115 		if (guiMoveTimer > 0)
116 		{
117 			guiMoveTimer -= dt;
118 			if (guiMoveTimer < 0) guiMoveTimer = 0;
119 		}
120 
121 		if (guiMoveTimer==0)
122 		{
123 			Direction dir = DIR_NONE;
124 			Vector p = core->joystick.position;
125 			if (!p.isLength2DIn(0.4))
126 			{
127 				if (fabsf(p.x) > fabsf(p.y))
128 				{
129 					if (p.x > 0)
130 						dir = DIR_RIGHT;
131 					else
132 						dir = DIR_LEFT;
133 				}
134 				else
135 				{
136 					if (p.y > 0)
137 						dir = DIR_DOWN;
138 					else
139 						dir = DIR_UP;
140 				}
141 			}
142 			else
143 			{
144 				StateObject *obj = dsq->getTopStateObject();
145 				if (obj)
146 				{
147 					if (obj->isActing(ACTION_MENULEFT))			dir = DIR_LEFT;
148 					else if (obj->isActing(ACTION_MENURIGHT))	dir = DIR_RIGHT;
149 					else if (obj->isActing(ACTION_MENUUP))		dir = DIR_UP;
150 					else if (obj->isActing(ACTION_MENUDOWN))	dir = DIR_DOWN;
151 				}
152 			}
153 
154 			if (dir == DIR_NONE) return;
155 
156 			const float moveDelay = 0.2;
157 
158 			AquariaGuiElement *gui = 0;
159 			if (dir > DIR_NONE && dir < DIR_MAX)
160 			{
161 				gui = dirMove[dir];
162 				if (gui)
163 				{
164 					gui->setFocus(true);
165 					//this->setFocus(false);
166 
167 
168 
169 					guiMoveTimer = moveDelay;
170 				}
171 			}
172 
173 			if (!gui)
174 			{
175 				debugLog("updating closest");
176 				int smallDist = -1, dist = 0;
177 
178 				AquariaGuiElement *gui = 0, *closest = 0;
179 				int ch = 64;
180 				for (GuiElements::iterator i = guiElements.begin(); i != guiElements.end(); i++)
181 				{
182 					gui = (*i);
183 					if (gui != this && gui->isGuiVisible() && gui->canDirMove)
184 					{
185 						int go = 0;
186 						Vector p1 = getGuiPosition();
187 						Vector p2 = gui->getGuiPosition();
188 
189 						if (dir == DIR_DOWN)
190 						{
191 							if (fabsf(p1.x - p2.x) < ch)
192 							{
193 								if (p2.y > p1.y) go = 1;
194 								p1.x = p2.x = 0;
195 							}
196 						}
197 						else if (dir == DIR_UP)
198 						{
199 							if (fabsf(p1.x - p2.x) < ch)
200 							{
201 								if (p2.y < p1.y) go = 1;
202 								p1.x = p2.x = 0;
203 							}
204 						}
205 						else if (dir == DIR_RIGHT)
206 						{
207 							if (fabsf(p1.y - p2.y) < ch)
208 							{
209 								if (p2.x > p1.x) go = 1;
210 								p1.y = p2.y = 0;
211 							}
212 						}
213 						else if (dir == DIR_LEFT)
214 						{
215 							if (fabsf(p1.y - p2.y) < ch)
216 							{
217 								if (p2.x < p1.x) go = 1;
218 								p1.y = p2.y = 0;
219 							}
220 						}
221 						else
222 						{
223 							continue;
224 						}
225 
226 						if (go)
227 						{
228 							dist = (p1 - p2).getSquaredLength2D();
229 
230 							if (smallDist == -1 || dist < smallDist)
231 							{
232 								closest = gui;
233 								smallDist = dist;
234 							}
235 						}
236 						else
237 						{
238 							continue;
239 						}
240 					}
241 				}
242 
243 				if (closest)
244 				{
245 					closest->setFocus(true);
246 
247 					guiMoveTimer = moveDelay;
248 				}
249 			}
250 		}
251 	}
252 }
253 
getClosestGuiElement(const Vector & pos)254 AquariaGuiElement *AquariaGuiElement::getClosestGuiElement(const Vector& pos)
255 {
256 	AquariaGuiElement *gui = 0, *closest = 0;
257 	float minlen = 0;
258 	for (GuiElements::iterator i = guiElements.begin(); i != guiElements.end(); i++)
259 	{
260 		gui = (*i);
261 		if (gui->isGuiVisible() && gui->hasInput())
262 		{
263 			Vector dist = gui->getGuiPosition() - pos;
264 			float len = dist.getSquaredLength2D();
265 			if(!closest || len < minlen)
266 			{
267 				closest = gui;
268 				minlen = len;
269 			}
270 		}
271 	}
272 	return closest;
273 }
274 
275 
AquariaGuiQuad()276 AquariaGuiQuad::AquariaGuiQuad() : Quad(), AquariaGuiElement()
277 {
278 }
279 
destroy()280 void AquariaGuiQuad::destroy()
281 {
282 	Quad::destroy();
283 	AquariaGuiElement::clean();
284 }
285 
getGuiPosition()286 Vector AquariaGuiQuad::getGuiPosition()
287 {
288 	return getWorldPosition();
289 }
290 
isGuiVisible()291 bool AquariaGuiQuad::isGuiVisible()
292 {
293 	return !isHidden() && alpha.x > 0 && alphaMod > 0 && renderQuad;
294 }
295 
update(float dt)296 void AquariaGuiQuad::update(float dt)
297 {
298 	// super hacky
299 	if (hasInput())
300 	{
301 		Quad::update(dt);
302 	}
303 	else
304 	{
305 		updateMovement(dt);
306 		Quad::onUpdate(dt);
307 	}
308 }
309 
onUpdate(float dt)310 void AquariaGuiQuad::onUpdate(float dt)
311 {
312 	updateMovement(dt);
313 	Quad::onUpdate(dt);
314 }
315 
316 // Joystick input threshold at which we start sliding (0.0-1.0); must be
317 // less than updateMovement() threshold.
318 const float SLIDER_JOY_THRESHOLD = 0.39;
319 // Initial delay before repeating for slider input (seconds).
320 const float SLIDER_REPEAT_DELAY = 0.4;
321 // Scale factor for delay as repeats continue.
322 const float SLIDER_REPEAT_ACCEL = 0.8;
323 
AquariaSlider()324 AquariaSlider::AquariaSlider()
325 : Slider(90, 12, "gui/slider-bg", "gui/slider-fg"), AquariaGuiElement()
326 // len, grab radius
327 {
328 	inputTimer = inputDelay = 0;
329 	_hadInput = false;
330 }
331 
onUpdate(float dt)332 void AquariaSlider::onUpdate(float dt)
333 {
334 	if (!hasInput())
335 	{
336 		inputTimer = inputDelay = 0;
337 		AquariaGuiElement::updateMovement(dt);
338 		RenderObject::onUpdate(dt);
339 	}
340 	else
341 	{
342 		if (!doSliderInput(dt))
343 			AquariaGuiElement::updateMovement(dt);
344 		Slider::onUpdate(dt);
345 	}
346 }
347 
doSliderInput(float dt)348 bool AquariaSlider::doSliderInput(float dt)
349 {
350 	if (!(core->mouse.position - this->position).isLength2DIn(5))
351 		return false;
352 
353 	float inputAmount;  // How much to adjust by?
354 
355 	StateObject *obj = dsq->getTopStateObject();
356 	if (core->joystick.position.x <= -SLIDER_JOY_THRESHOLD)
357 		inputAmount = -0.1f;
358 	else if (core->joystick.position.x >= SLIDER_JOY_THRESHOLD)
359 		inputAmount = +0.1f;
360 	else if (core->joystick.dpadLeft)
361 		inputAmount = -0.1f;
362 	else if (core->joystick.dpadRight)
363 		inputAmount = +0.1f;
364 	else if (obj && obj->isActing(ACTION_MENULEFT))
365 		inputAmount = -0.1f;
366 	else if (obj && obj->isActing(ACTION_MENURIGHT))
367 		inputAmount = +0.1f;
368 	else
369 		inputAmount = 0;
370 
371 	if (inputAmount != 0)
372 	{
373 		inputTimer += dt;
374 		if (inputTimer >= inputDelay)
375 		{
376 			float oldValue = value;
377 			setValue(value + inputAmount);
378 			if (value != oldValue)
379 				_hadInput = true;
380 
381 			inputTimer = 0;
382 			if (inputDelay == 0)
383 				inputDelay = SLIDER_REPEAT_DELAY;
384 			else
385 				inputDelay *= SLIDER_REPEAT_ACCEL;
386 		}
387 		return true;
388 	}
389 	else
390 	{
391 		inputTimer = inputDelay = 0;
392 		return false;
393 	}
394 }
395 
destroy()396 void AquariaSlider::destroy()
397 {
398 	Slider::destroy();
399 	AquariaGuiElement::clean();
400 }
401 
getGuiPosition()402 Vector AquariaSlider::getGuiPosition()
403 {
404 	return getWorldPosition();
405 }
406 
isGuiVisible()407 bool AquariaSlider::isGuiVisible()
408 {
409 	return !isHidden() && alpha.x > 0 && alphaMod > 0;
410 }
411 
AquariaCheckBox()412 AquariaCheckBox::AquariaCheckBox()
413 : CheckBox(12, "gui/check-bg", "gui/check-fg", "Click"), AquariaGuiElement()
414 {
415 }
416 
onUpdate(float dt)417 void AquariaCheckBox::onUpdate(float dt)
418 {
419 	AquariaGuiElement::updateMovement(dt);
420 	if (!hasInput())
421 	{
422 		RenderObject::onUpdate(dt);
423 	}
424 	else
425 	{
426 		CheckBox::onUpdate(dt);
427 	}
428 }
429 
destroy()430 void AquariaCheckBox::destroy()
431 {
432 	CheckBox::destroy();
433 	AquariaGuiElement::clean();
434 }
435 
getGuiPosition()436 Vector AquariaCheckBox::getGuiPosition()
437 {
438 	return getWorldPosition();
439 }
440 
isGuiVisible()441 bool AquariaCheckBox::isGuiVisible()
442 {
443 	return !isHidden() && alpha.x > 0 && alphaMod > 0;
444 }
445 
446 
447 AquariaKeyConfig *AquariaKeyConfig::waitingForInput = 0;
448 
449 
AquariaKeyConfig(const std::string & actionInputName,InputSetType inputSetType,int inputIdx)450 AquariaKeyConfig::AquariaKeyConfig(const std::string &actionInputName, InputSetType inputSetType, int inputIdx)
451 : AquariaGuiElement(), RenderObject(), actionInputName(actionInputName), inputSetType(inputSetType), inputIdx(inputIdx)
452 {
453 
454 	bg = new Quad();
455 	if (inputSetType == INPUTSET_OTHER)
456 		bg->setWidthHeight(40, 20);
457 	else
458 		bg->setWidthHeight(100, 20);
459 
460 	bg->color = Vector(0.5, 0.5, 0.5);
461 	bg->alphaMod = 0;
462 	addChild(bg, PM_POINTER);
463 
464 	/*
465 	label = new BitmapText(&dsq->smallFont);
466 	label->setText("KeyConfig");
467 	label->parentManagedPointer = 1;
468 	label->position = Vector(0, -10);
469 	label->scale = Vector(0.8, 0.8);
470 	addChild(label);
471 	*/
472 
473 	//keyConfigFont = new DebugFont(6, "keyConfig");
474 
475 	keyConfigFont = new TTFText(&dsq->fontArialSmallest);
476 
477 	keyConfigFont->setAlign(ALIGN_CENTER);
478 	//keyConfigFont->position = Vector(0, -10);
479 	addChild(keyConfigFont, PM_POINTER);
480 
481 
482 	keyDown = false;
483 
484 	locked = 0;
485 
486 
487 	toggleEnterKey(false);
488 }
489 
destroy()490 void AquariaKeyConfig::destroy()
491 {
492 	AquariaGuiElement::clean();
493 	RenderObject::destroy();
494 
495 	if (waitingForInput == this)
496 		waitingForInput = 0;
497 }
498 
getGuiPosition()499 Vector AquariaKeyConfig::getGuiPosition()
500 {
501 	return getWorldPosition();
502 }
503 
isGuiVisible()504 bool AquariaKeyConfig::isGuiVisible()
505 {
506 	return !isHidden() && alpha.x > 0 && alphaMod > 0;
507 }
508 
toggleEnterKey(int on)509 void AquariaKeyConfig::toggleEnterKey(int on)
510 {
511 	if (on==1)
512 	{
513 		bg->color = Vector(0.75, 0.75, 0.75);
514 		bg->alphaMod = 0.25;
515 	}
516 	else if (on == 0)
517 	{
518 		bg->alphaMod = 0;
519 		bg->color = Vector(0.1, 0.1, 0.1);
520 	}
521 	else
522 	{
523 		bg->alphaMod = 0.5;
524 		bg->color = Vector(0.5, 0.5, 0.5);
525 	}
526 	/*
527 	if (on)
528 	{
529 		label->scale = Vector(2, 2);
530 	}
531 	else
532 	{
533 		label->scale = Vector(1, 1);
534 	}
535 	*/
536 }
537 
setLock(int lock)538 void AquariaKeyConfig::setLock(int lock)
539 {
540 	locked = lock;
541 }
542 
onUpdate(float dt)543 void AquariaKeyConfig::onUpdate(float dt)
544 {
545 	static bool inLoop = false;
546 
547 	if (inLoop) return;
548 
549 
550 
551 
552 
553 	AquariaGuiElement::updateMovement(dt);
554 
555 	RenderObject::onUpdate(dt);
556 
557 
558 	if (!hasInput() || alpha.x <= 0) return;
559 
560 	inLoop = true;
561 
562 	int *k = 0;
563 
564 	ActionInput *ai = 0;
565 
566 	if (inputSetType != INPUTSET_OTHER)
567 	{
568 		ai = dsq->user.control.actionSet.getActionInputByName(actionInputName);
569 
570 		if (!ai)
571 		{
572 			exit_error("Could not find actionInput: " + actionInputName);
573 		}
574 		switch(inputSetType)
575 		{
576 		case INPUTSET_KEY:
577 			k = &ai->key[inputIdx];
578 		break;
579 		case INPUTSET_MOUSE:
580 			k = &ai->mse[inputIdx];
581 		break;
582 		case INPUTSET_JOY:
583 			k = &ai->joy[inputIdx];
584 		break;
585 		default:
586 			k = 0;
587 		break;
588 		}
589 	}
590 
591 	int *value = 0;
592 
593 	if (inputSetType == INPUTSET_OTHER)
594 	{
595 		if (actionInputName == "s1ax")
596 			value = &dsq->user.control.s1ax;
597 		else if (actionInputName == "s1ay")
598 			value = &dsq->user.control.s1ay;
599 		else if (actionInputName == "s2ax")
600 			value = &dsq->user.control.s2ax;
601 		else if (actionInputName == "s2ay")
602 			value = &dsq->user.control.s2ay;
603 	}
604 
605 	if (waitingForInput == this)
606 	{
607 		std::string s;
608 		s = "_";
609 		for (int i = 0; i < int(dsq->game->getTimer(5)); i++)
610 		{
611 			s += "_";
612 		}
613 		keyConfigFont->setText(s);
614 	}
615 	else
616 	{
617 		if (k)
618 		{
619 			keyConfigFont->setText(getInputCodeToString(*k));
620 		}
621 		else if (value)
622 		{
623 			std::ostringstream os;
624 			os << (*value);
625 			keyConfigFont->setText(os.str());
626 		}
627 	}
628 
629 	if (waitingForInput == this)
630 	{
631 		switch(inputSetType)
632 		{
633 		case INPUTSET_OTHER:
634 		{
635 			if (value)
636 			{
637 				for (int i = 0; i < KEY_MAXARRAY; i++)
638 				{
639 					if (core->getKeyState(i))
640 					{
641 						if (i != KEY_ESCAPE)
642 						{
643 							/*
644 							if (i == KEY_DELETE || i == KEY_BACKSPACE)
645 							else
646 							{
647 							*/
648 							/*
649 							if (i == KEY_0 || i == KEY_1 || i == KEY_2 || i == KEY_3 || i == KEY_4 || i == KEY_5 || i == KEY_6 || i == KEY_7
650 								|| i == KEY_8 || i == KEY_9)
651 							*/
652 							if (i >= KEY_0 && i <= KEY_9)
653 							{
654 								*value = i-KEY_0;
655 							}
656 						}
657 
658 						while (dsq->game->getKeyState(i))
659 						{
660 							dsq->main(0.1);
661 						}
662 
663 						toggleEnterKey(0);
664 						waitingForInput = 0;
665 						AquariaGuiElement::canDirMoveGlobal = true;
666 						break;
667 					}
668 				}
669 			}
670 		}
671 		break;
672 		case INPUTSET_KEY:
673 		{
674 			for (int i = 0; i < KEY_MAXARRAY; i++)
675 			{
676 				if (core->getKeyState(i))
677 				{
678 					if (i != KEY_ESCAPE)
679 					{
680 						if (i == KEY_DELETE || i == KEY_BACKSPACE)
681 							*k = 0;
682 						else
683 							*k = i;
684 					}
685 
686 					while (dsq->game->getKeyState(i))
687 					{
688 						dsq->main(0.1);
689 					}
690 
691 					toggleEnterKey(0);
692 					waitingForInput = 0;
693 					AquariaGuiElement::canDirMoveGlobal = true;
694 					break;
695 				}
696 			}
697 		}
698 		break;
699 		case INPUTSET_MOUSE:
700 		break;
701 		case INPUTSET_JOY:
702 		{
703 			if (core->getKeyState(KEY_DELETE) || core->getKeyState(KEY_BACKSPACE))
704 			{
705 				*k = 0;
706 				toggleEnterKey(0);
707 				waitingForInput = 0;
708 				AquariaGuiElement::canDirMoveGlobal = true;
709 			}
710 			else
711 			{
712 				for (int i = ActionMapper::JOY1_BUTTON_0; i <= ActionMapper::JOY1_BUTTON_16; i++)
713 				{
714 					if (dsq->game->getKeyState(i))
715 					{
716 						*k = i;
717 
718 						while (dsq->game->getKeyState(i))
719 						{
720 							dsq->main(0.1);
721 						}
722 
723 						toggleEnterKey(0);
724 						waitingForInput = 0;
725 						AquariaGuiElement::canDirMoveGlobal = true;
726 						break;
727 					}
728 				}
729 			}
730 		}
731 		break;
732 		}
733 	}
734 
735 	Vector p = getWorldPosition();
736 
737 	if (waitingForInput == this || (!waitingForInput &&
738 		(core->mouse.position.x > (p.x - bg->getWidth()*0.5f) && core->mouse.position.x < (p.x + bg->getWidth()*0.5f)
739 		 && core->mouse.position.y > (p.y - bg->getHeight()*0.5f) && core->mouse.position.y < (p.y + bg->getHeight()*0.5f)
740 		 )))
741 	{
742 		if (waitingForInput != this)
743 		{
744 			toggleEnterKey(-1);
745 		}
746 
747 
748 		if (!keyDown && (core->mouse.buttons.left || core->mouse.buttons.right/* || core->getKeyState(KEY_RETURN)*/))
749 		{
750 			keyDown = true;
751 		}
752 		else if (keyDown && (!core->mouse.buttons.left && !core->mouse.buttons.right /*&& !core->getKeyState(KEY_RETURN)*/))
753 		{
754 			keyDown = false;
755 
756 			if (!locked)
757 			{
758 				if (waitingForInput == this)
759 				{
760 					waitingForInput = 0;
761 					toggleEnterKey(0);
762 					AquariaGuiElement::canDirMoveGlobal = true;
763 				}
764 				else
765 				{
766 					waitingForInput = this;
767 					toggleEnterKey(1);
768 					AquariaGuiElement::canDirMoveGlobal = false;
769 				}
770 			}
771 			else
772 			{
773 				dsq->sound->playSfx("denied");
774 			}
775 		}
776 	}
777 	else
778 	{
779 		toggleEnterKey(0);
780 		keyDown = false;
781 	}
782 
783 	inLoop = false;
784 }
785 
AquariaMenuItem()786 AquariaMenuItem::AquariaMenuItem() : Quad(), ActionMapper(), AquariaGuiElement()
787 {
788 	quad = glow = 0;
789 	choice = -1;
790 	ability = 0;
791 	xmlItem = 0;
792 	int sz = 20;
793 
794 	shareAlpha = 0;
795 
796 	font = 0;
797 
798 	font = new BitmapText(&dsq->font);
799 	font->setFontSize(sz);
800 	font->position = Vector(0, -sz/2, 0);
801 	addChild(font, PM_POINTER, RBP_ON);
802 
803 	glowFont = new BitmapText(&dsq->font);
804 	glowFont->setFontSize(sz);
805 	glowFont->position = Vector(0, -sz/2, 0);
806 	glowFont->setBlendType(BLEND_ADD);
807 	glowFont->alpha = 0;
808 	//glowFont->scale.interpolateTo(Vector(1.1,1.1), 0.5, -1, 1, 1);
809 	addChild(glowFont, PM_POINTER, RBP_OFF);
810 
811 	//setTexture("bubble");
812 	//this->shareAlphaWithChildren = true;
813 	width = 0;
814 	height = 0;
815 	highlighted = false;
816 	/*
817 	width = 256;
818 	height = 64;
819 	*/
820 	cull = false;
821 	followCamera = 1;
822 	addAction(MakeFunctionEvent(AquariaMenuItem, onClick), ActionMapper::MOUSE_BUTTON_LEFT, 0);
823 	addAction(MakeFunctionEvent(AquariaMenuItem, onClick), ActionMapper::MOUSE_BUTTON_RIGHT, 0);
824 
825 	renderQuad = false;
826 }
827 
destroy()828 void AquariaMenuItem::destroy()
829 {
830 	setFocus(false);
831 	Quad::destroy();
832 	AquariaGuiElement::clean();
833 }
834 
getGuiPosition()835 Vector AquariaMenuItem::getGuiPosition()
836 {
837 	return getWorldPosition();
838 }
839 
isGuiVisible()840 bool AquariaMenuItem::isGuiVisible()
841 {
842 	return !isHidden() && alpha.x > 0 && alphaMod > 0;
843 }
844 
useSound(const std::string & tex)845 void AquariaMenuItem::useSound(const std::string &tex)
846 {
847 	useSfx = tex;
848 }
849 
useQuad(const std::string & tex)850 bool AquariaMenuItem::useQuad(const std::string &tex)
851 {
852 	if (quad)
853 	{
854 		debugLog("trying to call useQuad twice on the same object");
855 		return true;
856 	}
857 	quad = new Quad;
858 	bool good = quad->setTexture(tex);
859 	addChild(quad, PM_POINTER);
860 	return good;
861 }
862 
useGlow(const std::string & tex,int w,int h)863 void AquariaMenuItem::useGlow(const std::string &tex, int w, int h)
864 {
865 	if (glow)
866 	{
867 		debugLog("trying to call useGlow twice on the same object");
868 		return;
869 	}
870 	glow = new Quad;
871 	glow->setTexture(tex);
872 	glow->setWidthHeight(w, h);
873 	glow->setBlendType(BLEND_ADD);
874 	glow->alpha = 0;
875 	addChild(glow, PM_POINTER);
876 }
877 
onClick()878 void AquariaMenuItem::onClick()
879 {
880 	if (hasInput() && highlighted && dsq->menuSelectDelay == 0)
881 	{
882 		dsq->menuSelectDelay = MENUSELECTDELAY;
883 
884 		if (!useSfx.empty())
885 			dsq->sound->playSfx(useSfx);
886 		else
887 			dsq->playMenuSelectSfx();
888 
889 		event.call();
890 
891 		//glowFont->scale.interpolateTo(Vector(4,4), 0.5, 1, 1);
892 		//glowFont->alpha.interpolateTo(0, 0.5);
893 		//scale.interpolateTo(Vector(4, 4), 3);
894 	}
895 }
896 
setLabel(const std::string & label)897 void AquariaMenuItem::setLabel(const std::string &label)
898 {
899 	font->setText(label);
900 	glowFont->setText(label);
901 }
902 
toggleHighlight(bool state)903 void AquariaMenuItem::toggleHighlight(bool state)
904 {
905 	highlighted = state;
906 	if (highlighted)
907 	{
908 		if (glow)
909 		{
910 			glow->alpha.interpolateTo(0.3, 0.2);
911 		}
912 		else
913 		{
914 			glowFont->alpha.interpolateTo(0.3, 0.2);
915 		}
916 		//scale.interpolateTo(Vector(1.1, 1.1), 0.2);
917 	}
918 	else
919 	{
920 		if (glow)
921 			glow->alpha.interpolateTo(0, 0.2);
922 		else
923 			glowFont->alpha.interpolateTo(0, 0.2);
924 	}
925 		//scale.interpolateTo(Vector(1,1), 0.2);
926 }
927 
onUpdate(float dt)928 void AquariaMenuItem::onUpdate(float dt)
929 {
930 	AquariaGuiElement::updateMovement(dt);
931 
932 	if (font)
933 	{
934 		font->alpha = this->alpha;
935 	}
936 	Quad::onUpdate(dt);
937 
938 	if (shareAlpha)
939 	{
940 		if (quad) quad->alphaMod = alpha.x;
941 		if (glow) glow->alphaMod = alpha.x;
942 	}
943 
944 	if (this->alpha.x < 1.0) return;
945 
946 	if (hasInput())
947 		ActionMapper::onUpdate(dt);
948 
949 	if (quad)
950 	{
951 		quad->alpha.x = alpha.x;
952 	}
953 
954 	/*
955 	font->position = this->position;
956 	font->alpha = this->alpha;
957 	*/
958 	if (hasInput())
959 	{
960 		if (alpha.x == 1)
961 		{
962 			bool on = true;
963 
964 
965 			if (isCursorInMenuItem())
966 			{
967 				if (!highlighted)
968 					toggleHighlight(true);
969 			}
970 			else
971 				on = false;
972 
973 			if (!on && highlighted)
974 				toggleHighlight(false);
975 		}
976 		else
977 		{
978 			if (highlighted)
979 				toggleHighlight(false);
980 		}
981 	}
982 }
983 
isCursorInMenuItem()984 bool AquariaMenuItem::isCursorInMenuItem()
985 {
986 	Vector v = dsq->mouse.position;
987 	int hw = font->getWidthOnScreen()/2;
988 	int hh = 20;
989 	if (hw < 64)
990 		hw = 64;
991 	if (glow)
992 	{
993 		hw = glow->getWidth()/2.0f;
994 		hh = glow->getHeight()/2.0f;
995 	}
996 	if (rotation.z == 90)
997 	{
998 		std::swap(hw, hh);
999 	}
1000 	Vector pos = getWorldPosition();
1001 	if (v.y > pos.y - hh && v.y < pos.y + hh)
1002 	{
1003 		if (v.x > pos.x - hw && v.x < pos.x + hw)
1004 		{
1005 			return true;
1006 		}
1007 	}
1008 	return false;
1009 }
1010