1 /*
2 Scan Tailor - Interactive post-processing tool for scanned pages.
3 Copyright (C) 2007-2009 Joseph Artsimovich <joseph_a@mail.ru>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "InteractionHandler.h"
20 #include <QKeyEvent>
21 #include <QPainter>
22 #include <boost/lambda/bind.hpp>
23 #include <boost/lambda/construct.hpp>
24 #include <boost/lambda/lambda.hpp>
25 #include "InteractionState.h"
26
27 #define DISPATCH(list, call) \
28 { \
29 HandlerList::iterator it(list->begin()); \
30 const HandlerList::iterator end(list->end()); \
31 while (it != end) { \
32 (it++)->call; \
33 } \
34 }
35
36 #define RETURN_IF_ACCEPTED(event) \
37 { \
38 if (event->isAccepted()) { \
39 return; \
40 } \
41 }
42
43 namespace {
44 class ScopedClearAcceptance {
45 DECLARE_NON_COPYABLE(ScopedClearAcceptance)
46
47 public:
48 explicit ScopedClearAcceptance(QEvent* event);
49
50 ~ScopedClearAcceptance();
51
52 private:
53 QEvent* m_event;
54 bool m_wasAccepted;
55 };
56
57
ScopedClearAcceptance(QEvent * event)58 ScopedClearAcceptance::ScopedClearAcceptance(QEvent* event) : m_event(event), m_wasAccepted(event->isAccepted()) {
59 m_event->setAccepted(false);
60 }
61
~ScopedClearAcceptance()62 ScopedClearAcceptance::~ScopedClearAcceptance() {
63 if (m_wasAccepted) {
64 m_event->setAccepted(true);
65 }
66 }
67 } // anonymous namespace
68
InteractionHandler()69 InteractionHandler::InteractionHandler() : m_preceeders(new HandlerList), m_followers(new HandlerList) {}
70
~InteractionHandler()71 InteractionHandler::~InteractionHandler() {
72 using namespace boost::lambda;
73 m_preceeders->clear_and_dispose(bind(delete_ptr(), _1));
74 m_followers->clear_and_dispose(bind(delete_ptr(), _1));
75 }
76
paint(QPainter & painter,const InteractionState & interaction)77 void InteractionHandler::paint(QPainter& painter, const InteractionState& interaction) {
78 // Keep them alive in case this object gets destroyed.
79 intrusive_ptr<HandlerList> preceeders(m_preceeders);
80 intrusive_ptr<HandlerList> followers(m_followers);
81
82 DISPATCH(preceeders, paint(painter, interaction));
83 painter.save();
84 onPaint(painter, interaction);
85 painter.restore();
86 DISPATCH(followers, paint(painter, interaction));
87 }
88
proximityUpdate(const QPointF & screen_mouse_pos,InteractionState & interaction)89 void InteractionHandler::proximityUpdate(const QPointF& screen_mouse_pos, InteractionState& interaction) {
90 // Keep them alive in case this object gets destroyed.
91 intrusive_ptr<HandlerList> preceeders(m_preceeders);
92 intrusive_ptr<HandlerList> followers(m_followers);
93
94 DISPATCH(preceeders, proximityUpdate(screen_mouse_pos, interaction));
95 onProximityUpdate(screen_mouse_pos, interaction);
96 assert(!interaction.captured() && "onProximityUpdate() must not capture interaction");
97 DISPATCH(followers, proximityUpdate(screen_mouse_pos, interaction));
98 }
99
keyPressEvent(QKeyEvent * event,InteractionState & interaction)100 void InteractionHandler::keyPressEvent(QKeyEvent* event, InteractionState& interaction) {
101 RETURN_IF_ACCEPTED(event);
102
103 // Keep them alive in case this object gets destroyed.
104 intrusive_ptr<HandlerList> preceeders(m_preceeders);
105 intrusive_ptr<HandlerList> followers(m_followers);
106
107 DISPATCH(preceeders, keyPressEvent(event, interaction));
108 RETURN_IF_ACCEPTED(event);
109 onKeyPressEvent(event, interaction);
110 ScopedClearAcceptance guard(event);
111 DISPATCH(followers, keyPressEvent(event, interaction));
112 }
113
keyReleaseEvent(QKeyEvent * event,InteractionState & interaction)114 void InteractionHandler::keyReleaseEvent(QKeyEvent* event, InteractionState& interaction) {
115 RETURN_IF_ACCEPTED(event);
116 // Keep them alive in case this object gets destroyed.
117 intrusive_ptr<HandlerList> preceeders(m_preceeders);
118 intrusive_ptr<HandlerList> followers(m_followers);
119
120 DISPATCH(preceeders, keyReleaseEvent(event, interaction));
121 RETURN_IF_ACCEPTED(event);
122 onKeyReleaseEvent(event, interaction);
123 ScopedClearAcceptance guard(event);
124 DISPATCH(followers, keyReleaseEvent(event, interaction));
125 }
126
mousePressEvent(QMouseEvent * event,InteractionState & interaction)127 void InteractionHandler::mousePressEvent(QMouseEvent* event, InteractionState& interaction) {
128 RETURN_IF_ACCEPTED(event);
129
130 // Keep them alive in case this object gets destroyed.
131 intrusive_ptr<HandlerList> preceeders(m_preceeders);
132 intrusive_ptr<HandlerList> followers(m_followers);
133
134 DISPATCH(preceeders, mousePressEvent(event, interaction));
135 RETURN_IF_ACCEPTED(event);
136 onMousePressEvent(event, interaction);
137 ScopedClearAcceptance guard(event);
138 DISPATCH(followers, mousePressEvent(event, interaction));
139 }
140
mouseReleaseEvent(QMouseEvent * event,InteractionState & interaction)141 void InteractionHandler::mouseReleaseEvent(QMouseEvent* event, InteractionState& interaction) {
142 RETURN_IF_ACCEPTED(event);
143 // Keep them alive in case this object gets destroyed.
144 intrusive_ptr<HandlerList> preceeders(m_preceeders);
145 intrusive_ptr<HandlerList> followers(m_followers);
146
147 DISPATCH(preceeders, mouseReleaseEvent(event, interaction));
148 RETURN_IF_ACCEPTED(event);
149 onMouseReleaseEvent(event, interaction);
150 ScopedClearAcceptance guard(event);
151 DISPATCH(followers, mouseReleaseEvent(event, interaction));
152 }
153
mouseDoubleClickEvent(QMouseEvent * event,InteractionState & interaction)154 void InteractionHandler::mouseDoubleClickEvent(QMouseEvent* event, InteractionState& interaction) {
155 RETURN_IF_ACCEPTED(event);
156 // Keep them alive in case this object gets destroyed.
157 intrusive_ptr<HandlerList> preceeders(m_preceeders);
158 intrusive_ptr<HandlerList> followers(m_followers);
159
160 DISPATCH(preceeders, mouseDoubleClickEvent(event, interaction));
161 RETURN_IF_ACCEPTED(event);
162 onMouseDoubleClickEvent(event, interaction);
163 ScopedClearAcceptance guard(event);
164 DISPATCH(followers, mouseDoubleClickEvent(event, interaction));
165 }
166
mouseMoveEvent(QMouseEvent * event,InteractionState & interaction)167 void InteractionHandler::mouseMoveEvent(QMouseEvent* event, InteractionState& interaction) {
168 RETURN_IF_ACCEPTED(event);
169
170 // Keep them alive in case this object gets destroyed.
171 intrusive_ptr<HandlerList> preceeders(m_preceeders);
172 intrusive_ptr<HandlerList> followers(m_followers);
173
174 DISPATCH(preceeders, mouseMoveEvent(event, interaction));
175 RETURN_IF_ACCEPTED(event);
176 onMouseMoveEvent(event, interaction);
177 ScopedClearAcceptance guard(event);
178 DISPATCH(followers, mouseMoveEvent(event, interaction));
179 }
180
wheelEvent(QWheelEvent * event,InteractionState & interaction)181 void InteractionHandler::wheelEvent(QWheelEvent* event, InteractionState& interaction) {
182 RETURN_IF_ACCEPTED(event);
183
184 // Keep them alive in case this object gets destroyed.
185 intrusive_ptr<HandlerList> preceeders(m_preceeders);
186 intrusive_ptr<HandlerList> followers(m_followers);
187
188 DISPATCH(preceeders, wheelEvent(event, interaction));
189 RETURN_IF_ACCEPTED(event);
190 onWheelEvent(event, interaction);
191 ScopedClearAcceptance guard(event);
192 DISPATCH(followers, wheelEvent(event, interaction));
193 }
194
contextMenuEvent(QContextMenuEvent * event,InteractionState & interaction)195 void InteractionHandler::contextMenuEvent(QContextMenuEvent* event, InteractionState& interaction) {
196 RETURN_IF_ACCEPTED(event);
197 // Keep them alive in case this object gets destroyed.
198 intrusive_ptr<HandlerList> preceeders(m_preceeders);
199 intrusive_ptr<HandlerList> followers(m_followers);
200
201 DISPATCH(preceeders, contextMenuEvent(event, interaction));
202 RETURN_IF_ACCEPTED(event);
203 onContextMenuEvent(event, interaction);
204 ScopedClearAcceptance guard(event);
205 DISPATCH(followers, contextMenuEvent(event, interaction));
206 }
207
makePeerPreceeder(InteractionHandler & handler)208 void InteractionHandler::makePeerPreceeder(InteractionHandler& handler) {
209 handler.unlink();
210 HandlerList::node_algorithms::link_before(this, &handler);
211 }
212
makePeerFollower(InteractionHandler & handler)213 void InteractionHandler::makePeerFollower(InteractionHandler& handler) {
214 handler.unlink();
215 HandlerList::node_algorithms::link_after(this, &handler);
216 }
217
makeFirstPreceeder(InteractionHandler & handler)218 void InteractionHandler::makeFirstPreceeder(InteractionHandler& handler) {
219 handler.unlink();
220 m_preceeders->push_front(handler);
221 }
222
makeLastPreceeder(InteractionHandler & handler)223 void InteractionHandler::makeLastPreceeder(InteractionHandler& handler) {
224 handler.unlink();
225 m_preceeders->push_back(handler);
226 }
227
makeFirstFollower(InteractionHandler & handler)228 void InteractionHandler::makeFirstFollower(InteractionHandler& handler) {
229 handler.unlink();
230 m_followers->push_front(handler);
231 }
232
makeLastFollower(InteractionHandler & handler)233 void InteractionHandler::makeLastFollower(InteractionHandler& handler) {
234 handler.unlink();
235 m_followers->push_back(handler);
236 }
237
defaultInteractionPermitter(const InteractionState & interaction)238 bool InteractionHandler::defaultInteractionPermitter(const InteractionState& interaction) {
239 return !interaction.captured();
240 }
241