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
spacer_widget.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5#include "layoutinfo_p.h"
6
7#include <QtDesigner/abstractformwindow.h>
8#include <QtDesigner/abstractformeditor.h>
9#include <QtDesigner/propertysheet.h>
10#include <QtDesigner/qextensionmanager.h>
11
12#include <QtWidgets/qlayout.h>
13#include <QtGui/qpainter.h>
14#include <QtGui/qevent.h>
15#include <QtCore/qdebug.h>
16
18
19using namespace Qt::StringLiterals;
20
21// The Spacer widget is Designer representation of QLayoutItem.
22// It uses QLayoutItem's sizeHint property as QWidget
23// sizeHint and the QLayoutItem's sizeType property as QWidget size policy.
24// If it is not within a layout, it adds a margin (m_SizeOffset) around it
25// to avoid being shrunk to an invisible state when the sizeHint is reset to 0,0
26// and enables sizeHandle-resizing. In a layout, however, this m_SizeOffset
27// should not be applied for pixel-exact design.
28
29Spacer::Spacer(QWidget *parent) :
30 QWidget(parent)
31{
32 setAttribute(Qt::WA_MouseNoMask);
33 m_formWindow = QDesignerFormWindowInterface::findFormWindow(this);
34 setSizeType(QSizePolicy::Expanding);
35}
36
37bool Spacer::event(QEvent *e)
38{
39 switch (e->type()) {
40 case QEvent::ToolTip:
41 updateToolTip(); // Tooltip includes size, so, refresh on demand
42 break;
43 case QEvent::ParentChange: // Cache information about 'being in layout' which is expensive to calculate.
44 m_layoutState = UnknownLayoutState;
45 break;
46 default:
47 break;
48 }
49 return QWidget::event(e);
50}
51
52bool Spacer::isInLayout() const
53{
54 if (m_layoutState == UnknownLayoutState) {
55 m_layoutState = OutsideLayout;
56 if (m_formWindow)
57 if (const QWidget *parent = parentWidget())
58 if (qdesigner_internal::LayoutInfo::managedLayoutType(m_formWindow->core(), parent) != qdesigner_internal::LayoutInfo::NoLayout)
59 m_layoutState = InLayout;
60 }
61 return m_layoutState == InLayout;
62}
63
64void Spacer::paintEvent(QPaintEvent *)
65{
66 // Only draw spacers when we're editting widgets
67 if (m_formWindow != nullptr && m_formWindow->currentTool() != 0)
68 return;
69
70 QPainter p(this);
71 p.setPen(Qt::blue);
72 const int w = width();
73 const int h = height();
74 if (w * h == 0)
75 return;
76
77 if (w <= m_SizeOffset.width() || h <= m_SizeOffset.height()) {
78 const int lw = w - 1;
79 const int lh = h - 1;
80 switch (m_orientation) {
81 case Qt::Horizontal:
82 p.drawLine(0, 0, 0, lh);
83 p.drawLine(lw, 0, lw, lh);
84 break;
85 case Qt::Vertical:
86 p.drawLine(0, 0, lw, 0);
87 p.drawLine(0, lh, lw, lh);
88 break;
89 }
90 return;
91 }
92 if (m_orientation == Qt::Horizontal) {
93 const int dist = 3;
94 const int amplitude = qMin(3, h / 3);
95 const int base = h / 2;
96 int i = 0;
97 p.setPen(Qt::white);
98 for (i = 0; i < w / 3 +2; ++i)
99 p.drawLine(i * dist, base - amplitude, i * dist + dist / 2, base + amplitude);
100 p.setPen(Qt::blue);
101 for (i = 0; i < w / 3 +2; ++i)
102 p.drawLine(i * dist + dist / 2, base + amplitude, i * dist + dist, base - amplitude);
103 const int y = h/2;
104 p.drawLine(0, y-10, 0, y+10);
105 p.drawLine(w - 1, y-10, w - 1, y+10);
106 } else {
107 const int dist = 3;
108 const int amplitude = qMin(3, w / 3);
109 const int base = w / 2;
110 int i = 0;
111 p.setPen(Qt::white);
112 for (i = 0; i < h / 3 +2; ++i)
113 p.drawLine(base - amplitude, i * dist, base + amplitude,i * dist + dist / 2);
114 p.setPen(Qt::blue);
115 for (i = 0; i < h / 3 +2; ++i)
116 p.drawLine(base + amplitude, i * dist + dist / 2, base - amplitude, i * dist + dist);
117 const int x = w/2;
118 p.drawLine(x-10, 0, x+10, 0);
119 p.drawLine(x-10, h - 1, x+10, h - 1);
120 }
121}
122
123void Spacer::resizeEvent(QResizeEvent* e)
124{
125 QWidget::resizeEvent(e);
126 // When resized by widget handle dragging after a reset (QSize(0, 0)):
127 // Mark the property as changed (geometry and sizeHint are in sync except for 'changed').
128 if (m_formWindow) {
129 const QSize oldSize = e->oldSize();
130 if (oldSize.isNull() || oldSize.width() <= m_SizeOffset.width() || oldSize.height() <= m_SizeOffset.height())
131 if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_formWindow->core()->extensionManager(), this))
132 sheet->setChanged(sheet->indexOf(u"sizeHint"_s), true);
133 }
134
135 updateMask();
136
137 if (!m_interactive)
138 return;
139
140 if (!isInLayout()) { // Allow size-handle resize only if not in layout
141 const QSize currentSize = size();
142 if (currentSize.width() >= m_SizeOffset.width() && currentSize.height() >= m_SizeOffset.height())
143 m_sizeHint = currentSize - m_SizeOffset;
144 }
145}
146
147void Spacer::updateMask()
148{
149 QRegion r(rect());
150 const int w = width();
151 const int h = height();
152 if (w > 1 && h > 1) {
153 if (m_orientation == Qt::Horizontal) {
154 const int amplitude = qMin(3, h / 3);
155 const int base = h / 2;
156 r = r.subtracted(QRect(1, 0, w - 2, base - amplitude));
157 r = r.subtracted(QRect(1, base + amplitude, w - 2, h - base - amplitude));
158 } else {
159 const int amplitude = qMin(3, w / 3);
160 const int base = w / 2;
161 r = r.subtracted(QRect(0, 1, base - amplitude, h - 2));
162 r = r.subtracted(QRect(base + amplitude, 1, w - base - amplitude, h - 2));
163 }
164 }
165 setMask(r);
166}
167
168void Spacer::setSizeType(QSizePolicy::Policy t)
169{
170 const QSizePolicy sizeP = m_orientation == Qt::Vertical ? QSizePolicy(QSizePolicy::Minimum, t) : QSizePolicy(t, QSizePolicy::Minimum);
171 setSizePolicy(sizeP);
172}
173
174
175QSizePolicy::Policy Spacer::sizeType() const
176{
177 return m_orientation == Qt::Vertical ? sizePolicy().verticalPolicy() : sizePolicy().horizontalPolicy();
178}
179
180Qt::Alignment Spacer::alignment() const
181{
182 // For grid layouts
183 return m_orientation == Qt::Vertical ? Qt::AlignHCenter : Qt::AlignVCenter;
184}
185
186QSize Spacer::sizeHint() const
187{
188 return isInLayout() ? m_sizeHint : m_sizeHint + m_SizeOffset;
189}
190
191QSize Spacer::sizeHintProperty() const
192{
193 return m_sizeHint;
194}
195
196void Spacer::setSizeHintProperty(const QSize &s)
197{
198 m_sizeHint = s;
199
200 if (!isInLayout()) // Visible resize only if not in layout
201 resize(s + m_SizeOffset);
202
203 updateGeometry();
204}
205
206Qt::Orientation Spacer::orientation() const
207{
208 return m_orientation;
209}
210
211void Spacer::setOrientation(Qt::Orientation o)
212{
213 if (m_orientation == o)
214 return;
215
216 const QSizePolicy::Policy st = sizeType(); // flip size type
217 m_orientation = o;
218 setSizeType(st);
219
220 if (m_interactive) {
221 m_sizeHint = QSize(m_sizeHint.height(), m_sizeHint.width());
222 if (!isInLayout())
223 resize(m_sizeHint + m_SizeOffset);
224 }
225
226 updateMask();
227 update();
228 updateGeometry();
229}
230
231void Spacer::updateToolTip()
232{
233 const QString format = m_orientation == Qt::Horizontal ? tr("Horizontal Spacer '%1', %2 x %3") : tr("Vertical Spacer '%1', %2 x %3");
234 QString msg = format.arg(objectName()).arg(m_sizeHint.width()).arg(m_sizeHint.height());
235 setToolTip(msg);
236}
237
238QT_END_NAMESPACE
Combined button and popup list for selecting options.