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 *> &regions() 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