| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- #include "CmWindowDockManager.h"
- #include "CmEditorWindowManager.h"
- #include "CmQtEditorWindow.h"
- #include "CmDebug.h"
- #include <QtWidgets/QWidget>
- #include <QtWidgets/QLayout>
- #include <QtWidgets/QSplitter>
- namespace CamelotEditor
- {
- WindowDockManager::WindowDockManager(QWidget* centralWidget, QtDockOverlayWidget* dockOverlayWidget)
- :mDockOverlayWidget(dockOverlayWidget), mCentralWidget(centralWidget), mCentralSplitter(nullptr), mLastDraggedWindow(nullptr)
- {
- QVBoxLayout* boxLayout = new QVBoxLayout();
- boxLayout->setMargin(0);
- boxLayout->setSpacing(0);
- mCentralWidget->setLayout(boxLayout);
- mCentralSplitter = new QSplitter(mCentralWidget);
- mCentralSplitter->setChildrenCollapsible(false);
- boxLayout->addWidget(mCentralSplitter);
- }
- void WindowDockManager::windowDragged(QtEditorWindow* window, const QPoint& mousePos)
- {
- assert(window != nullptr);
- if(mLastDraggedWindow != window)
- {
- mLastDragPosition = mousePos;
- mLastDraggedWindow = window;
- }
- if(!window->isDocked())
- {
- vector<UINT32>::type windowsToIgnore;
- windowsToIgnore.push_back(window->getId()); // Ignore myself
- QtEditorWindow* windowUnderMouse = gEditorWindowManager().getWindowAtPosition(mousePos, windowsToIgnore);
- QWidget* dragOverWidget = nullptr;
- bool contentUnderMouse = false;
- bool tabBarUnderMouse = false;
- if(windowUnderMouse != nullptr)
- {
- dragOverWidget = windowUnderMouse->getContentWidget();
- QPoint localMousePos = dragOverWidget->mapFromGlobal(mousePos);
- if(dragOverWidget->geometry().contains(localMousePos))
- contentUnderMouse = true;
-
- QWidget* tabBarWidget = windowUnderMouse->getTabWidget();
- localMousePos = tabBarWidget->mapFromGlobal(mousePos);
- if(tabBarWidget->geometry().contains(localMousePos))
- tabBarUnderMouse = true;
- }
- if(!tabBarUnderMouse && dragOverWidget == nullptr && isPositionInDockArea(mousePos))
- {
- dragOverWidget = mCentralWidget;
- contentUnderMouse = true;
- }
- if(contentUnderMouse)
- {
- mDockOverlayWidget->highlightTabDropLocation(-1);
- mDockOverlayWidget->disableTabDropOverlay();
- // Draw dock overlay
- if(dragOverWidget != nullptr)
- {
- WindowDragDropLocation dragLocation = getDropLocationAtPosition(dragOverWidget, mousePos);
- std::vector<QPolygon> dropLocations = getDropLocations(dragOverWidget);
- QPoint drawOffset = mCentralWidget->mapToGlobal(QPoint(0, 0)) - mDockOverlayWidget->mapToGlobal(QPoint(0, 0));
- mDockOverlayWidget->enableDropOverlay(dropLocations, drawOffset);
- if(dragLocation != CM_WINDROP_CENTER)
- mDockOverlayWidget->highlightDropLocation(dragLocation);
- else
- mDockOverlayWidget->highlightDropLocation(CM_WINDROP_NONE);
- }
- else
- {
- mDockOverlayWidget->highlightDropLocation(CM_WINDROP_NONE);
- mDockOverlayWidget->disableDropOverlay();
- }
- }
- if(tabBarUnderMouse)
- {
- mDockOverlayWidget->highlightDropLocation(CM_WINDROP_NONE);
- mDockOverlayWidget->disableDropOverlay();
- // Draw tab bar overlay
- if(windowUnderMouse != nullptr)
- {
- std::vector<QPolygon> tabDropLocations = windowUnderMouse->getTabBarDropLocations();
- INT32 activeTabDropLocation = windowUnderMouse->getActiveTabBarDropLocation(mousePos);
- if(activeTabDropLocation != -1)
- {
- QPoint drawOffset = -mDockOverlayWidget->mapToGlobal(QPoint(0, 0));
- mDockOverlayWidget->enableTabDropOverlay(tabDropLocations, drawOffset);
-
- mDockOverlayWidget->highlightTabDropLocation(activeTabDropLocation);
- }
- }
- }
- }
- else
- {
- QPoint diff = mLastDragPosition - mousePos;
-
- if(diff.manhattanLength() > 4)
- {
- undockWindow(window);
- }
- }
- }
- void WindowDockManager::windowReleased(QtEditorWindow* window, const QPoint& mousePos)
- {
- mDockOverlayWidget->highlightDropLocation(CM_WINDROP_NONE);
- mDockOverlayWidget->disableDropOverlay();
- mDockOverlayWidget->highlightTabDropLocation(-1);
- mDockOverlayWidget->disableTabDropOverlay();
- if(mLastDraggedWindow != window)
- {
- mLastDragPosition = mousePos;
- mLastDraggedWindow = window;
- }
- QPoint diff = mLastDragPosition - mousePos;
- bool wasDragged = diff.manhattanLength() > 4; // Ensure user actually moved the window
- if(wasDragged && !window->isDocked())
- {
- vector<UINT32>::type windowsToIgnore;
- windowsToIgnore.push_back(window->getId()); // Ignore myself
- QtEditorWindow* windowUnderCursor = gEditorWindowManager().getWindowAtPosition(mousePos, windowsToIgnore);
- if(windowUnderCursor != nullptr)
- {
- bool contentUnderMouse = false;
- bool tabBarUnderMouse = false;
- QWidget* contentWidget = windowUnderCursor->getContentWidget();
- QPoint localMousePos = contentWidget->mapFromGlobal(mousePos);
- if(contentWidget->geometry().contains(localMousePos))
- contentUnderMouse = true;
- QWidget* tabBarWidget = windowUnderCursor->getTabWidget();
- localMousePos = tabBarWidget->mapFromGlobal(mousePos);
- if(tabBarWidget->geometry().contains(localMousePos))
- tabBarUnderMouse = true;
- if(contentUnderMouse)
- {
- WindowDragDropLocation dropLocation = getDropLocationAtPosition(windowUnderCursor->getContentWidget(), mousePos);
- dockWindow(window, windowUnderCursor, dropLocation);
- }
- else if(tabBarUnderMouse)
- {
- INT32 dropLocation = windowUnderCursor->getActiveTabBarDropLocation(mousePos);
- if(dropLocation != -1)
- {
- while(window->getNumWidgets() > 0)
- {
- QtEditorWidget* widget = window->getWidget(0);
- window->removeWidget(0);
- windowUnderCursor->insertWidget(dropLocation, widget);
- }
- window->closeWindow();
- }
- }
- }
- else
- {
- if(isPositionInDockArea(mousePos))
- {
- WindowDragDropLocation dropLocation = getDropLocationAtPosition(mCentralWidget, mousePos);
- dockWindow(window, nullptr, dropLocation);
- }
- }
- }
- }
- void WindowDockManager::windowClosed(QtEditorWindow* window)
- {
- if(window->isDocked())
- undockWindow(window);
- }
- bool WindowDockManager::isDocked(const QtEditorWindow* window) const
- {
- auto findIter = mDockedWindows.find(const_cast<QtEditorWindow*>(window));
- return findIter != mDockedWindows.end();
- }
- WindowDragDropLocation WindowDockManager::getDockLocation(const QtEditorWindow* window) const
- {
- auto findIter = mDockedWindows.find(const_cast<QtEditorWindow*>(window));
- assert(findIter != mDockedWindows.end());
- return findIter->second.dockLocation;
- }
- INT32 WindowDockManager::getDockParentId(const QtEditorWindow* window) const
- {
- auto findIter = mDockedWindows.find(const_cast<QtEditorWindow*>(window));
- assert(findIter != mDockedWindows.end());
- return findIter->second.parentId;
- }
- bool WindowDockManager::isPositionInDockArea(const QPoint& globalPos)
- {
- QPoint globalWidgetPos = mCentralWidget->mapToGlobal(QPoint(0, 0));
- QRect widgetRect(globalWidgetPos, mCentralWidget->geometry().size());
- return widgetRect.contains(globalPos);
- }
- WindowDragDropLocation WindowDockManager::getDropLocationAtPosition(const QWidget* widget, const QPoint& globalPos)
- {
- assert(widget != nullptr);
- QPoint localPos = mCentralWidget->mapFromGlobal(globalPos);
- std::vector<QPolygon> dragLocations = getDropLocations(widget);
- int idx = 0;
- for(auto iter = dragLocations.begin(); iter != dragLocations.end(); ++iter)
- {
- if(iter->containsPoint(localPos, Qt::OddEvenFill))
- return (WindowDragDropLocation)idx;
- ++idx;
- }
- return CM_WINDROP_NONE;
- }
- void WindowDockManager::dockWindow(QtEditorWindow* windowToDock, QtEditorWindow* dockAtWidget, WindowDragDropLocation dockAtPosition)
- {
- assert(windowToDock != nullptr);
- auto findIter = mDockedWindows.find(windowToDock);
- assert(findIter == mDockedWindows.end());
- if(dockAtPosition == CM_WINDROP_NONE || dockAtPosition == CM_WINDROP_CENTER)
- return;
- if(dockAtWidget == nullptr)
- {
- mCentralSplitter->addWidget(windowToDock);
- windowToDock->dock();
- }
- else
- {
- QSplitter* parentSplitter = dynamic_cast<QSplitter*>(dockAtWidget->parentWidget());
- if(parentSplitter == nullptr)
- {
- LOGWRN("Trying to dock a window to a widget that doesn't have a parent splitter.");
- return;
- }
- if(parentSplitter->orientation() == Qt::Horizontal)
- {
- int idxDockAt = parentSplitter->indexOf(dockAtWidget);
- if(dockAtPosition == CM_WINDROP_LEFT)
- parentSplitter->insertWidget(idxDockAt, windowToDock);
- else if(dockAtPosition == CM_WINDROP_RIGHT)
- parentSplitter->insertWidget(idxDockAt + 1, windowToDock);
- else // Top or bottom
- {
- QSplitter* newSplitter = new QSplitter();
- newSplitter->setOrientation(Qt::Vertical);
- newSplitter->setChildrenCollapsible(false);
-
- if(dockAtPosition == CM_WINDROP_TOP)
- {
- newSplitter->addWidget(windowToDock);
- newSplitter->addWidget(dockAtWidget);
- }
- else
- {
- newSplitter->addWidget(dockAtWidget);
- newSplitter->addWidget(windowToDock);
- }
- parentSplitter->insertWidget(idxDockAt, newSplitter);
- }
- }
- else
- {
- int idxDockAt = parentSplitter->indexOf(dockAtWidget);
- if(dockAtPosition == CM_WINDROP_TOP)
- parentSplitter->insertWidget(idxDockAt, windowToDock);
- else if(dockAtPosition == CM_WINDROP_BOTTOM)
- parentSplitter->insertWidget(idxDockAt + 1, windowToDock);
- else // Left or right
- {
- QSplitter* newSplitter = new QSplitter();
- newSplitter->setOrientation(Qt::Horizontal);
- newSplitter->setChildrenCollapsible(false);
- if(dockAtPosition == CM_WINDROP_LEFT)
- {
- newSplitter->addWidget(windowToDock);
- newSplitter->addWidget(dockAtWidget);
- }
- else
- {
- newSplitter->addWidget(dockAtWidget);
- newSplitter->addWidget(windowToDock);
- }
- parentSplitter->insertWidget(idxDockAt, newSplitter);
- }
- }
- windowToDock->dock();
- }
- DockedWindowInfo dockedInfo;
- dockedInfo.dockLocation = dockAtPosition;
- if(dockAtWidget == nullptr)
- dockedInfo.parentId = -1;
- else
- dockedInfo.parentId = dockAtWidget->getId();
- mDockedWindows[windowToDock] = dockedInfo;
- }
- void WindowDockManager::undockWindow(QtEditorWindow* windowToUndock)
- {
- CM_ASSERT(windowToUndock != nullptr);
- QSplitter* parentSplitter = dynamic_cast<QSplitter*>(windowToUndock->parentWidget());
- if(parentSplitter == nullptr)
- {
- LOGWRN("Trying to dock a window to a widget that doesn't have a parent splitter.");
- return;
- }
- windowToUndock->setParent(mCentralWidget);
- windowToUndock->undock();
- windowToUndock->show();
- // Check if there is just one widget in splitter, so there's no need for a splitter at all
- if(parentSplitter != mCentralSplitter && parentSplitter->count() == 1)
- {
- QSplitter* topParentSplitter = dynamic_cast<QSplitter*>(parentSplitter->parentWidget());
- if(topParentSplitter == nullptr)
- {
- CM_EXCEPT(InternalErrorException, "Splitter is not root splitter, but doesn't have a splitter parent.");
- }
- QWidget* remainingWidget = parentSplitter->widget(0);
- int splitterIdx = topParentSplitter->indexOf(parentSplitter);
- topParentSplitter->insertWidget(splitterIdx, remainingWidget);
- delete parentSplitter;
- }
- auto findIter = mDockedWindows.find(windowToUndock);
- CM_ASSERT(findIter != mDockedWindows.end());
- mDockedWindows.erase(findIter);
- }
- std::vector<QPolygon> WindowDockManager::getDropLocations(const QWidget* widget)
- {
- QPoint topLeft = widget->mapToGlobal(QPoint(0, 0));
- topLeft = mCentralWidget->mapFromGlobal(topLeft);
- QRect largeRect(topLeft.x() + 1, topLeft.y() + 1, widget->width() - 2, widget->height() - 2);
- int sizeOffset = widget->width() < widget->height() ? (widget->width() / 10) : (widget->height() / 10);
- QRect smallRect(topLeft.x() + sizeOffset, topLeft.y() + sizeOffset, widget->width() - 2 * sizeOffset, widget->height() - 2 * sizeOffset);
- QPolygon left(4);
- left[0] = largeRect.topLeft();
- left[1] = largeRect.bottomLeft();
- left[2] = smallRect.bottomLeft();
- left[3] = smallRect.topLeft();
- QPolygon right(4);
- right[0] = largeRect.topRight();
- right[1] = largeRect.bottomRight();
- right[2] = smallRect.bottomRight();
- right[3] = smallRect.topRight();
- QPolygon top(4);
- top[0] = largeRect.topLeft();
- top[1] = largeRect.topRight();
- top[2] = smallRect.topRight();
- top[3] = smallRect.topLeft();
- QPolygon bottom(4);
- bottom[0] = largeRect.bottomRight();
- bottom[1] = largeRect.bottomLeft();
- bottom[2] = smallRect.bottomLeft();
- bottom[3] = smallRect.bottomRight();
- QPolygon center(4);
- center[0] = smallRect.topLeft();
- center[1] = smallRect.topRight();
- center[2] = smallRect.bottomRight();
- center[3] = smallRect.bottomLeft();
- std::vector<QPolygon> dragLocations;
- dragLocations.push_back(left);
- dragLocations.push_back(right);
- dragLocations.push_back(top);
- dragLocations.push_back(bottom);
- dragLocations.push_back(center);
- return dragLocations;
- }
- WindowDockManager& gWindowDockManager()
- {
- return WindowDockManager::instance();
- }
- }
|