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