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 <QStyle>
17#include <QMouseEvent>
18#include <QPainter>
19#include <QTimer>
20
21namespace Marble
22{
23
24class MarbleLineEditPrivate
25{
26public:
27 QLabel* m_clearButton;
28
29 QLabel* m_decoratorButton;
30
31 QPixmap m_clearPixmap;
32
33 QPixmap m_decoratorPixmap;
34
35 QTimer m_progressTimer;
36
37 QVector<QPixmap> m_progressAnimation;
38
39 int m_currentFrame;
40
41 int m_iconSize;
42
43 explicit MarbleLineEditPrivate( MarbleLineEdit* parent );
44
45 void createProgressAnimation();
46};
47
48MarbleLineEditPrivate::MarbleLineEditPrivate( MarbleLineEdit* parent ) :
49 m_clearButton( new QLabel( parent ) ), m_decoratorButton( new QLabel( parent ) ),
50 m_currentFrame( 0 ), m_iconSize( 16 )
51{
52 m_clearButton->setCursor( Qt::ArrowCursor );
53 m_clearButton->setToolTip( QObject::tr( "Clear" ) );
54 m_decoratorButton->setCursor( Qt::ArrowCursor );
55 createProgressAnimation();
56 m_progressTimer.setInterval( 100 );
57 if ( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ) {
58 m_iconSize = 32;
59 }
60}
61
62void MarbleLineEditPrivate::createProgressAnimation()
63{
64 // Size parameters
65 qreal const h = m_iconSize / 2.0; // Half of the icon size
66 qreal const q = h / 2.0; // Quarter of the icon size
67 qreal const d = 7.5; // Circle diameter
68 qreal const r = d / 2.0; // Circle radius
69
70 // Canvas parameters
71 QImage canvas( m_iconSize, m_iconSize, QImage::Format_ARGB32 );
72 QPainter painter( &canvas );
73 painter.setRenderHint( QPainter::Antialiasing, true );
74 painter.setPen( QColor ( Qt::gray ) );
75 painter.setBrush( QColor( Qt::white ) );
76
77 // Create all frames
78 for( double t = 0.0; t < 2 * M_PI; t += M_PI / 8.0 ) {
79 canvas.fill( Qt::transparent );
80 QRectF firstCircle( h - r + q * cos( t ), h - r + q * sin( t ), d, d );
81 QRectF secondCircle( h - r + q * cos( t + M_PI ), h - r + q * sin( t + M_PI ), d, d );
82 painter.drawEllipse( firstCircle );
83 painter.drawEllipse( secondCircle );
84 m_progressAnimation.push_back( QPixmap::fromImage( canvas ) );
85 }
86}
87
88MarbleLineEdit::MarbleLineEdit( QWidget *parent ) :
89 QLineEdit( parent ), d( new MarbleLineEditPrivate( this ) )
90{
91 updateClearButtonIcon( text() );
92 updateClearButton();
93
94 setDecorator( d->m_decoratorPixmap );
96 SLOT(updateClearButtonIcon(QString)) );
97 connect( &d->m_progressTimer, SIGNAL(timeout()),
98 this, SLOT(updateProgress()) );
99}
100
102{
103 delete d;
104}
105
106void MarbleLineEdit::setDecorator(const QPixmap &decorator)
107{
108 d->m_decoratorPixmap = decorator;
109 d->m_decoratorButton->setPixmap( d->m_decoratorPixmap );
110 int const padding = 2 + d->m_decoratorPixmap.width();
111
112 QString const prefixDirection = layoutDirection() == Qt::LeftToRight ? "left" : "right";
114 if ( !d->m_decoratorPixmap.isNull() ) {
115 decoratorStyleSheet = QString( "; padding-%1: %2" ).arg( prefixDirection ).arg( padding );
116 }
117 // Padding for clear button to avoid text underflow
118 QString const postfixDirection = layoutDirection() == Qt::LeftToRight ? "right" : "left";
119 QString styleSheet = QString( ":enabled { padding-%1: %2; %3}").arg( postfixDirection ).arg( padding ).arg( decoratorStyleSheet );
120
121 bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
122 if ( !smallScreen ) {
124 }
125}
126
127void MarbleLineEdit::setBusy(bool busy)
128{
129 if ( busy ) {
130 d->m_progressTimer.start();
131 } else {
132 d->m_progressTimer.stop();
133 d->m_decoratorButton->setPixmap( d->m_decoratorPixmap );
134 }
135}
136
137void MarbleLineEdit::updateClearButtonIcon( const QString& text )
138{
139 d->m_clearButton->setVisible( text.length() > 0 );
140 if ( d->m_clearButton->pixmap() && !d->m_clearButton->pixmap()->isNull() ) {
141 return;
142 }
143
144 QString const direction = layoutDirection() == Qt::LeftToRight ? "rtl" : "ltr";
145 int const size = (MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen) ? 32 : 16;
146 QPixmap pixmap = QPixmap(QStringLiteral(":/icons/%1x%1/edit-clear-locationbar-%2.png").arg(size).arg(direction));
147 d->m_clearButton->setPixmap( pixmap );
148}
149
150void MarbleLineEdit::updateClearButton()
151{
152 const QSize geom = size();
153 const int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth, nullptr, this );
154 const int pixmapSize = d->m_clearButton->pixmap()->width() + 1;
155 const int decoratorSize = d->m_decoratorPixmap.width() + 1;
156
157 int y = ( geom.height() - pixmapSize ) / 2;
158 if ( layoutDirection() == Qt::LeftToRight ) {
159 d->m_clearButton->move( geom.width() - frameWidth - pixmapSize - decoratorSize, y );
160 d->m_decoratorButton->move( frameWidth - decoratorSize + 1, y );
161 } else {
162 d->m_clearButton->move( frameWidth - decoratorSize + 1, y );
163 d->m_decoratorButton->move( geom.width() - frameWidth - pixmapSize - decoratorSize, y );
164 }
165}
166
167void MarbleLineEdit::updateProgress()
168{
169 if ( !d->m_progressAnimation.isEmpty() ) {
170 d->m_currentFrame = ( d->m_currentFrame + 1 ) % d->m_progressAnimation.size();
171 QPixmap frame = d->m_progressAnimation[d->m_currentFrame];
172 d->m_decoratorButton->setPixmap( frame );
173 }
174}
175
176void MarbleLineEdit::mouseReleaseEvent( QMouseEvent* e )
177{
178 if ( d->m_clearButton == childAt( e->pos() ) ) {
180 if ( e->button() == Qt::MiddleButton ) {
182 setText( newText );
183 } else {
184 setSelection( 0, text().size() );
185 del();
187 }
189 }
190
191 if ( d->m_decoratorButton == childAt( e->pos() ) ) {
192 emit decoratorButtonClicked();
193 }
194
196}
197
198void MarbleLineEdit::resizeEvent( QResizeEvent * event )
199{
200 updateClearButton();
202}
203
204} // namespace Marble
205
206#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
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
QString tr(const char *sourceText, const char *disambiguation, int n)
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
Qt::MouseButton button() 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
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 Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.