Skip to content

Commit

Permalink
Qt/CodeViewWidget: Indent branch arrows based on free space rather th…
Browse files Browse the repository at this point in the history
…an reserving a full column for each.
  • Loading branch information
AdmiralCurtiss committed Mar 15, 2020
1 parent 18127e2 commit 9c98b65
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 5 deletions.
81 changes: 76 additions & 5 deletions Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct CodeViewBranch
{
u32 src_addr;
u32 dst_addr;
u32 indentation = 0;
bool is_link;
};

Expand All @@ -60,11 +61,10 @@ class BranchDisplayDelegate : public QStyledItemDelegate

constexpr u32 x_offset_in_branch_for_vertical_line = 10;
const u32 addr = m_parent->AddressForRow(index.row());
u32 current_branch_index = 0;
for (const CodeViewBranch& branch : m_parent->m_branches)
{
const int y_center = option.rect.top() + option.rect.height() / 2;
const int x_left = option.rect.left() + WIDTH_PER_BRANCH_ARROW * current_branch_index;
const int x_left = option.rect.left() + WIDTH_PER_BRANCH_ARROW * branch.indentation;
const int x_right = x_left + x_offset_in_branch_for_vertical_line;

if (branch.is_link)
Expand Down Expand Up @@ -108,8 +108,6 @@ class BranchDisplayDelegate : public QStyledItemDelegate
}
}
}

++current_branch_index;
}

painter->restore();
Expand Down Expand Up @@ -322,15 +320,88 @@ void CodeViewWidget::Update()
}
}

CalculateBranchIndentation();

u32 max_indent = 0;
for (const CodeViewBranch& branch : m_branches)
max_indent = std::max(max_indent, branch.indentation);

resizeColumnsToContents();
setColumnWidth(CODE_VIEW_COLUMN_BRANCH_ARROWS,
static_cast<int>(WIDTH_PER_BRANCH_ARROW * m_branches.size()));
static_cast<int>(WIDTH_PER_BRANCH_ARROW * (max_indent + 1)));
g_symbolDB.FillInCallers();

repaint();
m_updating = false;
}

void CodeViewWidget::CalculateBranchIndentation()
{
const size_t rows = rowCount();
const size_t columns = m_branches.size();
if (rows < 1 || columns < 1)
return;

// process in order of how much vertical space the drawn arrow would take up
// so shorter arrows go further to the left
const auto priority = [](const CodeViewBranch& b) {
return b.is_link ? 0 : (std::max(b.src_addr, b.dst_addr) - std::min(b.src_addr, b.dst_addr));
};
std::stable_sort(m_branches.begin(), m_branches.end(),
[&priority](const CodeViewBranch& lhs, const CodeViewBranch& rhs) {
return priority(lhs) < priority(rhs);
});

// build a 2D lookup table representing the columns and rows the arrow could be drawn in
// and try to place all branch arrows in it as far left as possible
std::vector<bool> arrow_space_used(columns * rows, false);
const auto index = [&](u32 column, u32 row) { return column * rows + row; };
const u32 first_visible_addr = AddressForRow(0);
const u32 last_visible_addr = AddressForRow(static_cast<int>(rows - 1));
for (CodeViewBranch& branch : m_branches)
{
const u32 arrow_src_addr = branch.src_addr;
const u32 arrow_dst_addr = branch.is_link ? branch.src_addr : branch.dst_addr;
const u32 arrow_addr_lower = std::min(arrow_src_addr, arrow_dst_addr);
const u32 arrow_addr_higher = std::max(arrow_src_addr, arrow_dst_addr);
const bool is_visible =
last_visible_addr >= arrow_addr_lower || first_visible_addr <= arrow_addr_higher;
if (!is_visible)
continue;

const u32 arrow_first_visible_addr =
std::clamp(arrow_addr_lower, first_visible_addr, last_visible_addr);
const u32 arrow_last_visible_addr =
std::clamp(arrow_addr_higher, first_visible_addr, last_visible_addr);
const u32 arrow_first_visible_row = (arrow_first_visible_addr - first_visible_addr) / 4;
const u32 arrow_last_visible_row = (arrow_last_visible_addr - first_visible_addr) / 4;

const auto free_column = [&]() -> std::optional<u32> {
for (u32 column = 0; column < columns; ++column)
{
const bool column_is_free = [&] {
for (u32 row = arrow_first_visible_row; row <= arrow_last_visible_row; ++row)
{
if (arrow_space_used[index(column, row)])
return false;
}
return true;
}();
if (column_is_free)
return column;
}
return std::nullopt;
}();

if (!free_column)
continue;

branch.indentation = *free_column;
for (u32 row = arrow_first_visible_row; row <= arrow_last_visible_row; ++row)
arrow_space_used[index(*free_column, row)] = true;
}
}

u32 CodeViewWidget::GetAddress() const
{
return m_address;
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DolphinQt/Debugger/CodeViewWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ class CodeViewWidget : public QTableWidget
void OnReplaceInstruction();
void OnRestoreInstruction();

void CalculateBranchIndentation();

bool m_updating = false;

u32 m_address = 0;
Expand Down

0 comments on commit 9c98b65

Please sign in to comment.