1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom 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.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef TrenchBroom_ToolController
21 #define TrenchBroom_ToolController
22 
23 #include "TrenchBroom.h"
24 #include "VecMath.h"
25 #include "ToolChain.h"
26 #include "Model/Hit.h"
27 #include "Model/HitQuery.h"
28 #include "View/InputState.h"
29 
30 namespace TrenchBroom {
31     namespace Model {
32         class PickResult;
33     }
34 
35     namespace Renderer {
36         class RenderBatch;
37         class RenderContext;
38     }
39 
40     namespace View {
41         class Tool;
42 
43         class PickingPolicy {
44         public:
45             virtual ~PickingPolicy();
46         public:
47             virtual void doPick(const InputState& inputState, Model::PickResult& pickResult) = 0;
48         };
49 
50         class NoPickingPolicy : public PickingPolicy {
51         public:
52             virtual ~NoPickingPolicy();
53         public:
54             void doPick(const InputState& inputState, Model::PickResult& pickResult);
55         };
56 
57         class KeyPolicy {
58         public:
59             virtual ~KeyPolicy();
60         public:
61             virtual void doModifierKeyChange(const InputState& inputState) = 0;
62         };
63 
64         class NoKeyPolicy : public KeyPolicy {
65         public:
66             virtual ~NoKeyPolicy();
67         public:
68             void doModifierKeyChange(const InputState& inputState);
69         };
70 
71         class MousePolicy {
72         public:
73             virtual ~MousePolicy();
74         public:
75             virtual void doMouseDown(const InputState& inputState);
76             virtual void doMouseUp(const InputState& inputState);
77             virtual bool doMouseClick(const InputState& inputState);
78             virtual bool doMouseDoubleClick(const InputState& inputState);
79             virtual void doMouseMove(const InputState& inputState);
80             virtual void doMouseScroll(const InputState& inputState);
81         };
82 
83         typedef MousePolicy NoMousePolicy;
84 
85         class MouseDragPolicy {
86         public:
87             virtual ~MouseDragPolicy();
88         public:
89             virtual bool doStartMouseDrag(const InputState& inputState) = 0;
90             virtual bool doMouseDrag(const InputState& inputState) = 0;
91             virtual void doEndMouseDrag(const InputState& inputState) = 0;
92             virtual void doCancelMouseDrag() = 0;
93         };
94 
95         class NoMouseDragPolicy : public MouseDragPolicy {
96         public:
97             virtual ~NoMouseDragPolicy();
98         public:
99             bool doStartMouseDrag(const InputState& inputState);
100             bool doMouseDrag(const InputState& inputState);
101             void doEndMouseDrag(const InputState& inputState);
102             void doCancelMouseDrag();
103         };
104 
105         class DragRestricter {
106         public:
107             virtual ~DragRestricter();
108             bool hitPoint(const InputState& inputState, Vec3& point) const;
109         private:
110             virtual bool doComputeHitPoint(const InputState& inputState, Vec3& point) const = 0;
111         };
112 
113         class PlaneDragRestricter : public DragRestricter {
114         private:
115             const Plane3 m_plane;
116         public:
117             PlaneDragRestricter(const Plane3& plane);
118         private:
119             bool doComputeHitPoint(const InputState& inputState, Vec3& point) const;
120         };
121 
122         class CircleDragRestricter : public DragRestricter {
123         private:
124             const Vec3 m_center;
125             const Vec3 m_normal;
126             const FloatType m_radius;
127         public:
128             CircleDragRestricter(const Vec3& center, const Vec3& normal, FloatType radius);
129         private:
130             bool doComputeHitPoint(const InputState& inputState, Vec3& point) const;
131         };
132 
133         class LineDragRestricter : public DragRestricter {
134         private:
135             const Line3 m_line;
136         public:
137             LineDragRestricter(const Line3& line);
138         private:
139             bool doComputeHitPoint(const InputState& inputState, Vec3& point) const;
140         };
141 
142         class SurfaceDragHelper {
143         private:
144             bool m_hitTypeSet;
145             bool m_occludedTypeSet;
146             bool m_minDistanceSet;
147 
148             bool m_pickable;
149             bool m_selected;
150             Model::Hit::HitType m_hitTypeValue;
151             Model::Hit::HitType m_occludedTypeValue;
152             FloatType m_minDistanceValue;
153         public:
154             SurfaceDragHelper();
155             virtual ~SurfaceDragHelper();
156 
157             void setPickable(bool pickable);
158             void setSelected(bool selected);
159             void setType(Model::Hit::HitType type);
160             void setOccluded(Model::Hit::HitType type);
161             void setMinDistance(FloatType minDistance);
162         protected:
163             Model::HitQuery query(const InputState& inputState) const;
164         };
165 
166         class SurfaceDragRestricter : public SurfaceDragHelper, public DragRestricter {
167         private:
168             bool doComputeHitPoint(const InputState& inputState, Vec3& point) const;
169         };
170 
171         class DragSnapper {
172         public:
173             virtual ~DragSnapper();
174 
175             bool snap(const InputState& inputState, const Vec3& lastPoint, Vec3& curPoint) const;
176         private:
177             virtual bool doSnap(const InputState& inputState, const Vec3& lastPoint, Vec3& curPoint) const = 0;
178         };
179 
180         class NoDragSnapper : public DragSnapper {
181         private:
182             bool doSnap(const InputState& inputState, const Vec3& lastPoint, Vec3& curPoint) const;
183         };
184 
185         class Grid;
186 
187         class AbsoluteDragSnapper : public DragSnapper {
188         private:
189             const Grid& m_grid;
190         public:
191             AbsoluteDragSnapper(const Grid& grid);
192         private:
193             bool doSnap(const InputState& inputState, const Vec3& lastPoint, Vec3& curPoint) const;
194         };
195 
196         class DeltaDragSnapper : public DragSnapper {
197         private:
198             const Grid& m_grid;
199         public:
200             DeltaDragSnapper(const Grid& grid);
201         private:
202             bool doSnap(const InputState& inputState, const Vec3& lastPoint, Vec3& curPoint) const;
203         };
204 
205         class CircleDragSnapper : public DragSnapper {
206         private:
207             const Grid& m_grid;
208             const Vec3 m_start;
209             const Vec3 m_center;
210             const Vec3 m_normal;
211             const FloatType m_radius;
212         public:
213             CircleDragSnapper(const Grid& grid, const Vec3& start, const Vec3& center, const Vec3& normal, FloatType radius);
214         private:
215             bool doSnap(const InputState& inputState, const Vec3& lastPoint, Vec3& curPoint) const;
216         };
217 
218         class SurfaceDragSnapper : public SurfaceDragHelper, public DragSnapper {
219         private:
220             const Grid& m_grid;
221         public:
222             SurfaceDragSnapper(const Grid& grid);
223         private:
224             bool doSnap(const InputState& inputState, const Vec3& lastPoint, Vec3& curPoint) const;
225         private:
226             virtual Plane3 doGetPlane(const InputState& inputState, const Model::Hit& hit) const = 0;
227         };
228 
229         class RestrictedDragPolicy : public MouseDragPolicy {
230         private:
231             DragRestricter* m_restricter;
232             DragSnapper* m_snapper;
233             Vec3 m_dragOrigin;
234             Vec3 m_initialPoint;
235             Vec3 m_curPoint;
236             Vec3 m_lastPoint;
237         protected:
238             struct DragInfo {
239                 DragRestricter* restricter;
240                 DragSnapper* snapper;
241                 bool setInitialPoint;
242                 Vec3 initialPoint;
243 
244                 DragInfo();
245                 DragInfo(DragRestricter* i_restricter, DragSnapper* i_snapper);
246                 DragInfo(DragRestricter* i_restricter, DragSnapper* i_snapper, const Vec3& i_initialPoint);
247 
248                 bool skip() const;
249             };
250 
251             typedef enum {
252                 DR_Continue,
253                 DR_Deny,
254                 DR_Cancel
255             } DragResult;
256         public:
257             RestrictedDragPolicy();
258             virtual ~RestrictedDragPolicy();
259         private:
260             bool dragging() const;
261             void deleteRestricter();
262             void deleteSnapper();
263         protected:
264             const Vec3& dragOrigin() const;
265             const Vec3& initialPoint() const;
266             const Vec3& lastPoint() const;
267             const Vec3& curPoint() const;
268 
269             bool hitPoint(const InputState& inputState, Vec3& result) const;
270         public:
271             bool doStartMouseDrag(const InputState& inputState);
272             bool doMouseDrag(const InputState& inputState);
273             void doEndMouseDrag(const InputState& inputState);
274             void doCancelMouseDrag();
275 
276             void setRestricter(const InputState& inputState, DragRestricter* restricter, bool resetInitialPoint);
277             void setSnapper(const InputState& inputState, DragSnapper* snapper);
278 
279             bool snapPoint(const InputState& inputState, const Vec3& lastPoint, Vec3& point) const;
280         private: // subclassing interface
281             virtual DragInfo doStartDrag(const InputState& inputState) = 0;
282             virtual DragResult doDrag(const InputState& inputState, const Vec3& lastPoint, const Vec3& curPoint) = 0;
283             virtual void doEndDrag(const InputState& inputState) = 0;
284             virtual void doCancelDrag() = 0;
285         };
286 
287         class RenderPolicy {
288         public:
289             virtual ~RenderPolicy();
290         public:
291             virtual void doSetRenderOptions(const InputState& inputState, Renderer::RenderContext& renderContext) const;
292             virtual void doRender(const InputState& inputState, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch);
293         };
294 
295         typedef RenderPolicy NoRenderPolicy;
296 
297         class DropPolicy {
298         public:
299             virtual ~DropPolicy();
300         public:
301             virtual bool doDragEnter(const InputState& inputState, const String& payload) = 0;
302             virtual bool doDragMove(const InputState& inputState) = 0;
303             virtual void doDragLeave(const InputState& inputState) = 0;
304             virtual bool doDragDrop(const InputState& inputState) = 0;
305         };
306 
307         class NoDropPolicy : public DropPolicy {
308         public:
309             virtual ~NoDropPolicy();
310         public:
311             bool doDragEnter(const InputState& inputState, const String& payload);
312             bool doDragMove(const InputState& inputState);
313             void doDragLeave(const InputState& inputState);
314             bool doDragDrop(const InputState& inputState);
315         };
316 
317         class ToolController {
318         public:
319             virtual ~ToolController();
320 
321             Tool* tool();
322             bool toolActive();
323 
324             virtual void pick(const InputState& inputState, Model::PickResult& pickResult) = 0;
325 
326             virtual void modifierKeyChange(const InputState& inputState) = 0;
327 
328             virtual void mouseDown(const InputState& inputState) = 0;
329             virtual void mouseUp(const InputState& inputState) = 0;
330             virtual bool mouseClick(const InputState& inputState) = 0;
331             virtual bool mouseDoubleClick(const InputState& inputState) = 0;
332             virtual void mouseMove(const InputState& inputState) = 0;
333             virtual void mouseScroll(const InputState& inputState) = 0;
334 
335             virtual bool startMouseDrag(const InputState& inputState) = 0;
336             virtual bool mouseDrag(const InputState& inputState) = 0;
337             virtual void endMouseDrag(const InputState& inputState) = 0;
338             virtual void cancelMouseDrag() = 0;
339             virtual bool thisToolDragging() const = 0;
340             virtual bool anyToolDragging(const InputState& inputState) const = 0;
341 
342             virtual void setRenderOptions(const InputState& inputState, Renderer::RenderContext& renderContext) = 0;
343             virtual void render(const InputState& inputState, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) = 0;
344 
345             virtual bool dragEnter(const InputState& inputState, const String& payload) = 0;
346             virtual bool dragMove(const InputState& inputState) = 0;
347             virtual void dragLeave(const InputState& inputState) = 0;
348             virtual bool dragDrop(const InputState& inputState) = 0;
349 
350             virtual bool cancel() = 0;
351         protected:
352             void refreshViews();
353         private:
354             virtual Tool* doGetTool() = 0;
355         };
356 
357         template <class PickingPolicyType, class KeyPolicyType, class MousePolicyType, class MouseDragPolicyType, class RenderPolicyType, class DropPolicyType>
358         class ToolControllerBase : public ToolController, protected PickingPolicyType, protected KeyPolicyType, protected MousePolicyType, protected MouseDragPolicyType, protected RenderPolicyType, protected DropPolicyType {
359         private:
360             bool m_dragging;
361         public:
ToolControllerBase()362             ToolControllerBase() :
363             m_dragging(false) {}
364 
~ToolControllerBase()365             virtual ~ToolControllerBase() {}
366 
pick(const InputState & inputState,Model::PickResult & pickResult)367             void pick(const InputState& inputState, Model::PickResult& pickResult) {
368                 if (toolActive())
369                     static_cast<PickingPolicyType*>(this)->doPick(inputState, pickResult);
370             }
371 
modifierKeyChange(const InputState & inputState)372             void modifierKeyChange(const InputState& inputState) {
373                 if (toolActive())
374                     static_cast<KeyPolicyType*>(this)->doModifierKeyChange(inputState);
375             }
376 
mouseDown(const InputState & inputState)377             void mouseDown(const InputState& inputState) {
378                 if (toolActive())
379                     static_cast<MousePolicyType*>(this)->doMouseDown(inputState);
380             }
381 
mouseUp(const InputState & inputState)382             void mouseUp(const InputState& inputState) {
383                 if (toolActive())
384                     static_cast<MousePolicyType*>(this)->doMouseUp(inputState);
385             }
386 
mouseClick(const InputState & inputState)387             bool mouseClick(const InputState& inputState) {
388                 if (toolActive())
389                     return static_cast<MousePolicyType*>(this)->doMouseClick(inputState);
390                 return false;
391             }
392 
mouseDoubleClick(const InputState & inputState)393             bool mouseDoubleClick(const InputState& inputState) {
394                 if (toolActive())
395                     return static_cast<MousePolicyType*>(this)->doMouseDoubleClick(inputState);
396                 return false;
397             }
398 
mouseMove(const InputState & inputState)399             void mouseMove(const InputState& inputState) {
400                 if (toolActive())
401                     static_cast<MousePolicyType*>(this)->doMouseMove(inputState);
402             }
403 
mouseScroll(const InputState & inputState)404             void mouseScroll(const InputState& inputState) {
405                 if (toolActive())
406                     static_cast<MousePolicyType*>(this)->doMouseScroll(inputState);
407             }
408 
startMouseDrag(const InputState & inputState)409             bool startMouseDrag(const InputState& inputState) {
410                 m_dragging = (toolActive() && static_cast<MouseDragPolicyType*>(this)->doStartMouseDrag(inputState));
411                 return m_dragging;
412             }
413 
mouseDrag(const InputState & inputState)414             bool mouseDrag(const InputState& inputState) {
415                 assert(thisToolDragging() && toolActive());
416                 return static_cast<MouseDragPolicyType*>(this)->doMouseDrag(inputState);
417             }
418 
endMouseDrag(const InputState & inputState)419             void endMouseDrag(const InputState& inputState) {
420                 assert(thisToolDragging() && toolActive());
421                 static_cast<MouseDragPolicyType*>(this)->doEndMouseDrag(inputState);
422                 m_dragging = false;
423             }
424 
cancelMouseDrag()425             void cancelMouseDrag() {
426                 assert(thisToolDragging() && toolActive());
427                 static_cast<MouseDragPolicyType*>(this)->doCancelMouseDrag();
428                 m_dragging = false;
429             }
430 
thisToolDragging()431             bool thisToolDragging() const {
432                 return m_dragging;
433             }
434 
anyToolDragging(const InputState & inputState)435             bool anyToolDragging(const InputState& inputState) const {
436                 return inputState.anyToolDragging();
437             }
438 
setRenderOptions(const InputState & inputState,Renderer::RenderContext & renderContext)439             void setRenderOptions(const InputState& inputState, Renderer::RenderContext& renderContext) {
440                 if (toolActive())
441                     static_cast<RenderPolicyType*>(this)->doSetRenderOptions(inputState, renderContext);
442             }
443 
render(const InputState & inputState,Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)444             void render(const InputState& inputState, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) {
445                 if (toolActive())
446                     static_cast<RenderPolicyType*>(this)->doRender(inputState, renderContext, renderBatch);
447             }
448 
dragEnter(const InputState & inputState,const String & payload)449             bool dragEnter(const InputState& inputState, const String& payload) {
450                 if (toolActive())
451                     return static_cast<DropPolicyType*>(this)->doDragEnter(inputState, payload);
452                 return false;
453             }
454 
dragMove(const InputState & inputState)455             bool dragMove(const InputState& inputState) {
456                 if (toolActive())
457                     return static_cast<DropPolicyType*>(this)->doDragMove(inputState);
458                 return false;
459             }
460 
dragLeave(const InputState & inputState)461             void dragLeave(const InputState& inputState) {
462                 if (toolActive())
463                     static_cast<DropPolicyType*>(this)->doDragLeave(inputState);
464             }
465 
dragDrop(const InputState & inputState)466             bool dragDrop(const InputState& inputState) {
467                 if (toolActive())
468                     return static_cast<DropPolicyType*>(this)->doDragDrop(inputState);
469                 return false;
470             }
471 
cancel()472             bool cancel() {
473                 return doCancel();
474             }
475         private:
476             virtual bool doCancel() = 0;
477         };
478 
479         class ToolControllerGroup : public ToolControllerBase<PickingPolicy, KeyPolicy, MousePolicy, MouseDragPolicy, RenderPolicy, DropPolicy> {
480         private:
481             ToolChain m_chain;
482             ToolController* m_dragReceiver;
483             ToolController* m_dropReceiver;
484         public:
485             ToolControllerGroup();
486             virtual ~ToolControllerGroup();
487         protected:
488             void addController(ToolController* controller);
489         protected:
490             virtual void doPick(const InputState& inputState, Model::PickResult& pickResult);
491 
492             virtual void doModifierKeyChange(const InputState& inputState);
493 
494             virtual void doMouseDown(const InputState& inputState);
495             virtual void doMouseUp(const InputState& inputState);
496             virtual bool doMouseClick(const InputState& inputState);
497             virtual bool doMouseDoubleClick(const InputState& inputState);
498             virtual void doMouseMove(const InputState& inputState);
499             virtual void doMouseScroll(const InputState& inputState);
500 
501             bool doStartMouseDrag(const InputState& inputState);
502             bool doMouseDrag(const InputState& inputState);
503             void doEndMouseDrag(const InputState& inputState);
504             void doCancelMouseDrag();
505 
506             virtual void doSetRenderOptions(const InputState& inputState, Renderer::RenderContext& renderContext) const;
507             virtual void doRender(const InputState& inputState, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch);
508 
509             bool doDragEnter(const InputState& inputState, const String& payload);
510             bool doDragMove(const InputState& inputState);
511             void doDragLeave(const InputState& inputState);
512             bool doDragDrop(const InputState& inputState);
513 
514             virtual bool doCancel();
515         private: // subclassing interface
516             virtual bool doShouldHandleMouseDrag(const InputState& inputState) const;
517             virtual void doMouseDragStarted(const InputState& inputState);
518             virtual void doMouseDragged(const InputState& inputState);
519             virtual void doMouseDragEnded(const InputState& inputState);
520             virtual void doMouseDragCancelled();
521 
522             virtual bool doShouldHandleDrop(const InputState& inputState, const String& payload) const;
523         };
524     }
525 }
526 
527 #endif /* defined(TrenchBroom_ToolController) */
528