mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 01:20:42 +00:00
Add thumbnails to texture tooltips in pipeline state view
* If there would be no tooltip otherwise, it just shows the thumbnail. Otherwise any tooltip text (like view parameters or image layout) is displayed below the thumbnail
This commit is contained in:
@@ -132,19 +132,23 @@ RDTipLabel::RDTipLabel(QWidget *listener) : QLabel(NULL), mouseListener(listener
|
||||
setWindowOpacity(opacity / 255.0);
|
||||
}
|
||||
|
||||
QSize RDTipLabel::getSizeForTip(QString text)
|
||||
QSize RDTipLabel::configureTip(QWidget *, QModelIndex, QString text)
|
||||
{
|
||||
setText(text);
|
||||
return sizeHint();
|
||||
return minimumSizeHint();
|
||||
}
|
||||
|
||||
void RDTipLabel::showTip(QPoint pos, QString text)
|
||||
void RDTipLabel::showTip(QPoint pos)
|
||||
{
|
||||
move(pos);
|
||||
setText(text);
|
||||
show();
|
||||
}
|
||||
|
||||
bool RDTipLabel::forceTip(QWidget *widget, QModelIndex idx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void RDTipLabel::paintEvent(QPaintEvent *ev)
|
||||
{
|
||||
QStylePainter p(this);
|
||||
@@ -234,7 +238,7 @@ void RDTreeView::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
QString tooltip = m_currentHoverIndex.data(Qt::ToolTipRole).toString();
|
||||
|
||||
if(!tooltip.isEmpty())
|
||||
if(!tooltip.isEmpty() || m_Tooltip->forceTip(this, m_currentHoverIndex))
|
||||
{
|
||||
// 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
|
||||
@@ -248,7 +252,7 @@ void RDTreeView::mouseMoveEvent(QMouseEvent *e)
|
||||
// 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));
|
||||
tooltipRect.setSize(m_Tooltip->configureTip(this, m_currentHoverIndex, tooltip));
|
||||
|
||||
// clip by the available geometry in x
|
||||
if(tooltipRect.right() > screenAvailGeom.right())
|
||||
@@ -259,7 +263,7 @@ void RDTreeView::mouseMoveEvent(QMouseEvent *e)
|
||||
if(tooltipRect.bottom() > screenAvailGeom.bottom())
|
||||
tooltipRect.moveBottom(p.y() - cursorSize.y());
|
||||
|
||||
m_Tooltip->showTip(tooltipRect.topLeft(), tooltip);
|
||||
m_Tooltip->showTip(tooltipRect.topLeft());
|
||||
m_CurrentTooltipElided = false;
|
||||
}
|
||||
}
|
||||
@@ -414,7 +418,8 @@ bool RDTreeView::viewportEvent(QEvent *event)
|
||||
// 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_Tooltip->configureTip(this, index, fullText);
|
||||
m_Tooltip->showTip(viewport()->mapToGlobal(option.rect.topLeft()));
|
||||
m_CurrentTooltipElided = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +51,9 @@ struct ITreeViewTipDisplay
|
||||
{
|
||||
public:
|
||||
virtual void hideTip() = 0;
|
||||
virtual QSize getSizeForTip(QString text) = 0;
|
||||
virtual void showTip(QPoint pos, QString text) = 0;
|
||||
virtual QSize configureTip(QWidget *widget, QModelIndex idx, QString text) = 0;
|
||||
virtual void showTip(QPoint pos) = 0;
|
||||
virtual bool forceTip(QWidget *widget, QModelIndex idx) = 0;
|
||||
};
|
||||
|
||||
class RDTipLabel : public QLabel, public ITreeViewTipDisplay
|
||||
@@ -66,8 +67,9 @@ public:
|
||||
explicit RDTipLabel(QWidget *listener = NULL);
|
||||
|
||||
void hideTip() { hide(); }
|
||||
QSize getSizeForTip(QString text);
|
||||
void showTip(QPoint pos, QString text);
|
||||
QSize configureTip(QWidget *widget, QModelIndex idx, QString text);
|
||||
void showTip(QPoint pos);
|
||||
bool forceTip(QWidget *widget, QModelIndex idx);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *);
|
||||
|
||||
@@ -668,6 +668,13 @@ QAbstractItemDelegate *RDTreeWidget::itemDelegate() const
|
||||
return m_userDelegate;
|
||||
}
|
||||
|
||||
RDTreeWidgetItem *RDTreeWidget::itemForIndex(QModelIndex idx) const
|
||||
{
|
||||
if(idx.model() == m_model)
|
||||
return m_model->itemForIndex(idx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RDTreeWidget::copyItem(QPoint pos, RDTreeWidgetItem *item)
|
||||
{
|
||||
copyIndex(pos, m_model->indexForItem(item, 0));
|
||||
|
||||
@@ -238,6 +238,8 @@ public:
|
||||
void setItemDelegate(QAbstractItemDelegate *delegate);
|
||||
QAbstractItemDelegate *itemDelegate() const;
|
||||
|
||||
RDTreeWidgetItem *itemForIndex(QModelIndex idx) const;
|
||||
|
||||
void copyItem(QPoint pos, RDTreeWidgetItem *item);
|
||||
|
||||
void setColumns(const QStringList &columns);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QStylePainter>
|
||||
#include <QSvgRenderer>
|
||||
#include <QToolButton>
|
||||
#include <QXmlStreamWriter>
|
||||
@@ -80,11 +81,122 @@ static uint32_t byteSize(const ResourceFormat &fmt)
|
||||
return fmt.compByteWidth * fmt.compCount;
|
||||
}
|
||||
|
||||
RDPreviewTooltip::RDPreviewTooltip(PipelineStateViewer *parent, CustomPaintWidget *thumbnail,
|
||||
ICaptureContext &ctx)
|
||||
: QFrame(parent), m_Ctx(ctx)
|
||||
{
|
||||
int margin = style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, NULL, this);
|
||||
int opacity = style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, NULL, this);
|
||||
|
||||
pipe = parent;
|
||||
|
||||
setWindowFlags(Qt::ToolTip);
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
setForegroundRole(QPalette::ToolTipText);
|
||||
setBackgroundRole(QPalette::ToolTipBase);
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
setWindowOpacity(opacity / 255.0);
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
|
||||
QHBoxLayout *hbox = new QHBoxLayout;
|
||||
QVBoxLayout *vbox = new QVBoxLayout;
|
||||
label = new QLabel(this);
|
||||
|
||||
label->setMargin(margin + 1);
|
||||
label->setAlignment(Qt::AlignLeft);
|
||||
label->setIndent(1);
|
||||
|
||||
title = new QLabel(this);
|
||||
title->setMargin(margin + 1);
|
||||
title->setAlignment(Qt::AlignLeft);
|
||||
title->setIndent(1);
|
||||
|
||||
setLayout(vbox);
|
||||
vbox->addWidget(title);
|
||||
vbox->addLayout(hbox);
|
||||
|
||||
hbox->addWidget(thumbnail);
|
||||
hbox->addStretch();
|
||||
|
||||
vbox->addWidget(label);
|
||||
}
|
||||
|
||||
void RDPreviewTooltip::hideTip()
|
||||
{
|
||||
hide();
|
||||
}
|
||||
|
||||
QSize RDPreviewTooltip::configureTip(QWidget *widget, QModelIndex idx, QString text)
|
||||
{
|
||||
ResourceId id = pipe->updateThumbnail(widget, idx);
|
||||
if(id != ResourceId())
|
||||
{
|
||||
title->setText(m_Ctx.GetResourceName(id));
|
||||
title->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
title->hide();
|
||||
}
|
||||
label->setText(text);
|
||||
label->setVisible(!text.isEmpty());
|
||||
layout()->update();
|
||||
layout()->activate();
|
||||
return minimumSizeHint();
|
||||
}
|
||||
|
||||
void RDPreviewTooltip::showTip(QPoint pos)
|
||||
{
|
||||
move(pos);
|
||||
resize(minimumSize());
|
||||
show();
|
||||
}
|
||||
|
||||
bool RDPreviewTooltip::forceTip(QWidget *widget, QModelIndex idx)
|
||||
{
|
||||
return pipe->hasThumbnail(widget, idx);
|
||||
}
|
||||
|
||||
void RDPreviewTooltip::paintEvent(QPaintEvent *ev)
|
||||
{
|
||||
QStylePainter p(this);
|
||||
QStyleOptionFrame opt;
|
||||
opt.init(this);
|
||||
p.drawPrimitive(QStyle::PE_PanelTipLabel, opt);
|
||||
p.end();
|
||||
|
||||
QWidget::paintEvent(ev);
|
||||
}
|
||||
|
||||
void RDPreviewTooltip::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
QStyleHintReturnMask frameMask;
|
||||
QStyleOption option;
|
||||
option.init(this);
|
||||
if(style()->styleHint(QStyle::SH_ToolTip_Mask, &option, this, &frameMask))
|
||||
setMask(frameMask.region);
|
||||
|
||||
QWidget::resizeEvent(e);
|
||||
}
|
||||
|
||||
PipelineStateViewer::PipelineStateViewer(ICaptureContext &ctx, QWidget *parent)
|
||||
: QFrame(parent), ui(new Ui::PipelineStateViewer), m_Ctx(ctx)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->thumbnail->SetContext(m_Ctx);
|
||||
ui->layout->removeWidget(ui->thumbnail);
|
||||
|
||||
m_Tooltip = new RDPreviewTooltip(this, ui->thumbnail, m_Ctx);
|
||||
|
||||
QColor c = palette().color(QPalette::ToolTipBase).toRgb();
|
||||
|
||||
m_TexDisplay.backgroundColor = FloatVector();
|
||||
m_TexDisplay.backgroundColor.w = 1.0f;
|
||||
|
||||
// auto-fit and center scale
|
||||
m_TexDisplay.scale = -1.0f;
|
||||
|
||||
m_D3D11 = NULL;
|
||||
m_D3D12 = NULL;
|
||||
m_GL = NULL;
|
||||
@@ -105,6 +217,8 @@ PipelineStateViewer::~PipelineStateViewer()
|
||||
m_Ctx.BuiltinWindowClosed(this);
|
||||
m_Ctx.RemoveCaptureViewer(this);
|
||||
|
||||
delete m_Tooltip;
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
@@ -121,6 +235,24 @@ void PipelineStateViewer::OnCaptureLoaded()
|
||||
|
||||
if(m_Current)
|
||||
m_Current->OnCaptureLoaded();
|
||||
|
||||
WindowingData thumbData = ui->thumbnail->GetWidgetWindowingData();
|
||||
|
||||
m_Ctx.Replay().BlockInvoke([thumbData, this](IReplayController *r) {
|
||||
m_Output = r->CreateOutput(thumbData, ReplayOutputType::Texture);
|
||||
|
||||
ui->thumbnail->SetOutput(m_Output);
|
||||
|
||||
RT_UpdateAndDisplay(r);
|
||||
});
|
||||
}
|
||||
|
||||
void PipelineStateViewer::RT_UpdateAndDisplay(IReplayController *r)
|
||||
{
|
||||
if(m_Output != NULL)
|
||||
m_Output->SetTextureDisplay(m_TexDisplay);
|
||||
|
||||
GUIInvoke::call(this, [this]() { ui->thumbnail->update(); });
|
||||
}
|
||||
|
||||
void PipelineStateViewer::OnCaptureClosed()
|
||||
@@ -1057,6 +1189,77 @@ void PipelineStateViewer::ShowResourceContextMenu(RDTreeWidget *widget, const QP
|
||||
RDDialog::show(&contextMenu, widget->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
ResourceId PipelineStateViewer::updateThumbnail(QWidget *widget, QModelIndex idx)
|
||||
{
|
||||
ResourceId id;
|
||||
|
||||
RDTreeWidget *treeWidget = qobject_cast<RDTreeWidget *>(widget);
|
||||
if(treeWidget)
|
||||
{
|
||||
RDTreeWidgetItem *item = treeWidget->itemForIndex(idx);
|
||||
|
||||
if(item)
|
||||
{
|
||||
if(m_D3D11)
|
||||
id = m_D3D11->GetResource(item);
|
||||
else if(m_D3D12)
|
||||
id = m_D3D12->GetResource(item);
|
||||
else if(m_GL)
|
||||
id = m_GL->GetResource(item);
|
||||
else if(m_Vulkan)
|
||||
id = m_Vulkan->GetResource(item);
|
||||
}
|
||||
|
||||
TextureDescription *tex = m_Ctx.GetTexture(id);
|
||||
|
||||
if(tex)
|
||||
{
|
||||
m_TexDisplay.resourceId = id;
|
||||
INVOKE_MEMFN(RT_UpdateAndDisplay);
|
||||
|
||||
float aspect = (float)tex->width / (float)qMax(1U, tex->height);
|
||||
|
||||
// keep height fixed at 100, and make width match the aspect ratio of the texture - up to 21:9
|
||||
// ratio
|
||||
ui->thumbnail->setFixedSize((int)qBound(100.0f, aspect * 100.0f, (21.0f / 9.0f) * 100.0f), 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->thumbnail->setFixedSize(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
bool PipelineStateViewer::hasThumbnail(QWidget *widget, QModelIndex idx)
|
||||
{
|
||||
RDTreeWidget *treeWidget = qobject_cast<RDTreeWidget *>(widget);
|
||||
if(treeWidget)
|
||||
{
|
||||
ResourceId id;
|
||||
|
||||
RDTreeWidgetItem *item = treeWidget->itemForIndex(idx);
|
||||
|
||||
if(item)
|
||||
{
|
||||
if(m_D3D11)
|
||||
id = m_D3D11->GetResource(item);
|
||||
else if(m_D3D12)
|
||||
id = m_D3D12->GetResource(item);
|
||||
else if(m_GL)
|
||||
id = m_GL->GetResource(item);
|
||||
else if(m_Vulkan)
|
||||
id = m_Vulkan->GetResource(item);
|
||||
}
|
||||
|
||||
if(id != ResourceId() && m_Ctx.GetTexture(id))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PipelineStateViewer::SetupResourceView(RDTreeWidget *widget)
|
||||
{
|
||||
auto handler = [this, widget](const QPoint &pos) {
|
||||
@@ -1091,6 +1294,8 @@ void PipelineStateViewer::SetupResourceView(RDTreeWidget *widget)
|
||||
|
||||
widget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
QObject::connect(widget, &RDTreeWidget::customContextMenuRequested, handler);
|
||||
|
||||
widget->setCustomTooltip(m_Tooltip);
|
||||
}
|
||||
|
||||
QString PipelineStateViewer::GetVBufferFormatString(uint32_t slot)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include "Code/Interface/QRDInterface.h"
|
||||
#include "Widgets/Extended/RDTreeView.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
@@ -40,12 +41,39 @@ class QMenu;
|
||||
class RDLabel;
|
||||
class RDTreeWidgetItem;
|
||||
class RDTreeWidget;
|
||||
class CustomPaintWidget;
|
||||
|
||||
class D3D11PipelineStateViewer;
|
||||
class D3D12PipelineStateViewer;
|
||||
class GLPipelineStateViewer;
|
||||
class VulkanPipelineStateViewer;
|
||||
|
||||
class PipelineStateViewer;
|
||||
|
||||
class RDPreviewTooltip : public QFrame, public ITreeViewTipDisplay
|
||||
{
|
||||
private:
|
||||
Q_OBJECT
|
||||
|
||||
PipelineStateViewer *pipe = NULL;
|
||||
QLabel *title = NULL;
|
||||
QLabel *label = NULL;
|
||||
ICaptureContext &m_Ctx;
|
||||
|
||||
public:
|
||||
explicit RDPreviewTooltip(PipelineStateViewer *parent, CustomPaintWidget *thumbnail,
|
||||
ICaptureContext &ctx);
|
||||
|
||||
void hideTip();
|
||||
QSize configureTip(QWidget *widget, QModelIndex idx, QString text);
|
||||
void showTip(QPoint pos);
|
||||
bool forceTip(QWidget *widget, QModelIndex idx);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *);
|
||||
void resizeEvent(QResizeEvent *);
|
||||
};
|
||||
|
||||
class PipelineStateViewer : public QFrame, public IPipelineStateViewer, public ICaptureViewer
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -84,6 +112,9 @@ public:
|
||||
void setTopologyDiagram(QLabel *diagram, Topology topo);
|
||||
void setMeshViewPixmap(RDLabel *meshView);
|
||||
|
||||
ResourceId updateThumbnail(QWidget *widget, QModelIndex idx);
|
||||
bool hasThumbnail(QWidget *widget, QModelIndex idx);
|
||||
|
||||
QXmlStreamWriter *beginHTMLExport();
|
||||
void exportHTMLTable(QXmlStreamWriter &xml, const QStringList &cols,
|
||||
const QList<QVariantList> &rows);
|
||||
@@ -101,6 +132,13 @@ private:
|
||||
|
||||
QMenu *editMenus[6] = {};
|
||||
|
||||
RDPreviewTooltip *m_Tooltip = NULL;
|
||||
|
||||
TextureDisplay m_TexDisplay;
|
||||
IReplayOutput *m_Output = NULL;
|
||||
|
||||
void RT_UpdateAndDisplay(IReplayController *r);
|
||||
|
||||
void AddResourceUsageEntry(QMenu &menu, uint32_t start, uint32_t end, ResourceUsage usage);
|
||||
void ShowResourceContextMenu(RDTreeWidget *widget, const QPoint &pos, ResourceId id,
|
||||
const rdcarray<EventUsage> &usage);
|
||||
|
||||
@@ -29,8 +29,25 @@
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CustomPaintWidget" name="thumbnail" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CustomPaintWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Widgets/CustomPaintWidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
Reference in New Issue
Block a user