/* * The MIT License (MIT) * * Copyright (c) 2014 Pavel Strakhov * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #ifndef TOOLWINDOWMANAGER_H #define TOOLWINDOWMANAGER_H #include #include #include #include #include #include #include #include #include #include class ToolWindowManagerArea; class ToolWindowManagerWrapper; /*! * \brief The ToolWindowManager class provides docking tool behavior. * * The behavior is similar to tool windows mechanism in Visual Studio or Eclipse. * User can arrange tool windows * in tabs, dock it to any border, split with vertical and horizontal splitters, * tabify them together and detach to floating windows. * * See https://github.com/Riateche/toolwindowmanager for detailed description. */ class ToolWindowManager : public QWidget { Q_OBJECT /*! * \brief The delay between showing the next suggestion of drop location in milliseconds. * * When user starts a tool window drag and moves mouse pointer to a position, there can be * an ambiguity in new position of the tool window. If user holds the left mouse button and * stops mouse movements, all possible suggestions will be indicated periodically, one at a time. * * Default value is 1000 (i.e. 1 second). * * Access functions: suggestionSwitchInterval, setSuggestionSwitchInterval. * */ Q_PROPERTY(int suggestionSwitchInterval READ suggestionSwitchInterval WRITE setSuggestionSwitchInterval) /*! * \brief Maximal distance in pixels between mouse position and area border that allows * to display a suggestion. * * Default value is 12. * * Access functions: borderSensitivity, setBorderSensitivity. */ Q_PROPERTY(int borderSensitivity READ borderSensitivity WRITE setBorderSensitivity) /*! * \brief Visible width of rubber band line that is used to display drop suggestions. * * Default value is the same as QSplitter::handleWidth default value on current platform. * * Access functions: rubberBandLineWidth, setRubberBandLineWidth. * */ Q_PROPERTY(int rubberBandLineWidth READ rubberBandLineWidth WRITE setRubberBandLineWidth) /*! * \brief Whether or not to allow floating windows to be created. * * Default value is to allow it. * * Access functions: allowFloatingWindow, setAllowFloatingWindow. * */ Q_PROPERTY(int allowFloatingWindow READ allowFloatingWindow WRITE setAllowFloatingWindow) public: /*! * \brief Creates a manager with given \a parent. */ explicit ToolWindowManager(QWidget *parent = 0); /*! * \brief Destroys the widget. Additionally all tool windows and all floating windows * created by this widget are destroyed. */ virtual ~ToolWindowManager(); //! Toolwindow properties enum ToolWindowProperty { //! Disables all drag/docking ability by the user DisallowUserDocking = 0x1, //! Hides the close button on the tab for this tool window HideCloseButton = 0x2, //! Disable the user being able to drag this tab in the tab bar, to rearrange DisableDraggableTab = 0x4, //! When the tool window is closed, hide it instead of removing it HideOnClose = 0x8, }; //! Type of AreaReference. enum AreaReferenceType { //! The area tool windows has been added to most recently. LastUsedArea, //! New area in a detached window. NewFloatingArea, //! Area inside the manager widget (only available when there is no tool windows in it). EmptySpace, //! Tool window is hidden. NoArea, //! Existing area specified in AreaReference argument. AddTo, //! New area to the left of the area specified in AreaReference argument. LeftOf, //! New area to the right of the area specified in AreaReference argument. RightOf, //! New area to the top of the area specified in AreaReference argument. TopOf, //! New area to the bottom of the area specified in AreaReference argument. BottomOf }; /*! * \brief The AreaReference class represents a place where tool windows should be moved. */ class AreaReference { public: /*! * Creates an area reference of the given \a type. If \a type requires specifying * area, it should be given in \a area argument. Otherwise \a area should have default value (0). */ AreaReference(AreaReferenceType type = NoArea, ToolWindowManagerArea* area = 0, float percentage = 0.5f); //! Returns type of the reference. AreaReferenceType type() const { return m_type; } //! Returns area of the reference, or 0 if it was not specified. ToolWindowManagerArea* area() const; private: AreaReferenceType m_type; QWidget* m_widget; float m_percentage; QWidget* widget() const { return m_widget; } float percentage() const { return m_percentage; } AreaReference(AreaReferenceType type, QWidget* widget); void setWidget(QWidget* widget); friend class ToolWindowManager; }; /*! * Adds \a toolWindow to the manager and moves it to the position specified by * \a area. This function is a shortcut for ToolWindowManager::addToolWindows. */ void addToolWindow(QWidget* toolWindow, const AreaReference& area); /*! * Sets the set of \a properties on \a toolWindow that is already added to the manager. */ void setToolWindowProperties(QWidget* toolWindow, ToolWindowProperty properties); /*! * Returns the set of \a properties on \a toolWindow. */ ToolWindowProperty toolWindowProperties(QWidget* toolWindow); /*! * \brief Adds \a toolWindows to the manager and moves it to the position specified by * \a area. * The manager takes ownership of the tool windows and will delete them upon destruction. * * toolWindow->windowIcon() and toolWindow->windowTitle() will be used as the icon and title * of the tab that represents the tool window. * * If you intend to use ToolWindowManager::saveState * and ToolWindowManager::restoreState functions, you must set objectName() of each added * tool window to a non-empty unique string. */ void addToolWindows(QList toolWindows, const AreaReference& area); /*! * Returns area that contains \a toolWindow, or 0 if \a toolWindow is hidden. */ ToolWindowManagerArea* areaOf(QWidget* toolWindow); /*! * \brief Moves \a toolWindow to the position specified by \a area. * * \a toolWindow must be added to the manager prior to calling this function. */ void moveToolWindow(QWidget* toolWindow, AreaReference area); /*! * \brief Moves \a toolWindows to the position specified by \a area. * * \a toolWindows must be added to the manager prior to calling this function. */ void moveToolWindows(QList toolWindows, AreaReference area); /*! * \brief Removes \a toolWindow from the manager. \a toolWindow becomes a hidden * top level widget. The ownership of \a toolWindow is returned to the caller. */ void removeToolWindow(QWidget* toolWindow); /*! * \brief Returns all tool window added to the manager. */ const QList& toolWindows() { return m_toolWindows; } /*! * Hides \a toolWindow. * * \a toolWindow must be added to the manager prior to calling this function. */ void hideToolWindow(QWidget* toolWindow) { moveToolWindow(toolWindow, NoArea); } /*! * \brief saveState */ QVariantMap saveState(); /*! * \brief restoreState */ void restoreState(const QVariantMap& data); typedef std::function CreateCallback; void setToolWindowCreateCallback(const CreateCallback &cb) { m_createCallback = cb; } QWidget *createToolWindow(const QString& objectName); bool checkValidSplitter(QWidget *w); /*! \cond PRIVATE */ void setSuggestionSwitchInterval(int msec); int suggestionSwitchInterval(); int borderSensitivity() { return m_borderSensitivity; } void setBorderSensitivity(int pixels); void setRubberBandLineWidth(int pixels); int rubberBandLineWidth() { return m_rubberBandLineWidth; } void setAllowFloatingWindow(bool pixels); bool allowFloatingWindow() { return m_allowFloatingWindow; } /*! \endcond */ /*! * Returns the widget that is used to display rectangular drop suggestions. */ QRubberBand* rectRubberBand() { return m_rectRubberBand; } /*! * Returns the widget that is used to display line drop suggestions. */ QRubberBand* lineRubberBand() { return m_lineRubberBand; } signals: /*! * \brief This signal is emitted when \a toolWindow may be hidden or shown. * \a visible indicates new visibility state of the tool window. */ void toolWindowVisibilityChanged(QWidget* toolWindow, bool visible); private: QList m_toolWindows; // all added tool windows QHash m_toolWindowProperties; // all tool window properties QList m_areas; // all areas for this manager QList m_wrappers; // all wrappers for this manager int m_borderSensitivity; int m_rubberBandLineWidth; // list of tool windows that are currently dragged, or empty list if there is no current drag QList m_draggedToolWindows; QLabel* m_dragIndicator; // label used to display dragged content QRubberBand* m_rectRubberBand; // placeholder objects used for displaying drop suggestions QRubberBand* m_lineRubberBand; bool m_allowFloatingWindow; // Allow floating windows from this docking area QList m_suggestions; //full list of suggestions for current cursor position int m_dropCurrentSuggestionIndex; // index of currently displayed drop suggestion // (e.g. always 0 if there is only one possible drop location) QTimer m_dropSuggestionSwitchTimer; // used for switching drop suggestions CreateCallback m_createCallback; // last widget used for adding tool windows, or 0 if there isn't one // (warning: may contain pointer to deleted object) ToolWindowManagerArea* m_lastUsedArea; void handleNoSuggestions(); //remove tool window from its area (if any) and set parent to 0 void releaseToolWindow(QWidget* toolWindow); void simplifyLayout(); //remove constructions that became useless void startDrag(const QList& toolWindows); QVariantMap saveSplitterState(QSplitter* splitter); QSplitter* restoreSplitterState(const QVariantMap& data); void findSuggestions(ToolWindowManagerWrapper *wrapper); QRect sideSensitiveArea(QWidget* widget, AreaReferenceType side); QRect sidePlaceHolderRect(QWidget* widget, AreaReferenceType side); void updateDragPosition(); void finishDrag(); bool dragInProgress() { return !m_draggedToolWindows.isEmpty(); } friend class ToolWindowManagerArea; friend class ToolWindowManagerWrapper; protected: /*! * \brief Creates new splitter and sets its default properties. You may reimplement * this function to change properties of all splitters used by this class. */ virtual QSplitter* createSplitter(); /*! * \brief Creates new area and sets its default properties. You may reimplement * this function to change properties of all tab widgets used by this class. */ virtual ToolWindowManagerArea *createArea(); /*! * \brief Generates a pixmap that is used to represent the data in a drag and drop operation * near the mouse cursor. * You may reimplement this function to use different pixmaps. */ virtual QPixmap generateDragPixmap(const QList &toolWindows); private slots: void showNextDropSuggestion(); void tabCloseRequested(int index); void windowTitleChanged(const QString &title); }; inline ToolWindowManager::ToolWindowProperty operator|(ToolWindowManager::ToolWindowProperty a, ToolWindowManager::ToolWindowProperty b) { return ToolWindowManager::ToolWindowProperty(int(a) | int(b)); } #endif // TOOLWINDOWMANAGER_H