mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-23 22:25:55 +00:00
Move tooltip handling from RDTreeWidget to RDTreeView
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QDesktopWidget>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
@@ -35,7 +36,6 @@
|
||||
#include <QScrollBar>
|
||||
#include <QStack>
|
||||
#include <QStylePainter>
|
||||
#include <QToolTip>
|
||||
#include <QWheelEvent>
|
||||
#include "Code/QRDUtils.h"
|
||||
#include "Code/Resources.h"
|
||||
@@ -132,6 +132,19 @@ RDTipLabel::RDTipLabel(QWidget *listener) : QLabel(NULL), mouseListener(listener
|
||||
setWindowOpacity(opacity / 255.0);
|
||||
}
|
||||
|
||||
QSize RDTipLabel::getSizeForTip(QString text)
|
||||
{
|
||||
setText(text);
|
||||
return sizeHint();
|
||||
}
|
||||
|
||||
void RDTipLabel::showTip(QPoint pos, QString text)
|
||||
{
|
||||
move(pos);
|
||||
setText(text);
|
||||
show();
|
||||
}
|
||||
|
||||
void RDTipLabel::paintEvent(QPaintEvent *ev)
|
||||
{
|
||||
QStylePainter p(this);
|
||||
@@ -187,23 +200,72 @@ RDTreeView::RDTreeView(QWidget *parent) : QTreeView(parent)
|
||||
m_delegate = new RDTreeViewDelegate(this);
|
||||
QTreeView::setItemDelegate(m_delegate);
|
||||
|
||||
m_ElidedTooltip = new RDTipLabel(viewport());
|
||||
m_ElidedTooltip->hide();
|
||||
m_TooltipLabel = new RDTipLabel(viewport());
|
||||
m_TooltipLabel->hide();
|
||||
m_CurrentTooltipElided = false;
|
||||
|
||||
m_Tooltip = m_TooltipLabel;
|
||||
}
|
||||
|
||||
RDTreeView::~RDTreeView()
|
||||
{
|
||||
setModel(NULL);
|
||||
|
||||
delete m_ElidedTooltip;
|
||||
delete m_TooltipLabel;
|
||||
}
|
||||
|
||||
void RDTreeView::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
if(m_ElidedTooltip->isVisible() && !m_ElidedTooltip->geometry().contains(QCursor::pos()))
|
||||
m_ElidedTooltip->hide();
|
||||
QModelIndex oldHoverIndex = m_currentHoverIndex;
|
||||
|
||||
if(m_CurrentTooltipElided && m_TooltipLabel->isVisible() &&
|
||||
!m_TooltipLabel->geometry().contains(QCursor::pos()))
|
||||
m_Tooltip->hideTip();
|
||||
|
||||
m_currentHoverIndex = indexAt(e->pos());
|
||||
|
||||
if(oldHoverIndex != m_currentHoverIndex)
|
||||
{
|
||||
if(m_instantTooltips)
|
||||
{
|
||||
m_Tooltip->hideTip();
|
||||
|
||||
if(m_currentHoverIndex.isValid())
|
||||
{
|
||||
QString tooltip = m_currentHoverIndex.data(Qt::ToolTipRole).toString();
|
||||
|
||||
if(!tooltip.isEmpty())
|
||||
{
|
||||
// We don't use QToolTip since we have a custom tooltip for showing elided results, and we
|
||||
// use that for consistency. This also makes it easier to slot in a custom tooltip widget
|
||||
// externally.
|
||||
QPoint p = QCursor::pos();
|
||||
|
||||
// estimate, as this is not easily queryable
|
||||
const QPoint cursorSize(16, 16);
|
||||
const QRect screenAvailGeom = QApplication::desktop()->availableGeometry(p);
|
||||
|
||||
// start with the tooltip placed bottom-right of the cursor, as the default
|
||||
QRect tooltipRect;
|
||||
tooltipRect.setTopLeft(p + cursorSize);
|
||||
tooltipRect.setSize(m_Tooltip->getSizeForTip(tooltip));
|
||||
|
||||
// clip by the available geometry in x
|
||||
if(tooltipRect.right() > screenAvailGeom.right())
|
||||
tooltipRect.moveRight(screenAvailGeom.right());
|
||||
|
||||
// if we'd go out of bounds in y, place the tooltip above the cursor. Don't just clip like
|
||||
// in x, because that could place the tooltip over the cursor.
|
||||
if(tooltipRect.bottom() > screenAvailGeom.bottom())
|
||||
tooltipRect.moveBottom(p.y() - cursorSize.y());
|
||||
|
||||
m_Tooltip->showTip(tooltipRect.topLeft(), tooltip);
|
||||
m_CurrentTooltipElided = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QTreeView::mouseMoveEvent(e);
|
||||
}
|
||||
|
||||
@@ -215,8 +277,15 @@ void RDTreeView::wheelEvent(QWheelEvent *e)
|
||||
|
||||
void RDTreeView::leaveEvent(QEvent *e)
|
||||
{
|
||||
if(m_ElidedTooltip->isVisible() && !m_ElidedTooltip->geometry().contains(QCursor::pos()))
|
||||
m_ElidedTooltip->hide();
|
||||
if(m_CurrentTooltipElided)
|
||||
{
|
||||
if(m_TooltipLabel->isVisible() && !m_TooltipLabel->geometry().contains(QCursor::pos()))
|
||||
m_Tooltip->hideTip();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Tooltip->hideTip();
|
||||
}
|
||||
|
||||
m_currentHoverIndex = QModelIndex();
|
||||
|
||||
@@ -306,40 +375,48 @@ void RDTreeView::collapseAll(QModelIndex index)
|
||||
|
||||
bool RDTreeView::viewportEvent(QEvent *event)
|
||||
{
|
||||
if(m_TooltipElidedItems && event->type() == QEvent::ToolTip)
|
||||
if(event->type() == QEvent::ToolTip)
|
||||
{
|
||||
QHelpEvent *he = (QHelpEvent *)event;
|
||||
QModelIndex index = indexAt(he->pos());
|
||||
// if we're doing instant tooltips this is all handled in the mousemove handler, don't do
|
||||
// anything here
|
||||
if(m_instantTooltips)
|
||||
return true;
|
||||
|
||||
QAbstractItemDelegate *delegate = m_userDelegate;
|
||||
|
||||
if(!delegate)
|
||||
delegate = QTreeView::itemDelegate(index);
|
||||
|
||||
if(delegate)
|
||||
if(m_TooltipElidedItems)
|
||||
{
|
||||
QStyleOptionViewItem option;
|
||||
option.initFrom(this);
|
||||
option.rect = visualRect(index);
|
||||
QHelpEvent *he = (QHelpEvent *)event;
|
||||
QModelIndex index = indexAt(he->pos());
|
||||
|
||||
// delegates get first dibs at processing the event
|
||||
bool ret = delegate->helpEvent(he, this, option, index);
|
||||
QAbstractItemDelegate *delegate = m_userDelegate;
|
||||
|
||||
if(ret)
|
||||
return true;
|
||||
if(!delegate)
|
||||
delegate = QTreeView::itemDelegate(index);
|
||||
|
||||
QSize desiredSize = delegate->sizeHint(option, index);
|
||||
|
||||
if(desiredSize.width() > option.rect.width())
|
||||
if(delegate)
|
||||
{
|
||||
const QString fullText = index.data(Qt::DisplayRole).toString();
|
||||
if(!fullText.isEmpty())
|
||||
QStyleOptionViewItem option;
|
||||
option.initFrom(this);
|
||||
option.rect = visualRect(index);
|
||||
|
||||
// delegates get first dibs at processing the event
|
||||
bool ret = delegate->helpEvent(he, this, option, index);
|
||||
|
||||
if(ret)
|
||||
return true;
|
||||
|
||||
QSize desiredSize = delegate->sizeHint(option, index);
|
||||
|
||||
if(desiredSize.width() > option.rect.width())
|
||||
{
|
||||
// need to use a custom label tooltip since the QToolTip freaks out as we're placing it
|
||||
// underneath the cursor instead of next to it (so that the tooltip lines up over the row)
|
||||
m_ElidedTooltip->move(viewport()->mapToGlobal(option.rect.topLeft()));
|
||||
m_ElidedTooltip->setText(fullText);
|
||||
m_ElidedTooltip->show();
|
||||
const QString fullText = index.data(Qt::DisplayRole).toString();
|
||||
if(!fullText.isEmpty())
|
||||
{
|
||||
// need to use a custom label tooltip since the QToolTip freaks out as we're placing it
|
||||
// underneath the cursor instead of next to it (so that the tooltip lines up over the
|
||||
// row)
|
||||
m_Tooltip->showTip(viewport()->mapToGlobal(option.rect.topLeft()), fullText);
|
||||
m_CurrentTooltipElided = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,18 +47,28 @@ public:
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
class RDTipLabel : public QLabel
|
||||
struct ITreeViewTipDisplay
|
||||
{
|
||||
public:
|
||||
virtual void hideTip() = 0;
|
||||
virtual QSize getSizeForTip(QString text) = 0;
|
||||
virtual void showTip(QPoint pos, QString text) = 0;
|
||||
};
|
||||
|
||||
class RDTipLabel : public QLabel, public ITreeViewTipDisplay
|
||||
{
|
||||
private:
|
||||
Q_OBJECT
|
||||
|
||||
int m_TooltipMargin = 0;
|
||||
QWidget *mouseListener;
|
||||
|
||||
public:
|
||||
explicit RDTipLabel(QWidget *listener = NULL);
|
||||
|
||||
int tipMargin() { return m_TooltipMargin; }
|
||||
void hideTip() { hide(); }
|
||||
QSize getSizeForTip(QString text);
|
||||
void showTip(QPoint pos, QString text);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *);
|
||||
void mousePressEvent(QMouseEvent *);
|
||||
@@ -76,6 +86,7 @@ class RDTreeView : public QTreeView
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool customCopyPasteHandler READ customCopyPasteHandler WRITE setCustomCopyPasteHandler)
|
||||
Q_PROPERTY(bool instantTooltips READ instantTooltips WRITE setInstantTooltips)
|
||||
public:
|
||||
explicit RDTreeView(QWidget *parent = 0);
|
||||
virtual ~RDTreeView();
|
||||
@@ -97,10 +108,17 @@ public:
|
||||
bool ignoreIconSize() { return m_IgnoreIconSize; }
|
||||
bool customCopyPasteHandler() { return m_customCopyPaste; }
|
||||
void setCustomCopyPasteHandler(bool custom) { m_customCopyPaste = custom; }
|
||||
bool instantTooltips() { return m_instantTooltips; }
|
||||
void setInstantTooltips(bool instant) { m_instantTooltips = instant; }
|
||||
QModelIndex currentHoverIndex() const { return m_currentHoverIndex; }
|
||||
void setItemDelegate(QAbstractItemDelegate *delegate);
|
||||
QAbstractItemDelegate *itemDelegate() const;
|
||||
|
||||
void setCustomTooltip(ITreeViewTipDisplay *tip)
|
||||
{
|
||||
m_Tooltip = tip;
|
||||
m_TooltipElidedItems = false;
|
||||
}
|
||||
void setModel(QAbstractItemModel *model) override;
|
||||
|
||||
// state is the storage to save the expansion state into
|
||||
@@ -168,6 +186,7 @@ private:
|
||||
bool m_VisibleGridLines = true;
|
||||
bool m_TooltipElidedItems = true;
|
||||
bool m_customCopyPaste = false;
|
||||
bool m_instantTooltips = false;
|
||||
|
||||
QMap<uint, RDTreeViewExpansionState> m_Expansions;
|
||||
|
||||
@@ -179,7 +198,9 @@ private:
|
||||
QAbstractItemDelegate *m_userDelegate = NULL;
|
||||
RDTreeViewDelegate *m_delegate;
|
||||
|
||||
RDTipLabel *m_ElidedTooltip;
|
||||
RDTipLabel *m_TooltipLabel;
|
||||
ITreeViewTipDisplay *m_Tooltip;
|
||||
bool m_CurrentTooltipElided = false;
|
||||
|
||||
int m_VertMargin = 6;
|
||||
bool m_IgnoreIconSize = false;
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
#include <QToolTip>
|
||||
#include "Code/Interface/QRDInterface.h"
|
||||
#include "Code/QRDUtils.h"
|
||||
#include "Code/Resources.h"
|
||||
@@ -259,7 +258,7 @@ public:
|
||||
item->m_fore = value.value<QBrush>();
|
||||
ret = true;
|
||||
}
|
||||
else if(role == Qt::ToolTipRole && !widget->m_instantTooltips)
|
||||
else if(role == Qt::ToolTipRole)
|
||||
{
|
||||
item->m_tooltip = value.toString();
|
||||
ret = true;
|
||||
@@ -359,7 +358,7 @@ QVariant RDTreeWidgetItem::data(int column, int role) const
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
else if(role == Qt::ToolTipRole && !m_widget->m_instantTooltips)
|
||||
else if(role == Qt::ToolTipRole)
|
||||
{
|
||||
if(!m_tooltip.isEmpty())
|
||||
return m_tooltip;
|
||||
@@ -784,27 +783,6 @@ void RDTreeWidget::mouseMoveEvent(QMouseEvent *e)
|
||||
m_model->itemChanged(oldHover, roles);
|
||||
m_model->itemChanged(newHover, roles);
|
||||
|
||||
if(m_instantTooltips)
|
||||
{
|
||||
QToolTip::hideText();
|
||||
|
||||
if(newHover && !newHover->m_tooltip.isEmpty())
|
||||
{
|
||||
// the documentation says:
|
||||
//
|
||||
// "If text is empty the tool tip is hidden. If the text is the same as the currently shown
|
||||
// tooltip, the tip will not move. You can force moving by first hiding the tip with an
|
||||
// empty
|
||||
// text, and then showing the new tip at the new position."
|
||||
//
|
||||
// However the actual implementation has some kind of 'fading' check, so if you hide then
|
||||
// immediately show, it will try to reuse the tooltip and end up not moving it at all if the
|
||||
// text hasn't changed.
|
||||
QToolTip::showText(QCursor::pos(), lit(" "), this);
|
||||
QToolTip::showText(QCursor::pos(), newHover->m_tooltip, this);
|
||||
}
|
||||
}
|
||||
|
||||
emit hoverItemChanged(newHover);
|
||||
|
||||
emit mouseMove(e);
|
||||
@@ -831,8 +809,6 @@ void RDTreeWidget::leaveEvent(QEvent *e)
|
||||
if(m_currentHoverIndex.isValid())
|
||||
{
|
||||
RDTreeWidgetItem *item = m_model->itemForIndex(m_currentHoverIndex);
|
||||
if(!item->m_tooltip.isEmpty() && m_instantTooltips)
|
||||
QToolTip::hideText();
|
||||
m_model->itemChanged(item, {Qt::DecorationRole, Qt::BackgroundRole, Qt::ForegroundRole});
|
||||
}
|
||||
|
||||
|
||||
@@ -210,7 +210,6 @@ class RDTreeWidget : public RDTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool instantTooltips READ instantTooltips WRITE setInstantTooltips)
|
||||
public:
|
||||
explicit RDTreeWidget(QWidget *parent = 0);
|
||||
~RDTreeWidget();
|
||||
@@ -226,8 +225,6 @@ public:
|
||||
void setHoverHandCursor(bool hand) { m_hoverHandCursor = hand; }
|
||||
void setHoverClickActivate(bool click) { m_activateOnClick = click; }
|
||||
void setClearSelectionOnFocusLoss(bool clear) { m_clearSelectionOnFocusLoss = clear; }
|
||||
bool instantTooltips() { return m_instantTooltips; }
|
||||
void setInstantTooltips(bool instant) { m_instantTooltips = instant; }
|
||||
RDTreeWidgetItem *invisibleRootItem() { return m_root; }
|
||||
void addTopLevelItem(RDTreeWidgetItem *item) { m_root->addChild(item); }
|
||||
RDTreeWidgetItem *topLevelItem(int index) const { return m_root->child(index); }
|
||||
@@ -314,7 +311,6 @@ private:
|
||||
|
||||
QVector<Qt::Alignment> m_alignments;
|
||||
|
||||
bool m_instantTooltips = false;
|
||||
int m_hoverColumn = -1;
|
||||
QIcon m_normalHoverIcon;
|
||||
QIcon m_activeHoverIcon;
|
||||
|
||||
Reference in New Issue
Block a user