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