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 <[email protected]>
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 
21 namespace Marble
22 {
23 
24 class MarbleLineEditPrivate
25 {
26 public:
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 
48 MarbleLineEditPrivate::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 
62 void 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 
88 MarbleLineEdit::MarbleLineEdit( QWidget *parent ) :
89  QLineEdit( parent ), d( new MarbleLineEditPrivate( this ) )
90 {
91  updateClearButtonIcon( text() );
92  updateClearButton();
93 
94  setDecorator( d->m_decoratorPixmap );
95  connect( this, SIGNAL(textChanged(QString)),
96  SLOT(updateClearButtonIcon(QString)) );
97  connect( &d->m_progressTimer, SIGNAL(timeout()),
98  this, SLOT(updateProgress()) );
99 }
100 
102 {
103  delete d;
104 }
105 
106 void 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";
113  QString decoratorStyleSheet;
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 
127 void 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 
137 void 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 
150 void 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 
167 void 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 
176 void MarbleLineEdit::mouseReleaseEvent( QMouseEvent* e )
177 {
178  if ( d->m_clearButton == childAt( e->pos() ) ) {
179  QString newText;
180  if ( e->button() == Qt::MiddleButton ) {
182  setText( newText );
183  } else {
184  setSelection( 0, text().size() );
185  del();
186  emit clearButtonClicked();
187  }
188  emit textChanged( newText );
189  }
190 
191  if ( d->m_decoratorButton == childAt( e->pos() ) ) {
192  emit decoratorButtonClicked();
193  }
194 
196 }
197 
198 void MarbleLineEdit::resizeEvent( QResizeEvent * event )
199 {
200  updateClearButton();
202 }
203 
204 } // namespace Marble
205 
206 #include "moc_MarbleLineEdit.cpp"
QPoint pos() const const
QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags)
Qt::MouseButton button() const const
void setSelection(int start, int length)
virtual void resizeEvent(QResizeEvent *event)
~MarbleLineEdit() override
Destructor.
int width() const const
MiddleButton
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual bool event(QEvent *e) override
virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
void del()
QClipboard * clipboard()
QStyle * style() const const
int height() const const
void clearButtonClicked()
The clear button was clicked with the left mouse button.
void textChanged(const QString &text)
ArrowCursor
QString text(QClipboard::Mode mode) const const
Binds a QML item to a specific geodetic location in screen coordinates.
PM_DefaultFrameWidth
virtual void mouseReleaseEvent(QMouseEvent *e) override
QWidget * childAt(int x, int y) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
LeftToRight
QString tr(const char *sourceText, const char *disambiguation, int n)
int width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 04:12:27 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.