VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/extensions/QISplitter.cpp@ 100347

Last change on this file since 100347 was 100086, checked in by vboxsync, 20 months ago

FE/Qt: bugref:10450: Qt6 compatibility bits for QMouseEvent; Replacing QMouseEvent::globalPos with QSinglePointEvent::globalPosition.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.2 KB
Line 
1/* $Id: QISplitter.cpp 100086 2023-06-06 15:15:12Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Qt extensions: QISplitter class implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QApplication>
30#include <QEvent>
31#include <QPainter>
32#include <QPaintEvent>
33
34/* GUI includes: */
35#include "QISplitter.h"
36#ifdef VBOX_WS_MAC
37# include "UICursor.h"
38#endif
39
40
41/** QSplitterHandle subclass representing flat line. */
42class QIFlatSplitterHandle : public QSplitterHandle
43{
44 Q_OBJECT;
45
46public:
47
48 /** Constructs flat splitter handle passing @a enmOrientation and @a pParent to the base-class. */
49 QIFlatSplitterHandle(Qt::Orientation enmOrientation, QISplitter *pParent);
50
51 /** Defines @a color. */
52 void configureColor(const QColor &color);
53
54protected:
55
56 /** Handles paint @a pEvent. */
57 virtual void paintEvent(QPaintEvent *pEvent) RT_OVERRIDE;
58
59private:
60
61 /** Holds the main color. */
62 QColor m_color;
63};
64
65
66/** QSplitterHandle subclass representing shaded line. */
67class QIShadeSplitterHandle : public QSplitterHandle
68{
69 Q_OBJECT;
70
71public:
72
73 /** Constructs shaded splitter handle passing @a enmOrientation and @a pParent to the base-class. */
74 QIShadeSplitterHandle(Qt::Orientation enmOrientation, QISplitter *pParent);
75
76 /** Defines colors to passed @a color1 and @a color2. */
77 void configureColors(const QColor &color1, const QColor &color2);
78
79protected:
80
81 /** Handles paint @a pEvent. */
82 virtual void paintEvent(QPaintEvent *pEvent) RT_OVERRIDE;
83
84private:
85
86 /** Holds the main color. */
87 QColor m_color;
88 /** Holds the color1. */
89 QColor m_color1;
90 /** Holds the color2. */
91 QColor m_color2;
92};
93
94
95#ifdef VBOX_WS_MAC
96/** QSplitterHandle subclass representing shaded line for macOS. */
97class QIDarwinSplitterHandle : public QSplitterHandle
98{
99 Q_OBJECT;
100
101public:
102
103 /** Constructs shaded splitter handle passing @a enmOrientation and @a pParent to the base-class. */
104 QIDarwinSplitterHandle(Qt::Orientation enmOrientation, QISplitter *pParent);
105
106 /** Returns size-hint. */
107 QSize sizeHint() const;
108
109protected:
110
111 /** Handles paint @a pEvent. */
112 virtual void paintEvent(QPaintEvent *pEvent) RT_OVERRIDE;
113};
114#endif /* VBOX_WS_MAC */
115
116
117/*********************************************************************************************************************************
118* Class QIFlatSplitterHandle implementation. *
119*********************************************************************************************************************************/
120
121QIFlatSplitterHandle::QIFlatSplitterHandle(Qt::Orientation enmOrientation, QISplitter *pParent)
122 : QSplitterHandle(enmOrientation, pParent)
123{
124}
125
126void QIFlatSplitterHandle::configureColor(const QColor &color)
127{
128 m_color = color;
129 update();
130}
131
132void QIFlatSplitterHandle::paintEvent(QPaintEvent *pEvent)
133{
134 QPainter painter(this);
135 painter.fillRect(pEvent->rect(), m_color);
136}
137
138
139/*********************************************************************************************************************************
140* Class QIShadeSplitterHandle implementation. *
141*********************************************************************************************************************************/
142
143QIShadeSplitterHandle::QIShadeSplitterHandle(Qt::Orientation enmOrientation, QISplitter *pParent)
144 : QSplitterHandle(enmOrientation, pParent)
145{
146 QColor windowColor = QApplication::palette().color(QPalette::Active, QPalette::Window);
147 QColor frameColor = QApplication::palette().color(QPalette::Active, QPalette::Text);
148 frameColor.setAlpha(100);
149 m_color1 = windowColor;
150 m_color2 = windowColor;
151 m_color = frameColor;
152}
153
154void QIShadeSplitterHandle::configureColors(const QColor &color1, const QColor &color2)
155{
156 m_color1 = color1;
157 m_color2 = color2;
158 update();
159}
160
161void QIShadeSplitterHandle::paintEvent(QPaintEvent *pEvent)
162{
163 QPainter painter(this);
164 QLinearGradient gradient;
165 QGradientStop point1(0, m_color1);
166 QGradientStop point2(0.5, m_color);
167 QGradientStop point3(1, m_color2);
168 QGradientStops stops;
169 stops << point1 << point2 << point3;
170 gradient.setStops(stops);
171 if (orientation() == Qt::Horizontal)
172 {
173 gradient.setStart(rect().left() + 1, 0);
174 gradient.setFinalStop(rect().right(), 0);
175 }
176 else
177 {
178 gradient.setStart(0, rect().top() + 1);
179 gradient.setFinalStop(0, rect().bottom());
180 }
181 painter.fillRect(pEvent->rect(), gradient);
182}
183
184
185/*********************************************************************************************************************************
186* Class QIDarwinSplitterHandle implementation. *
187*********************************************************************************************************************************/
188
189#ifdef VBOX_WS_MAC
190
191QIDarwinSplitterHandle::QIDarwinSplitterHandle(Qt::Orientation enmOrientation, QISplitter *pParent)
192 : QSplitterHandle(enmOrientation, pParent)
193{
194}
195
196QSize QIDarwinSplitterHandle::sizeHint() const
197{
198 QSize parent = QSplitterHandle::sizeHint();
199 if (orientation() == Qt::Vertical)
200 return parent + QSize(0, 3);
201 else
202 return QSize(1, parent.height());
203}
204
205void QIDarwinSplitterHandle::paintEvent(QPaintEvent *)
206{
207 QPainter painter(this);
208
209 QColor topColor(145, 145, 145);
210 QColor bottomColor(142, 142, 142);
211 QColor gradientStart(252, 252, 252);
212 QColor gradientStop(223, 223, 223);
213
214 if (orientation() == Qt::Vertical)
215 {
216 painter.setPen(topColor);
217 painter.drawLine(0, 0, width(), 0);
218 painter.setPen(bottomColor);
219 painter.drawLine(0, height() - 1, width(), height() - 1);
220
221 QLinearGradient linearGrad(QPointF(0, 0), QPointF(0, height() -3));
222 linearGrad.setColorAt(0, gradientStart);
223 linearGrad.setColorAt(1, gradientStop);
224 painter.fillRect(QRect(QPoint(0,1), size() - QSize(0, 2)), QBrush(linearGrad));
225 }
226 else
227 {
228 painter.setPen(topColor);
229 painter.drawLine(0, 0, 0, height());
230 }
231}
232
233#endif /* VBOX_WS_MAC */
234
235
236/*********************************************************************************************************************************
237* Class QISplitter implementation. *
238*********************************************************************************************************************************/
239
240QISplitter::QISplitter(QWidget *pParent /* = 0 */)
241 : QSplitter(pParent)
242 , m_enmType(Shade)
243 , m_fPolished(false)
244#ifdef VBOX_WS_MAC
245 , m_fHandleGrabbed(false)
246#endif
247{
248 qApp->installEventFilter(this);
249}
250
251QISplitter::QISplitter(Qt::Orientation enmOrientation, Type enmType, QWidget *pParent /* = 0 */)
252 : QSplitter(enmOrientation, pParent)
253 , m_enmType(enmType)
254 , m_fPolished(false)
255#ifdef VBOX_WS_MAC
256 , m_fHandleGrabbed(false)
257#endif
258{
259 qApp->installEventFilter(this);
260}
261
262void QISplitter::configureColor(const QColor &color)
263{
264 m_color = color;
265 for (int i = 1; i < count(); ++i)
266 {
267 QIFlatSplitterHandle *pHandle = qobject_cast<QIFlatSplitterHandle*>(handle(i));
268 if (pHandle && m_color.isValid())
269 pHandle->configureColor(m_color);
270 }
271}
272
273void QISplitter::configureColors(const QColor &color1, const QColor &color2)
274{
275 m_color1 = color1; m_color2 = color2;
276 for (int i = 1; i < count(); ++i)
277 {
278 QIShadeSplitterHandle *pHandle = qobject_cast<QIShadeSplitterHandle*>(handle(i));
279 if (pHandle && m_color1.isValid() && m_color2.isValid())
280 pHandle->configureColors(m_color1, m_color2);
281 }
282}
283
284bool QISplitter::eventFilter(QObject *pWatched, QEvent *pEvent)
285{
286 /* Handles events for handle: */
287 if (pWatched == handle(1))
288 {
289 switch (pEvent->type())
290 {
291 /* Restore default position on double-click: */
292 case QEvent::MouseButtonDblClick:
293 restoreState(m_baseState);
294 break;
295 default:
296 break;
297 }
298 }
299
300#ifdef VBOX_WS_MAC
301 // WORKAROUND:
302 // Special handling on the Mac. Cause there the horizontal handle is only 1
303 // pixel wide, its hard to catch. Therefor we make some invisible area
304 // around the handle and forwarding the mouse events to the handle, if the
305 // user presses the left mouse button.
306 else if ( m_enmType == Native
307 && orientation() == Qt::Horizontal
308 && count() > 1
309 && qApp->activeWindow() == window())
310 {
311 switch (pEvent->type())
312 {
313 case QEvent::MouseButtonPress:
314 case QEvent::MouseMove:
315 {
316 const int margin = 3;
317 QMouseEvent *pMouseEvent = static_cast<QMouseEvent*>(pEvent);
318#ifndef VBOX_IS_QT6_OR_LATER /* QMouseEvent::globalPos was replaced with QSinglePointEvent::globalPosition in Qt6 */
319 const QPoint gPos = pMouseEvent->globalPos();
320#else
321 const QPoint gPos = pMouseEvent->globalPosition().toPoint();
322#endif
323 for (int i=1; i < count(); ++i)
324 {
325 QWidget *pHandle = handle(i);
326 if ( pHandle
327 && pHandle != pWatched)
328 {
329 /* Check if we hit the handle */
330 bool fMarginHit = QRect(pHandle->mapToGlobal(QPoint(0, 0)), pHandle->size()).adjusted(-margin, 0, margin, 0).contains(gPos);
331 if (pEvent->type() == QEvent::MouseButtonPress)
332 {
333 /* If we have a handle position hit and the left button is pressed, start the grabbing. */
334 if ( fMarginHit
335 && pMouseEvent->buttons().testFlag(Qt::LeftButton))
336 {
337 m_fHandleGrabbed = true;
338 UICursor::setCursor(this, Qt::SplitHCursor);
339 qApp->postEvent(pHandle, new QMouseEvent(pMouseEvent->type(),
340 pHandle->mapFromGlobal(gPos),
341 pMouseEvent->button(),
342 pMouseEvent->buttons(),
343 pMouseEvent->modifiers()));
344 return true;
345 }
346 }
347 else if (pEvent->type() == QEvent::MouseMove)
348 {
349 /* If we are in the near of the handle or currently dragging, forward the mouse event. */
350 if ( fMarginHit
351 || ( m_fHandleGrabbed
352 && pMouseEvent->buttons().testFlag(Qt::LeftButton)))
353 {
354 UICursor::setCursor(this, Qt::SplitHCursor);
355 qApp->postEvent(pHandle, new QMouseEvent(pMouseEvent->type(),
356 pHandle->mapFromGlobal(gPos),
357 pMouseEvent->button(),
358 pMouseEvent->buttons(),
359 pMouseEvent->modifiers()));
360 return true;
361 }
362
363 /* If not, reset the state. */
364 m_fHandleGrabbed = false;
365 UICursor::setCursor(this, Qt::ArrowCursor);
366 }
367 }
368 }
369 break;
370 }
371 case QEvent::WindowDeactivate:
372 case QEvent::MouseButtonRelease:
373 {
374 m_fHandleGrabbed = false;
375 UICursor::setCursor(this, Qt::ArrowCursor);
376 break;
377 }
378 default:
379 break;
380 }
381 }
382#endif /* VBOX_WS_MAC */
383
384 /* Call to base-class: */
385 return QSplitter::eventFilter(pWatched, pEvent);
386}
387
388void QISplitter::showEvent(QShowEvent *pEvent)
389{
390 /* Remember default position: */
391 if (!m_fPolished)
392 {
393 m_fPolished = true;
394 m_baseState = saveState();
395 }
396
397 /* Call to base-class: */
398 return QSplitter::showEvent(pEvent);
399}
400
401QSplitterHandle *QISplitter::createHandle()
402{
403 /* Create native handle: */
404 switch (m_enmType)
405 {
406 case Flat:
407 {
408 QIFlatSplitterHandle *pHandle = new QIFlatSplitterHandle(orientation(), this);
409 if (m_color.isValid())
410 pHandle->configureColor(m_color);
411 return pHandle;
412 }
413 case Shade:
414 {
415 QIShadeSplitterHandle *pHandle = new QIShadeSplitterHandle(orientation(), this);
416 if (m_color1.isValid() && m_color2.isValid())
417 pHandle->configureColors(m_color1, m_color2);
418 return pHandle;
419 }
420 case Native:
421 {
422#ifdef VBOX_WS_MAC
423 return new QIDarwinSplitterHandle(orientation(), this);
424#else
425 return new QSplitterHandle(orientation(), this);
426#endif
427 }
428 }
429 return 0;
430}
431
432
433#include "QISplitter.moc"
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette