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