Marble

MarbleLineEdit.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// The code in this file is largely based on KDE's KLineEdit class
4// as included in KDE 4.5. See there for its authors:
5// https://api.kde.org/4.x-api/kdelibs-apidocs/kdeui/html/klineedit_8cpp.html
6//
7// SPDX-FileCopyrightText: 2010, 2012 Dennis Nienhüser <nienhueser@kde.org>
8//
9
10#include "MarbleLineEdit.h"
11#include "MarbleGlobal.h"
12
13#include <QApplication>
14#include <QClipboard>
15#include <QLabel>
16#include <QMouseEvent>
17#include <QPainter>
18#include <QPixmap>
19#include <QStyle>
20#include <QTimer>
21
22namespace Marble
23{
24
25class MarbleLineEditPrivate
26{
27public:
28 QLabel *const m_clearButton;
29
30 QLabel *const m_decoratorButton;
31
32 QPixmap m_clearPixmap;
33
34 QPixmap m_decoratorPixmap;
35
36 QTimer m_progressTimer;
37
38 QList<QPixmap> m_progressAnimation;
39
40 int m_currentFrame;
41
42 int m_iconSize;
43
44 explicit MarbleLineEditPrivate(MarbleLineEdit *parent);
45
46 void createProgressAnimation();
47};
48
49MarbleLineEditPrivate::MarbleLineEditPrivate(MarbleLineEdit *parent)
50 : m_clearButton(new QLabel(parent))
51 , m_decoratorButton(new QLabel(parent))
52 , m_currentFrame(0)
53 , m_iconSize(16)
54{
55 m_clearButton->setCursor(Qt::ArrowCursor);
56 m_clearButton->setToolTip(QObject::tr("Clear"));
57 m_decoratorButton->setCursor(Qt::ArrowCursor);
58 createProgressAnimation();
59 m_progressTimer.setInterval(100);
60 if (MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen) {
61 m_iconSize = 32;
62 }
63}
64
65void MarbleLineEditPrivate::createProgressAnimation()
66{
67 // Size parameters
68 qreal const h = m_iconSize / 2.0; // Half of the icon size
69 qreal const q = h / 2.0; // Quarter of the icon size
70 qreal const d = 7.5; // Circle diameter
71 qreal const r = d / 2.0; // Circle radius
72
73 // Canvas parameters
74 QImage canvas(m_iconSize, m_iconSize, QImage::Format_ARGB32);
75 QPainter painter(&canvas);
76 painter.setRenderHint(QPainter::Antialiasing, true);
77 painter.setPen(QColor(Qt::gray));
78 painter.setBrush(QColor(Qt::white));
79
80 // Create all frames
81 for (double t = 0.0; t < 2 * M_PI; t += M_PI / 8.0) {
82 canvas.fill(Qt::transparent);
83 QRectF firstCircle(h - r + q * cos(t), h - r + q * sin(t), d, d);
84 QRectF secondCircle(h - r + q * cos(t + M_PI), h - r + q * sin(t + M_PI), d, d);
85 painter.drawEllipse(firstCircle);
86 painter.drawEllipse(secondCircle);
87 m_progressAnimation.push_back(QPixmap::fromImage(canvas));
88 }
89}
90
91MarbleLineEdit::MarbleLineEdit(QWidget *parent)
92 : QLineEdit(parent)
93 , d(new MarbleLineEditPrivate(this))
94{
95 updateClearButtonIcon(text());
96 updateClearButton();
97
98 setDecorator(d->m_decoratorPixmap);
99 connect(this, &QLineEdit::textChanged, this, &MarbleLineEdit::updateClearButtonIcon);
100 connect(&d->m_progressTimer, &QTimer::timeout, this, &MarbleLineEdit::updateProgress);
101}
102
104{
105 delete d;
106}
107
108void MarbleLineEdit::setDecorator(const QPixmap &decorator)
109{
110 d->m_decoratorPixmap = decorator;
111 d->m_decoratorButton->setPixmap(d->m_decoratorPixmap);
112 int const padding = 2 + d->m_decoratorPixmap.width();
113
114 QString const prefixDirection = layoutDirection() == Qt::LeftToRight ? "left" : "right";
115 QString decoratorStyleSheet;
116 if (!d->m_decoratorPixmap.isNull()) {
117 decoratorStyleSheet = QStringLiteral("; padding-%1: %2").arg(prefixDirection).arg(padding);
118 }
119 // Padding for clear button to avoid text underflow
120 QString const postfixDirection = layoutDirection() == Qt::LeftToRight ? "right" : "left";
121 QString styleSheet = QStringLiteral(":enabled { padding-%1: %2; %3}").arg(postfixDirection).arg(padding).arg(decoratorStyleSheet);
122
123 bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
124 if (!smallScreen) {
126 }
127}
128
129void MarbleLineEdit::setBusy(bool busy)
130{
131 if (busy) {
132 d->m_progressTimer.start();
133 } else {
134 d->m_progressTimer.stop();
135 d->m_decoratorButton->setPixmap(d->m_decoratorPixmap);
136 }
137}
138
139void MarbleLineEdit::updateClearButtonIcon(const QString &text)
140{
141 d->m_clearButton->setVisible(text.length() > 0);
142 if (!d->m_clearButton->pixmap().isNull()) {
143 return;
144 }
145
146 QString const direction = layoutDirection() == Qt::LeftToRight ? "rtl" : "ltr";
147 int const size = (MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen) ? 32 : 16;
148 QPixmap pixmap = QPixmap(QStringLiteral(":/icons/%1x%1/edit-clear-locationbar-%2.png").arg(size).arg(direction));
149 d->m_clearButton->setPixmap(pixmap);
150}
151
152void MarbleLineEdit::updateClearButton()
153{
154 const QSize geom = size();
155 const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, this);
156 const int pixmapSize = d->m_clearButton->pixmap().width() + 1;
157 const int decoratorSize = d->m_decoratorPixmap.width() + 1;
158
159 int y = (geom.height() - pixmapSize) / 2;
161 d->m_clearButton->move(geom.width() - frameWidth - pixmapSize - decoratorSize, y);
162 d->m_decoratorButton->move(frameWidth - decoratorSize + 1, y);
163 } else {
164 d->m_clearButton->move(frameWidth - decoratorSize + 1, y);
165 d->m_decoratorButton->move(geom.width() - frameWidth - pixmapSize - decoratorSize, y);
166 }
167}
168
169void MarbleLineEdit::updateProgress()
170{
171 if (!d->m_progressAnimation.isEmpty()) {
172 d->m_currentFrame = (d->m_currentFrame + 1) % d->m_progressAnimation.size();
173 QPixmap frame = d->m_progressAnimation[d->m_currentFrame];
174 d->m_decoratorButton->setPixmap(frame);
175 }
176}
177
178void MarbleLineEdit::mouseReleaseEvent(QMouseEvent *e)
179{
180 if (d->m_clearButton == childAt(e->pos())) {
181 QString newText;
182 if (e->button() == Qt::MiddleButton) {
184 setText(newText);
185 } else {
186 setSelection(0, text().size());
187 del();
189 }
190 Q_EMIT textChanged(newText);
191 }
192
193 if (d->m_decoratorButton == childAt(e->pos())) {
194 Q_EMIT decoratorButtonClicked();
195 }
196
198}
199
200void MarbleLineEdit::resizeEvent(QResizeEvent *event)
201{
202 updateClearButton();
204}
205
206} // namespace Marble
207
208#include "moc_MarbleLineEdit.cpp"
void clearButtonClicked()
The clear button was clicked with the left mouse button.
~MarbleLineEdit() override
Destructor.
Binds a QML item to a specific geodetic location in screen coordinates.
QString text(Mode mode) const const
QClipboard * clipboard()
void del()
virtual bool event(QEvent *e) override
virtual void mouseReleaseEvent(QMouseEvent *e) override
void setSelection(int start, int length)
void textChanged(const QString &text)
QPoint pos() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString tr(const char *sourceText, const char *disambiguation, int n)
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
Qt::MouseButton button() const const
int height() const const
int width() const const
QString arg(Args &&... args) const const
PM_DefaultFrameWidth
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
ArrowCursor
LeftToRight
MiddleButton
void timeout()
QWidget * childAt(const QPoint &p) const const
virtual void resizeEvent(QResizeEvent *event)
QStyle * style() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 8 2024 12:02:44 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.