From 0fea9ab8a43ab27c8ee9edb3f7682a500f4d546e Mon Sep 17 00:00:00 2001 From: GigabiteStudios Date: Fri, 19 Jun 2026 15:52:20 -0500 Subject: [PATCH] Fix selection reset on background refresh, support per-repo table column widths, fix minimap drag scrolling & colors, indent details panels --- src/managers/user_data.cpp | 69 +++++++++++++++++++++++++++++++++++++- src/managers/user_data.h | 5 +-- src/ui/diff_viewer.cpp | 4 ++- src/ui/gitree_ui.cpp | 28 +++++++++++----- 4 files changed, 93 insertions(+), 13 deletions(-) diff --git a/src/managers/user_data.cpp b/src/managers/user_data.cpp index af006e2..cd64ab5 100644 --- a/src/managers/user_data.cpp +++ b/src/managers/user_data.cpp @@ -206,10 +206,33 @@ void UserData::load() if (const ikv_node_t *widths = object_value(settings, "commit_table_columns", IKV_ARRAY)) { const uint32_t count = std::min( - ikv_array_size(widths), static_cast(commit_table_column_widths_.size())); + ikv_array_size(widths), 4); for (uint32_t index = 0; index < count; ++index) commit_table_column_widths_[index] = static_cast(ikv_as_float(ikv_array_get(widths, index))); } + if (const ikv_node_t *repos = object_value(settings, "repository_settings", IKV_ARRAY)) + { + for (uint32_t index = 0; index < ikv_array_size(repos); ++index) + { + const ikv_node_t *repo_entry = ikv_array_get(repos, index); + if (ikv_node_type(repo_entry) != IKV_OBJECT) + continue; + const ikv_node_t *path_node = object_value(repo_entry, "path", IKV_STRING); + const ikv_node_t *widths_node = object_value(repo_entry, "commit_table_columns", IKV_ARRAY); + if (!path_node || !widths_node) + continue; + const char *path_str = ikv_as_string(path_node); + if (path_str && *path_str) + { + std::string normalized_path = normalizePath(path_str); + std::array &arr = repo_column_widths_[normalized_path]; + arr = commit_table_column_widths_; + const uint32_t count = std::min(ikv_array_size(widths_node), 4); + for (uint32_t c = 0; c < count; ++c) + arr[c] = static_cast(ikv_as_float(ikv_array_get(widths_node, c))); + } + } + } } if (const ikv_node_t *history = object_value(root, "recently_closed", IKV_ARRAY)) { @@ -279,6 +302,11 @@ void UserData::load() height = std::clamp(height, 42.0f, 500.0f); for (float &width : commit_table_column_widths_) width = std::clamp(width, 0.0f, 1200.0f); + for (auto &[repo, widths_arr] : repo_column_widths_) + { + for (float &width : widths_arr) + width = std::clamp(width, 0.0f, 1200.0f); + } if (open_repositories_.empty()) active_repository_ = 0; else @@ -570,6 +598,16 @@ void UserData::save() const for (const float width : commit_table_column_widths_) ikv_array_add_float(widths, width); + ikv_node_t *repos = ikv_object_add_array(settings, "repository_settings", IKV_OBJECT); + for (const auto &[repo_path, col_widths] : repo_column_widths_) + { + ikv_node_t *repo_entry = ikv_array_add_object(repos); + ikv_object_set_string(repo_entry, "path", repo_path.c_str()); + ikv_node_t *repo_widths = ikv_object_add_array(repo_entry, "commit_table_columns", IKV_FLOAT); + for (const float w : col_widths) + ikv_array_add_float(repo_widths, w); + } + ikv_node_t *history = ikv_object_add_array(root, "recently_closed", IKV_STRING); for (const auto &path : recently_closed_) ikv_array_add_string(history, path.c_str()); @@ -596,3 +634,32 @@ void UserData::save() const ikv_free(root); removeLegacyFiles(); } + +float UserData::commitTableColumnWidth(const std::string &repo_path, size_t index) const +{ + if (index >= 4) + return 0.0f; + std::string normalized = normalizePath(repo_path); + auto it = repo_column_widths_.find(normalized); + if (it != repo_column_widths_.end()) + return it->second[index]; + return commit_table_column_widths_[index]; +} + +void UserData::setCommitTableColumnWidth(const std::string &repo_path, size_t index, float width) +{ + if (index >= 4) + return; + std::string normalized = normalizePath(repo_path); + std::array &widths = repo_column_widths_[normalized]; + + // If this is a new entry, initialize with default global widths first + auto it = repo_column_widths_.find(normalized); + if (it->second[0] == 0.0f && it->second[1] == 0.0f && it->second[2] == 0.0f && it->second[3] == 0.0f) + { + widths = commit_table_column_widths_; + } + + widths[index] = width; + save(); +} diff --git a/src/managers/user_data.h b/src/managers/user_data.h index 61305f8..b054822 100644 --- a/src/managers/user_data.h +++ b/src/managers/user_data.h @@ -30,7 +30,7 @@ public: [[nodiscard]] float sidebarSectionHeight(size_t index) const { return sidebar_section_heights_.at(index); } [[nodiscard]] bool sidebarCollapsed() const { return sidebar_collapsed_; } [[nodiscard]] bool sidebarSectionOpen(size_t index) const { return sidebar_section_open_.at(index); } - [[nodiscard]] float commitTableColumnWidth(size_t index) const { return commit_table_column_widths_.at(index); } + [[nodiscard]] float commitTableColumnWidth(const std::string &repo_path, size_t index) const; [[nodiscard]] int pullMode() const { return pull_mode_; } [[nodiscard]] int zoomPercent() const { return zoom_percent_; } [[nodiscard]] std::optional remoteCredential(const std::string &remote_url) const; @@ -41,7 +41,7 @@ public: void setSidebarSectionHeight(size_t index, float height) { sidebar_section_heights_.at(index) = height; } void setSidebarCollapsed(bool collapsed) { sidebar_collapsed_ = collapsed; } void setSidebarSectionOpen(size_t index, bool open) { sidebar_section_open_.at(index) = open; } - void setCommitTableColumnWidth(size_t index, float width) { commit_table_column_widths_.at(index) = width; } + void setCommitTableColumnWidth(const std::string &repo_path, size_t index, float width); void setPullMode(int mode) { pull_mode_ = mode; @@ -76,6 +76,7 @@ private: std::array sidebar_section_heights_ = {110.0f, 220.0f, 90.0f, 150.0f}; bool sidebar_collapsed_ = false; std::array sidebar_section_open_ = {true, true, true, true}; + std::unordered_map> repo_column_widths_; std::array commit_table_column_widths_ = {0.0f, 0.0f, 0.0f, 0.0f}; int pull_mode_ = 1; int zoom_percent_ = 100; diff --git a/src/ui/diff_viewer.cpp b/src/ui/diff_viewer.cpp index 0587043..c3980ba 100644 --- a/src/ui/diff_viewer.cpp +++ b/src/ui/diff_viewer.cpp @@ -439,7 +439,7 @@ std::vector buildMinimapSegments(const std::string& text, Syntax if (std::isspace(value)) { size_t end = cursor + 1; while (end < text.size() && std::isspace(static_cast(text[end]))) ++end; - addMinimapSegment(segments, std::max(0.04f, static_cast(end - cursor) * 0.18f), IM_COL32(0, 0, 0, 0)); + addMinimapSegment(segments, static_cast(end - cursor) * 0.22f, IM_COL32(0, 0, 0, 0)); cursor = end; continue; } @@ -588,7 +588,9 @@ void drawMinimap(const std::vector& entries, const ImVec2& viewpor if ((hovered || active) && ImGui::IsMouseDown(ImGuiMouseButton_Left)) { const float mouse_ratio = std::clamp((ImGui::GetIO().MousePos.y - minimum.y) / std::max(1.0f, content_size.y), 0.0f, 1.0f); const float target = std::clamp(mouse_ratio * rendered_height - clamped_visible_height * 0.5f, 0.0f, max_scroll_y); + ImGui::BeginChild("diff_content_main"); ImGui::SetScrollY(target); + ImGui::EndChild(); } draw->AddRectFilled({minimum.x + scaled(1.0f, scale), viewport_y}, {minimum.x + viewport_size.x - scaled(1.0f, scale), viewport_y + viewport_height}, diff --git a/src/ui/gitree_ui.cpp b/src/ui/gitree_ui.cpp index c4f95e7..af714d0 100644 --- a/src/ui/gitree_ui.cpp +++ b/src/ui/gitree_ui.cpp @@ -368,8 +368,9 @@ void transfer_repository_state(RepositoryView& source, RepositoryView& target) { target.undo_action = std::move(source.undo_action); target.redo_action = std::move(source.redo_action); } - std::string selected_commit_hash(const RepositoryView& repository) { + if (repository.selected_commit == -1) + return "working_tree"; if (repository.selected_commit < 0 || repository.selected_commit >= static_cast(repository.commits.size())) return {}; return oid_string(repository.commits[static_cast(repository.selected_commit)].oid); @@ -377,6 +378,10 @@ std::string selected_commit_hash(const RepositoryView& repository) { void restore_selected_commit(RepositoryView& repository, const std::string& hash) { if (hash.empty()) return; + if (hash == "working_tree") { + repository.selected_commit = -1; + return; + } git_oid target{}; if (git_oid_fromstr(&target, hash.c_str()) != 0) return; for (size_t index = 0; index < repository.commits.size(); ++index) { @@ -1954,15 +1959,15 @@ void draw_commit_table() { float graph_width = default_graph_width; float date_width = default_date_width; if (g_user_data) { - reference_width = std::clamp(ui(g_user_data->commitTableColumnWidth(0)), + reference_width = std::clamp(ui(g_user_data->commitTableColumnWidth(repo().path, 0)), ui(120.0f), std::max(ui(120.0f), available_table_width * 0.45f)); - graph_width = std::clamp(ui(g_user_data->commitTableColumnWidth(1)), + graph_width = std::clamp(ui(g_user_data->commitTableColumnWidth(repo().path, 1)), ui(90.0f), std::max(ui(90.0f), available_table_width * 0.35f)); - date_width = std::clamp(ui(g_user_data->commitTableColumnWidth(3)), + date_width = std::clamp(ui(g_user_data->commitTableColumnWidth(repo().path, 3)), ui(130.0f), std::max(ui(130.0f), available_table_width * 0.30f)); - if (g_user_data->commitTableColumnWidth(0) <= 0.0f) reference_width = default_reference_width; - if (g_user_data->commitTableColumnWidth(1) <= 0.0f) graph_width = default_graph_width; - if (g_user_data->commitTableColumnWidth(3) <= 0.0f) date_width = default_date_width; + if (g_user_data->commitTableColumnWidth(repo().path, 0) <= 0.0f) reference_width = default_reference_width; + if (g_user_data->commitTableColumnWidth(repo().path, 1) <= 0.0f) graph_width = default_graph_width; + if (g_user_data->commitTableColumnWidth(repo().path, 3) <= 0.0f) date_width = default_date_width; } if (reference_width + graph_width + date_width > available_table_width - ui(120.0f)) { const float scale = std::max(0.5f, (available_table_width - ui(120.0f)) / @@ -2020,7 +2025,7 @@ void draw_commit_table() { ImGui::TableHeadersRow(); if (g_user_data) { for (int column = 0; column < 4; ++column) - g_user_data->setCommitTableColumnWidth(static_cast(column), + g_user_data->setCommitTableColumnWidth(repo().path, static_cast(column), ImGui::GetColumnWidth(column) / g_ui_scale); } ImGui::PopStyleColor(); @@ -2033,8 +2038,9 @@ void draw_commit_table() { const float row_left = cursor.x - ImGui::GetStyle().CellPadding.x; const float row_top = cursor.y - ImGui::GetStyle().CellPadding.y; const float message_left = row_left + reference_width + graph_width; + const float scrollbar_size = ImGui::GetWindowWidth() - ImGui::GetWindowContentRegionMax().x > 0.0f ? ImGui::GetStyle().ScrollbarSize : 0.0f; const float row_right = message_left + message_width + date_width + - ImGui::GetStyle().CellPadding.x * 2.0f; + ImGui::GetStyle().CellPadding.x * 2.0f - scrollbar_size; const ImVec2 mouse = ImGui::GetIO().MousePos; hovered = ImGui::IsWindowHovered() && mouse.x >= row_left && mouse.x < row_right && mouse.y >= row_top && mouse.y < row_top + row_height; @@ -2594,6 +2600,7 @@ void draw_files(const std::vector& files, bool staged_filter = false, } void draw_working_details() { + ImGui::Indent(ui(10.0f)); int staged = 0; for (const auto& file : repo().working_files) if (file.staged) ++staged; const int unstaged = static_cast(repo().working_files.size()) - staged; @@ -2804,9 +2811,11 @@ void draw_working_details() { ImGui::EndDisabled(); ImGui::Unindent(ui(8.0f)); ImGui::EndChild(); + ImGui::Unindent(ui(10.0f)); } void draw_commit_details() { + ImGui::Indent(ui(10.0f)); const int selected = std::clamp(repo().selected_commit, 0, static_cast(repo().commits.size() - 1)); g_git_manager->loadCommitChanges(repo(), selected, g_notice); auto& commit = repo().commits[selected]; @@ -2918,6 +2927,7 @@ void draw_commit_details() { ? commit.all_files : commit.changed_files; draw_files(displayed_files, false, false, oid_string(commit.oid)); ImGui::EndChild(); + ImGui::Unindent(ui(10.0f)); } void draw_details(float width) {