mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-04 17:10:47 +00:00
58eb49ce5b
* This lets us use the existing logic for hovering columns, to get things like the hand cursor, while still only showing it for resource entries.
339 lines
11 KiB
C++
339 lines
11 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2016-2026 Baldur Karlsson
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include "RDTreeView.h"
|
|
|
|
class RDTreeWidget;
|
|
class RDTreeWidgetModel;
|
|
|
|
class RDTreeWidgetItem
|
|
{
|
|
public:
|
|
RDTreeWidgetItem() = default;
|
|
RDTreeWidgetItem(const QVariantList &values);
|
|
RDTreeWidgetItem(const std::initializer_list<QVariant> &values);
|
|
~RDTreeWidgetItem();
|
|
|
|
QVariant data(int column, int role) const;
|
|
void setData(int column, int role, const QVariant &value);
|
|
|
|
void addChild(RDTreeWidgetItem *item);
|
|
void insertChild(int index, RDTreeWidgetItem *child);
|
|
|
|
// the data above requires allocating a bunch of vectors since it's stored per-column. Where
|
|
// possible, just use this single per-item tag
|
|
inline QVariant tag() const { return m_tag; }
|
|
inline void setTag(const QVariant &value) { m_tag = value; }
|
|
// inline accessors to the private data
|
|
inline void setIcon(int column, const QIcon &icon)
|
|
{
|
|
if(column >= m_icons.size())
|
|
{
|
|
m_text.resize(column + 1);
|
|
m_icons.resize(m_text.size());
|
|
}
|
|
|
|
m_icons[column] = icon;
|
|
dataChanged(column, Qt::DecorationRole);
|
|
}
|
|
inline RDTreeWidgetItem *child(int index) const { return m_children[index]; }
|
|
inline int indexOfChild(RDTreeWidgetItem *child) const { return m_children.indexOf(child); }
|
|
RDTreeWidgetItem *takeChild(int index);
|
|
void removeChild(RDTreeWidgetItem *child);
|
|
void clear();
|
|
inline int dataCount() const { return m_text.count(); }
|
|
inline int childCount() const { return m_children.count(); }
|
|
inline RDTreeWidgetItem *parent() const { return m_parent; }
|
|
inline RDTreeWidget *treeWidget() const { return m_widget; }
|
|
inline void setBold(bool bold)
|
|
{
|
|
m_bold = bold;
|
|
dataChanged(0, Qt::FontRole);
|
|
}
|
|
inline bool bold() const { return m_bold; }
|
|
inline void setItalic(bool italic)
|
|
{
|
|
m_italic = italic;
|
|
dataChanged(0, Qt::FontRole);
|
|
}
|
|
inline bool italic() const { return m_italic; }
|
|
inline void setTreeColor(QColor col) { m_treeCol = col; }
|
|
inline void setBackgroundColor(QColor background) { setBackground(QBrush(background)); }
|
|
inline void setForegroundColor(QColor foreground) { setForeground(QBrush(foreground)); }
|
|
inline void setBackground(QBrush background)
|
|
{
|
|
if(m_back != background)
|
|
{
|
|
m_back = background;
|
|
dataChanged(0, Qt::BackgroundRole);
|
|
}
|
|
}
|
|
inline void setForeground(QBrush foreground)
|
|
{
|
|
if(m_fore != foreground)
|
|
{
|
|
m_fore = foreground;
|
|
dataChanged(0, Qt::ForegroundRole);
|
|
}
|
|
}
|
|
inline QBrush background() { return m_back; }
|
|
inline QBrush foreground() { return m_fore; }
|
|
inline QString text(int column) const { return m_text[column].toString(); }
|
|
inline void setText(int column, const QVariant &value)
|
|
{
|
|
if(column >= m_text.size())
|
|
{
|
|
m_text.resize(column + 1);
|
|
m_icons.resize(m_text.size());
|
|
}
|
|
|
|
m_text[column] = value;
|
|
checkForResourceId(column);
|
|
dataChanged(column, Qt::DisplayRole);
|
|
}
|
|
inline void setToolTip(const QString &value)
|
|
{
|
|
m_tooltip = value;
|
|
dataChanged(0, Qt::ToolTipRole);
|
|
}
|
|
inline void setToolTip(int column, const QString &value)
|
|
{
|
|
setData(column, Qt::ToolTipRole, value);
|
|
dataChanged(0, Qt::ToolTipRole);
|
|
}
|
|
inline bool editable(int column) const { return m_editable & (1U << column); }
|
|
inline void setEditable(int column, bool edit)
|
|
{
|
|
uint32_t mask = 1U << column;
|
|
|
|
if(edit)
|
|
m_editable |= mask;
|
|
else
|
|
m_editable &= ~mask;
|
|
}
|
|
|
|
inline Qt::CheckState checkState(int column) const
|
|
{
|
|
return (Qt::CheckState)data(column, Qt::CheckStateRole).toInt();
|
|
}
|
|
inline void setCheckState(int column, Qt::CheckState state)
|
|
{
|
|
setData(column, Qt::CheckStateRole, int(state));
|
|
dataChanged(column, Qt::CheckStateRole);
|
|
}
|
|
|
|
private:
|
|
void checkForResourceId(int column);
|
|
|
|
void sort(int column, Qt::SortOrder order);
|
|
|
|
friend class RDTreeWidget;
|
|
friend class RDTreeWidgetModel;
|
|
|
|
void setWidget(RDTreeWidget *widget);
|
|
RDTreeWidget *m_widget = NULL;
|
|
|
|
RDTreeWidgetItem *m_parent = NULL;
|
|
QVector<RDTreeWidgetItem *> m_children;
|
|
|
|
struct RoleData
|
|
{
|
|
RoleData() : role(0), data() {}
|
|
RoleData(int r, const QVariant &d) : role(r), data(d) {}
|
|
int role;
|
|
QVariant data;
|
|
};
|
|
|
|
void dataChanged(int column, int role);
|
|
|
|
// per-column properties
|
|
QVector<QVariant> m_text;
|
|
QVector<QIcon> m_icons;
|
|
// each element, per-column, is a list of other data values
|
|
// we allocate this lazily only if it's really needed
|
|
QVector<QVector<RoleData>> *m_data = NULL;
|
|
|
|
// bitfield of editable columns
|
|
uint32_t m_editable = 0;
|
|
|
|
// per-item properties
|
|
QString m_tooltip;
|
|
bool m_bold = false;
|
|
bool m_italic = false;
|
|
QColor m_treeCol;
|
|
QBrush m_back;
|
|
QBrush m_fore;
|
|
QVariant m_tag;
|
|
};
|
|
|
|
class RDTreeWidgetItemIterator
|
|
{
|
|
public:
|
|
RDTreeWidgetItemIterator(RDTreeWidget *widget);
|
|
|
|
RDTreeWidgetItemIterator &operator++();
|
|
inline const RDTreeWidgetItemIterator operator++(int)
|
|
{
|
|
RDTreeWidgetItemIterator it = *this;
|
|
++(*this);
|
|
return it;
|
|
}
|
|
|
|
// TODO implement operator-- if we need it.
|
|
/*
|
|
RDTreeWidgetItemIterator &operator--();
|
|
inline const RDTreeWidgetItemIterator operator--(int)
|
|
{
|
|
RDTreeWidgetItemIterator it = *this;
|
|
--(*this);
|
|
return it;
|
|
}
|
|
*/
|
|
|
|
inline RDTreeWidgetItem *operator*() const { return m_Current; }
|
|
private:
|
|
RDTreeWidgetItem *m_Current;
|
|
};
|
|
|
|
class RDTreeWidget : public RDTreeView
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit RDTreeWidget(QWidget *parent = 0);
|
|
~RDTreeWidget();
|
|
|
|
void setHoverIconColumn(int column, QIcon normal, QIcon hover)
|
|
{
|
|
m_hoverColumn = column;
|
|
m_normalHoverIcon = normal;
|
|
m_activeHoverIcon = hover;
|
|
m_hoverHandCursor = true;
|
|
m_activateOnClick = true;
|
|
m_hoverRole = -1;
|
|
}
|
|
void setHoverRole(int role) { m_hoverRole = role; }
|
|
void setHoverHandCursor(bool hand) { m_hoverHandCursor = hand; }
|
|
void setHoverClickActivate(bool click) { m_activateOnClick = click; }
|
|
void setClearSelectionOnFocusLoss(bool clear) { m_clearSelectionOnFocusLoss = clear; }
|
|
RDTreeWidgetItem *invisibleRootItem() { return m_root; }
|
|
void addTopLevelItem(RDTreeWidgetItem *item) { m_root->addChild(item); }
|
|
void insertTopLevelItem(int idx, RDTreeWidgetItem *item) { m_root->insertChild(idx, item); }
|
|
RDTreeWidgetItem *topLevelItem(int index) const { return m_root->child(index); }
|
|
int indexOfTopLevelItem(RDTreeWidgetItem *item) const { return m_root->indexOfChild(item); }
|
|
RDTreeWidgetItem *takeTopLevelItem(int index) { return m_root->takeChild(index); }
|
|
int topLevelItemCount() const { return m_root->childCount(); }
|
|
void beginUpdate();
|
|
void endUpdate();
|
|
void setColumnAlignment(int column, Qt::Alignment align);
|
|
|
|
RDTreeWidgetItem *itemForIndex(QModelIndex idx) const;
|
|
|
|
void copyItem(QPoint pos, RDTreeWidgetItem *item);
|
|
|
|
typedef std::function<bool(int, Qt::SortOrder, const RDTreeWidgetItem *, const RDTreeWidgetItem *)>
|
|
ComparisonFunction;
|
|
|
|
void setSortComparison(ComparisonFunction comparison) { m_SortComparison = comparison; }
|
|
void setColumns(const QStringList &columns);
|
|
const QStringList &getHeaders() const { return m_headers; }
|
|
QString headerText(int column) const { return m_headers[column]; }
|
|
void setHeaderText(int column, const QString &text);
|
|
RDTreeWidgetItem *selectedItem() const;
|
|
RDTreeWidgetItem *currentItem() const;
|
|
void setSelectedItem(RDTreeWidgetItem *node);
|
|
void setCurrentItem(RDTreeWidgetItem *node);
|
|
|
|
RDTreeWidgetItem *itemAt(const QPoint &p) const;
|
|
RDTreeWidgetItem *itemAt(int x, int y) const { return itemAt(QPoint(x, y)); }
|
|
void expandItem(RDTreeWidgetItem *item);
|
|
void expandAllItems(RDTreeWidgetItem *item);
|
|
void collapseItem(RDTreeWidgetItem *item);
|
|
void collapseAllItems(RDTreeWidgetItem *item);
|
|
void scrollToItem(RDTreeWidgetItem *item);
|
|
void editItem(RDTreeWidgetItem *item);
|
|
|
|
void clear();
|
|
|
|
signals:
|
|
void mouseMove(QMouseEvent *e);
|
|
void itemClicked(RDTreeWidgetItem *item, int column);
|
|
void itemChanged(RDTreeWidgetItem *item, int column);
|
|
void itemDoubleClicked(RDTreeWidgetItem *item, int column);
|
|
void itemActivated(RDTreeWidgetItem *item, int column);
|
|
void currentItemChanged(RDTreeWidgetItem *current, RDTreeWidgetItem *previous);
|
|
void hoverItemChanged(RDTreeWidgetItem *item);
|
|
void itemSelectionChanged();
|
|
|
|
public slots:
|
|
|
|
private:
|
|
void mouseMoveEvent(QMouseEvent *e) override;
|
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
|
void leaveEvent(QEvent *e) override;
|
|
void focusOutEvent(QFocusEvent *event) override;
|
|
|
|
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override;
|
|
void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override;
|
|
|
|
void setModel(QAbstractItemModel *model) override {}
|
|
void itemDataChanged(RDTreeWidgetItem *item, int column, int role);
|
|
void beginInsertChild(RDTreeWidgetItem *item, int index);
|
|
void endInsertChild(RDTreeWidgetItem *item, int index);
|
|
|
|
friend class RDTreeWidgetModel;
|
|
friend class RDTreeWidgetItem;
|
|
|
|
// invisible root item, used to simplify recursion by even top-level items having a parent
|
|
RDTreeWidgetItem *m_root;
|
|
|
|
RDTreeWidgetModel *m_model;
|
|
|
|
bool m_clearing = false;
|
|
|
|
QStringList m_headers;
|
|
|
|
ComparisonFunction m_SortComparison;
|
|
|
|
bool m_queueUpdates = false;
|
|
|
|
RDTreeWidgetItem *m_queuedItem;
|
|
QPair<int, int> m_lowestIndex;
|
|
QPair<int, int> m_highestIndex;
|
|
uint64_t m_queuedRoles = 0;
|
|
bool m_queuedChildren = false;
|
|
|
|
QVector<Qt::Alignment> m_alignments;
|
|
|
|
int m_hoverColumn = -1;
|
|
int m_hoverRole = -1;
|
|
QIcon m_normalHoverIcon;
|
|
QIcon m_activeHoverIcon;
|
|
bool m_hoverHandCursor = false;
|
|
bool m_clearSelectionOnFocusLoss = false;
|
|
bool m_activateOnClick = false;
|
|
};
|