KDDockWidgets API Documentation  1.6
Separator.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KDDockWidgets.
3 
4  SPDX-FileCopyrightText: 2019-2022 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 
29 using namespace Layouting;
30 
31 Separator *Separator::s_separatorBeingDragged = nullptr;
32 
33 namespace {
34 
35 bool rubberBandIsTopLevel()
36 {
38 }
39 
40 }
41 
43 static int s_numSeparators = 0;
44 
45 struct 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 
65 Separator::Separator(Widget *hostWidget)
66  : d(new Private(hostWidget))
67 {
69 }
70 
71 Separator::~Separator()
72 {
74  delete d;
75  if (isBeingDragged())
76  s_separatorBeingDragged = nullptr;
77 }
78 
79 bool Separator::isVertical() const
80 {
81  return d->orientation == Qt::Vertical;
82 }
83 
84 void 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 
97 Qt::Orientation Separator::orientation() const
98 {
99  return d->orientation;
100 }
101 
102 void 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 
118 void 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 
125 void 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 
171 void 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 
181 void 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 
192 int Separator::position() const
193 {
194  const QPoint topLeft = d->geometry.topLeft();
195  return isVertical() ? topLeft.y() : topLeft.x();
196 }
197 
198 QObject *Separator::host() const
199 {
200  return d->m_hostWidget ? d->m_hostWidget->asQObject() : nullptr;
201 }
202 
203 void 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 
217 ItemBoxContainer *Separator::parentContainer() const
218 {
219  return d->parentContainer;
220 }
221 
222 void 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 
238 bool Separator::isResizing()
239 {
240  return s_separatorBeingDragged != nullptr;
241 }
242 
243 int Separator::numSeparators()
244 {
245  return s_numSeparators;
246 }
247 
248 void 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 
267 bool Separator::isBeingDragged() const
268 {
269  return s_separatorBeingDragged == this;
270 }
QRect::setSize
void setSize(const QSize &size)
MultiSplitterConfig.h
QRect
ItemBoxContainer
Widget.h
An abstraction/wrapper around QWidget, QtQuickItem or anything else.
Layouting::Config::self
static Config & self()
returns the singleton Config instance
Definition: MultiSplitterConfig.cpp:44
s_numSeparators
static int s_numSeparators
internal counter just for unit-tests
Definition: Separator.cpp:43
Layouting::Config::Flag::LazyResize
@ LazyResize
Separator
QSize
QPoint::x
int x() const const
QPoint::y
int y() const const
Qt::LeftButton
LeftButton
QObject
Layouting::Widget
An abstraction/wrapper around QWidget, QtQuickItem or anything else.
Definition: Widget.h:77
Qt::Orientation
Orientation
QRect::moveTop
void moveTop(int y)
KDDockWidgets::Config::InternalFlag_TopLevelIndicatorRubberBand
@ InternalFlag_TopLevelIndicatorRubberBand
with more exotic setups. This flag can be used to override.
Definition: Config.h:138
Config.h
Application-wide config to tune certain behaviours of the framework.
QRect::translate
void translate(int dx, int dy)
Layouting::Config::flags
Config::Flags flags() const
returns the flags;
Definition: MultiSplitterConfig.cpp:85
QRect::moveTo
void moveTo(int x, int y)
QRect::moveLeft
void moveLeft(int x)
Layouting
Definition: FrameworkWidgetFactory.h:32
QPoint
KDDockWidgets::Config::self
static Config & self()
returns the singleton Config instance
Definition: Config.cpp:84

© 2019-2022 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 Thu Sep 15 2022 00:16:29 for KDDockWidgets API Documentation by doxygen 1.8.20