Skip to content

Commit

Permalink
[QgsFilterLineEdit] use QLineEdit::addAction instead of hacking paint…
Browse files Browse the repository at this point in the history
…Event

this gets much more simple
  • Loading branch information
3nids committed Jan 16, 2018
1 parent d1a922b commit 9bf943a
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 169 deletions.
8 changes: 0 additions & 8 deletions python/gui/qgsfilterlineedit.sip
Original file line number Diff line number Diff line change
Expand Up @@ -257,16 +257,8 @@ Will select all text when this widget receives the focus.
%End

protected:
virtual void mousePressEvent( QMouseEvent *e );

virtual void mouseMoveEvent( QMouseEvent *e );

virtual void focusInEvent( QFocusEvent *e );

virtual void paintEvent( QPaintEvent *e );

virtual void leaveEvent( QEvent *e );


};

Expand Down
176 changes: 31 additions & 145 deletions src/gui/qgsfilterlineedit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "qgsapplication.h"
#include "qgsanimatedicon.h"

#include <QAction>
#include <QToolButton>
#include <QStyle>
#include <QFocusEvent>
Expand All @@ -28,84 +29,42 @@ QgsFilterLineEdit::QgsFilterLineEdit( QWidget *parent, const QString &nullValue
: QLineEdit( parent )
, mNullValue( nullValue )
{
// need mouse tracking to handle cursor changes
setMouseTracking( true );

QIcon clearIcon = QgsApplication::getThemeIcon( "/mIconClearText.svg" );

// icon size is about 2/3 height of text, but minimum size of 16
int iconSize = std::floor( std::max( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 0.75, 16.0 ) );

mClearIconSize = QSize( iconSize, iconSize );
mClearIconPixmap = clearIcon.pixmap( mClearIconSize );
QIcon hoverIcon = QgsApplication::getThemeIcon( "/mIconClearTextHover.svg" );
mClearHoverPixmap = hoverIcon.pixmap( mClearIconSize );
QIcon clearIcon;
clearIcon.addPixmap( QgsApplication::getThemeIcon( "/mIconClearText.svg" ).pixmap( QSize( iconSize, iconSize ) ), QIcon::Normal, QIcon::On );
clearIcon.addPixmap( QgsApplication::getThemeIcon( "/mIconClearTextHover.svg" ).pixmap( QSize( iconSize, iconSize ) ), QIcon::Selected, QIcon::On );
mClearAction = new QAction( clearIcon, this );
mClearAction->setCheckable( false );
addAction( mClearAction, QLineEdit::TrailingPosition );
connect( mClearAction, &QAction::triggered, this, &QgsFilterLineEdit::clearValue );

QIcon searchIcon = QgsApplication::getThemeIcon( "/search.svg" );
mSearchIconSize = QSize( iconSize, iconSize );
mSearchIconPixmap = searchIcon.pixmap( mSearchIconSize );

// Make some space for the clear icon
QMargins margins( textMargins( ) );
margins.setRight( iconSize );
setTextMargins( margins );
mSearchAction = new QAction( searchIcon, this );
mSearchAction->setCheckable( false );
addAction( mSearchAction, QLineEdit::TrailingPosition );
mSearchAction->setVisible( false );

connect( this, &QLineEdit::textChanged, this,
&QgsFilterLineEdit::onTextChanged );
}

void QgsFilterLineEdit::setShowClearButton( bool visible )
{
bool changed = mClearButtonVisible != visible;
mClearButtonVisible = visible;
if ( !visible )
mClearHover = false;

if ( changed )
update();
updateClearIcon();
}

void QgsFilterLineEdit::setShowSearchIcon( bool visible )
{
bool changed = mSearchIconVisible != visible;
if ( changed )
{
mSearchIconVisible = visible;
update();
}
}

void QgsFilterLineEdit::mousePressEvent( QMouseEvent *e )
{
if ( !mFocusInEvent )
QLineEdit::mousePressEvent( e );
else
mFocusInEvent = false;

if ( shouldShowClear() && clearRect().contains( e->pos() ) )
{
clearValue();
}
mSearchIconVisible = visible;
mSearchAction->setVisible( visible );
}

void QgsFilterLineEdit::mouseMoveEvent( QMouseEvent *e )
void QgsFilterLineEdit::updateClearIcon()
{
QLineEdit::mouseMoveEvent( e );
if ( shouldShowClear() && clearRect().contains( e->pos() ) )
{
if ( !mClearHover )
{
setCursor( Qt::ArrowCursor );
mClearHover = true;
update();
}
}
else if ( mClearHover )
{
setCursor( Qt::IBeamCursor );
mClearHover = false;
update();
}
mClearAction->setVisible( shouldShowClear() );
}

void QgsFilterLineEdit::focusInEvent( QFocusEvent *e )
Expand All @@ -132,57 +91,14 @@ void QgsFilterLineEdit::clearValue()
break;
}

if ( mClearHover )
{
setCursor( Qt::IBeamCursor );
mClearHover = false;
}

setModified( true );
emit cleared();
}

