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 int 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 Qt::CursorShape shape = cursor.shape();
116 if (m_cursorShapeToValue.contains(key: shape))
117 return m_cursorShapeToValue[shape];
118#endif
119 return -1;
120}
121
122#ifndef QT_NO_CURSOR
123QCursor QtCursorDatabase::valueToCursor(int value) const
124{
125 if (m_valueToCursorShape.contains(key: value))
126 return QCursor(m_valueToCursorShape[value]);
127 return {};
128}
129#endif
130
131Q_GLOBAL_STATIC(QtCursorDatabase, cursorDatabase)
132
133QtCursorDatabase *QtCursorDatabase::instance()
134{
135 return cursorDatabase();
136}
137
138QPixmap QtPropertyBrowserUtils::brushValuePixmap(const QBrush &b)
139{
140 QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
141 img.fill(pixel: 0);
142
143 QPainter painter(&img);
144 painter.setCompositionMode(QPainter::CompositionMode_Source);
145 painter.fillRect(x: 0, y: 0, w: img.width(), h: img.height(), b);
146 QColor color = b.color();
147 if (color.alpha() != 255) { // indicate alpha by an inset
148 QBrush opaqueBrush = b;
149 color.setAlpha(255);
150 opaqueBrush.setColor(color);
151 painter.fillRect(x: img.width() / 4, y: img.height() / 4,
152 w: img.width() / 2, h: img.height() / 2, b: opaqueBrush);
153 }
154 painter.end();
155 return QPixmap::fromImage(image: img);
156}
157
158QIcon QtPropertyBrowserUtils::brushValueIcon(const QBrush &b)
159{
160 return QIcon(brushValuePixmap(b));
161}
162
163QString QtPropertyBrowserUtils::colorValueText(const QColor &c)
164{
165 return QCoreApplication::translate(context: "QtPropertyBrowserUtils", key: "[%1, %2, %3] (%4)")
166 .arg(a: c.red()).arg(a: c.green()).arg(a: c.blue()).arg(a: c.alpha());
167}
168
169QPixmap QtPropertyBrowserUtils::fontValuePixmap(const QFont &font)
170{
171 QFont f = font;
172 QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
173 img.fill(pixel: 0);
174 QPainter p(&img);
175 p.setRenderHint(hint: QPainter::TextAntialiasing, on: true);
176 p.setRenderHint(hint: QPainter::Antialiasing, on: true);
177 f.setPointSize(13);
178 p.setFont(f);
179 QTextOption t;
180 t.setAlignment(Qt::AlignCenter);
181 p.drawText(r: QRect(0, 0, 16, 16), text: QString(QLatin1Char('A')), o: t);
182 return QPixmap::fromImage(image: img);
183}
184
185QIcon QtPropertyBrowserUtils::fontValueIcon(const QFont &f)
186{
187 return QIcon(fontValuePixmap(font: f));
188}
189
190QString QtPropertyBrowserUtils::fontValueText(const QFont &f)
191{
192 return QCoreApplication::translate(context: "QtPropertyBrowserUtils", key: "[%1, %2]")
193 .arg(a: f.family()).arg(a: f.pointSize());
194}
195
196QString QtPropertyBrowserUtils::dateFormat()
197{
198 QLocale loc;
199 QString format = loc.dateFormat(format: QLocale::ShortFormat);
200 // Change dd.MM.yy, MM/dd/yy to 4 digit years
201 if (format.count(c: QLatin1Char('y')) == 2)
202 format.insert(i: format.indexOf(c: QLatin1Char('y')), s: "yy"_L1);
203 return format;
204}
205
206QString QtPropertyBrowserUtils::timeFormat()
207{
208 QLocale loc;
209 // ShortFormat is missing seconds on UNIX.
210 return loc.timeFormat(format: QLocale::LongFormat);
211}
212
213QString QtPropertyBrowserUtils::dateTimeFormat()
214{
215 QString format = dateFormat();
216 format += QLatin1Char(' ');
217 format += timeFormat();
218 return format;
219}
220
221QtBoolEdit::QtBoolEdit(QWidget *parent) :
222 QWidget(parent),
223 m_checkBox(new QCheckBox(this)),
224 m_textVisible(true)
225{
226 auto *lt = new QHBoxLayout;
227 if (QApplication::layoutDirection() == Qt::LeftToRight)
228 lt->setContentsMargins(left: 4, top: 0, right: 0, bottom: 0);
229 else
230 lt->setContentsMargins(left: 0, top: 0, right: 4, bottom: 0);
231 lt->addWidget(m_checkBox);
232 setLayout(lt);
233 connect(sender: m_checkBox, signal: &QAbstractButton::toggled, context: this, slot: &QtBoolEdit::toggled);
234 setFocusProxy(m_checkBox);
235 m_checkBox->setText(tr(s: "True"));
236}
237
238void QtBoolEdit::setTextVisible(bool textVisible)
239{
240 if (m_textVisible == textVisible)
241 return;
242
243 m_textVisible = textVisible;
244 if (m_textVisible)
245 m_checkBox->setText(isChecked() ? tr(s: "True") : tr(s: "False"));
246 else
247 m_checkBox->setText(QString());
248}
249
250Qt::CheckState QtBoolEdit::checkState() const
251{
252 return m_checkBox->checkState();
253}
254
255void QtBoolEdit::setCheckState(Qt::CheckState state)
256{
257 m_checkBox->setCheckState(state);
258}
259
260bool QtBoolEdit::isChecked() const
261{
262 return m_checkBox->isChecked();
263}
264
265void QtBoolEdit::setChecked(bool c)
266{
267 m_checkBox->setChecked(c);
268 if (!m_textVisible)
269 return;
270 m_checkBox->setText(isChecked() ? tr(s: "True") : tr(s: "False"));
271}
272
273bool QtBoolEdit::blockCheckBoxSignals(bool block)
274{
275 return m_checkBox->blockSignals(b: block);
276}
277
278void QtBoolEdit::mousePressEvent(QMouseEvent *event)
279{
280 if (event->buttons() == Qt::LeftButton) {
281 m_checkBox->click();
282 event->accept();
283 } else {
284 QWidget::mousePressEvent(event);
285 }
286}
287
288QT_END_NAMESPACE
289

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