From 27181ae7dc81499dd3912849be7642a6f2fbceeb Mon Sep 17 00:00:00 2001 From: hachem Date: Sat, 29 Aug 2026 21:44:34 +0200 Subject: fix: rework source tree appearance --- src/ui/ui.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index c3a7fa2..c152ad1 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -55,6 +55,15 @@ namespace Hsdbg const ImU32 BREAKPOINT_DISABLED_COLOR = IM_COL32(120, 90, 90, 255); const ImU32 BREAKPOINT_HOVER_COLOR = IM_COL32(226, 84, 84, 90); + // folders read as structure, so they take a cool tint; the file that is + // currently open in the source view keeps its accent even when the row + // is not the selected one, so it stays easy to find in a long tree + const ImU32 SOURCE_FOLDER_COLOR = IM_COL32(150, 178, 214, 255); + const ImU32 SOURCE_OPEN_FILE_COLOR = IM_COL32(126, 194, 126, 255); + + // the dim connectors drawn between a folder and its children + const ImU32 SOURCE_TREE_LINE_COLOR = IM_COL32(110, 110, 122, 160); + auto breakpoint_at(Debugger& debugger, const Instruction& instruction) -> const Breakpoint* { for (const Breakpoint& candidate : debugger.breakpoints()) @@ -1087,6 +1096,8 @@ namespace Hsdbg const SourceNode tree = build_source_tree(files); const std::filesystem::path& open = m_source_view.path(); + ImDrawList* const draw_list = ImGui::GetWindowDrawList(); + const auto draw_node = [&](this const auto& self, const SourceNode& node) -> void { if (!source_node_matches(node, m_source_filter)) @@ -1096,7 +1107,15 @@ namespace Hsdbg { const bool selected = node.path == open; - if (ImGui::Selectable(node.name.c_str(), selected)) + if (selected) + ImGui::PushStyleColor(ImGuiCol_Text, SOURCE_OPEN_FILE_COLOR); + + const bool clicked = ImGui::Selectable(node.name.c_str(), selected); + + if (selected) + ImGui::PopStyleColor(); + + if (clicked) { open_source(node.path); ImGui::SetWindowFocus(PANEL_SOURCE); @@ -1109,16 +1128,48 @@ namespace Hsdbg } ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_SpanAvailWidth | - ImGuiTreeNodeFlags_OpenOnArrow; + ImGuiTreeNodeFlags_OpenOnArrow | + ImGuiTreeNodeFlags_OpenOnDoubleClick; if (m_source_filter.empty()) flags |= ImGuiTreeNodeFlags_DefaultOpen; - if (!ImGui::TreeNodeEx(node.name.c_str(), flags)) + ImGui::PushStyleColor(ImGuiCol_Text, SOURCE_FOLDER_COLOR); + const bool open_node = ImGui::TreeNodeEx(node.name.c_str(), flags); + ImGui::PopStyleColor(); + + if (!open_node) return; + // connect this folder to each visible child the way `tree` + // does: a vertical spine down the gutter with a horizontal + // tick out to every child, the spine ending at the last one. + // the glyphs would be tofu in the default font, so the lines + // are drawn by hand + const float indent = ImGui::GetStyle().IndentSpacing; + const float half_row = ImGui::GetTextLineHeight() * 0.5f; + const float spine_x = ImGui::GetCursorScreenPos().x - indent * 0.5f; + const float top_y = ImGui::GetCursorScreenPos().y; + float last_y = top_y; + for (const SourceNode& child : node.children) + { + if (!source_node_matches(child, m_source_filter)) + continue; + + const float row_y = ImGui::GetCursorScreenPos().y + half_row; + + draw_list->AddLine(ImVec2(spine_x, row_y), + ImVec2(spine_x + indent * 0.5f - 3.0f, row_y), + SOURCE_TREE_LINE_COLOR); + last_y = row_y; + self(child); + } + + draw_list->AddLine(ImVec2(spine_x, top_y), + ImVec2(spine_x, last_y), + SOURCE_TREE_LINE_COLOR); ImGui::TreePop(); }; -- cgit v1.3