void QgsFilterLineEdit::paintEvent( QPaintEvent *e )
{
QLineEdit::paintEvent( e );
if ( shouldShowClear() )
{
QRect r = clearRect();
QPainter p( this );
if ( mClearHover )
p.drawPixmap( r.left(), r.top(), mClearHoverPixmap );
else
p.drawPixmap( r.left(), r.top(), mClearIconPixmap );
}

if ( mSearchIconVisible && !shouldShowClear() )
{
QRect r = searchRect();
QPainter p( this );
p.drawPixmap( r.left(), r.top(), mSearchIconPixmap );
}

if ( mShowSpinner )
{
QRect r = busySpinnerRect();
QPainter p( this );
p.drawPixmap( r.left(), r.top(), mBusySpinner->icon().pixmap( r.size() ) );
}
}

void QgsFilterLineEdit::leaveEvent( QEvent *e )
{
if ( mClearHover )
{
mClearHover = false;
update();
}

QLineEdit::leaveEvent( e );
}

void QgsFilterLineEdit::onTextChanged( const QString &text )
{
updateClearIcon();

if ( isNull() )
{
setStyleSheet( QStringLiteral( "QLineEdit { font: italic; color: gray; } %1" ).arg( mStyleSheet ) );
Expand All @@ -193,17 +109,15 @@ void QgsFilterLineEdit::onTextChanged( const QString &text )
setStyleSheet( mStyleSheet );
emit valueChanged( text );
}

if ( mClearHover && !shouldShowClear() )
{
setCursor( Qt::IBeamCursor );
mClearHover = false;
}
}

void QgsFilterLineEdit::updateBusySpinner()
{
update();
if ( !mBusySpinnerAction )
{
mBusySpinnerAction = addAction( mBusySpinnerAnimatedIcon->icon(), QLineEdit::TrailingPosition );
}
mBusySpinnerAction->setIcon( mBusySpinnerAnimatedIcon->icon() );
}

bool QgsFilterLineEdit::selectOnFocus() const
Expand All @@ -227,20 +141,22 @@ bool QgsFilterLineEdit::showSpinner() const

void QgsFilterLineEdit::setShowSpinner( bool showSpinner )
{

if ( showSpinner == mShowSpinner )
return;

if ( showSpinner )
{
if ( !mBusySpinner )
mBusySpinner = new QgsAnimatedIcon( QgsApplication::iconPath( QStringLiteral( "/mIconLoading.gif" ) ), this );
if ( !mBusySpinnerAnimatedIcon )
mBusySpinnerAnimatedIcon = new QgsAnimatedIcon( QgsApplication::iconPath( QStringLiteral( "/mIconLoading.gif" ) ), this );

mBusySpinner->connectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
mBusySpinnerAnimatedIcon->connectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
}
else
{
mBusySpinner->disconnectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
update();
mBusySpinnerAnimatedIcon->disconnectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
removeAction( mBusySpinnerAction );
mBusySpinnerAction = nullptr;
}

mShowSpinner = showSpinner;
Expand All @@ -262,33 +178,3 @@ bool QgsFilterLineEdit::shouldShowClear() const
}
return false; //avoid warnings
}

QRect QgsFilterLineEdit::clearRect() const
{
int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
return QRect( rect().right() - frameWidth * 2 - mClearIconSize.width(),
( rect().bottom() + 1 - mClearIconSize.height() ) / 2,
mClearIconSize.width(),
mClearIconSize.height() );
}

QRect QgsFilterLineEdit::busySpinnerRect() const
{
int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );

int offset = shouldShowClear() ? mClearIconSize.width() + frameWidth * 2 : frameWidth;

return QRect( rect().right() - offset - mClearIconSize.width(),
( rect().bottom() + 1 - mClearIconSize.height() ) / 2,
mClearIconSize.width(),
mClearIconSize.height() );
}

QRect QgsFilterLineEdit::searchRect() const
{
int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
return QRect( rect().left() + frameWidth * 2,
( rect().bottom() + 1 - mSearchIconSize.height() ) / 2,
mSearchIconSize.width(),
mSearchIconSize.height() );
}
21 changes: 5 additions & 16 deletions src/gui/qgsfilterlineedit.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,17 +254,17 @@ class GUI_EXPORT QgsFilterLineEdit : public QLineEdit
void selectOnFocusChanged();

protected:
void mousePressEvent( QMouseEvent *e ) override;
void mouseMoveEvent( QMouseEvent *e ) override;
void focusInEvent( QFocusEvent *e ) override;
void paintEvent( QPaintEvent *e ) override;
void leaveEvent( QEvent *e ) override;

private slots:
void onTextChanged( const QString &text );
void updateBusySpinner();
void updateClearIcon();

private:
QAction *mClearAction;
QAction *mSearchAction;
QAction *mBusySpinnerAction = nullptr;

bool mClearButtonVisible = true;
bool mSearchIconVisible = false;
Expand All @@ -276,23 +276,12 @@ class GUI_EXPORT QgsFilterLineEdit : public QLineEdit
QString mDefaultValue;
QString mStyleSheet;
bool mFocusInEvent = false;
bool mClearHover = false;
bool mSelectOnFocus = false;

QSize mClearIconSize;
QPixmap mClearIconPixmap;
QPixmap mClearHoverPixmap;

QSize mSearchIconSize;
QPixmap mSearchIconPixmap;
QgsAnimatedIcon *mBusySpinner = nullptr;
QgsAnimatedIcon *mBusySpinnerAnimatedIcon = nullptr;

//! Returns true if clear button should be shown
bool shouldShowClear() const;

QRect clearRect() const;
QRect searchRect() const;
QRect busySpinnerRect() const;
};

/// @cond PRIVATE
Expand Down

0 comments on commit 9bf943a

Please sign in to comment.