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