File indexing completed on 2024-04-21 03:49:43
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // The code in this file is largely based on KDE's KLineEdit class 0004 // as included in KDE 4.5. See there for its authors: 0005 // https://api.kde.org/4.x-api/kdelibs-apidocs/kdeui/html/klineedit_8cpp.html 0006 // 0007 // SPDX-FileCopyrightText: 2010, 2012 Dennis Nienhüser <nienhueser@kde.org> 0008 // 0009 0010 #include "MarbleLineEdit.h" 0011 #include "MarbleGlobal.h" 0012 0013 #include <QApplication> 0014 #include <QClipboard> 0015 #include <QLabel> 0016 #include <QStyle> 0017 #include <QMouseEvent> 0018 #include <QPainter> 0019 #include <QTimer> 0020 0021 namespace Marble 0022 { 0023 0024 class MarbleLineEditPrivate 0025 { 0026 public: 0027 QLabel* m_clearButton; 0028 0029 QLabel* m_decoratorButton; 0030 0031 QPixmap m_clearPixmap; 0032 0033 QPixmap m_decoratorPixmap; 0034 0035 QTimer m_progressTimer; 0036 0037 QVector<QPixmap> m_progressAnimation; 0038 0039 int m_currentFrame; 0040 0041 int m_iconSize; 0042 0043 explicit MarbleLineEditPrivate( MarbleLineEdit* parent ); 0044 0045 void createProgressAnimation(); 0046 }; 0047 0048 MarbleLineEditPrivate::MarbleLineEditPrivate( MarbleLineEdit* parent ) : 0049 m_clearButton( new QLabel( parent ) ), m_decoratorButton( new QLabel( parent ) ), 0050 m_currentFrame( 0 ), m_iconSize( 16 ) 0051 { 0052 m_clearButton->setCursor( Qt::ArrowCursor ); 0053 m_clearButton->setToolTip( QObject::tr( "Clear" ) ); 0054 m_decoratorButton->setCursor( Qt::ArrowCursor ); 0055 createProgressAnimation(); 0056 m_progressTimer.setInterval( 100 ); 0057 if ( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ) { 0058 m_iconSize = 32; 0059 } 0060 } 0061 0062 void MarbleLineEditPrivate::createProgressAnimation() 0063 { 0064 // Size parameters 0065 qreal const h = m_iconSize / 2.0; // Half of the icon size 0066 qreal const q = h / 2.0; // Quarter of the icon size 0067 qreal const d = 7.5; // Circle diameter 0068 qreal const r = d / 2.0; // Circle radius 0069 0070 // Canvas parameters 0071 QImage canvas( m_iconSize, m_iconSize, QImage::Format_ARGB32 ); 0072 QPainter painter( &canvas ); 0073 painter.setRenderHint( QPainter::Antialiasing, true ); 0074 painter.setPen( QColor ( Qt::gray ) ); 0075 painter.setBrush( QColor( Qt::white ) ); 0076 0077 // Create all frames 0078 for( double t = 0.0; t < 2 * M_PI; t += M_PI / 8.0 ) { 0079 canvas.fill( Qt::transparent ); 0080 QRectF firstCircle( h - r + q * cos( t ), h - r + q * sin( t ), d, d ); 0081 QRectF secondCircle( h - r + q * cos( t + M_PI ), h - r + q * sin( t + M_PI ), d, d ); 0082 painter.drawEllipse( firstCircle ); 0083 painter.drawEllipse( secondCircle ); 0084 m_progressAnimation.push_back( QPixmap::fromImage( canvas ) ); 0085 } 0086 } 0087 0088 MarbleLineEdit::MarbleLineEdit( QWidget *parent ) : 0089 QLineEdit( parent ), d( new MarbleLineEditPrivate( this ) ) 0090 { 0091 updateClearButtonIcon( text() ); 0092 updateClearButton(); 0093 0094 setDecorator( d->m_decoratorPixmap ); 0095 connect( this, SIGNAL(textChanged(QString)), 0096 SLOT(updateClearButtonIcon(QString)) ); 0097 connect( &d->m_progressTimer, SIGNAL(timeout()), 0098 this, SLOT(updateProgress()) ); 0099 } 0100 0101 MarbleLineEdit::~MarbleLineEdit() 0102 { 0103 delete d; 0104 } 0105 0106 void MarbleLineEdit::setDecorator(const QPixmap &decorator) 0107 { 0108 d->m_decoratorPixmap = decorator; 0109 d->m_decoratorButton->setPixmap( d->m_decoratorPixmap ); 0110 int const padding = 2 + d->m_decoratorPixmap.width(); 0111 0112 QString const prefixDirection = layoutDirection() == Qt::LeftToRight ? "left" : "right"; 0113 QString decoratorStyleSheet; 0114 if ( !d->m_decoratorPixmap.isNull() ) { 0115 decoratorStyleSheet = QString( "; padding-%1: %2" ).arg( prefixDirection ).arg( padding ); 0116 } 0117 // Padding for clear button to avoid text underflow 0118 QString const postfixDirection = layoutDirection() == Qt::LeftToRight ? "right" : "left"; 0119 QString styleSheet = QString( ":enabled { padding-%1: %2; %3}").arg( postfixDirection ).arg( padding ).arg( decoratorStyleSheet ); 0120 0121 bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; 0122 if ( !smallScreen ) { 0123 setStyleSheet( styleSheet ); 0124 } 0125 } 0126 0127 void MarbleLineEdit::setBusy(bool busy) 0128 { 0129 if ( busy ) { 0130 d->m_progressTimer.start(); 0131 } else { 0132 d->m_progressTimer.stop(); 0133 d->m_decoratorButton->setPixmap( d->m_decoratorPixmap ); 0134 } 0135 } 0136 0137 void MarbleLineEdit::updateClearButtonIcon( const QString& text ) 0138 { 0139 d->m_clearButton->setVisible( text.length() > 0 ); 0140 if ( d->m_clearButton->pixmap() && !d->m_clearButton->pixmap()->isNull() ) { 0141 return; 0142 } 0143 0144 QString const direction = layoutDirection() == Qt::LeftToRight ? "rtl" : "ltr"; 0145 int const size = (MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen) ? 32 : 16; 0146 QPixmap pixmap = QPixmap(QStringLiteral(":/icons/%1x%1/edit-clear-locationbar-%2.png").arg(size).arg(direction)); 0147 d->m_clearButton->setPixmap( pixmap ); 0148 } 0149 0150 void MarbleLineEdit::updateClearButton() 0151 { 0152 const QSize geom = size(); 0153 const int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth, nullptr, this ); 0154 const int pixmapSize = d->m_clearButton->pixmap()->width() + 1; 0155 const int decoratorSize = d->m_decoratorPixmap.width() + 1; 0156 0157 int y = ( geom.height() - pixmapSize ) / 2; 0158 if ( layoutDirection() == Qt::LeftToRight ) { 0159 d->m_clearButton->move( geom.width() - frameWidth - pixmapSize - decoratorSize, y ); 0160 d->m_decoratorButton->move( frameWidth - decoratorSize + 1, y ); 0161 } else { 0162 d->m_clearButton->move( frameWidth - decoratorSize + 1, y ); 0163 d->m_decoratorButton->move( geom.width() - frameWidth - pixmapSize - decoratorSize, y ); 0164 } 0165 } 0166 0167 void MarbleLineEdit::updateProgress() 0168 { 0169 if ( !d->m_progressAnimation.isEmpty() ) { 0170 d->m_currentFrame = ( d->m_currentFrame + 1 ) % d->m_progressAnimation.size(); 0171 QPixmap frame = d->m_progressAnimation[d->m_currentFrame]; 0172 d->m_decoratorButton->setPixmap( frame ); 0173 } 0174 } 0175 0176 void MarbleLineEdit::mouseReleaseEvent( QMouseEvent* e ) 0177 { 0178 if ( d->m_clearButton == childAt( e->pos() ) ) { 0179 QString newText; 0180 if ( e->button() == Qt::MiddleButton ) { 0181 newText = QApplication::clipboard()->text( QClipboard::Selection ); 0182 setText( newText ); 0183 } else { 0184 setSelection( 0, text().size() ); 0185 del(); 0186 emit clearButtonClicked(); 0187 } 0188 emit textChanged( newText ); 0189 } 0190 0191 if ( d->m_decoratorButton == childAt( e->pos() ) ) { 0192 emit decoratorButtonClicked(); 0193 } 0194 0195 QLineEdit::mouseReleaseEvent( e ); 0196 } 0197 0198 void MarbleLineEdit::resizeEvent( QResizeEvent * event ) 0199 { 0200 updateClearButton(); 0201 QLineEdit::resizeEvent( event ); 0202 } 0203 0204 } // namespace Marble 0205 0206 #include "moc_MarbleLineEdit.cpp"