-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New QgsFloatingWidget widget for easy creation of widgets which "float"
above a layout. Supports setting another widget as a anchor point for the widget, eg the floating widget could be set so that it's always placed to the top-right of the anchor widget.
- Loading branch information
1 parent
f85d24e
commit 5da2513
Showing
6 changed files
with
514 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
/*************************************************************************** | ||
qgsfloatingwidget.cpp | ||
--------------------- | ||
begin : April 2016 | ||
copyright : (C) Nyall Dawson | ||
email : nyall dot dawson at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgsfloatingwidget.h" | ||
#include <QEvent> | ||
|
||
|
||
// | ||
// QgsFloatingWidget | ||
// | ||
|
||
QgsFloatingWidget::QgsFloatingWidget( QWidget *parent ) | ||
: QWidget( parent ) | ||
, mAnchorWidget( nullptr ) | ||
, mParentEventFilter( nullptr ) | ||
, mAnchorEventFilter( nullptr ) | ||
, mFloatAnchorPoint( BottomMiddle ) | ||
, mAnchorWidgetAnchorPoint( TopMiddle ) | ||
{ | ||
if ( parent ) | ||
{ | ||
mParentEventFilter = new QgsFloatingWidgetEventFilter( parent ); | ||
parent->installEventFilter( mParentEventFilter ); | ||
connect( mParentEventFilter, SIGNAL( anchorPointChanged() ), this, SLOT( anchorPointChanged() ) ); | ||
} | ||
} | ||
|
||
void QgsFloatingWidget::setAnchorWidget( QWidget *widget ) | ||
{ | ||
// remove existing event filter | ||
if ( mAnchorWidget ) | ||
{ | ||
mAnchorWidget->removeEventFilter( mAnchorEventFilter ); | ||
delete mAnchorEventFilter; | ||
mAnchorEventFilter = nullptr; | ||
} | ||
|
||
mAnchorWidget = widget; | ||
if ( mAnchorWidget ) | ||
{ | ||
mAnchorEventFilter = new QgsFloatingWidgetEventFilter( mAnchorWidget ); | ||
mAnchorWidget->installEventFilter( mAnchorEventFilter ); | ||
connect( mAnchorEventFilter, SIGNAL( anchorPointChanged() ), this, SLOT( anchorPointChanged() ) ); | ||
} | ||
|
||
anchorPointChanged(); | ||
} | ||
|
||
QWidget *QgsFloatingWidget::anchorWidget() | ||
{ | ||
return mAnchorWidget; | ||
} | ||
|
||
void QgsFloatingWidget::showEvent( QShowEvent *e ) | ||
{ | ||
anchorPointChanged(); | ||
QWidget::showEvent( e ); | ||
} | ||
|
||
void QgsFloatingWidget::anchorPointChanged() | ||
{ | ||
if ( mAnchorWidget ) | ||
{ | ||
QPoint anchorWidgetOrigin; | ||
|
||
switch ( mAnchorWidgetAnchorPoint ) | ||
{ | ||
case TopLeft: | ||
anchorWidgetOrigin = QPoint( 0, 0 ); | ||
break; | ||
case TopMiddle: | ||
anchorWidgetOrigin = QPoint( mAnchorWidget->width() / 2, 0 ); | ||
break; | ||
case TopRight: | ||
anchorWidgetOrigin = QPoint( mAnchorWidget->width(), 0 ); | ||
break; | ||
case MiddleLeft: | ||
anchorWidgetOrigin = QPoint( 0, mAnchorWidget->height() / 2 ); | ||
break; | ||
case Middle: | ||
anchorWidgetOrigin = QPoint( mAnchorWidget->width() / 2, mAnchorWidget->height() / 2 ); | ||
break; | ||
case MiddleRight: | ||
anchorWidgetOrigin = QPoint( mAnchorWidget->width(), mAnchorWidget->height() / 2 ); | ||
break; | ||
case BottomLeft: | ||
anchorWidgetOrigin = QPoint( 0, mAnchorWidget->height() ); | ||
break; | ||
case BottomMiddle: | ||
anchorWidgetOrigin = QPoint( mAnchorWidget->width() / 2, mAnchorWidget->height() ); | ||
break; | ||
case BottomRight: | ||
anchorWidgetOrigin = QPoint( mAnchorWidget->width(), mAnchorWidget->height() ); | ||
break; | ||
} | ||
|
||
anchorWidgetOrigin = mAnchorWidget->mapTo( parentWidget(), anchorWidgetOrigin ); | ||
int anchorX = anchorWidgetOrigin.x(); | ||
int anchorY = anchorWidgetOrigin.y(); | ||
|
||
switch ( mFloatAnchorPoint ) | ||
{ | ||
case TopLeft: | ||
break; | ||
case TopMiddle: | ||
anchorX = anchorX - width() / 2; | ||
break; | ||
case TopRight: | ||
anchorX = anchorX - width(); | ||
break; | ||
case MiddleLeft: | ||
anchorY = anchorY - height() / 2; | ||
break; | ||
case Middle: | ||
anchorY = anchorY - height() / 2; | ||
anchorX = anchorX - width() / 2; | ||
break; | ||
case MiddleRight: | ||
anchorX = anchorX - width(); | ||
anchorY = anchorY - height() / 2; | ||
break; | ||
case BottomLeft: | ||
anchorY = anchorY - height(); | ||
break; | ||
case BottomMiddle: | ||
anchorX = anchorX - width() / 2; | ||
anchorY = anchorY - height(); | ||
break; | ||
case BottomRight: | ||
anchorX = anchorX - width(); | ||
anchorY = anchorY - height(); | ||
break; | ||
} | ||
|
||
// constrain x so that widget floats within parent widget | ||
anchorX = qBound( 0, anchorX, parentWidget()->width() - width() ); | ||
|
||
move( anchorX, anchorY ); | ||
} | ||
} | ||
|
||
// | ||
// QgsFloatingWidgetEventFilter | ||
// | ||
|
||
/// @cond PRIVATE | ||
QgsFloatingWidgetEventFilter::QgsFloatingWidgetEventFilter( QWidget *parent ) | ||
: QObject( parent ) | ||
{ | ||
|
||
} | ||
|
||
bool QgsFloatingWidgetEventFilter::eventFilter( QObject *object, QEvent *event ) | ||
{ | ||
Q_UNUSED( object ); | ||
switch ( event->type() ) | ||
{ | ||
case QEvent::Move: | ||
case QEvent::Resize: | ||
emit anchorPointChanged(); | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
|
||
///@endcond |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/*************************************************************************** | ||
qgsfloatingwidget.h | ||
------------------- | ||
begin : April 2016 | ||
copyright : (C) Nyall Dawson | ||
email : nyall dot dawson at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
#ifndef QGSFLOATINGWIDGET_H | ||
#define QGSFLOATINGWIDGET_H | ||
|
||
#include <QWidget> | ||
|
||
|
||
/** \ingroup gui | ||
* \class QgsFloatingWidget | ||
* A QWidget subclass for creating widgets which float outside of the normal Qt layout | ||
* system. Floating widgets use an "anchor widget" to determine how they are anchored | ||
* within their parent widget. | ||
* \note Added in version 2.16 | ||
*/ | ||
|
||
class GUI_EXPORT QgsFloatingWidget: public QWidget | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
|
||
//! Reference points for anchoring widget position | ||
enum AnchorPoint | ||
{ | ||
TopLeft, //!< Top-left of widget | ||
TopMiddle, //!< Top center of widget | ||
TopRight, //!< Top-right of widget | ||
MiddleLeft, //!< Middle left of widget | ||
Middle, //!< Middle of widget | ||
MiddleRight, //!< Middle right of widget | ||
BottomLeft, //!< Bottom-left of widget | ||
BottomMiddle, //!< Bottom center of widget | ||
BottomRight, //!< Bottom-right of widget | ||
}; | ||
|
||
QgsFloatingWidget( QWidget* parent = nullptr ); | ||
|
||
/** Sets the widget to "anchor" the floating widget to. The floating widget will be repositioned whenever the | ||
* anchor widget moves or is resized so that it maintains the same relative position to the anchor widget. | ||
* @param widget anchor widget. Both the floating widget and the anchor widget must share some common parent. | ||
* @see anchorWidget() | ||
*/ | ||
void setAnchorWidget( QWidget* widget ); | ||
|
||
/** Returns the widget that the floating widget is "anchored" tto. The floating widget will be repositioned whenever the | ||
* anchor widget moves or is resized so that it maintains the same relative position to the anchor widget. | ||
* @see setAnchorWidget() | ||
*/ | ||
QWidget* anchorWidget(); | ||
|
||
/** Returns the floating widget's anchor point, which corresponds to the point on the widget which should remain | ||
* fixed in the same relative position whenever the widget's parent is resized or moved. | ||
* @see setAnchorPoint() | ||
*/ | ||
AnchorPoint anchorPoint() const { return mFloatAnchorPoint; } | ||
|
||
/** Sets the floating widget's anchor point, which corresponds to the point on the widget which should remain | ||
* fixed in the same relative position whenever the widget's parent is resized or moved. | ||
* @param point anchor point | ||
* @see anchorPoint() | ||
*/ | ||
void setAnchorPoint( AnchorPoint point ) { mFloatAnchorPoint = point; anchorPointChanged(); } | ||
|
||
/** Returns the anchor widget's anchor point, which corresponds to the point on the anchor widget which | ||
* the floating widget should "attach" to. The floating widget should remain fixed in the same relative position | ||
* to this anchor widget whenever the widget's parent is resized or moved. | ||
* @see setAnchorWidgetPoint() | ||
*/ | ||
AnchorPoint anchorWidgetPoint() const { return mAnchorWidgetAnchorPoint; } | ||
|
||
/** Returns the anchor widget's anchor point, which corresponds to the point on the anchor widget which | ||
* the floating widget should "attach" to. The floating widget should remain fixed in the same relative position | ||
* to this anchor widget whenever the widget's parent is resized or moved. | ||
* @see setAnchorWidgetPoint() | ||
*/ | ||
void setAnchorWidgetPoint( AnchorPoint point ) { mAnchorWidgetAnchorPoint = point; anchorPointChanged(); } | ||
|
||
protected: | ||
void showEvent( QShowEvent* e ) override; | ||
|
||
private slots: | ||
|
||
//! Repositions the floating widget to a changed anchor point | ||
void anchorPointChanged(); | ||
|
||
private: | ||
|
||
QWidget* mAnchorWidget; | ||
QObject* mParentEventFilter; | ||
QObject* mAnchorEventFilter; | ||
AnchorPoint mFloatAnchorPoint; | ||
AnchorPoint mAnchorWidgetAnchorPoint; | ||
|
||
}; | ||
|
||
/// @cond PRIVATE | ||
|
||
class QgsFloatingWidgetEventFilter: public QObject | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
|
||
QgsFloatingWidgetEventFilter( QWidget* parent = nullptr ); | ||
|
||
virtual bool eventFilter( QObject* object, QEvent* event ) override; | ||
|
||
signals: | ||
|
||
//! Emitted when the filter's parent is moved or resized | ||
void anchorPointChanged(); | ||
|
||
}; | ||
|
||
/// @endcond | ||
|
||
#endif // QGSFLOATINGWIDGET_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.