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

© 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 Mon Mar 7 2022 02:01:21 for KDDockWidgets API Documentation by doxygen 1.8.20