1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Designer of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "spacer_widget_p.h"
30#include "layoutinfo_p.h"
31
32#include <QtDesigner/abstractformwindow.h>
33#include <QtDesigner/abstractformeditor.h>
34#include <QtDesigner/propertysheet.h>
35#include <QtDesigner/qextensionmanager.h>
36
37#include <QtWidgets/qlayout.h>
38#include <QtGui/qpainter.h>
39#include <QtGui/qevent.h>
40#include <QtCore/qdebug.h>
41
42QT_BEGIN_NAMESPACE
43
44// The Spacer widget is Designer representation of QLayoutItem.
45// It uses QLayoutItem's sizeHint property as QWidget
46// sizeHint and the QLayoutItem's sizeType property as QWidget size policy.
47// If it is not within a layout, it adds a margin (m_SizeOffset) around it
48// to avoid being shrunk to an invisible state when the sizeHint is reset to 0,0
49// and enables sizeHandle-resizing. In a layout, however, this m_SizeOffset
50// should not be applied for pixel-exact design.
51
52Spacer::Spacer(QWidget *parent) :
53 QWidget(parent)
54{
55 setAttribute(Qt::WA_MouseNoMask);
56 m_formWindow = QDesignerFormWindowInterface::findFormWindow(w: this);
57 setSizeType(QSizePolicy::Expanding);
58}
59
60bool Spacer::event(QEvent *e)
61{
62 switch (e->type()) {
63 case QEvent::ToolTip:
64 updateToolTip(); // Tooltip includes size, so, refresh on demand
65 break;
66 case QEvent::ParentChange: // Cache information about 'being in layout' which is expensive to calculate.
67 m_layoutState = UnknownLayoutState;
68 break;
69 default:
70 break;
71 }
72 return QWidget::event(event: e);
73}
74
75bool Spacer::isInLayout() const
76{
77 if (m_layoutState == UnknownLayoutState) {
78 m_layoutState = OutsideLayout;
79 if (m_formWindow)
80 if (const QWidget *parent = parentWidget())
81 if (qdesigner_internal::LayoutInfo::managedLayoutType(core: m_formWindow->core(), w: parent) != qdesigner_internal::LayoutInfo::NoLayout)
82 m_layoutState = InLayout;
83 }
84 return m_layoutState == InLayout;
85}
86
87void Spacer::paintEvent(QPaintEvent *)
88{
89 // Only draw spacers when we're editting widgets
90 if (m_formWindow != nullptr && m_formWindow->currentTool() != 0)
91 return;
92
93 QPainter p(this);
94 p.setPen(Qt::blue);
95 const int w = width();
96 const int h = height();
97 if (w * h == 0)
98 return;
99
100 if (w <= m_SizeOffset.width() || h <= m_SizeOffset.height()) {
101 const int lw = w - 1;
102 const int lh = h - 1;
103 switch (m_orientation) {
104 case Qt::Horizontal:
105 p.drawLine(x1: 0, y1: 0, x2: 0, y2: lh);
106 p.drawLine(x1: lw, y1: 0, x2: lw, y2: lh);
107 break;
108 case Qt::Vertical:
109 p.drawLine(x1: 0, y1: 0, x2: lw, y2: 0);
110 p.drawLine(x1: 0, y1: lh, x2: lw, y2: lh);
111 break;
112 }
113 return;
114 }
115 if (m_orientation == Qt::Horizontal) {
116 const int dist = 3;
117 const int amplitude = qMin(a: 3, b: h / 3);
118 const int base = h / 2;
119 int i = 0;
120 p.setPen(Qt::white);
121 for (i = 0; i < w / 3 +2; ++i)
122 p.drawLine(x1: i * dist, y1: base - amplitude, x2: i * dist + dist / 2, y2: base + amplitude);
123 p.setPen(Qt::blue);
124 for (i = 0; i < w / 3 +2; ++i)
125 p.drawLine(x1: i * dist + dist / 2, y1: base + amplitude, x2: i * dist + dist, y2: base - amplitude);
126 const int y = h/2;
127 p.drawLine(x1: 0, y1: y-10, x2: 0, y2: y+10);
128 p.drawLine(x1: w - 1, y1: y-10, x2: w - 1, y2: y+10);
129 } else {
130 const int dist = 3;
131 const int amplitude = qMin(a: 3, b: w / 3);
132 const int base = w / 2;
133 int i = 0;
134 p.setPen(Qt::white);
135 for (i = 0; i < h / 3 +2; ++i)
136 p.drawLine(x1: base - amplitude, y1: i * dist, x2: base + amplitude,y2: i * dist + dist / 2);
137 p.setPen(Qt::blue);
138 for (i = 0; i < h / 3 +2; ++i)
139 p.drawLine(x1: base + amplitude, y1: i * dist + dist / 2, x2: base - amplitude, y2: i * dist + dist);
140 const int x = w/2;
141 p.drawLine(x1: x-10, y1: 0, x2: x+10, y2: 0);
142 p.drawLine(x1: x-10, y1: h - 1, x2: x+10, y2: h - 1);
143 }
144}
145
146void Spacer::resizeEvent(QResizeEvent* e)
147{
148 QWidget::resizeEvent(event: e);
149 // When resized by widget handle dragging after a reset (QSize(0, 0)):
150 // Mark the property as changed (geometry and sizeHint are in sync except for 'changed').
151 if (m_formWindow) {
152 const QSize oldSize = e->oldSize();
153 if (oldSize.isNull() || oldSize.width() <= m_SizeOffset.width() || oldSize.height() <= m_SizeOffset.height())
154 if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(manager: m_formWindow->core()->extensionManager(), object: this))
155 sheet->setChanged(index: sheet->indexOf(QStringLiteral("sizeHint")), changed: true);
156 }
157
158 updateMask();
159
160 if (!m_interactive)
161 return;
162
163 if (!isInLayout()) { // Allow size-handle resize only if not in layout
164 const QSize currentSize = size();
165 if (currentSize.width() >= m_SizeOffset.width() && currentSize.height() >= m_SizeOffset.height())
166 m_sizeHint = currentSize - m_SizeOffset;
167 }
168}
169
170void Spacer::updateMask()
171{
172 QRegion r(rect());
173 const int w = width();
174 const int h = height();
175 if (w > 1 && h > 1) {
176 if (m_orientation == Qt::Horizontal) {
177 const int amplitude = qMin(a: 3, b: h / 3);
178 const int base = h / 2;
179 r = r.subtracted(r: QRect(1, 0, w - 2, base - amplitude));
180 r = r.subtracted(r: QRect(1, base + amplitude, w - 2, h - base - amplitude));
181 } else {
182 const int amplitude = qMin(a: 3, b: w / 3);
183 const int base = w / 2;
184 r = r.subtracted(r: QRect(0, 1, base - amplitude, h - 2));
185 r = r.subtracted(r: QRect(base + amplitude, 1, w - base - amplitude, h - 2));
186 }
187 }
188 setMask(r);
189}
190
191void Spacer::setSizeType(QSizePolicy::Policy t)
192{
193 const QSizePolicy sizeP = m_orientation == Qt::Vertical ? QSizePolicy(QSizePolicy::Minimum, t) : QSizePolicy(t, QSizePolicy::Minimum);
194 setSizePolicy(sizeP);
195}
196
197
198QSizePolicy::Policy Spacer::sizeType() const
199{
200 return m_orientation == Qt::Vertical ? sizePolicy().verticalPolicy() : sizePolicy().horizontalPolicy();
201}
202
203Qt::Alignment Spacer::alignment() const
204{
205 // For grid layouts
206 return m_orientation == Qt::Vertical ? Qt::AlignHCenter : Qt::AlignVCenter;
207}
208
209QSize Spacer::sizeHint() const
210{
211 return isInLayout() ? m_sizeHint : m_sizeHint + m_SizeOffset;
212}
213
214QSize Spacer::sizeHintProperty() const
215{
216 return m_sizeHint;
217}
218
219void Spacer::setSizeHintProperty(const QSize &s)
220{
221 m_sizeHint = s;
222
223 if (!isInLayout()) // Visible resize only if not in layout
224 resize(s + m_SizeOffset);
225
226 updateGeometry();
227}
228
229Qt::Orientation Spacer::orientation() const
230{
231 return m_orientation;
232}
233
234void Spacer::setOrientation(Qt::Orientation o)
235{
236 if (m_orientation == o)
237 return;
238
239 const QSizePolicy::Policy st = sizeType(); // flip size type
240 m_orientation = o;
241 setSizeType(st);
242
243 if (m_interactive) {
244 m_sizeHint = QSize(m_sizeHint.height(), m_sizeHint.width());
245 if (!isInLayout())
246 resize(m_sizeHint + m_SizeOffset);
247 }
248
249 updateMask();
250 update();
251 updateGeometry();
252}
253
254void Spacer::updateToolTip()
255{
256 const QString format = m_orientation == Qt::Horizontal ? tr(s: "Horizontal Spacer '%1', %2 x %3") : tr(s: "Vertical Spacer '%1', %2 x %3");
257 QString msg = format.arg(a: objectName()).arg(a: m_sizeHint.width()).arg(a: m_sizeHint.height());
258 setToolTip(msg);
259}
260
261QT_END_NAMESPACE
262

source code of qttools/src/designer/src/lib/shared/spacer_widget.cpp