KDDockWidgets API Documentation 1.7
Loading...
Searching...
No Matches
Separator.cpp
Go to the documentation of this file.
1/*
2 This file is part of KDDockWidgets.
3
4 SPDX-FileCopyrightText: 2019-2023 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_p.h"
13#include "Widget.h"
14#include "Logging_p.h"
15#include "Item_p.h"
16#include "MultiSplitterConfig.h"
17#include "Config.h"
18
19#include <QGuiApplication>
20
21#ifdef KDDOCKWIDGETS_QTWIDGETS
22#include <QWidget>
23#endif
24
25#ifdef Q_OS_WIN
26#include <windows.h>
27#endif
28
29using namespace Layouting;
30
31Separator *Separator::s_separatorBeingDragged = nullptr;
32
33namespace {
34
35bool rubberBandIsTopLevel()
36{
38}
39
40}
41
43static int s_numSeparators = 0;
44
45struct Separator::Private
46{
47 // Only set when anchor is moved through mouse. Side1 if going towards left or top, Side2 otherwise.
48
49 Private(Widget *host)
50 : m_hostWidget(host)
51 {
52 }
53
54 Qt::Orientation orientation = Qt::Horizontal;
55 QRect geometry;
56 int lazyPosition = 0;
57 // SeparatorOptions m_options; TODO: Have a Layouting::Config
58 Widget *lazyResizeRubberBand = nullptr;
59 ItemBoxContainer *parentContainer = nullptr;
60 Layouting::Side lastMoveDirection = Side1;
61 const bool usesLazyResize = Config::self().flags() & Config::Flag::LazyResize;
62 Widget *const m_hostWidget;
63};
64
65Separator::Separator(Widget *hostWidget)
66 : d(new Private(hostWidget))
67{
69}
70
71Separator::~Separator()
72{
74 delete d;
75 if (isBeingDragged())
76 s_separatorBeingDragged = nullptr;
77}
78
79bool Separator::isVertical() const
80{
81 return d->orientation == Qt::Vertical;
82}
83
84void Separator::move(int p)
85{
86 auto w = asWidget();
87 if (!w)
88 return;
89
90 if (isVertical()) {
91 w->move(w->x(), p);
92 } else {
93 w->move(p, w->y());
94 }
95}
96
97Qt::Orientation Separator::orientation() const
98{
99 return d->orientation;
100}
101
102void Separator::onMousePress()
103{
104 s_separatorBeingDragged = this;
105
106 qCDebug(separators) << "Drag started";
107
108 if (d->lazyResizeRubberBand) {
109 setLazyPosition(position());
110 d->lazyResizeRubberBand->show();
111#ifdef KDDOCKWIDGETS_QTWIDGETS
112 if (rubberBandIsTopLevel())
113 d->lazyResizeRubberBand->asQWidget()->raise();
114#endif
115 }
116}
117
118void Separator::onMouseDoubleClick()
119{
120 // a double click means we'll resize the left and right neighbour so that they occupy
121 // the same size (or top/bottom, depending on orientation).
122 d->parentContainer->requestEqualSize(this);
123}
124
125void Separator::onMouseMove(QPoint pos)
126{
127 if (!isBeingDragged())
128 return;
129
130 if (!(qApp->mouseButtons() & Qt::LeftButton)) {
131 qCDebug(separators) << Q_FUNC_INFO << "Ignoring spurious mouse event. Someone ate our ReleaseEvent";
132 onMouseReleased();
133 return;
134 }
135
136#ifdef Q_OS_WIN
137 // Try harder, Qt can be wrong, if mixed with MFC
138 const bool mouseButtonIsReallyDown = (GetKeyState(VK_LBUTTON) & 0x8000) || (GetKeyState(VK_RBUTTON) & 0x8000);
139 if (!mouseButtonIsReallyDown) {
140 qCDebug(separators) << Q_FUNC_INFO << "Ignoring spurious mouse event. Someone ate our ReleaseEvent";
141 onMouseReleased();
142 return;
143 }
144#endif
145
146 const int positionToGoTo = Layouting::pos(pos, d->orientation);
147 const int minPos = d->parentContainer->minPosForSeparator_global(this);
148 const int maxPos = d->parentContainer->maxPosForSeparator_global(this);
149
150 if ((positionToGoTo > maxPos && position() <= positionToGoTo) || (positionToGoTo < minPos && position() >= positionToGoTo)) {
151 // if current pos is 100, and max is 80, we do allow going to 90.
152 // Would continue to violate, but only by 10, so allow.
153
154 // On the other hand, if we're already past max-pos, don't make it worse and just
155 // return if positionToGoTo is further away from maxPos.
156
157 // Same reasoning for minPos
158 return;
159 }
160
161 d->lastMoveDirection = positionToGoTo < position() ? Side1
162 : (positionToGoTo > position() ? Side2
163 : Side1); // Last case shouldn't happen though.
164
165 if (d->lazyResizeRubberBand)
166 setLazyPosition(positionToGoTo);
167 else
168 d->parentContainer->requestSeparatorMove(this, positionToGoTo - position());
169}
170
171void Separator::onMouseReleased()
172{
173 if (d->lazyResizeRubberBand) {
174 d->lazyResizeRubberBand->hide();
175 d->parentContainer->requestSeparatorMove(this, d->lazyPosition - position());
176 }
177
178 s_separatorBeingDragged = nullptr;
179}
180
181void Separator::setGeometry(QRect r)
182{
183 if (r != d->geometry) {
184 d->geometry = r;
185 if (auto w = asWidget()) {
186 w->setGeometry(r);
187 w->setVisible(true);
188 }
189 }
190}
191
192int Separator::position() const
193{
194 const QPoint topLeft = d->geometry.topLeft();
195 return isVertical() ? topLeft.y() : topLeft.x();
196}
197
198QObject *Separator::host() const
199{
200 return d->m_hostWidget ? d->m_hostWidget->asQObject() : nullptr;
201}
202
203void Separator::init(ItemBoxContainer *parentContainer, Qt::Orientation orientation)
204{
205 if (!parentContainer) {
206 qWarning() << Q_FUNC_INFO << "null parentContainer";
207 return;
208 }
209
210 d->parentContainer = parentContainer;
211 d->orientation = orientation;
212 d->lazyResizeRubberBand = d->usesLazyResize ? createRubberBand(rubberBandIsTopLevel() ? nullptr : d->m_hostWidget)
213 : nullptr;
214 asWidget()->setVisible(true);
215}
216
217ItemBoxContainer *Separator::parentContainer() const
218{
219 return d->parentContainer;
220}
221
222void Separator::setGeometry(int pos, int pos2, int length)
223{
224 QRect newGeo = d->geometry;
225 if (isVertical()) {
226 // The separator itself is horizontal
227 newGeo.setSize(QSize(length, Item::separatorThickness));
228 newGeo.moveTo(pos2, pos);
229 } else {
230 // The separator itself is vertical
231 newGeo.setSize(QSize(Item::separatorThickness, length));
232 newGeo.moveTo(pos, pos2);
233 }
234
235 setGeometry(newGeo);
236}
237
238bool Separator::isResizing()
239{
240 return s_separatorBeingDragged != nullptr;
241}
242
243int Separator::numSeparators()
244{
245 return s_numSeparators;
246}
247
248void Separator::setLazyPosition(int pos)
249{
250 if (d->lazyPosition != pos) {
251 d->lazyPosition = pos;
252
253 QRect geo = asWidget()->geometry();
254 if (isVertical()) {
255 geo.moveTop(pos);
256 } else {
257 geo.moveLeft(pos);
258 }
259#ifdef KDDOCKWIDGETS_QTWIDGETS
260 if (rubberBandIsTopLevel())
261 geo.translate(d->m_hostWidget->asQWidget()->mapToGlobal(QPoint(0, 0)));
262#endif
263 d->lazyResizeRubberBand->setGeometry(geo);
264 }
265}
266
267bool Separator::isBeingDragged() const
268{
269 return s_separatorBeingDragged == this;
270}
Application-wide config to tune certain behaviours of the framework.
static int s_numSeparators
internal counter just for unit-tests
Definition Separator.cpp:43
An abstraction/wrapper around QWidget, QtQuickItem or anything else.
InternalFlags internalFlags() const
Definition Config.cpp:225
@ InternalFlag_TopLevelIndicatorRubberBand
with more exotic setups. This flag can be used to override.
Definition Config.h:139
static Config & self()
returns the singleton Config instance
Definition Config.cpp:84
Config::Flags flags() const
returns the flags;
static Config & self()
returns the singleton Config instance
An abstraction/wrapper around QWidget, QtQuickItem or anything else.
Definition Widget.h:77
int x() const const
int y() const const
void moveLeft(int x)
void moveTo(int x, int y)
void moveTop(int y)
void setSize(const QSize &size)
void translate(int dx, int dy)
LeftButton
Orientation

© 2019-2023 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 on Wed Nov 1 2023 00:02:31 for KDDockWidgets API Documentation by doxygen 1.9.8