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
4#include "qtpropertybrowserutils_p.h"
5#include <QtWidgets/QApplication>
6#include <QtGui/QPainter>
7#include <QtWidgets/QHBoxLayout>
8#include <QtGui/QMouseEvent>
9#include <QtWidgets/QCheckBox>
10#include <QtWidgets/QLineEdit>
11#include <QtWidgets/QMenu>
12#include <QtCore/QLocale>
13
14QT_BEGIN_NAMESPACE
15
16using namespace Qt::StringLiterals;
17
18// Make sure icons are removed as soon as QApplication is destroyed, otherwise,
19// handles are leaked on X11.
20static void clearCursorDatabase()
21{
22 QtCursorDatabase::instance()->clear();
23}
24
25QtCursorDatabase::QtCursorDatabase()
26{
27 qAddPostRoutine(clearCursorDatabase);
28
29 appendCursor(shape: Qt::ArrowCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Arrow"),
30 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-arrow.png"_L1));
31 appendCursor(shape: Qt::UpArrowCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Up Arrow"),
32 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-uparrow.png"_L1));
33 appendCursor(shape: Qt::CrossCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Cross"),
34 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-cross.png"_L1));
35 appendCursor(shape: Qt::WaitCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Wait"),
36 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-wait.png"_L1));
37 appendCursor(shape: Qt::IBeamCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "IBeam"),
38 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-ibeam.png"_L1));
39 appendCursor(shape: Qt::SizeVerCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Size Vertical"),
40 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-sizev.png"_L1));
41 appendCursor(shape: Qt::SizeHorCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Size Horizontal"),
42 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-sizeh.png"_L1));
43 appendCursor(shape: Qt::SizeFDiagCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Size Backslash"),
44 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-sizef.png"_L1));
45 appendCursor(shape: Qt::SizeBDiagCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Size Slash"),
46 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-sizeb.png"_L1));
47 appendCursor(shape: Qt::SizeAllCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Size All"),
48 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-sizeall.png"_L1));
49 appendCursor(shape: Qt::BlankCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Blank"),
50 icon: QIcon());
51 appendCursor(shape: Qt::SplitVCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Split Vertical"),
52 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-vsplit.png"_L1));
53 appendCursor(shape: Qt::SplitHCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Split Horizontal"),
54 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-hsplit.png"_L1));
55 appendCursor(shape: Qt::PointingHandCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Pointing Hand"),
56 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-hand.png"_L1));
57 appendCursor(shape: Qt::ForbiddenCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Forbidden"),
58 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-forbidden.png"_L1));
59 appendCursor(shape: Qt::OpenHandCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Open Hand"),
60 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-openhand.png"_L1));
61 appendCursor(shape: Qt::ClosedHandCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Closed Hand"),
62 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-closedhand.png"_L1));
63 appendCursor(shape: Qt::WhatsThisCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "What's This"),
64 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-whatsthis.png"_L1));
65 appendCursor(shape: Qt::BusyCursor, name: QCoreApplication::translate(context: "QtCursorDatabase", key: "Busy"),
66 icon: QIcon(":/qt-project.org/qtpropertybrowser/images/cursor-busy.png"_L1));
67}
68
69void QtCursorDatabase::clear()
70{
71 m_cursorNames.clear();
72 m_cursorIcons.clear();
73 m_valueToCursorShape.clear();
74 m_cursorShapeToValue.clear();
75}
76
77void QtCursorDatabase::appendCursor(Qt::CursorShape shape, const QString &name, const QIcon &icon)
78{
79 if (m_cursorShapeToValue.contains(key: shape))
80 return;
81 const qsizetype value = m_cursorNames.size();
82 m_cursorNames.append(t: name);
83 m_cursorIcons.insert(key: value, value: icon);
84 m_valueToCursorShape.insert(key: value, value: shape);
85 m_cursorShapeToValue.insert(key: shape, value);
86}
87
88QStringList QtCursorDatabase::cursorShapeNames() const
89{
90 return m_cursorNames;
91}
92
93QMap<int, QIcon> QtCursorDatabase::cursorShapeIcons() const
94{
95 return m_cursorIcons;
96}
97
98QString QtCursorDatabase::cursorToShapeName(const QCursor &cursor) const
99{
100 int val = cursorToValue(cursor);
101 if (val >= 0)
102 return m_cursorNames.at(i: val);
103 return {};
104}
105
106QIcon QtCursorDatabase::cursorToShapeIcon(const QCursor &cursor) const
107{
108 int val = cursorToValue(cursor);
109 return m_cursorIcons.value(key: val);
110}
111
112int QtCursorDatabase::cursorToValue(const QCursor &cursor) const
113{
114#ifndef QT_NO_CURSOR
115 return m_cursorShapeToValue.value(key: cursor.shape(), defaultValue: -1);
116#endif
117 return -1;
118}
119
120#ifndef QT_NO_CURSOR
121QCursor QtCursorDatabase::valueToCursor(int value) const
122{
123 auto it = m_valueToCursorShape.constFind(key: value);
124 if (it != m_valueToCursorShape.cend())
125 return QCursor(it.value());
126 return {};
127}
128#endif
129
130Q_GLOBAL_STATIC(QtCursorDatabase, cursorDatabase)
131
132QtCursorDatabase *QtCursorDatabase::instance()
133{
134 return cursorDatabase();
135}
136
137QPixmap QtPropertyBrowserUtils::brushValuePixmap(const QBrush &b)
138{
139 QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
140 img.fill(pixel: 0);
141
142 QPainter painter(&img);
143 painter.setCompositionMode(QPainter::CompositionMode_Source);
144 painter.fillRect(x: 0, y: 0, w: img.width(), h: img.height(), b);
145 QColor color = b.color();
146 if (color.alpha() != 255) { // indicate alpha by an inset
147 QBrush opaqueBrush = b;
148 color.setAlpha(255);
149 opaqueBrush.setColor(color);
150 painter.fillRect(x: img.width() / 4, y: img.height() / 4,
151 w: img.width() / 2, h: img.height() / 2, b: opaqueBrush);
152 }
153 painter.end();
154 return QPixmap::fromImage(image: img);
155}
156
157QIcon QtPropertyBrowserUtils::brushValueIcon(const QBrush &b)
158{
159 return QIcon(brushValuePixmap(b));
160}
161
162QString QtPropertyBrowserUtils::colorValueText(QColor c)
163{
164 return QCoreApplication::translate(context: "QtPropertyBrowserUtils", key: "[%1, %2, %3] (%4)")
165 .arg(a: c.red()).arg(a: c.green()).arg(a: c.blue()).arg(a: c.alpha());
166}
167
168QPixmap QtPropertyBrowserUtils::fontValuePixmap(const QFont &font)
169{
170 QFont f = font;
171 QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
172 img.fill(pixel: 0);
173 QPainter p(&img);
174 p.setRenderHint(hint: QPainter::TextAntialiasing, on: true);
175 p.setRenderHint(hint: QPainter::Antialiasing, on: true);
176 f.setPointSize(13);
177 p.setFont(f);
178 QTextOption t;
179 t.setAlignment(Qt::AlignCenter);
180 p.drawText(r: QRect(0, 0, 16, 16), text: QString(QLatin1Char('A')), o: t);
181 return QPixmap::fromImage(image: img);
182}
183
184QIcon QtPropertyBrowserUtils::fontValueIcon(const QFont &f)
185{
186 return QIcon(fontValuePixmap(font: f));
187}
188
189QString QtPropertyBrowserUtils::fontValueText(const QFont &f)
190{
191 return QCoreApplication::translate(context: "QtPropertyBrowserUtils", key: "[%1, %2]")
192 .arg(a: f.family()).arg(a: f.pointSize());
193}
194
195QString QtPropertyBrowserUtils::dateFormat()
196{
197 QLocale loc;
198 QString format = loc.dateFormat(format: QLocale::ShortFormat);
199 // Change dd.MM.yy, MM/dd/yy to 4 digit years
200 if (format.count(c: QLatin1Char('y')) == 2)
201 format.insert(i: format.indexOf(ch: QLatin1Char('y')), s: "yy"_L1);
202 return format;
203}
204
205QString QtPropertyBrowserUtils::timeFormat()
206{
207 QLocale loc;
208 // ShortFormat is missing seconds on UNIX.
209 return loc.timeFormat(format: QLocale::LongFormat);
210}
211
212QString QtPropertyBrowserUtils::dateTimeFormat()
213{
214 QString format = dateFormat();
215 format += QLatin1Char(' ');
216 format += timeFormat();
217 return format;
218}
219
220QtBoolEdit::QtBoolEdit(QWidget *parent) :
221 QWidget(parent),
222 m_checkBox(new QCheckBox(this)),
223 m_textVisible(true)
224{
225 auto *lt = new QHBoxLayout;
226 if (QApplication::layoutDirection() == Qt::LeftToRight)
227 lt->setContentsMargins(left: 4, top: 0, right: 0, bottom: 0);
228 else
229 lt->setContentsMargins(left: 0, top: 0, right: 4, bottom: 0);
230 lt->addWidget(m_checkBox);
231 setLayout(lt);
232 connect(sender: m_checkBox, signal: &QAbstractButton::toggled, context: this, slot: &QtBoolEdit::toggled);
233 setFocusProxy(m_checkBox);
234 m_checkBox->setText(tr(s: "True"));
235}
236
237void QtBoolEdit::setTextVisible(bool textVisible)
238{
239 if (m_textVisible == textVisible)
240 return;
241
242 m_textVisible = textVisible;
243 if (m_textVisible)
244 m_checkBox->setText(isChecked() ? tr(s: "True") : tr(s: "False"));
245 else
246 m_checkBox->setText(QString());
247}
248
249Qt::CheckState QtBoolEdit::checkState() const
250{
251 return m_checkBox->checkState();
252}
253
254void QtBoolEdit::setCheckState(Qt::CheckState state)
255{
256 m_checkBox->setCheckState(state);
257}
258
259bool QtBoolEdit::isChecked() const
260{
261 return m_checkBox->isChecked();
262}
263
264void QtBoolEdit::setChecked(bool c)
265{
266 m_checkBox->setChecked(c);
267 if (!m_textVisible)
268 return;
269 m_checkBox->setText(isChecked() ? tr(s: "True") : tr(s: "False"));
270}
271
272bool QtBoolEdit::blockCheckBoxSignals(bool block)
273{
274 return m_checkBox->blockSignals(b: block);
275}
276
277void QtBoolEdit::mousePressEvent(QMouseEvent *event)
278{
279 if (event->buttons() == Qt::LeftButton) {
280 m_checkBox->click();
281 event->accept();
282 } else {
283 QWidget::mousePressEvent(event);
284 }
285}
286
287QT_END_NAMESPACE
288

source code of qttools/src/shared/qtpropertybrowser/qtpropertybrowserutils.cpp