Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "docktoolbarview.h"
24 :
25 : #include <QCoreApplication>
26 : #include <QQuickWindow>
27 :
28 : #include "kddockwidgets/src/core/DockWidget.h"
29 : #include "kddockwidgets/src/core/FloatingWindow.h"
30 : #include "kddockwidgets/src/core/Draggable_p.h"
31 : #include "kddockwidgets/src/qtquick/views/DockWidget.h"
32 : #include "kddockwidgets/src/qtquick/views/View.h"
33 :
34 : // This include pulls in kdbindings/signal.h which is incompatible with
35 : // Qt's `emit` macro being defined. Temporarily undefine it, then restore it.
36 : #ifdef emit
37 : #undef emit
38 : #include "kddockwidgets/src/core/WindowBeingDragged_p.h"
39 : #define emit
40 : #else
41 : #include "kddockwidgets/src/core/WindowBeingDragged_p.h"
42 : #endif
43 :
44 : #include "log.h"
45 : #include "docktypes.h"
46 :
47 : using namespace muse::dock;
48 :
49 : class DockToolBarView::DockToolBarDraggable : public KDDockWidgets::Core::Draggable
50 : {
51 : public:
52 6 : explicit DockToolBarDraggable(KDDockWidgets::Core::DockWidget* dw)
53 6 : : KDDockWidgets::Core::Draggable(dw->ctx(), dw->view())
54 6 : , m_dockWidget(dw)
55 : {
56 6 : }
57 :
58 0 : void setMouseArea(QQuickItem* area)
59 : {
60 0 : m_mouseArea = area;
61 0 : }
62 :
63 0 : std::unique_ptr<KDDockWidgets::Core::WindowBeingDragged> makeWindow() override
64 : {
65 0 : if (!m_dockWidget) {
66 0 : return {};
67 : }
68 :
69 0 : KDDockWidgets::Core::FloatingWindow* floatingWindow = m_dockWidget->floatingWindow();
70 0 : if (floatingWindow) {
71 0 : return std::make_unique<KDDockWidgets::Core::WindowBeingDragged>(floatingWindow, this);
72 : }
73 :
74 : //! NOTE: The drag controller consumes the mouse moves, so the main window keeps hovering
75 : //! the press position, where other items appear after the toolbar is undocked
76 0 : if (QQuickWindow* mainWindow = KDDockWidgets::QtQuick::asQQuickItem(m_dockWidget)->window()) {
77 0 : QEvent leaveEvent(QEvent::Leave);
78 0 : QCoreApplication::sendEvent(mainWindow, &leaveEvent);
79 0 : }
80 :
81 0 : m_dockWidget->setFloating(true);
82 0 : floatingWindow = m_dockWidget->floatingWindow();
83 0 : return std::make_unique<KDDockWidgets::Core::WindowBeingDragged>(floatingWindow, this);
84 : }
85 :
86 0 : KDDockWidgets::Core::DockWidget* singleDockWidget() const override
87 : {
88 0 : return m_dockWidget;
89 : }
90 :
91 0 : bool isMDI() const override { return false; }
92 0 : bool isWindow() const override { return false; }
93 :
94 0 : KDDockWidgets::Point mapToWindow(KDDockWidgets::Point pos) const override
95 : {
96 0 : if (!m_mouseArea || !m_dockWidget) {
97 0 : return pos;
98 : }
99 :
100 0 : auto* dockWidgetItem = KDDockWidgets::QtQuick::asQQuickItem(m_dockWidget);
101 0 : if (!dockWidgetItem) {
102 0 : return pos;
103 : }
104 :
105 0 : QPointF result = m_mouseArea->mapToItem(dockWidgetItem, QPointF(pos.x(), pos.y()));
106 0 : result.setX(result.x() + DOCK_WINDOW_SHADOW);
107 0 : result.setY(result.y() + DOCK_WINDOW_SHADOW);
108 0 : return KDDockWidgets::Point(result.x(), result.y());
109 : }
110 :
111 : private:
112 : KDDockWidgets::Core::DockWidget* m_dockWidget = nullptr;
113 : QQuickItem* m_mouseArea = nullptr;
114 : };
115 :
116 : //! NOTE: parent (MouseArea) will be set later
117 46 : DockToolBarView::DockToolBarView(QQuickItem* parent)
118 46 : : DockBase(DockType::ToolBar, parent)
119 : {
120 46 : setLocation(Location::Top);
121 46 : }
122 :
123 52 : DockToolBarView::~DockToolBarView()
124 : {
125 46 : delete m_draggable;
126 52 : }
127 :
128 0 : Qt::Orientation DockToolBarView::orientation() const
129 : {
130 0 : return m_orientation;
131 : }
132 :
133 27 : int DockToolBarView::alignment() const
134 : {
135 27 : return m_alignment;
136 : }
137 :
138 0 : void DockToolBarView::setOrientation(Qt::Orientation orientation)
139 : {
140 0 : if (orientation == m_orientation) {
141 0 : return;
142 : }
143 :
144 0 : m_orientation = orientation;
145 0 : emit orientationChanged(orientation);
146 : }
147 :
148 46 : void DockToolBarView::setAlignment(int alignment)
149 : {
150 46 : if (alignment == m_alignment) {
151 31 : return;
152 : }
153 :
154 15 : m_alignment = alignment;
155 15 : emit alignmentChanged(alignment);
156 : }
157 :
158 0 : void DockToolBarView::setDraggableMouseArea(QQuickItem* mouseArea)
159 : {
160 0 : IF_ASSERT_FAILED(m_draggable) {
161 0 : return;
162 : }
163 :
164 0 : m_draggable->setMouseArea(mouseArea);
165 :
166 : // Redirect mouse events from the grip/mouseArea to the dock widget view
167 : // so the DragController can initiate dragging when the user drags the grip
168 0 : auto* dwView = qobject_cast<KDDockWidgets::QtQuick::DockWidget*>(
169 0 : KDDockWidgets::QtQuick::asQQuickItem(dockWidget()));
170 0 : if (dwView) {
171 0 : dwView->redirectMouseEvents(mouseArea);
172 : }
173 : }
174 :
175 6 : void DockToolBarView::componentComplete()
176 : {
177 6 : DockBase::componentComplete();
178 :
179 6 : m_draggable = new DockToolBarDraggable(dockWidget());
180 6 : }
181 :
182 6 : void DockToolBarView::init()
183 : {
184 6 : if (canChangeOrientation()) {
185 0 : if (height() > width()) {
186 0 : setOrientation(Qt::Vertical);
187 : } else {
188 0 : setOrientation(Qt::Horizontal);
189 : }
190 : }
191 :
192 6 : DockBase::init();
193 6 : }
194 :
195 6 : bool DockToolBarView::canChangeOrientation() const
196 : {
197 6 : if (!floatable()) {
198 0 : return false;
199 : }
200 :
201 6 : for (const DropDestination& dest : dropDestinations()) {
202 0 : if (dest.dropLocation == Location::Left || dest.dropLocation == Location::Right) {
203 0 : return true;
204 : }
205 6 : }
206 :
207 6 : return false;
208 : }
209 :
210 0 : void DockToolBarView::resetToDefault()
211 : {
212 0 : DockBase::resetToDefault();
213 :
214 0 : setOrientation(Qt::Horizontal);
215 0 : }
216 :
217 0 : void DockToolBarView::onGripDoubleClicked()
218 : {
219 0 : toggleFloating();
220 0 : }
221 :
222 0 : void DockToolBarView::toggleFloating()
223 : {
224 0 : if (auto* dw = dockWidget()) {
225 0 : bool wasFloating = dw->isFloating();
226 :
227 : // If the toolbar is floating, first make it think it is docked so it can update itself
228 : // for the docked state. Then we can actually dock it. This is a hack for toolbars that
229 : // change their size between the docked and undocked state, e.g. the Playback toolbar.
230 : // Otheriwse docking a toolbar that shrinks itself after docking leaves gaps.
231 0 : if (wasFloating) {
232 0 : doSetFloating(false);
233 : }
234 :
235 0 : dw->setFloating(!wasFloating);
236 :
237 0 : if (wasFloating) {
238 0 : if (dw->isFloating()) { // If it didn't dock for some reason, undo above hack
239 0 : doSetFloating(true);
240 : }
241 :
242 0 : emit floatingChanged();
243 : }
244 : }
245 0 : }
|