Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qgraphicswidget_p.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qglobal.h"
6
7#include <QtCore/qdebug.h>
8#include <QtCore/qnumeric.h>
13#include <QtWidgets/qapplication.h>
14#include <QtWidgets/qgraphicsscene.h>
15#include <QtWidgets/qstyleoption.h>
16#include <QtWidgets/QStyleOptionTitleBar>
17#include <QtWidgets/QGraphicsSceneMouseEvent>
18
20
21void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFlags)
22{
23 Q_Q(QGraphicsWidget);
24
25 attributes = 0;
26 isWidget = 1; // QGraphicsItem::isWidget() returns true.
27 focusNext = focusPrev = q;
28 focusPolicy = Qt::NoFocus;
29
30 adjustWindowFlags(&wFlags);
31 windowFlags = wFlags;
32
33 q->setParentItem(parentItem);
34 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::DefaultType));
35 q->setGraphicsItem(q);
36
38 q->unsetWindowFrameMargins();
39 flags |= QGraphicsItem::ItemUsesExtendedStyleOption;
40 flags |= QGraphicsItem::ItemSendsGeometryChanges;
41 if (windowFlags & Qt::Window)
42 flags |= QGraphicsItem::ItemIsPanel;
43}
44
45qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const
46{
47 Q_Q(const QGraphicsWidget);
48 int height = q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options);
49 return (qreal)height;
50}
51
52/*!
53 \internal
54*/
55QGraphicsWidgetPrivate::QGraphicsWidgetPrivate()
56 : margins(nullptr),
57 layout(nullptr),
60 inSetGeometry(false),
61 polished(false),
62 inSetPos(false),
63 autoFillBackground(false),
64 focusPolicy(Qt::NoFocus),
65 focusNext(nullptr),
66 focusPrev(nullptr),
67 windowFlags(),
68 windowData(nullptr),
70 windowFrameMargins(nullptr)
71{
72}
73
77
78/*!
79 \internal
80
81 Ensures that margins is allocated.
82 This function must be called before any dereferencing.
83*/
85{
86 if (!margins)
87 margins = std::make_unique<QMarginsF>();
88}
89
90/*!
91 \internal
92
93 Ensures that windowFrameMargins is allocated.
94 This function must be called before any dereferencing.
95*/
97{
98 if (!windowFrameMargins)
99 windowFrameMargins = std::make_unique<QMarginsF>();
100}
101
102/*!
103 \internal
104
105 Ensures that windowData is allocated.
106 This function must be called before any dereferencing.
107*/
109{
110 if (!windowData)
111 windowData = std::make_unique<WindowData>();
112}
113
114void QGraphicsWidgetPrivate::setPalette_helper(const QPalette &palette)
115{
116 if (this->palette == palette && this->palette.resolveMask() == palette.resolveMask())
117 return;
118 updatePalette(palette);
119}
120
121void QGraphicsWidgetPrivate::resolvePalette(uint inheritedMask)
122{
123 inheritedPaletteResolveMask = inheritedMask;
124 QPalette naturalPalette = naturalWidgetPalette();
125 QPalette resolvedPalette = palette.resolve(naturalPalette);
126 updatePalette(resolvedPalette);
127}
128
129void QGraphicsWidgetPrivate::updatePalette(const QPalette &palette)
130{
131 Q_Q(QGraphicsWidget);
132 // Update local palette setting.
133 this->palette = palette;
134
135 // Calculate new mask.
136 if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation))
138 int mask = palette.resolveMask() | inheritedPaletteResolveMask;
139
140 // Propagate to children.
141 for (int i = 0; i < children.size(); ++i) {
142 QGraphicsItem *item = children.at(i);
143 if (item->isWidget()) {
144 QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item);
145 if (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
146 w->d_func()->resolvePalette(mask);
147 } else {
148 item->d_ptr->resolvePalette(mask);
149 }
150 }
151
152 // Notify change.
153 QEvent event(QEvent::PaletteChange);
154 QCoreApplication::sendEvent(q, &event);
155}
156
157void QGraphicsWidgetPrivate::setLayoutDirection_helper(Qt::LayoutDirection direction)
158{
159 Q_Q(QGraphicsWidget);
160 if ((direction == Qt::RightToLeft) == (testAttribute(Qt::WA_RightToLeft)))
161 return;
162 q->setAttribute(Qt::WA_RightToLeft, (direction == Qt::RightToLeft));
163
164 // Propagate this change to all children.
165 for (int i = 0; i < children.size(); ++i) {
166 QGraphicsItem *item = children.at(i);
167 if (item->isWidget()) {
168 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
169 if (widget->parentWidget() && !widget->testAttribute(Qt::WA_SetLayoutDirection))
170 widget->d_func()->setLayoutDirection_helper(direction);
171 }
172 }
173
174 // Send the notification event to this widget item.
175 QEvent e(QEvent::LayoutDirectionChange);
176 QCoreApplication::sendEvent(q, &e);
177}
178
180{
181 Q_Q(QGraphicsWidget);
182 if (q->testAttribute(Qt::WA_SetLayoutDirection)) {
183 return;
184 }
185 if (QGraphicsWidget *parentWidget = q->parentWidget()) {
186 setLayoutDirection_helper(parentWidget->layoutDirection());
187 } else if (scene) {
188 // ### shouldn't the scene have a layoutdirection really? how does
189 // ### QGraphicsWidget get changes from QApplication::layoutDirection?
190 setLayoutDirection_helper(QGuiApplication::layoutDirection());
191 } else {
192 setLayoutDirection_helper(QGuiApplication::layoutDirection());
193 }
194}
195
197{
198 Q_Q(const QGraphicsWidget);
199 QPalette palette;
200 if (QGraphicsWidget *parent = q->parentWidget()) {
201 palette = parent->palette();
202 } else if (scene) {
203 palette = scene->palette();
204 }
205 palette.setResolveMask(0);
206 return palette;
207}
208
210{
211 if (this->font == font && this->font.resolveMask() == font.resolveMask())
212 return;
213 updateFont(font);
214}
215
216void QGraphicsWidgetPrivate::resolveFont(uint inheritedMask)
217{
218 Q_Q(QGraphicsWidget);
219 inheritedFontResolveMask = inheritedMask;
220 if (QGraphicsWidget *p = q->parentWidget())
221 inheritedFontResolveMask |= p->d_func()->inheritedFontResolveMask;
222 QFont naturalFont = naturalWidgetFont();
223 QFont resolvedFont = font.resolve(naturalFont);
224 updateFont(resolvedFont);
225}
226
227void QGraphicsWidgetPrivate::updateFont(const QFont &font)
228{
229 Q_Q(QGraphicsWidget);
230 // Update the local font setting.
231 this->font = font;
232
233 // Calculate new mask.
234 if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation))
236 int mask = font.resolveMask() | inheritedFontResolveMask;
237
238 // Propagate to children.
239 for (int i = 0; i < children.size(); ++i) {
240 QGraphicsItem *item = children.at(i);
241 if (item->isWidget()) {
242 QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item);
243 if (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
244 w->d_func()->resolveFont(mask);
245 } else {
246 item->d_ptr->resolveFont(mask);
247 }
248 }
249
250 if (!polished)
251 return;
252 // Notify change.
253 QEvent event(QEvent::FontChange);
254 QCoreApplication::sendEvent(q, &event);
255}
256
258{
259 Q_Q(const QGraphicsWidget);
260 QFont naturalFont; // ### no application font support
261 if (QGraphicsWidget *parent = q->parentWidget()) {
262 naturalFont = parent->font();
263 } else if (scene) {
264 naturalFont = scene->font();
265 }
266 naturalFont.setResolveMask(0);
267 return naturalFont;
268}
269
270void QGraphicsWidgetPrivate::initStyleOptionTitleBar(QStyleOptionTitleBar *option)
271{
272 Q_Q(QGraphicsWidget);
274 q->initStyleOption(option);
275 option->rect.setHeight(titleBarHeight(*option));
276 option->titleBarFlags = windowFlags;
277 option->subControls = QStyle::SC_TitleBarCloseButton | QStyle::SC_TitleBarLabel | QStyle::SC_TitleBarSysMenu;
278 option->activeSubControls = windowData->hoveredSubControl;
279 bool isActive = q->isActiveWindow();
280 option->state.setFlag(QStyle::State_Active, isActive);
281 if (isActive) {
282 option->titleBarState = Qt::WindowActive;
283 option->titleBarState |= QStyle::State_Active;
284 } else {
285 option->titleBarState = Qt::WindowNoState;
286 }
287 QFont windowTitleFont = QApplication::font("QMdiSubWindowTitleBar");
288 QRect textRect = q->style()->subControlRect(QStyle::CC_TitleBar, option, QStyle::SC_TitleBarLabel, nullptr);
289 option->text = QFontMetrics(windowTitleFont).elidedText(
290 windowData->windowTitle, Qt::ElideRight, textRect.width());
291}
292
293void QGraphicsWidgetPrivate::adjustWindowFlags(Qt::WindowFlags *flags)
294{
295 bool customize = (*flags & (Qt::CustomizeWindowHint
296 | Qt::FramelessWindowHint
297 | Qt::WindowTitleHint
298 | Qt::WindowSystemMenuHint
299 | Qt::WindowMinimizeButtonHint
300 | Qt::WindowMaximizeButtonHint
301 | Qt::WindowContextHelpButtonHint));
302
303 uint type = (*flags & Qt::WindowType_Mask);
304 if (customize)
305 ;
306 else if (type == Qt::Dialog || type == Qt::Sheet)
307 *flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowContextHelpButtonHint;
308 else if (type == Qt::Tool)
309 *flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint;
310 else if (type == Qt::Window || type == Qt::SubWindow)
311 *flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
312 | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint;
313}
314
315void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
316{
317 Q_Q(QGraphicsWidget);
319 if (windowData->grabbedSection != Qt::NoSection) {
320 if (windowData->grabbedSection == Qt::TitleBarArea) {
321 windowData->buttonSunken = false;
322 QStyleOptionTitleBar bar;
324 // make sure that the coordinates (rect and pos) we send to the style are positive.
325 bar.rect = q->windowFrameRect().toRect();
326 bar.rect.moveTo(0,0);
327 bar.rect.setHeight(q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &bar));
328 QPointF pos = event->pos();
329 if (windowFrameMargins) {
330 pos.rx() += windowFrameMargins->left();
331 pos.ry() += windowFrameMargins->top();
332 }
333 bar.subControls = QStyle::SC_TitleBarCloseButton;
334 if (q->style()->subControlRect(QStyle::CC_TitleBar, &bar,
335 QStyle::SC_TitleBarCloseButton,
336 event->widget()).contains(pos.toPoint())) {
337 q->close();
338 }
339 }
340 if (!(static_cast<QGraphicsSceneMouseEvent *>(event)->buttons()))
341 windowData->grabbedSection = Qt::NoSection;
342 event->accept();
343 }
344}
345
346void QGraphicsWidgetPrivate::windowFrameMousePressEvent(QGraphicsSceneMouseEvent *event)
347{
348 Q_Q(QGraphicsWidget);
349 if (event->button() != Qt::LeftButton)
350 return;
351
353 windowData->startGeometry = q->geometry();
354 windowData->grabbedSection = q->windowFrameSectionAt(event->pos());
356 if (windowData->grabbedSection == Qt::TitleBarArea
357 && windowData->hoveredSubControl == QStyle::SC_TitleBarCloseButton) {
358 windowData->buttonSunken = true;
359 q->update();
360 }
361 event->setAccepted(windowData->grabbedSection != Qt::NoSection);
362}
363
364/*
365 Used to calculate the
366 Precondition:
367 \a widget should support either hfw or wfh
368
369 If \a heightForWidth is set to false, this function will query the width for height
370 instead. \a width will then be interpreted as height, \a minh and \a maxh will be interpreted
371 as minimum width and maximum width.
372 */
373static qreal minimumHeightForWidth(qreal width, qreal minh, qreal maxh,
374 const QGraphicsWidget *widget,
375 bool heightForWidth = true)
376{
377 qreal minimumHeightForWidth = -1;
378 const bool hasHFW = QGraphicsLayoutItemPrivate::get(widget)->hasHeightForWidth();
379 if (hasHFW == heightForWidth) {
380 minimumHeightForWidth = hasHFW
381 ? widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(width, -1)).height()
382 : widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, width)).width(); //"width" is here height!
383 } else {
384 // widthForHeight
385 const qreal constraint = width;
386 while (maxh - minh > 0.1) {
387 qreal middle = minh + (maxh - minh)/2;
388 // ### really bad, if we are a widget with a layout it will call
389 // layout->effectiveSizeHint(Qt::MiniumumSize), which again will call
390 // sizeHint three times because of how the cache works
391 qreal hfw = hasHFW
392 ? widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(middle, -1)).height()
393 : widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, middle)).width();
394 if (hfw > constraint) {
395 minh = middle;
396 } else if (hfw <= constraint) {
397 maxh = middle;
398 }
399 }
400 minimumHeightForWidth = maxh;
401 }
402 return minimumHeightForWidth;
403}
404
405static qreal minimumWidthForHeight(qreal height, qreal minw, qreal maxw,
406 const QGraphicsWidget *widget)
407{
408 return minimumHeightForWidth(height, minw, maxw, widget, false);
409}
410
411static QSizeF closestAcceptableSize(const QSizeF &proposed,
412 const QGraphicsWidget *widget)
413{
414 const QSizeF current = widget->size();
415
416 qreal minw = proposed.width();
417 qreal maxw = current.width();
418 qreal minh = proposed.height();
419 qreal maxh = current.height();
420
421 qreal middlew = maxw;
422 qreal middleh = maxh;
423 qreal min_hfw;
424 min_hfw = minimumHeightForWidth(maxw, minh, maxh, widget);
425
426 do {
427 if (maxw - minw < 0.1) {
428 // we still haven't found anything, cut off binary search
429 minw = maxw;
430 minh = maxh;
431 }
432 middlew = minw + (maxw - minw)/2.0;
433 middleh = minh + (maxh - minh)/2.0;
434
435 min_hfw = minimumHeightForWidth(middlew, minh, maxh, widget);
436
437 if (min_hfw > middleh) {
438 minw = middlew;
439 minh = middleh;
440 } else if (min_hfw <= middleh) {
441 maxw = middlew;
442 maxh = middleh;
443 }
444 } while (maxw != minw);
445
446 min_hfw = minimumHeightForWidth(middlew, minh, maxh, widget);
447
448 QSizeF result;
449 if (min_hfw < maxh) {
450 result = QSizeF(middlew, min_hfw);
451 } else {
452 // Needed because of the cut-off we do above.
453 result = QSizeF(minimumWidthForHeight(maxh, proposed.width(), current.width(), widget), maxh);
454 }
455 return result;
456}
457
458static void _q_boundGeometryToSizeConstraints(const QRectF &startGeometry,
459 QRectF *rect, Qt::WindowFrameSection section,
460 const QSizeF &min, const QSizeF &max,
461 const QGraphicsWidget *widget)
462{
463 const QRectF proposedRect = *rect;
464 qreal width = qBound(min.width(), proposedRect.width(), max.width());
465 qreal height = qBound(min.height(), proposedRect.height(), max.height());
466
467 const bool hasHFW = QGraphicsLayoutItemPrivate::get(widget)->hasHeightForWidth();
468 const bool hasWFH = QGraphicsLayoutItemPrivate::get(widget)->hasWidthForHeight();
469
470 const bool widthChanged = proposedRect.width() != widget->size().width();
471 const bool heightChanged = proposedRect.height() != widget->size().height();
472
473 if (hasHFW || hasWFH) {
474 if (widthChanged || heightChanged) {
475 qreal minExtent;
476 qreal maxExtent;
477 qreal constraint;
478 qreal proposed;
479 if (hasHFW) {
480 minExtent = min.height();
481 maxExtent = max.height();
482 constraint = width;
483 proposed = proposedRect.height();
484 } else {
485 // width for height
486 minExtent = min.width();
487 maxExtent = max.width();
488 constraint = height;
489 proposed = proposedRect.width();
490 }
491 if (minimumHeightForWidth(constraint, minExtent, maxExtent, widget, hasHFW) > proposed) {
492 QSizeF effectiveSize = closestAcceptableSize(QSizeF(width, height), widget);
493 width = effectiveSize.width();
494 height = effectiveSize.height();
495 }
496 }
497 }
498
499 switch (section) {
500 case Qt::LeftSection:
501 rect->setRect(startGeometry.right() - qRound(width), startGeometry.top(),
502 qRound(width), startGeometry.height());
503 break;
504 case Qt::TopLeftSection:
505 rect->setRect(startGeometry.right() - qRound(width), startGeometry.bottom() - qRound(height),
506 qRound(width), qRound(height));
507 break;
508 case Qt::TopSection:
509 rect->setRect(startGeometry.left(), startGeometry.bottom() - qRound(height),
510 startGeometry.width(), qRound(height));
511 break;
512 case Qt::TopRightSection:
513 rect->setTop(rect->bottom() - qRound(height));
514 rect->setWidth(qRound(width));
515 break;
516 case Qt::RightSection:
517 rect->setWidth(qRound(width));
518 break;
519 case Qt::BottomRightSection:
520 rect->setWidth(qRound(width));
521 rect->setHeight(qRound(height));
522 break;
523 case Qt::BottomSection:
524 rect->setHeight(qRound(height));
525 break;
526 case Qt::BottomLeftSection:
527 rect->setRect(startGeometry.right() - qRound(width), startGeometry.top(),
528 qRound(width), qRound(height));
529 break;
530 default:
531 break;
532 }
533}
534
535void QGraphicsWidgetPrivate::windowFrameMouseMoveEvent(QGraphicsSceneMouseEvent *event)
536{
537 Q_Q(QGraphicsWidget);
539 if (!(event->buttons() & Qt::LeftButton) || windowData->hoveredSubControl != QStyle::SC_TitleBarLabel)
540 return;
541
542 QLineF delta(q->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)), event->pos());
543 QLineF parentDelta(q->mapToParent(delta.p1()), q->mapToParent(delta.p2()));
544 QLineF parentXDelta(q->mapToParent(QPointF(delta.p1().x(), 0)), q->mapToParent(QPointF(delta.p2().x(), 0)));
545 QLineF parentYDelta(q->mapToParent(QPointF(0, delta.p1().y())), q->mapToParent(QPointF(0, delta.p2().y())));
546
547 QRectF newGeometry;
548 switch (windowData->grabbedSection) {
549 case Qt::LeftSection:
550 newGeometry = QRectF(windowData->startGeometry.topLeft()
551 + QPointF(parentXDelta.dx(), parentXDelta.dy()),
552 windowData->startGeometry.size() - QSizeF(delta.dx(), delta.dy()));
553 break;
554 case Qt::TopLeftSection:
555 newGeometry = QRectF(windowData->startGeometry.topLeft()
556 + QPointF(parentDelta.dx(), parentDelta.dy()),
557 windowData->startGeometry.size() - QSizeF(delta.dx(), delta.dy()));
558 break;
559 case Qt::TopSection:
560 newGeometry = QRectF(windowData->startGeometry.topLeft()
561 + QPointF(parentYDelta.dx(), parentYDelta.dy()),
562 windowData->startGeometry.size() - QSizeF(0, delta.dy()));
563 break;
564 case Qt::TopRightSection:
565 newGeometry = QRectF(windowData->startGeometry.topLeft()
566 + QPointF(parentYDelta.dx(), parentYDelta.dy()),
567 windowData->startGeometry.size() - QSizeF(-delta.dx(), delta.dy()));
568 break;
569 case Qt::RightSection:
570 newGeometry = QRectF(windowData->startGeometry.topLeft(),
571 windowData->startGeometry.size() + QSizeF(delta.dx(), 0));
572 break;
573 case Qt::BottomRightSection:
574 newGeometry = QRectF(windowData->startGeometry.topLeft(),
575 windowData->startGeometry.size() + QSizeF(delta.dx(), delta.dy()));
576 break;
577 case Qt::BottomSection:
578 newGeometry = QRectF(windowData->startGeometry.topLeft(),
579 windowData->startGeometry.size() + QSizeF(0, delta.dy()));
580 break;
581 case Qt::BottomLeftSection:
582 newGeometry = QRectF(windowData->startGeometry.topLeft()
583 + QPointF(parentXDelta.dx(), parentXDelta.dy()),
584 windowData->startGeometry.size() - QSizeF(delta.dx(), -delta.dy()));
585 break;
586 case Qt::TitleBarArea:
587 newGeometry = QRectF(windowData->startGeometry.topLeft()
588 + QPointF(parentDelta.dx(), parentDelta.dy()),
589 windowData->startGeometry.size());
590 break;
591 case Qt::NoSection:
592 break;
593 }
594
595 if (windowData->grabbedSection != Qt::NoSection) {
596 _q_boundGeometryToSizeConstraints(windowData->startGeometry, &newGeometry,
597 windowData->grabbedSection,
598 q->effectiveSizeHint(Qt::MinimumSize),
599 q->effectiveSizeHint(Qt::MaximumSize),
600 q);
601 q->setGeometry(newGeometry);
602 }
603}
604
605void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent *event)
606{
607 Q_Q(QGraphicsWidget);
608 if (!hasDecoration())
609 return;
610
612
613 if (q->rect().contains(event->pos())) {
614 if (windowData->buttonMouseOver || windowData->hoveredSubControl != QStyle::SC_None)
616 return;
617 }
618
619 bool wasMouseOver = windowData->buttonMouseOver;
620 QRect oldButtonRect = windowData->buttonRect;
621 windowData->buttonRect = QRect();
622 windowData->buttonMouseOver = false;
623 QPointF pos = event->pos();
624 QStyleOptionTitleBar bar;
625 // make sure that the coordinates (rect and pos) we send to the style are positive.
626 if (windowFrameMargins) {
627 pos.rx() += windowFrameMargins->left();
628 pos.ry() += windowFrameMargins->top();
629 }
631 bar.rect = q->windowFrameRect().toRect();
632 bar.rect.moveTo(0,0);
633 bar.rect.setHeight(int(titleBarHeight(bar)));
634
635 Qt::CursorShape cursorShape = Qt::ArrowCursor;
636 bool needsSetCursorCall = true;
637 switch (q->windowFrameSectionAt(event->pos())) {
638 case Qt::TopLeftSection:
639 case Qt::BottomRightSection:
640 cursorShape = Qt::SizeFDiagCursor;
641 break;
642 case Qt::TopRightSection:
643 case Qt::BottomLeftSection:
644 cursorShape = Qt::SizeBDiagCursor;
645 break;
646 case Qt::LeftSection:
647 case Qt::RightSection:
648 cursorShape = Qt::SizeHorCursor;
649 break;
650 case Qt::TopSection:
651 case Qt::BottomSection:
652 cursorShape = Qt::SizeVerCursor;
653 break;
654 case Qt::TitleBarArea:
655 windowData->buttonRect = q->style()->subControlRect(
656 QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarCloseButton, nullptr);
657 if (windowData->buttonRect.contains(pos.toPoint()))
658 windowData->buttonMouseOver = true;
659 event->ignore();
660 break;
661 default:
662 needsSetCursorCall = false;
663 event->ignore();
664 }
665#ifndef QT_NO_CURSOR
666 if (needsSetCursorCall)
667 q->setCursor(cursorShape);
668#else
669 Q_UNUSED(needsSetCursorCall);
670 Q_UNUSED(cursorShape);
671#endif
672 // update buttons if we hover over them
673 windowData->hoveredSubControl = q->style()->hitTestComplexControl(QStyle::CC_TitleBar, &bar, pos.toPoint(), nullptr);
674 if (windowData->hoveredSubControl != QStyle::SC_TitleBarCloseButton)
675 windowData->hoveredSubControl = QStyle::SC_TitleBarLabel;
676
677 if (windowData->buttonMouseOver != wasMouseOver) {
678 if (!oldButtonRect.isNull())
679 q->update(QRectF(oldButtonRect).translated(q->windowFrameRect().topLeft()));
680 if (!windowData->buttonRect.isNull())
681 q->update(QRectF(windowData->buttonRect).translated(q->windowFrameRect().topLeft()));
682 }
683}
684
685void QGraphicsWidgetPrivate::windowFrameHoverLeaveEvent(QGraphicsSceneHoverEvent *event)
686{
687 Q_UNUSED(event);
688 Q_Q(QGraphicsWidget);
689 if (hasDecoration()) {
690 // ### restore the cursor, don't override it
691#ifndef QT_NO_CURSOR
692 q->unsetCursor();
693#endif
694
696
697 bool needsUpdate = false;
698 if (windowData->hoveredSubControl == QStyle::SC_TitleBarCloseButton
699 || windowData->buttonMouseOver)
700 needsUpdate = true;
701
702 // update the hover state (of buttons etc...)
703 windowData->hoveredSubControl = QStyle::SC_None;
704 windowData->buttonMouseOver = false;
705 windowData->buttonRect = QRect();
706 if (needsUpdate)
707 q->update(windowData->buttonRect);
708 }
709}
710
712{
713 return (windowFlags & Qt::Window) && (windowFlags & Qt::WindowTitleHint);
714}
715
716/**
717 * is called after a reparent has taken place to fix up the focus chain(s)
718 */
719void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *oldScene, QGraphicsScene *newScene)
720{
721 Q_Q(QGraphicsWidget);
722 Q_ASSERT(focusNext && focusPrev);
723
724 if (q_ptr->isPanel()) {
725 // panels are never a part of their parent's or ancestors' focus
726 // chains. so reparenting a panel is easy; there's nothing to
727 // do.
728 return;
729 }
730
731 // we're not a panel, so find the first widget in the focus chain
732 // (this), and the last (this, or the last widget that is still
733 // a descendent of this). also find the widgets that currently /
734 // before reparenting point to this widgets' focus chain.
735 QGraphicsWidget *focusFirst = q;
736 QGraphicsWidget *focusBefore = focusPrev;
737 QGraphicsWidget *focusLast = focusFirst;
738 QGraphicsWidget *focusAfter = focusNext;
739 do {
740 if (!q->isAncestorOf(focusAfter))
741 break;
742 focusLast = focusAfter;
743 } while ((focusAfter = focusAfter->d_func()->focusNext));
744
745 if (!parent && oldScene && oldScene != newScene && oldScene->d_func()->tabFocusFirst == q) {
746 // detach from old scene's top level focus chain.
747 oldScene->d_func()->tabFocusFirst = (focusAfter != q) ? focusAfter : nullptr;
748 }
749
750 // detach from current focus chain; skip this widget subtree.
751 focusBefore->d_func()->focusNext = focusAfter;
752 if (focusAfter)
753 focusAfter->d_func()->focusPrev = focusBefore;
754
755 if (newParent) {
756 // attach to new parent's focus chain as the last element
757 // in its chain.
758 QGraphicsWidget *newFocusFirst = newParent;
759 QGraphicsWidget *newFocusLast = newFocusFirst;
760 QGraphicsWidget *newFocusAfter = newFocusFirst->d_func()->focusNext;
761 do {
762 if (!newParent->isAncestorOf(newFocusAfter))
763 break;
764 newFocusLast = newFocusAfter;
765 } while ((newFocusAfter = newFocusAfter->d_func()->focusNext));
766
767 newFocusLast->d_func()->focusNext = q;
768 focusLast->d_func()->focusNext = newFocusAfter;
769 if (newFocusAfter)
770 newFocusAfter->d_func()->focusPrev = focusLast;
771 focusPrev = newFocusLast;
772 } else {
773 // no new parent, so just link up our own prev->last widgets.
774 focusPrev = focusLast;
775 focusLast->d_func()->focusNext = q;
776 }
777}
778
780{
781 delete (this->layout);
782 layout = l;
783 if (!l) {
784 Q_Q(QGraphicsWidget);
785 q->updateGeometry();
786 }
787}
788
790{
791 Q_Q(const QGraphicsWidget);
792 return q->geometry().width();
793}
794
796{
797 if (qIsNaN(w))
798 return;
799 Q_Q(QGraphicsWidget);
800 if (q->geometry().width() == w)
801 return;
802
803 q->setGeometry(QRectF(q->x(), q->y(), w, height()));
804}
805
807{
808 Q_Q(QGraphicsWidget);
809 q->setGeometry(QRectF(q->x(), q->y(), 0, height()));
810}
811
813{
814 Q_Q(const QGraphicsWidget);
815 return q->geometry().height();
816}
817
819{
820 if (qIsNaN(h))
821 return;
822 Q_Q(QGraphicsWidget);
823 if (q->geometry().height() == h)
824 return;
825
826 q->setGeometry(QRectF(q->x(), q->y(), width(), h));
827}
828
830{
831 Q_Q(QGraphicsWidget);
832 q->setGeometry(QRectF(q->x(), q->y(), width(), 0));
833}
834
836{
837 if (inSetGeometry)
838 return;
839 Q_Q(QGraphicsWidget);
840 inSetPos = 1;
841 // Ensure setGeometry is called (avoid recursion when setPos is
842 // called from within setGeometry).
843 q->setGeometry(QRectF(pos, q->size()));
844 inSetPos = 0 ;
845}
846
847QT_END_NAMESPACE
void windowFrameHoverLeaveEvent(QGraphicsSceneHoverEvent *event)
void setFont_helper(const QFont &font)
QGraphicsWidget * focusPrev
void windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent *event)
void setWidth(qreal) override
void ensureWindowFrameMargins() const
QGraphicsLayout * layout
void updatePalette(const QPalette &palette)
void setLayoutDirection_helper(Qt::LayoutDirection direction)
qreal height() const override
void windowFrameMouseMoveEvent(QGraphicsSceneMouseEvent *event)
qreal titleBarHeight(const QStyleOptionTitleBar &options) const
void updateFont(const QFont &font)
void resolveFont(uint inheritedMask) override
void setHeight(qreal) override
void init(QGraphicsItem *parentItem, Qt::WindowFlags wFlags)
void initStyleOptionTitleBar(QStyleOptionTitleBar *option)
QPalette naturalWidgetPalette() const
void setPalette_helper(const QPalette &palette)
qreal width() const override
void windowFrameMousePressEvent(QGraphicsSceneMouseEvent *event)
void resolvePalette(uint inheritedMask) override
void setLayout_helper(QGraphicsLayout *l)
void adjustWindowFlags(Qt::WindowFlags *wFlags)
QGraphicsWidget * focusNext
void windowFrameMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
\inmodule QtCore\reentrant
Definition qpoint.h:231
static void _q_boundGeometryToSizeConstraints(const QRectF &startGeometry, QRectF *rect, Qt::WindowFrameSection section, const QSizeF &min, const QSizeF &max, const QGraphicsWidget *widget)
static qreal minimumHeightForWidth(qreal width, qreal minh, qreal maxh, const QGraphicsWidget *widget, bool heightForWidth=true)
static qreal minimumWidthForHeight(qreal height, qreal minw, qreal maxw, const QGraphicsWidget *widget)
static QSizeF closestAcceptableSize(const QSizeF &proposed, const QGraphicsWidget *widget)