1 #pragma once 2 3 #ifndef DOCKLAYOUT_H 4 #define DOCKLAYOUT_H 5 6 #include "tcommon.h" 7 8 #include <QWidget> 9 #include <QAction> 10 11 #include <deque> 12 #include <vector> 13 #include <QLayout> 14 #include <QFrame> 15 #include "docklayout.h" 16 17 #undef DVAPI 18 #undef DVVAR 19 #ifdef TOONZQT_EXPORTS 20 #define DVAPI DV_EXPORT_API 21 #define DVVAR DV_EXPORT_VAR 22 #else 23 #define DVAPI DV_IMPORT_API 24 #define DVVAR DV_IMPORT_VAR 25 #endif 26 27 //------------------------------- 28 29 // Forward Declarations 30 class DockLayout; 31 class DockWidget; 32 33 class DockPlaceholder; 34 class DockSeparator; 35 class DockDecoAllocator; 36 37 class Region; 38 39 //======================================================================== 40 41 //-------------------------- 42 // Docking Lock Check 43 //-------------------------- 44 45 //! Singleton for docking system lock. 46 class DVAPI DockingCheck { 47 bool m_enabled; 48 QAction *m_toggle; DockingCheck()49 DockingCheck() : m_enabled(false), m_toggle(0) {} 50 51 public: 52 static DockingCheck *instance(); 53 void setToggle(QAction *toggle); isEnabled()54 bool isEnabled() const { return m_enabled; } 55 void setIsEnabled(bool on); 56 }; 57 58 //======================================================================== 59 60 //------------------- 61 // Dock Layout 62 //------------------- 63 64 //! DockLayout inherits the abstract QLayout to provide a docking system for 65 //! widgets. 66 /*! 67 \b IMPORTANT NOTE: Observe that the addWidget() method expects only widgets of 68 type DockWidget, so any other 69 widget type added to this kind of Layout will cause a run-time error. 70 71 \sa DockWidget and DockSeparator classes. 72 */ 73 class DVAPI DockLayout final : public QLayout { 74 std::vector<QLayoutItem *> m_items; 75 std::deque<Region *> m_regions; 76 77 DockWidget 78 *m_maximizedDock; // Let the layout know if there is a maximized widget 79 80 // Decoration-related allocator (separators) 81 DockDecoAllocator *m_decoAllocator; 82 83 public: 84 DockLayout(); 85 virtual ~DockLayout(); 86 87 // QLayout item handling (see Qt reference) 88 int count(void) const override; 89 void addItem(QLayoutItem *item) override; 90 QSize sizeHint() const override; 91 QSize minimumSize() const override; 92 QSize maximumSize() const override; 93 QLayoutItem *itemAt(int) const override; 94 QWidget *widgetAt(int) const; 95 QLayoutItem *takeAt(int) override; 96 void setGeometry(const QRect &rect) override; 97 98 void update(); // Re-applies partition found 99 void redistribute(); // Calculates partition 100 void applyTransform(const QTransform &transform); // Applies tranformation to 101 // known parition - Da 102 // rimuovere, non serve... 103 getMaximized()104 DockWidget *getMaximized() { return m_maximizedDock; } 105 void setMaximized( 106 DockWidget *item, 107 bool state = true); // Let DockLayout handle maximization requests 108 109 // Docking and undocking methods. 110 Region *dockItem(DockWidget *item, Region *r = 0, int idx = 0); 111 void dockItem(DockWidget *item, DockPlaceholder *place); 112 void dockItem(DockWidget *item, DockWidget *target, int regionSide); 113 bool undockItem(DockWidget *item); 114 void calculateDockPlaceholders(DockWidget *item); 115 116 // Query methods rootRegion()117 Region *rootRegion() const { 118 return m_regions.size() ? m_regions.front() : 0; 119 } regions()120 const std::deque<Region *> ®ions() const { return m_regions; } region(int i)121 Region *region(int i) const { return m_regions[i]; } 122 Region *find(DockWidget *item) const; 123 QWidget *containerOf(QPoint point) const; 124 125 // Save and load DockLayout states 126 typedef std::pair<std::vector<QRect>, QString> State; 127 128 State saveState(); 129 bool restoreState(const State &state); 130 131 // Decorations allocator 132 void setDecoAllocator(DockDecoAllocator *decoAllocator); 133 134 private: 135 void applyGeometry(); 136 inline void updateSeparatorCursors(); 137 Region *dockItemPrivate(DockWidget *item, Region *r, int idx); 138 139 // Insertion and removal check - called internally by dock/undockItem 140 bool isPossibleInsertion(DockWidget *item, Region *parentRegion, 141 int insertionIdx); 142 bool isPossibleRemoval(DockWidget *item, Region *parentRegion, 143 int removalIdx); 144 145 // Internal save function 146 void writeRegion(Region *r, QString &hierarchy); 147 }; 148 149 //======================================================================== 150 151 //----------------------- 152 // Dock Widget 153 //----------------------- 154 155 //! Dockable widgets are widget containers handled by DockLayout class. 156 /*! 157 DockLayouts accept only dock widgets of this class; so if you want to 158 place a given widget under this kind of layout, a DockWidget shell for 159 it must be allocated first. The following class implements base dock 160 widgets, with native floating decorations and no docked title bar. 161 It is encouraged to reimplement all the essential functions for custom aspect 162 and behaviour. 163 164 \sa DockLayout and DockPlaceholder classes. 165 */ 166 class DVAPI DockWidget : public QFrame { 167 friend class DockLayout; // DockLayout is granted access to placeholders' 168 // privates 169 friend class DockPlaceholder; // As above. 170 // friend Region; //Regions need access to m_saveIndex field. 171 public: 172 void maximizeDock(); 173 getCanFixWidth()174 bool getCanFixWidth() { return m_canFixWidth; } setCanFixWidth(bool fixed)175 void setCanFixWidth(bool fixed) { m_canFixWidth = fixed; } 176 177 protected: 178 // Private attributes for dragging purposes 179 bool m_floating; // Whether this window is floating or docked 180 bool m_wasFloating; 181 bool m_dragging; // Whether this window is being dragged 182 bool m_undocking; // Still docked, but after a mouse button press on a title 183 // bar. 184 // NOTE: m_dragging ==> !m_undocking; m_dragging=>m_floating. 185 186 // Private infos for resizing purposes 187 bool m_resizing; // Whether this window is being resized 188 int m_marginType; // Type of resize to consider 189 190 // Maximization 191 bool m_maximized; 192 193 // Level Strip and Style Editor use a fixed width on 194 // window resize to minimize user frustration 195 // This variable is only used by Level Strip right now. 196 // This is only true if the level strip is vertical. 197 bool m_canFixWidth = false; 198 199 private: 200 QPoint m_dragInitialPos; 201 QPoint m_dragMouseInitialPos; 202 203 // Widget and Layout links 204 DockLayout *m_parentLayout; 205 206 // Decoration-related allocator (placeholders) 207 DockDecoAllocator *m_decoAllocator; 208 209 int m_saveIndex; 210 211 protected: 212 // Protected infos for docking purposes 213 std::vector<DockPlaceholder *> m_placeholders; 214 DockPlaceholder *m_selectedPlace; 215 216 public: 217 DockWidget(QWidget *parent = 0, Qt::WindowFlags flags = Qt::Tool); 218 virtual ~DockWidget(); 219 220 // Returns the DockLayout owning \b this dock widget parentLayout()221 DockLayout *parentLayout() const { return m_parentLayout; } 222 isFloating()223 bool isFloating() const { return m_floating; } wasFloating()224 bool wasFloating() const { return m_wasFloating; } clearWasFloating()225 void clearWasFloating() { m_wasFloating = false; } isMaximized()226 bool isMaximized() const { return m_maximized; } 227 228 // Query functions 229 QWidget *hoveredWidget(QMouseEvent *me); 230 DockPlaceholder *placeAdjacentTo(DockWidget *dockWidget, int boundary); 231 DockPlaceholder *placeOfSeparator(DockSeparator *); placeholders()232 const std::vector<DockPlaceholder *> &placeholders() const { 233 return m_placeholders; 234 } 235 236 // Re-implementable functions for custom dock widgets. 237 238 //! Returns the minimum size of the dock widget when docked. This function 239 //! should be 240 //! reimlemented whenever minimum size changes between floating and docked 241 //! appearance. getDockedMinimumSize()242 virtual QSize getDockedMinimumSize() { return minimumSize(); } 243 244 //! Returns the maximum size of the dock widget when docked. This function 245 //! should be 246 //! reimlemented whenever minimum size changes between floating and docked 247 //! appearance. getDockedMaximumSize()248 virtual QSize getDockedMaximumSize() { return maximumSize(); } 249 250 //! This function is called in order to show the dock widget in its floating 251 //! status. No show() or update() 252 //! is needed in its body. 253 //! It can be reimplemented to build custom-styled dock widgets. setFloatingAppearance()254 virtual void setFloatingAppearance() { setWindowFlags(Qt::Tool); } 255 256 //! This function is called in order to show the dock widget in its docked 257 //! status. No show() or update() 258 //! is needed in its body. 259 //! It can be reimplemented to build custom-styled dock widgets. setDockedAppearance()260 virtual void setDockedAppearance() {} 261 262 virtual bool isDragGrip(QPoint p); isResizeGrip(QPoint)263 virtual int isResizeGrip(QPoint) { 264 return 0; // Native deco widgets handle margins and resizes on their own 265 } 266 267 enum { 268 leftMargin = 0x1, 269 rightMargin = 0x2, 270 topMargin = 0x4, 271 bottomMargin = 0x8 272 }; 273 274 // Placeholders-related methods 275 virtual void selectDockPlaceholder(QMouseEvent *me); 276 void clearDockPlaceholders(); 277 278 // Decorations allocator 279 void setDecoAllocator(DockDecoAllocator *decoAllocator); 280 281 // reimpremented in FlipbookPanel onDock(bool docked)282 virtual void onDock(bool docked) {} 283 284 private: 285 // Event handling 286 // Basic events 287 bool event(QEvent *e) override; 288 void mousePressEvent(QMouseEvent *me) override; 289 void mouseReleaseEvent(QMouseEvent *me) override; 290 void mouseMoveEvent(QMouseEvent *me) override; 291 void hoverMoveEvent(QHoverEvent *he); 292 293 protected: 294 // Customizable events 295 void wheelEvent(QWheelEvent *we) override; 296 void mouseDoubleClickEvent(QMouseEvent *me) override; windowTitleEvent(QEvent *)297 virtual void windowTitleEvent(QEvent *) {} 298 }; 299 300 //======================================================================== 301 302 //--------------------- 303 // DockSeparator 304 //--------------------- 305 306 //! Separators are interposition widgets among docked DockWidgets of a 307 //! DockLayout. 308 /*! 309 A DockSeparator has the role of separating sister Regions; it is always owned 310 by a parent 311 Region and inherits its subdivision (here separation) direction. It also 312 provides basical 313 interaction with the user, allowing itself to be shifted along separation 314 direction until 315 geometric constraints are met. 316 DockSeparator class can be inherited to build custom separators - in that 317 case, a 318 heir of DockDecoAllocator class allocating the new separator class must be 319 assigned to 320 the DockLayout. 321 It is also possible to specify the Separators' thickness used in a DockLayout 322 through the 323 QLayout::setSpacing(int) method. 324 325 \b NOTE: Observe that Separators' geometry is owned by the DockLayout to which 326 it belongs; it 327 is discouraged (but not forbidden) to manually modify it. You may, for 328 example, modify the 329 geometry of a DockSeparator when dragging a dock widget over it. 330 In any case, the layout will automatically regenerate Separators' geometry at 331 each update of 332 the layout. 333 334 \sa DockLayout and DockWidget classes. 335 */ 336 337 class DockSeparator : public QWidget { 338 friend class DockLayout; // Layout updates each DockSeparator during 339 // DockLayout::applyGeometry() 340 friend class Region; // Region may update a DockSeparator's parent during 341 // removeItem() 342 343 DockLayout *m_owner; 344 345 // Event-related infos 346 bool m_pressed; 347 QPoint m_oldOrigin; 348 QPoint m_oldPos; 349 350 // Structural infos 351 Region *m_parentRegion; 352 int m_index; 353 bool m_orientation; 354 355 // Constraint infos 356 double m_leftBound; 357 double m_rightBound; 358 359 public: 360 DockSeparator(DockLayout *owner, bool orientation, Region *parentRegion); ~DockSeparator()361 virtual ~DockSeparator() {} 362 363 // Structural getters getOrientation()364 bool getOrientation() const { return m_orientation; } getParentRegion()365 Region *getParentRegion() const { return m_parentRegion; } getIndex()366 int getIndex() const { return m_index; } 367 368 // Public setters 369 void shift(int dx); 370 371 private: 372 void calculateBounds(); 373 374 void mousePressEvent(QMouseEvent *me) override; 375 void mouseReleaseEvent(QMouseEvent *me) override; 376 void mouseMoveEvent(QMouseEvent *me) override; 377 }; 378 379 //======================================================================== 380 381 //--------------------------- 382 // Dock Placeholder 383 //--------------------------- 384 385 //! A dock placeholder contains the necessary informations about a possible 386 //! docking solution. 387 388 /*! 389 Dock placeholders are top-level widgets used by a DockLayout to draw docking 390 solutions for a dragged DockWidget. They are actually generated when 391 dragging of a DockWidget begins: if it belongs to a parent DockLayout, docking 392 possibilities are calculated and stored into the layout. 393 Placeholders selection and activation depend on the dragged dock window and 394 therefore 395 are of its own responsibility. 396 You may, however, inherit this class to provide custom placeholders; in this 397 case, 398 a DockDecoAllocator class reimplementing allocation of placeholders must be 399 assigned to 400 the owner dock widget. 401 402 \sa DockLayout and DockWidget classes 403 */ 404 class DockPlaceholder : public QWidget { 405 friend class DockLayout; // DockLayout is granted access to placeholders' 406 // privates 407 408 // Docking informations - private 409 Region *m_region; 410 int m_idx; 411 412 // Docking informations - public 413 int m_attributes; 414 415 // Owner 416 DockSeparator *m_separator; 417 DockWidget *m_owner; 418 419 public: 420 DockPlaceholder(DockWidget *owner, Region *r, int idx, int attributes = 0); ~DockPlaceholder()421 virtual ~DockPlaceholder() {} 422 423 // Member access methods 424 425 //! Returns DockSeparator on which docking takes place (if any) 426 DockSeparator *getSeparator() const; 427 //! Returns dockWidget owner getDockWidget()428 DockWidget *getDockWidget() const { return m_owner; } 429 //! Returns Region owner getParentRegion()430 Region *getParentRegion() const { return m_region; } 431 //! Returns insertion index into parent region getInsertionIdx()432 int getInsertionIdx() const { return m_idx; } 433 434 enum { 435 left = 0, 436 right = 1, 437 top = 2, 438 bottom = 3, 439 sepHor = 4, 440 sepVert = 5, 441 root = 6 442 }; getAttribute()443 int getAttribute() const { return m_attributes; } setAttribute(int attribute)444 void setAttribute(int attribute) { m_attributes = attribute; } 445 446 // Geometry functions 447 QRect parentGeometry() const; 448 virtual void buildGeometry(); 449 450 // Query functions 451 //! A root placeholder is passed only if no item is currently docked (special 452 //! case) isRoot()453 bool isRoot() const { return m_attributes == root; } 454 DockPlaceholder *parentPlaceholder(); 455 DockPlaceholder *greatestPlaceholder(); 456 DockPlaceholder *childPlaceholder(QPoint p); 457 DockPlaceholder *smallestPlaceholder(QPoint p); 458 459 private: 460 //! Let wheel events also be propagated to owner dock widget wheelEvent(QWheelEvent * we)461 void wheelEvent(QWheelEvent *we) override { m_owner->wheelEvent(we); } 462 }; 463 464 //=========================================== 465 466 //-------------------- 467 // Class Region 468 //-------------------- 469 470 //! Regions represent any rectangular space inside a DockLayout. 471 //! Normally there is no reason to deal with Regions, unless you want to 472 //! build complex docking systems or manually dock widgets into your code. 473 474 /*! 475 Regions are rectangular areas of the DockLayout's contentsRect() which 476 can be either subdiveded into subRegions (all in a given \b subdivision 477 \b direction) or contain a DockWidget. 478 Every subRegion, if present, has opposite subdivision direction with 479 respect to parent one. In addition, regions possess lists of separators 480 and placeholders found along its subdivision direction. 481 Region informations are owned by the DockLayout who allocates it; however, 482 they are read-only accessible by the user. 483 484 \sa DockLayout, DockWidget, DockSeparator and DockPlaceholder classes. 485 */ 486 487 class Region { 488 friend class DockLayout; // Layout is the main operating class over 489 // rectangular regions - need full access 490 friend class DockSeparator; // Separators need access to extremal sizes 491 // methods when moving themselves 492 493 DockLayout *m_owner; 494 DockWidget *m_item; 495 Region *m_parent; 496 std::deque<Region *> m_childList; 497 std::deque<DockSeparator *> m_separators; 498 499 std::vector<DockPlaceholder *> m_placeholders; 500 501 QRectF m_rect; 502 bool m_orientation; 503 504 int m_minimumSize[2]; 505 int m_maximumSize[2]; 506 507 int m_saveIndex; 508 509 public: 510 Region(DockLayout *owner, DockWidget *item = 0) m_owner(owner)511 : m_owner(owner), m_item(item), m_parent(0), m_orientation(0) {} 512 ~Region(); 513 514 enum { inf = 1000000 }; 515 enum { horizontal = 0, vertical = 1 }; 516 enum { left = 0x1, right = 0x2, top = 0x4, bottom = 0x8 }; 517 518 // Getters - public getOrientation()519 bool getOrientation() const { return m_orientation; } getGeometry()520 QRectF getGeometry() const { return m_rect; } getSize()521 QSizeF getSize() const { return QSizeF(m_rect.width(), m_rect.height()); } getParent()522 Region *getParent() const { return m_parent; } getItem()523 DockWidget *getItem() const { return m_item; } 524 getChildList()525 const std::deque<Region *> &getChildList() const { return m_childList; } childRegion(int i)526 Region *childRegion(int i) const { return m_childList[i]; } 527 separators()528 const std::deque<DockSeparator *> &separators() const { return m_separators; } separator(int i)529 DockSeparator *separator(int i) const { return m_separators[i]; } 530 placeholders()531 std::vector<DockPlaceholder *> &placeholders() { return m_placeholders; } placeholder(int i)532 DockPlaceholder *placeholder(int i) const { return m_placeholders[i]; } 533 534 unsigned int find(const Region *subRegion) const; 535 536 bool checkWidgetsToBeFixedWidth(std::vector<QWidget *> &widgets, 537 bool &fromDocking); 538 539 private: 540 // Setters - private setOrientation(bool orientation)541 void setOrientation(bool orientation) { m_orientation = orientation; } setGeometry(const QRectF & rect)542 void setGeometry(const QRectF &rect) { m_rect = rect; } setSize(const QSizeF & size)543 void setSize(const QSizeF &size) { m_rect.setSize(size); } setParent(Region * parent)544 void setParent(Region *parent) { m_parent = parent; } setItem(DockWidget * item)545 void setItem(DockWidget *item) { m_item = item; } 546 547 // Insertion and removal methods 548 void insertSubRegion(Region *subregion, int idx); 549 Region *insertItem(DockWidget *item, int idx); 550 void removeItem(DockWidget *item); 551 void insertSeparator(DockSeparator *sep); 552 void removeSeparator(); 553 554 // Extremal region sizes 555 //! Returns cached occupied space in \b this region along given \b direction. getMaximumSize(bool direction)556 inline int getMaximumSize(bool direction) const { 557 return m_maximumSize[direction]; 558 } 559 //! Returns cached occupied space in \b this region along given \b direction. getMinimumSize(bool direction)560 inline int getMinimumSize(bool direction) const { 561 return m_minimumSize[direction]; 562 } 563 564 bool addItemSize(DockWidget *item); 565 bool subItemSize(DockWidget *item); 566 void calculateExtremalSizes(); 567 int calculateMinimumSize(bool direction, bool recalcChildren); 568 int calculateMaximumSize(bool direction, bool recalcChildren); 569 570 // Redistribution function. 571 // The main feature of a Region consists of the redistribute() method, which 572 // extracts the optimal layout among the branching regions with \b this 573 // root. However, only the full redistribute() method in DockLayout is made 574 // public. 575 void redistribute(); 576 void restoreGeometry(); 577 // void updateSeparators(); 578 }; 579 580 //======================================================================== 581 582 //---------------------- 583 // Dock Allocator 584 //---------------------- 585 586 //! DockDecoAllocator class handles the allocation of decoration elements used 587 //! by our dock manager. 588 /*! 589 In order to implement custom appearances for the docking system, it 590 is possible to customize both DockSeparator and DockPlaceholder classes. Since 591 allocation of such objects is handled internally by the docking system, 592 it is necessary to reimplement allocator functions whenever decoration 593 classes change. 594 In order to assign a DockDecoAllocator to a DockLayout or DockWidget, the 595 respective 'setDecoAllocator' methods are provided. 596 597 \sa DockLayout, DockWidget, DockSeparator and DockPlaceholder classes. 598 */ 599 class DockDecoAllocator { 600 friend class DockLayout; 601 602 public: DockDecoAllocator()603 DockDecoAllocator() {} ~DockDecoAllocator()604 virtual ~DockDecoAllocator() {} 605 606 // Customizabile allocators 607 virtual DockSeparator *newSeparator(DockLayout *owner, bool orientation, 608 Region *parentRegion); 609 virtual DockPlaceholder *newPlaceholder(DockWidget *owner, Region *r, int idx, 610 int attributes); 611 612 private: 613 DockPlaceholder *newPlaceBuilt(DockWidget *owner, Region *r, int idx, 614 int attributes); 615 }; 616 617 #endif // SIMPLEQTTEST_H 618