351 lines
12 KiB
C
351 lines
12 KiB
C
|
/*
|
||
|
* 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 <QWidget>
|
||
|
#include <QHash>
|
||
|
#include <QVariant>
|
||
|
#include <QLabel>
|
||
|
|
||
|
#include <functional>
|
||
|
|
||
|
class ToolWindowManagerArea;
|
||
|
class ToolWindowManagerWrapper;
|
||
|
|
||
|
class QLabel;
|
||
|
class QSplitter;
|
||
|
|
||
|
/*!
|
||
|
* \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 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)
|
||
|
|
||
|
/*!
|
||
|
* \brief How much of a margin should be placed between drop hotspots.
|
||
|
*
|
||
|
* Default value is 4.
|
||
|
*
|
||
|
* Access functions: dropHotspotMargin, setDropHotspotMargin.
|
||
|
*
|
||
|
*/
|
||
|
Q_PROPERTY(int dropHotspotMargin READ dropHotspotMargin WRITE setDropHotspotMargin)
|
||
|
|
||
|
/*!
|
||
|
* \brief How wide and heigh each drop hotspot icon should be drawn at, in pixels.
|
||
|
*
|
||
|
* Default value is 32.
|
||
|
*
|
||
|
* Access functions: dropHotspotDimension, setDropHotspotDimension.
|
||
|
*
|
||
|
*/
|
||
|
Q_PROPERTY(int dropHotspotDimension READ dropHotspotDimension WRITE setDropHotspotDimension)
|
||
|
|
||
|
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,
|
||
|
//! Don't allow this tool window to be floated
|
||
|
DisallowFloatWindow = 0x10,
|
||
|
//! When displaying this tool window in tabs, always display the tabs even if there's only one
|
||
|
AlwaysDisplayFullTabs = 0x20,
|
||
|
};
|
||
|
|
||
|
//! 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,
|
||
|
//! New area to the left of the window containing the specified in AreaReference argument.
|
||
|
LeftWindowSide,
|
||
|
//! New area to the right of the window containing the specified in AreaReference argument.
|
||
|
RightWindowSide,
|
||
|
//! New area to the top of the window containing the specified in AreaReference argument.
|
||
|
TopWindowSide,
|
||
|
//! New area to the bottom of the window containing the specified in AreaReference argument.
|
||
|
BottomWindowSide,
|
||
|
//! Invalid value, just indicates the number of types available
|
||
|
NumReferenceTypes
|
||
|
};
|
||
|
|
||
|
/*!
|
||
|
* \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;
|
||
|
bool dragResult;
|
||
|
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<QWidget*> 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<QWidget*> 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<QWidget*>& 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); }
|
||
|
|
||
|
static ToolWindowManager* managerOf(QWidget* toolWindow);
|
||
|
static void closeToolWindow(QWidget *toolWindow);
|
||
|
static void raiseToolWindow(QWidget *toolWindow);
|
||
|
|
||
|
/*!
|
||
|
* \brief saveState
|
||
|
*/
|
||
|
QVariantMap saveState();
|
||
|
|
||
|
/*!
|
||
|
* \brief restoreState
|
||
|
*/
|
||
|
void restoreState(const QVariantMap& data);
|
||
|
|
||
|
typedef std::function<QWidget*(const QString &)> CreateCallback;
|
||
|
|
||
|
void setToolWindowCreateCallback(const CreateCallback &cb) { m_createCallback = cb; }
|
||
|
QWidget *createToolWindow(const QString& objectName);
|
||
|
|
||
|
void setHotspotPixmap(AreaReferenceType ref, const QPixmap &pix) { m_pixmaps[ref] = pix; }
|
||
|
|
||
|
void setDropHotspotMargin(int pixels);
|
||
|
bool dropHotspotMargin() { return m_dropHotspotMargin; }
|
||
|
|
||
|
void setDropHotspotDimension(int pixels);
|
||
|
bool dropHotspotDimension() { return m_dropHotspotDimension; }
|
||
|
|
||
|
/*! \cond PRIVATE */
|
||
|
void setAllowFloatingWindow(bool pixels);
|
||
|
bool allowFloatingWindow() { return m_allowFloatingWindow; }
|
||
|
/*! \endcond */
|
||
|
|
||
|
|
||
|
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<QWidget*> m_toolWindows; // all added tool windows
|
||
|
QHash<QWidget*, ToolWindowProperty> m_toolWindowProperties; // all tool window properties
|
||
|
QList<ToolWindowManagerArea*> m_areas; // all areas for this manager
|
||
|
QList<ToolWindowManagerWrapper*> m_wrappers; // all wrappers for this manager
|
||
|
// list of tool windows that are currently dragged, or empty list if there is no current drag
|
||
|
QList<QWidget*> m_draggedToolWindows;
|
||
|
ToolWindowManagerWrapper* m_draggedWrapper; // the wrapper if a whole float window is being dragged
|
||
|
ToolWindowManagerArea* m_hoverArea; // the area currently being hovered over in a drag
|
||
|
// a semi-transparent preview of where the dragged toolwindow(s) will be docked
|
||
|
QWidget* m_previewOverlay;
|
||
|
QWidget* m_previewTabOverlay;
|
||
|
QLabel* m_dropHotspots[NumReferenceTypes];
|
||
|
QPixmap m_pixmaps[NumReferenceTypes];
|
||
|
|
||
|
bool m_allowFloatingWindow; // Allow floating windows from this docking area
|
||
|
int m_dropHotspotMargin; // The pixels between drop hotspot icons
|
||
|
int m_dropHotspotDimension; // The pixel dimension of the hotspot icons
|
||
|
|
||
|
CreateCallback m_createCallback;
|
||
|
|
||
|
ToolWindowManagerWrapper* wrapperOf(QWidget* toolWindow);
|
||
|
|
||
|
void drawHotspotPixmaps();
|
||
|
|
||
|
bool allowClose(QWidget *toolWindow);
|
||
|
|
||
|
// last widget used for adding tool windows, or 0 if there isn't one
|
||
|
// (warning: may contain pointer to deleted object)
|
||
|
ToolWindowManagerArea* m_lastUsedArea;
|
||
|
//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<QWidget*>& toolWindows, ToolWindowManagerWrapper *wrapper);
|
||
|
|
||
|
QVariantMap saveSplitterState(QSplitter* splitter);
|
||
|
QSplitter* restoreSplitterState(const QVariantMap& data);
|
||
|
|
||
|
AreaReferenceType currentHotspot();
|
||
|
|
||
|
void updateDragPosition();
|
||
|
void abortDrag();
|
||
|
void finishDrag();
|
||
|
bool dragInProgress() { return !m_draggedToolWindows.isEmpty(); }
|
||
|
|
||
|
friend class ToolWindowManagerArea;
|
||
|
friend class ToolWindowManagerWrapper;
|
||
|
|
||
|
protected:
|
||
|
//! Event filter for grabbing and processing drag aborts.
|
||
|
virtual bool eventFilter(QObject *object, QEvent *event);
|
||
|
|
||
|
/*!
|
||
|
* \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();
|
||
|
|
||
|
private slots:
|
||
|
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
|