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/clickablewidget.h"
21 #include "ui/graphical/application.h"
22 #include "input/mouse/mouse.h"
23 
24 //------------------------------------------------------------------------------
cClickableWidget()25 cClickableWidget::cClickableWidget() :
26 	isPressed (false),
27 	mouseWasOver (false),
28 	consumeClick (true)
29 {}
30 
31 //------------------------------------------------------------------------------
cClickableWidget(const cPosition & position)32 cClickableWidget::cClickableWidget (const cPosition& position) :
33 	cWidget (position),
34 	isPressed (false),
35 	mouseWasOver (false),
36 	consumeClick (true)
37 {}
38 
39 //------------------------------------------------------------------------------
cClickableWidget(const cBox<cPosition> & area)40 cClickableWidget::cClickableWidget (const cBox<cPosition>& area) :
41 	cWidget (area),
42 	isPressed (false),
43 	mouseWasOver (false),
44 	consumeClick (true)
45 {}
46 
47 //------------------------------------------------------------------------------
addClickShortcut(cKeySequence keySequence,eMouseButtonType button)48 cShortcut& cClickableWidget::addClickShortcut (cKeySequence keySequence, eMouseButtonType button)
49 {
50 	auto shortcut = addShortcut (std::make_unique<cShortcut> (keySequence));
51 	signalConnectionManager.connect (shortcut->triggered, [button, this]()
52 	{
53 		auto application = getActiveApplication();
54 		auto mouse = getActiveMouse();
55 
56 		if (!application || !mouse) return;
57 
58 		this->handleClicked (*application, *mouse, button);
59 	});
60 	return *shortcut;
61 }
62 
63 //------------------------------------------------------------------------------
handleMouseMoved(cApplication & application,cMouse & mouse,const cPosition & offset)64 bool cClickableWidget::handleMouseMoved (cApplication& application, cMouse& mouse, const cPosition& offset)
65 {
66 	if (!application.hasMouseFocus (*this)) return false;
67 
68 	const bool mouseIsOver = isAt (mouse.getPosition());
69 
70 	if (mouseWasOver && !mouseIsOver)
71 	{
72 		if (isPressed)
73 		{
74 			setPressed (false);
75 		}
76 	}
77 	else if (!mouseWasOver && mouseIsOver)
78 	{
79 		if (application.hasMouseFocus (*this))
80 		{
81 			setPressed (true);
82 		}
83 	}
84 
85 	mouseWasOver = mouseIsOver;
86 
87 	return true;
88 }
89 
90 //------------------------------------------------------------------------------
handleMousePressed(cApplication & application,cMouse & mouse,eMouseButtonType button)91 bool cClickableWidget::handleMousePressed (cApplication& application, cMouse& mouse, eMouseButtonType button)
92 {
93 	if (isAt (mouse.getPosition()) && acceptButton (button))
94 	{
95 		getStartedClickWithin (button) = true;
96 		setPressed (true);
97 		application.grapMouseFocus (*this);
98 		return consumeClick;
99 	}
100 	return false;
101 }
102 
103 //------------------------------------------------------------------------------
finishMousePressed(cApplication & application,cMouse & mouse,eMouseButtonType button)104 void cClickableWidget::finishMousePressed (cApplication& application, cMouse& mouse, eMouseButtonType button)
105 {
106 	if (getStartedClickWithin (button))
107 	{
108 		getStartedClickWithin (button) = false;
109 		setPressed (false);
110 		application.releaseMouseFocus (*this);
111 	}
112 }
113 
114 //------------------------------------------------------------------------------
handleMouseReleased(cApplication & application,cMouse & mouse,eMouseButtonType button)115 bool cClickableWidget::handleMouseReleased (cApplication& application, cMouse& mouse, eMouseButtonType button)
116 {
117 	if (getStartedClickWithin (button))
118 	{
119 		finishMousePressed (application, mouse, button);
120 
121 		if (isAt (mouse.getPosition()))
122 		{
123 			if (handleClicked (application, mouse, button)) return consumeClick;
124 		}
125 	}
126 	return false;
127 }
128 
129 //------------------------------------------------------------------------------
handleLooseMouseFocus(cApplication & application)130 void cClickableWidget::handleLooseMouseFocus (cApplication& application)
131 {
132 	if (isPressed)
133 	{
134 		setPressed (false);
135 	}
136 	mouseWasOver = false;
137 
138 	for (auto i = startedClickWithin.begin(); i != startedClickWithin.end(); ++i)
139 	{
140 		i->second = false;
141 	}
142 }
143 
144 //------------------------------------------------------------------------------
setConsumeClick(bool consumeClick_)145 void cClickableWidget::setConsumeClick (bool consumeClick_)
146 {
147 	consumeClick = consumeClick_;
148 }
149 
150 //------------------------------------------------------------------------------
setPressed(bool pressed)151 void cClickableWidget::setPressed (bool pressed)
152 {
153 	isPressed = pressed;
154 }
155 
156 //------------------------------------------------------------------------------
acceptButton(eMouseButtonType button) const157 bool cClickableWidget::acceptButton (eMouseButtonType button) const
158 {
159 	return button == eMouseButtonType::Left;
160 }
161 
162 //------------------------------------------------------------------------------
getStartedClickWithin(eMouseButtonType button)163 bool& cClickableWidget::getStartedClickWithin (eMouseButtonType button)
164 {
165 	auto iter = startedClickWithin.find (button);
166 	if (iter == startedClickWithin.end())
167 	{
168 		return startedClickWithin[button] = false;
169 	}
170 	else return iter->second;
171 }
172