KDDockWidgets API Documentation 2.0
Loading...
Searching...
No Matches
core/Separator.cpp
Go to the documentation of this file.
1/*
2 This file is part of KDDockWidgets.
3
4 SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5 Author: SĂ©rgio Martins <sergio.martins@kdab.com>
6
7 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
8
9 Contact KDAB at <info@kdab.com> for commercial licensing options.
10*/
11
12#include "Separator.h"
13#include "layouting/Item_p.h"
14#include "layouting/LayoutingSeparator_p.h"
15#include "View.h"
16#include "Logging_p.h"
17#include "Layout.h"
18#include "Config.h"
19#include "Platform.h"
20#include "Controller.h"
21#include "core/ViewFactory.h"
22
23
24#ifdef Q_OS_WIN
25#include <Windows.h>
26#endif
27
28using namespace KDDockWidgets;
29using namespace KDDockWidgets::Core;
30
32static int s_numSeparators = 0;
33
34namespace {
35
36bool rubberBandIsTopLevel()
37{
40}
41
42}
43
44struct Separator::Private : public LayoutingSeparator
45{
46 // Only set when anchor is moved through mouse. Side1 if going towards left or top, Side2
47 // otherwise.
48
49 explicit Private(Core::Separator *qq, LayoutingHost *host, Qt::Orientation orientation, Core::ItemBoxContainer *parentContainer)
50 : LayoutingSeparator(host, orientation, parentContainer)
51 , q(qq)
52 {
54 }
55
56 ~Private() override;
57
58 Rect geometry() const override
59 {
60 return m_geometry;
61 }
62
63 void setGeometry(Rect r) override
64 {
65 q->setGeometry(r);
66 }
67
68 void free() override
69 {
70 delete q;
71 }
72
73 Core::Separator *const q;
74 Rect m_geometry;
75 int lazyPosition = 0;
76 View *lazyResizeRubberBand = nullptr;
77 const bool usesLazyResize = Config::self().flags() & Config::Flag_LazyResize;
78};
79
80namespace {
81Core::View *viewForLayoutingHost(LayoutingHost *host)
82{
83 // For KDDW, a LayoutingHost is always a Core::Layout
84 if (auto layout = Layout::fromLayoutingHost(host))
85 return layout->view();
86
87 return nullptr;
88}
89}
90
91Separator::Separator(LayoutingHost *host, Qt::Orientation orientation, Core::ItemBoxContainer *parentContainer)
92 : Controller(ViewType::Separator, Config::self().viewFactory()->createSeparator(this, viewForLayoutingHost(host)))
93 , d(new Private(this, host, orientation, parentContainer))
94{
95 view()->show();
96 view()->init();
97 d->lazyResizeRubberBand = d->usesLazyResize ? Config::self().viewFactory()->createRubberBand(
98 rubberBandIsTopLevel() ? nullptr : view())
99 : nullptr;
100 setVisible(true);
101}
102
104{
105 delete d;
106}
107
109{
110 return d->isVertical();
111}
112
114{
115 return d->position();
116}
117
119{
120 if (p == position())
121 return;
122
123 Rect geo = d->m_geometry;
124 if (isVertical()) {
125 geo.moveTop(p);
126 } else {
127 geo.moveLeft(p);
128 }
129 setGeometry(geo);
130
131 if (View *v = view()) {
132 if (isVertical()) {
133 v->move(v->x(), p);
134 } else {
135 v->move(p, v->y());
136 }
137 }
138}
139
141{
142 if (r == d->m_geometry)
143 return;
144
145 d->m_geometry = r;
146
147 if (View *v = view()) {
148 v->setGeometry(r);
149 }
150
151 setVisible(true);
152}
153
154// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
155void Separator::setGeometry(int pos, int pos2, int length)
156{
157 d->LayoutingSeparator::setGeometry(pos, pos2, length);
158}
159
161{
162 return d->m_orientation;
163}
164
165void Separator::setLazyPosition(int pos)
166{
167 if (pos == d->lazyPosition)
168 return;
169
170 View *v = view();
171
172 d->lazyPosition = pos;
173
174 Rect geo = v->geometry();
175 if (isVertical()) {
176 geo.moveTop(pos);
177 } else {
178 geo.moveLeft(pos);
179 }
180
181 if (rubberBandIsTopLevel() && Platform::instance()->isQtWidgets())
182 geo.translate(view()->mapToGlobal(Point(0, 0)));
183 d->lazyResizeRubberBand->setGeometry(geo);
184}
185
186bool Separator::usesLazyResize() const
187{
188 return d->usesLazyResize;
189}
190
192{
193 d->onMousePress();
194
195 KDDW_DEBUG("Drag started");
196
197 if (d->lazyResizeRubberBand) {
198 setLazyPosition(position());
199 d->lazyResizeRubberBand->show();
200 if (rubberBandIsTopLevel() && Platform::instance()->isQtWidgets())
201 d->lazyResizeRubberBand->raise();
202 }
203}
204
206{
207 if (d->lazyResizeRubberBand) {
208 d->lazyResizeRubberBand->hide();
209 d->m_parentContainer->requestSeparatorMove(d, d->lazyPosition - position());
210 }
211
212 d->onMouseRelease();
213}
214
216{
217 // a double click means we'll resize the left and right neighbour so that they occupy
218 // the same size (or top/bottom, depending on orientation).
219 d->m_parentContainer->requestEqualSize(d);
220}
221
223{
224 if (!d->isBeingDragged())
225 return;
226
227 if (Platform::instance()->isQt()) {
228 // Workaround a bug in Qt where we're getting mouse moves without without the button being
229 // pressed
230 if (!Platform::instance()->isLeftMouseButtonPressed()) {
231 KDDW_DEBUG(
232 "Separator::onMouseMove: Ignoring spurious mouse event. Someone ate our ReleaseEvent");
234 return;
235 }
236
237#ifdef KDDW_FRONTEND_QT_WINDOWS
238 // Try harder, Qt can be wrong, if mixed with MFC
239 const bool mouseButtonIsReallyDown =
240 (GetKeyState(VK_LBUTTON) & 0x8000) || (GetKeyState(VK_RBUTTON) & 0x8000);
241 if (!mouseButtonIsReallyDown) {
242 KDDW_DEBUG(
243 "Separator::onMouseMove: Ignoring spurious mouse event. Someone ate our ReleaseEvent");
245 return;
246 }
247#endif
248 }
249
250 if (d->lazyResizeRubberBand) {
251 const int positionToGoTo = d->onMouseMove(pos, /*moveSeparator=*/false);
252 if (positionToGoTo != -1)
253 setLazyPosition(positionToGoTo);
254 } else {
255 d->onMouseMove(pos, /*moveSeparator=*/true);
256 }
257}
258
259Core::ItemBoxContainer *Separator::parentContainer() const
260{
261 return d->m_parentContainer;
262}
263
264LayoutingSeparator *Separator::asLayoutingSeparator() const
265{
266 return d;
267}
268
271{
272 return LayoutingSeparator::s_separatorBeingDragged != nullptr;
273}
274
277{
278 return s_numSeparators;
279}
280
281Separator::Private::~Private()
282{
284}
Application-wide config to tune certain behaviours of the framework.
A widget that supports an arbitrary number of splitters (called Separators) in any combination of ver...
Singleton to allow to choose certain behaviours of the framework.
Definition Config.h:64
InternalFlags internalFlags() const
Definition Config.cpp:270
Core::ViewFactory * viewFactory() const
getter for the framework view factory
Definition Config.cpp:162
@ InternalFlag_TopLevelIndicatorRubberBand
with more exotic setups. This flag can be used to override.
Definition Config.h:171
static Config & self()
returns the singleton Config instance
Definition Config.cpp:87
Flags flags() const
returns the chosen flags
Definition Config.cpp:98
View * view() const
Returns the view associated with this controller, if any.
Point mapToGlobal(Point) const
static Layout * fromLayoutingHost(LayoutingHost *)
Definition Layout.cpp:399
static Platform * instance()
Returns the platform singleton.
LayoutingSeparator * asLayoutingSeparator() const
Qt::Orientation orientation() const
Core::ItemBoxContainer * parentContainer() const
static bool isResizing()
Returns whether we're dragging a separator. Can be useful for the app to stop other work while we're ...
virtual View * createRubberBand(View *parent) const =0
Called by the framework to create a RubberBand view to show as drop zone.
virtual void show()=0
virtual Rect geometry() const =0
static int s_numSeparators
internal counter just for unit-tests
ViewType
Each View type also has a specific Controller associated with, except for ViewType::None.
Definition Controller.h:26
Class to abstract QAction, so code still works with QtQuick and Flutter.
Orientation

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated by doxygen 1.9.8