Files
Aldbg/interface/callstack/CallstackView.hpp
2025-02-24 20:39:55 +08:00

273 lines
9.7 KiB
C++

#include <gtkmm.h>
namespace
{
class CallstackItem
{
public:
CallstackItem() = default;
CallstackItem(Glib::ustring callPoint, Glib::ustring stackBase, Glib::ustring symbol, Glib::ustring module, Glib::ustring depth);
CallstackItem(Glib::ustring callPoint, const std::vector<CallstackItem>& children);
CallstackItem(const CallstackItem& src) = default;
CallstackItem(CallstackItem&& src) noexcept = default;
CallstackItem& operator=(const CallstackItem& src) = default;
CallstackItem& operator=(CallstackItem&& src) noexcept = default;
~CallstackItem() = default;
Glib::ustring callPoint;
Glib::ustring stackBase;
Glib::ustring symbol;
Glib::ustring module;
Glib::ustring depth;
std::vector<CallstackItem> m_children;
}; // CallstackItem
CallstackItem::CallstackItem(Glib::ustring callPoint, Glib::ustring stackBase, Glib::ustring symbol, Glib::ustring module, Glib::ustring depth)
: callPoint(std::move(callPoint)), stackBase(std::move(stackBase)), symbol(std::move(symbol)), module(std::move(module)), depth(std::move(depth))
{ }
CallstackItem::CallstackItem(Glib::ustring callPoint,
const std::vector<CallstackItem>& children)
: callPoint(std::move(callPoint)), m_children(children)
{ }
}
class CallstackView : public Gtk::ColumnView
{
protected:
class ModelColumns : public Glib::Object
{
public:
std::vector<CallstackItem> m_children;
Glib::ustring callPoint;
Glib::ustring stackBase;
Glib::ustring symbol;
Glib::ustring module;
Glib::ustring depth;
static Glib::RefPtr<ModelColumns> create(const CallstackItem& item)
{
return Glib::make_refptr_for_instance<ModelColumns>(new ModelColumns(item));
}
protected:
explicit ModelColumns(const CallstackItem& item)
: m_children(item.m_children), callPoint(item.callPoint),
stackBase(item.stackBase), symbol(item.symbol),
module(item.module), depth(item.depth)
{ }
}; // ModelColumns
protected:
static Glib::RefPtr<Gio::ListModel> create_model(
const Glib::RefPtr<Glib::ObjectBase>& item)
{
auto col = std::dynamic_pointer_cast<ModelColumns>(item);
if (col && col->m_children.empty())
return {};
auto result = Gio::ListStore<ModelColumns>::create();
const std::vector<CallstackItem>& children = col ? col->m_children : std::vector<CallstackItem>();
for (const auto& child : children)
result->append(ModelColumns::create(child));
return result;
}
Glib::RefPtr<Gtk::TreeListModel> m_TreeListModel;
Glib::RefPtr<Gtk::MultiSelection> m_TreeSelection;
Glib::RefPtr<Gio::ListStore<ModelColumns>> _store;
public:
void append_group(const std::string &name, const std::vector<CallstackItem> &g)
{
CallstackItem k(name, g);
if(_store) _store->append(ModelColumns::create(k));
}
void clear()
{
_store->remove_all();
}
CallstackView (BaseObjectType *cobject, const Glib::RefPtr<Gtk::Builder> &refBuilder) : Gtk::ColumnView(cobject)
{
auto root = create_model({});
m_TreeListModel = Gtk::TreeListModel::create(root,
sigc::ptr_fun(&CallstackView::create_model), false, true);
m_TreeSelection = Gtk::MultiSelection::create(m_TreeListModel);
set_model(m_TreeSelection);
{
auto factory = Gtk::SignalListItemFactory::create();
factory->signal_setup().connect(
sigc::mem_fun(*this, &CallstackView::on_setup_keylabel));
factory->signal_bind().connect(
sigc::mem_fun(*this, &CallstackView::on_bind_callPoint));
auto column = Gtk::ColumnViewColumn::create("Call Point", factory);
column->set_fixed_width(200);
append_column(column);
factory = Gtk::SignalListItemFactory::create();
factory->signal_setup().connect(
sigc::mem_fun(*this, &CallstackView::on_setup_label));
factory->signal_bind().connect(
sigc::mem_fun(*this, &CallstackView::on_bind_stackBase));
column = Gtk::ColumnViewColumn::create("Stack Base", factory);
column->set_expand();
append_column(column);
factory = Gtk::SignalListItemFactory::create();
factory->signal_setup().connect(
sigc::mem_fun(*this, &CallstackView::on_setup_label));
factory->signal_bind().connect(
sigc::mem_fun(*this, &CallstackView::on_bind_symbol));
column = Gtk::ColumnViewColumn::create("Symbol", factory);
column->set_expand();
append_column(column);
factory = Gtk::SignalListItemFactory::create();
factory->signal_setup().connect(
sigc::mem_fun(*this, &CallstackView::on_setup_label));
factory->signal_bind().connect(
sigc::mem_fun(*this, &CallstackView::on_bind_module));
column = Gtk::ColumnViewColumn::create("Module", factory);
column->set_expand();
append_column(column);
factory = Gtk::SignalListItemFactory::create();
factory->signal_setup().connect(
sigc::mem_fun(*this, &CallstackView::on_setup_label));
factory->signal_bind().connect(
sigc::mem_fun(*this, &CallstackView::on_bind_depth));
column = Gtk::ColumnViewColumn::create("Depth", factory);
column->set_expand();
append_column(column);
}
_store = std::dynamic_pointer_cast<Gio::ListStore<ModelColumns>>(root);
}
void on_setup_keylabel(
const Glib::RefPtr<Gtk::ListItem>& list_item)
{
// Each ListItem contains a TreeExpander, which contains a Label.
// The Label shows the ModelColumns::m_holiday_name. That's done in on_bind_holiday().
auto expander = Gtk::make_managed<Gtk::TreeExpander>();
auto label = Gtk::make_managed<Gtk::Label>();
label->set_halign(Gtk::Align::START);
expander->set_child(*label);
list_item->set_child(*expander);
}
void on_setup_label(
const Glib::RefPtr<Gtk::ListItem>& list_item)
{
// Each ListItem contains a TreeExpander, which contains a Label.
// The Label shows the ModelColumns::m_holiday_name. That's done in on_bind_holiday().
auto label = Gtk::make_managed<Gtk::Label>();
label->set_halign(Gtk::Align::START);
list_item->set_child(*label);
}
void on_bind_callPoint(
const Glib::RefPtr<Gtk::ListItem>& list_item)
{
auto row = std::dynamic_pointer_cast<Gtk::TreeListRow>(list_item->get_item());
if (!row)
return;
auto col = std::dynamic_pointer_cast<ModelColumns>(row->get_item());
if (!col)
return;
auto expander = dynamic_cast<Gtk::TreeExpander*>(list_item->get_child());
if (!expander)
return;
expander->set_list_row(row);
auto label = dynamic_cast<Gtk::Label*>(expander->get_child());
if (!label)
return;
label->set_text(col->callPoint);
}
void on_bind_stackBase(
const Glib::RefPtr<Gtk::ListItem>& list_item)
{
auto row = std::dynamic_pointer_cast<Gtk::TreeListRow>(list_item->get_item());
if (!row)
return;
auto label = dynamic_cast<Gtk::Label*>(list_item->get_child());
if (!label)
return;
label->set_visible(!row->is_expandable());
if (row->is_expandable())
return;
auto col = std::dynamic_pointer_cast<ModelColumns>(row->get_item());
if (!col)
return;
label->set_text(col->stackBase);
}
void on_bind_symbol(
const Glib::RefPtr<Gtk::ListItem>& list_item)
{
auto row = std::dynamic_pointer_cast<Gtk::TreeListRow>(list_item->get_item());
if (!row)
return;
auto label = dynamic_cast<Gtk::Label*>(list_item->get_child());
if (!label)
return;
label->set_visible(!row->is_expandable());
if (row->is_expandable())
return;
auto col = std::dynamic_pointer_cast<ModelColumns>(row->get_item());
if (!col)
return;
label->set_text(col->symbol);
}
void on_bind_module(
const Glib::RefPtr<Gtk::ListItem>& list_item)
{
auto row = std::dynamic_pointer_cast<Gtk::TreeListRow>(list_item->get_item());
if (!row)
return;
auto label = dynamic_cast<Gtk::Label*>(list_item->get_child());
if (!label)
return;
label->set_visible(!row->is_expandable());
if (row->is_expandable())
return;
auto col = std::dynamic_pointer_cast<ModelColumns>(row->get_item());
if (!col)
return;
label->set_text(col->module);
}
void on_bind_depth(
const Glib::RefPtr<Gtk::ListItem>& list_item)
{
auto row = std::dynamic_pointer_cast<Gtk::TreeListRow>(list_item->get_item());
if (!row)
return;
auto label = dynamic_cast<Gtk::Label*>(list_item->get_child());
if (!label)
return;
label->set_visible(!row->is_expandable());
if (row->is_expandable())
return;
auto col = std::dynamic_pointer_cast<ModelColumns>(row->get_item());
if (!col)
return;
label->set_text(col->depth);
}
};