Skip to content
Permalink
Browse files

Rework QgsFilterLineEdit handling of clear button

Don't use a child button but instead paint the icon when
required. Improves interaction with the widget/clear
button.
  • Loading branch information
nyalldawson committed Sep 6, 2016
1 parent e1f21b0 commit 98f25f59e72992d29279bcba9dbba53c5598b2fe
@@ -666,6 +666,8 @@
<file>themes/default/mIconFormSelect.svg</file>
<file>themes/default/mActionMultiEdit.svg</file>
<file>themes/default/dependencies.svg</file>
<file>themes/default/mIconClearText.svg</file>
<file>themes/default/mIconClearTextHover.svg</file>
</qresource>
<qresource prefix="/images/tips">
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
height="16"
width="16"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="mIconClearText.svg">
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1215"
inkscape:window-height="776"
id="namedview8"
showgrid="true"
inkscape:zoom="23.6"
inkscape:cx="2.2245763"
inkscape:cy="8.3898305"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg2">
<inkscape:grid
type="xygrid"
id="grid4138" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#969696;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 4.6303139,3 1,8 4.6303139,13 14,13 14,3 13.824245,3 Z"
id="path2999"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
d="M 5.9226862,10.69629 11.701082,5.2732861"
id="path3775" />
<path
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
d="M 5.9226862,5.2732861 11.701082,10.69629"
id="path3777" />
</svg>
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
height="16"
width="16"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="mIconClearTextHover.svg">
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1215"
inkscape:window-height="776"
id="namedview8"
showgrid="true"
inkscape:zoom="23.6"
inkscape:cx="2.2245763"
inkscape:cy="8.3898305"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg2">
<inkscape:grid
type="xygrid"
id="grid4138" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 4.6303139,3 1,8 4.6303139,13 14,13 14,3 13.824245,3 Z"
id="path2999"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
d="M 5.9226862,10.69629 11.701082,5.2732861"
id="path3775" />
<path
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
d="M 5.9226862,5.2732861 11.701082,10.69629"
id="path3777" />
</svg>
@@ -46,8 +46,8 @@ class QgsFilterLineEdit : QLineEdit

protected:
void mousePressEvent( QMouseEvent* e );
void mouseMoveEvent( QMouseEvent* e );
void focusInEvent( QFocusEvent* e );
void resizeEvent( QResizeEvent* e );
void changeEvent( QEvent* e );
void paintEvent( QPaintEvent* e );
void leaveEvent( QEvent* e );
};
@@ -21,31 +21,30 @@
#include <QToolButton>
#include <QStyle>
#include <QFocusEvent>
#include <QPainter>

QgsFilterLineEdit::QgsFilterLineEdit( QWidget* parent, const QString& nullValue )
: QLineEdit( parent )
, mNullValue( nullValue )
, mFocusInEvent( false )
, mClearHover( false )
{
btnClear = new QToolButton( this );
btnClear->setIcon( QgsApplication::getThemeIcon( "/mIconClear.svg" ) );
btnClear->setCursor( Qt::ArrowCursor );
btnClear->setFocusPolicy( Qt::NoFocus );
btnClear->setStyleSheet( "QToolButton { border: none; padding: 0px; }" );
btnClear->hide();

connect( btnClear, SIGNAL( clicked() ), this, SLOT( clear() ) );
connect( btnClear, SIGNAL( clicked() ), this, SIGNAL( cleared() ) );
// need mouse tracking to handle cursor changes
setMouseTracking( true );

QIcon clearIcon = QgsApplication::getThemeIcon( "/mIconClearText.svg" );
mClearIconSize = QSize( 16, 16 );
mClearIconPixmap = clearIcon.pixmap( mClearIconSize );
QIcon hoverIcon = QgsApplication::getThemeIcon( "/mIconClearTextHover.svg" );
mClearHoverPixmap = hoverIcon.pixmap( mClearIconSize );

connect( this, SIGNAL( textChanged( const QString& ) ), this,
SLOT( onTextChanged( const QString& ) ) );

int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
mStyleSheet = QString( "QLineEdit { padding-right: %1px; } " )
.arg( btnClear->sizeHint().width() + frameWidth + 1 );

QSize msz = minimumSizeHint();
setMinimumSize( qMax( msz.width(), btnClear->sizeHint().height() + frameWidth * 2 + 2 ),
qMax( msz.height(), btnClear->sizeHint().height() + frameWidth * 2 + 2 ) );
setMinimumSize( qMax( msz.width(), mClearIconSize.width() + frameWidth * 2 + 2 ),
qMax( msz.height(), mClearIconSize.height() + frameWidth * 2 + 2 ) );
}

void QgsFilterLineEdit::mousePressEvent( QMouseEvent* e )
@@ -54,6 +53,32 @@ void QgsFilterLineEdit::mousePressEvent( QMouseEvent* e )
QLineEdit::mousePressEvent( e );
else
mFocusInEvent = false;

if ( shouldShowClear() && clearRect().contains( e->pos() ) )
{
clear();
emit cleared();
}
}

void QgsFilterLineEdit::mouseMoveEvent( QMouseEvent* e )
{
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();
}
}

void QgsFilterLineEdit::focusInEvent( QFocusEvent* e )
@@ -66,37 +91,39 @@ void QgsFilterLineEdit::focusInEvent( QFocusEvent* e )
}
}

void QgsFilterLineEdit::resizeEvent( QResizeEvent * )
{
QSize sz = btnClear->sizeHint();
int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
btnClear->move( rect().right() - frameWidth - sz.width(),
( rect().bottom() + 1 - sz.height() ) / 2 );
}

void QgsFilterLineEdit::clear()
{
setText( mNullValue );
setModified( true );
}

void QgsFilterLineEdit::changeEvent( QEvent *e )
{
QLineEdit::changeEvent( e );
btnClear->setVisible( isEnabled() && !isReadOnly() && !isNull() );
}

void QgsFilterLineEdit::paintEvent( QPaintEvent* e )
{
QLineEdit::paintEvent( e );
btnClear->setVisible( isEnabled() && !isReadOnly() && !isNull() );
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 );
}
}

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

QLineEdit::leaveEvent( e );
}

void QgsFilterLineEdit::onTextChanged( const QString &text )
{
btnClear->setVisible( isEnabled() && !isReadOnly() && !isNull() );

if ( isNull() )
{
setStyleSheet( QString( "QLineEdit { font: italic; color: gray; } %1" ).arg( mStyleSheet ) );
@@ -108,3 +135,17 @@ void QgsFilterLineEdit::onTextChanged( const QString &text )
emit valueChanged( text );
}
}

bool QgsFilterLineEdit::shouldShowClear() const
{
return isEnabled() && !isReadOnly() && !isNull();
}

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() );
}
@@ -70,20 +70,29 @@ class GUI_EXPORT QgsFilterLineEdit : public QLineEdit

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

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

private:
QString mNullValue;
QToolButton *btnClear;
QString mStyleSheet;
bool mFocusInEvent;
bool mClearHover;

QSize mClearIconSize;
QPixmap mClearIconPixmap;
QPixmap mClearHoverPixmap;

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

QRect clearRect() const;
};

#endif // QGSFILTERLINEEDIT_H

0 comments on commit 98f25f5

Please sign in to comment.
You can’t perform that action at this time.