7#include <QtWidgets/qapplication.h>
8#include <QtWidgets/qboxlayout.h>
9#include <QtWidgets/qcheckbox.h>
10#include <QtWidgets/qlineedit.h>
11#include <QtWidgets/qmenu.h>
13#include <QtGui/qevent.h>
14#include <QtGui/qpainter.h>
15#include <QtGui/qpainterstateguard.h>
17#include <QtCore/qhash.h>
18#include <QtCore/qlocale.h>
19#include <QtCore/qoperatingsystemversion.h>
25using namespace Qt::StringLiterals;
34using ShapeNames = QHash<Qt::CursorShape,
const char *>;
38 static const ShapeNames result =
39 {{Qt::ArrowCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Arrow")},
40 {Qt::UpArrowCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Up Arrow")},
41 {Qt::CrossCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Cross")},
42 {Qt::WaitCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Wait")},
43 {Qt::IBeamCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"IBeam")},
44 {Qt::SizeVerCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Size Vertical")},
45 {Qt::SizeHorCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Size Horizontal")},
46 {Qt::SizeFDiagCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Size Backslash")},
47 {Qt::SizeBDiagCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Size Slash")},
48 {Qt::SizeAllCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Size All")},
49 {Qt::BlankCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Blank")},
50 {Qt::SplitVCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Split Vertical")},
51 {Qt::SplitHCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Split Horizontal")},
52 {Qt::PointingHandCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Pointing Hand")},
53 {Qt::ForbiddenCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Forbidden")},
54 {Qt::OpenHandCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Open Hand")},
55 {Qt::ClosedHandCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Closed Hand")},
56 {Qt::WhatsThisCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"What's This")},
57 {Qt::BusyCursor, QT_TRANSLATE_NOOP(
"QtCursorDatabase",
"Busy")}};
61using CursorResource = std::pair<Qt::CursorShape, QLatin1StringView>;
64 {Qt::ArrowCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-arrow.png"_L1},
65 {Qt::UpArrowCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-uparrow.png"_L1},
66 {Qt::CrossCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-cross.png"_L1},
67 {Qt::WaitCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-wait.png"_L1},
68 {Qt::IBeamCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-ibeam.png"_L1},
69 {Qt::SizeVerCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-sizev.png"_L1},
70 {Qt::SizeHorCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-sizeh.png"_L1},
71 {Qt::SizeFDiagCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-sizef.png"_L1},
72 {Qt::SizeBDiagCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-sizeb.png"_L1},
73 {Qt::SizeAllCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-sizeall.png"_L1},
74 {Qt::SplitVCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-vsplit.png"_L1},
75 {Qt::SplitHCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-hsplit.png"_L1},
76 {Qt::PointingHandCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-hand.png"_L1},
77 {Qt::ForbiddenCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-forbidden.png"_L1},
78 {Qt::OpenHandCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-openhand.png"_L1},
79 {Qt::ClosedHandCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-closedhand.png"_L1},
80 {Qt::WhatsThisCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-whatsthis.png"_L1},
81 {Qt::BusyCursor,
":/qt-project.org/qtpropertybrowser/images/cursor-busy.png"_L1}
95 return new QtPixmapIconEngine(m_pixmap);
100 QPainterStateGuard psg(painter);
101 painter->setRenderHint(QPainter::Antialiasing,
true);
103 const auto dpr = painter->device()->devicePixelRatioF();
104 m_pixmap.setDevicePixelRatio(dpr);
106 qFuzzyCompare(dpr, 1) ? m_pixmap.size() : (QSizeF(m_pixmap.size()) / dpr).toSize();
107 const int dipWidth = dipSize.width();
108 const int dipHeight = dipSize.height();
109 if (dipWidth > rect.width() || dipHeight > rect.height()) {
110 painter->setRenderHint(QPainter::SmoothPixmapTransform);
111 painter->drawPixmap(rect, m_pixmap);
113 QPoint point = rect.topLeft();
114 if (dipWidth < rect.width())
115 point.rx() += (rect.width() - dipWidth) / 2;
116 if (dipHeight < rect.height())
117 point.ry() += (rect.height() - dipHeight) / 2;
118 painter->drawPixmap(point, m_pixmap);
128 return QIcon{
new QtPixmapIconEngine(QPixmap(fn))};
134 static constexpr auto root =
":/qt-project.org/windows/cursors/images/"_L1;
135 static constexpr QLatin1StringView suffixes[] = {
"_32.png"_L1,
"_48.png"_L1,
"_64.png"_L1};
137 for (
auto suffix : suffixes) {
138 const QString path = root + name + suffix;
139 QPixmap pixmap(path);
141 qWarning(
"%s: Failed to load \"%s\"",
__FUNCTION__, qPrintable(path));
143 result.addPixmap(pixmap);
151 static constexpr auto root =
":/qt-project.org/mac/cursors/images/"_L1;
152 const QString path = root + name;
153 QPixmap pixmap(path);
154 if (pixmap.isNull()) {
155 qWarning(
"%s: Failed to load \"%s\"",
__FUNCTION__, qPrintable(path));
158 return QIcon{
new QtPixmapIconEngine(pixmap)};
165 if constexpr (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Windows) {
166 appendCursor(Qt::ClosedHandCursor, getWindowsCursorIcon(
"closedhandcursor"_L1));
167 appendCursor(Qt::OpenHandCursor, getWindowsCursorIcon(
"openhandcursor"_L1));
168 appendCursor(Qt::SplitHCursor, getWindowsCursorIcon(
"splithcursor"_L1));
169 appendCursor(Qt::SplitVCursor, getWindowsCursorIcon(
"splitvcursor"_L1));
172 if constexpr (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::MacOS) {
173 appendCursor(Qt::BusyCursor, getCocoaCursorIcon(
"spincursor.png"_L1));
174 appendCursor(Qt::WaitCursor, getCocoaCursorIcon(
"waitcursor.png"_L1));
177 appendCursor(Qt::BlankCursor, QIcon{});
179 for (
const auto &cursorResource : cursorResources) {
180 if (!hasCursor(cursorResource.first))
181 appendCursor(cursorResource.first, getResourceCursorIcon(cursorResource.second));
187 m_cursorNames.clear();
188 m_cursorIcons.clear();
189 m_valueToCursorShape.clear();
190 m_cursorShapeToValue.clear();
193void QtCursorDatabase::appendCursor(Qt::CursorShape shape,
const QIcon &icon)
195 if (hasCursor(shape) || (shape != Qt::BlankCursor && icon.isNull()))
197 const qsizetype value = m_cursorNames.size();
198 const char *name = shapeNames().value(shape,
nullptr);
199 m_cursorNames.append(name ? QCoreApplication::translate(
"QtCursorDatabase", name) : QString{});
200 m_cursorIcons.insert(value, icon);
201 m_valueToCursorShape.insert(value, shape);
202 m_cursorShapeToValue.insert(shape, value);
207 return m_cursorNames;
212 return m_cursorIcons;
217 int val = cursorToValue(cursor);
219 return m_cursorNames.at(val);
225 int val = cursorToValue(cursor);
226 return m_cursorIcons.value(val);
232 return m_cursorShapeToValue.value(cursor.shape(), -1);
240 auto it = m_valueToCursorShape.constFind(value);
241 if (it != m_valueToCursorShape.cend())
242 return QCursor(it.value());
251 return cursorDatabase();
263 return new QtPropertyBrushValueIconEngine(m_brush);
268 QPainterStateGuard psg(painter);
269 painter->setCompositionMode(QPainter::CompositionMode_Source);
270 painter->fillRect(rect, m_brush);
271 QColor color = m_brush.color();
272 if (color.alpha() != 255) {
273 QBrush opaqueBrush = m_brush;
275 opaqueBrush.setColor(color);
276 const QPoint offset{rect.width() / 4, rect.height() / 4};
277 const QRect inset{rect.topLeft() + offset, rect.size() / 2};
278 painter->fillRect(inset, opaqueBrush);
287 qreal devicePixelRatio)
290 return engine.drawPixmap(size, devicePixelRatio);
300 return QCoreApplication::translate(
"QtPropertyBrowserUtils",
"[%1, %2, %3] (%4)")
301 .arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
313 return new QtPropertyFontValueIconEngine(m_font);
318 QPainterStateGuard psg(painter);
319 const auto maxDimension = qMax(rect.width(), rect.height());
320 m_font.setPointSize(maxDimension - 3);
321 painter->setPen(QPen(Qt::black));
322 painter->setFont(m_font);
323 painter->setRenderHint(QPainter::TextAntialiasing,
true);
324 painter->setRenderHint(QPainter::Antialiasing,
true);
325 painter->drawText(rect, QString(u'A'), QTextOption(Qt::AlignCenter));
333 qreal devicePixelRatio)
336 return engine.drawPixmap(size, devicePixelRatio);
346 return QCoreApplication::translate(
"QtPropertyBrowserUtils",
"[%1, %2]")
347 .arg(f.family()).arg(f.pointSize());
353 QString format = loc.dateFormat(QLocale::ShortFormat);
355 if (format.count(QLatin1Char(
'y')) == 2)
356 format.insert(format.indexOf(QLatin1Char(
'y')),
"yy"_L1);
364 return loc.timeFormat(QLocale::LongFormat);
369 QString format = dateFormat();
370 format += QLatin1Char(
' ');
371 format += timeFormat();
377 m_checkBox(
new QCheckBox(
this)),
380 auto *lt =
new QHBoxLayout;
381 if (QApplication::layoutDirection() == Qt::LeftToRight)
382 lt->setContentsMargins(4, 0, 0, 0);
384 lt->setContentsMargins(0, 0, 4, 0);
385 lt->addWidget(m_checkBox);
387 connect(m_checkBox, &QAbstractButton::toggled,
this, &QtBoolEdit::toggled);
388 setFocusProxy(m_checkBox);
389 m_checkBox->setText(tr(
"True"));
394 if (m_textVisible == textVisible)
397 m_textVisible = textVisible;
399 m_checkBox->setText(
isChecked() ? tr(
"True") : tr(
"False"));
401 m_checkBox->setText(QString());
406 return m_checkBox->checkState();
411 m_checkBox->setCheckState(state);
416 return m_checkBox->isChecked();
421 m_checkBox->setChecked(c);
424 m_checkBox->setText(
isChecked() ? tr(
"True") : tr(
"False"));
429 return m_checkBox->blockSignals(block);
434 if (event->buttons() == Qt::LeftButton) {
438 QWidget::mousePressEvent(event);
444 QPixmap result(size * devicePixelRatio);
445 result.fill(Qt::transparent);
446 result.setDevicePixelRatio(devicePixelRatio);
457 QPixmap result = createEmptyPixmap(size, scale);
458 QPainter painter(&result);
459 paint(&painter, QRect(0, 0, size.width(), size.height()), mode, state);
466 return scaledPixmap(size, QIcon::Mode::Normal, QIcon::State::On, devicePixelRatio);
Qt::CheckState checkState() const
void setTextVisible(bool textVisible)
bool blockCheckBoxSignals(bool block)
void setCheckState(Qt::CheckState state)
QCursor valueToCursor(int value) const
QStringList cursorShapeNames() const
int cursorToValue(const QCursor &cursor) const
QString cursorToShapeName(const QCursor &cursor) const
QIcon cursorToShapeIcon(const QCursor &cursor) const
static QtCursorDatabase * instance()
QMap< int, QIcon > cursorShapeIcons() const
QtPixmapIconEngine(QPixmap p)
QIconEngine * clone() const override
Reimplement this method to return a clone of this icon engine.
void paint(QPainter *painter, const QRect &rect, QIcon::Mode, QIcon::State) override
Uses the given painter to paint the icon with the required mode and state into the rectangle rect.
QtPropertyBrushValueIconEngine(const QBrush &b)
QIconEngine * clone() const override
Reimplement this method to return a clone of this icon engine.
void paint(QPainter *painter, const QRect &rect, QIcon::Mode, QIcon::State) override
Uses the given painter to paint the icon with the required mode and state into the rectangle rect.
void paint(QPainter *painter, const QRect &rect, QIcon::Mode, QIcon::State) override
Uses the given painter to paint the icon with the required mode and state into the rectangle rect.
QtPropertyFontValueIconEngine(const QFont &f)
QIconEngine * clone() const override
Reimplement this method to return a clone of this icon engine.
QPixmap drawPixmap(const QSize &size, qreal devicePixelRatio)
static QIcon getWindowsCursorIcon(QLatin1StringView name)
static void clearCursorDatabase()
static QIcon getCocoaCursorIcon(QLatin1StringView name)
static const ShapeNames & shapeNames()
static QIcon getResourceCursorIcon(const QString &fn)
static constexpr CursorResource cursorResources[]