diff --git a/src/ui/gitree_ui.cpp b/src/ui/gitree_ui.cpp index c566966..f2003d0 100644 --- a/src/ui/gitree_ui.cpp +++ b/src/ui/gitree_ui.cpp @@ -468,14 +468,47 @@ void draw_details() { ImGui::EndChild(); } -bool toolbar_action(const char* id, const char* icon, const char* tooltip) { +bool toolbar_action(const char* id, const char* label, const char* icon, const char* tooltip, + bool enabled = true, bool dropdown = false, float logical_width = 58.0f) { ImGui::PushID(id); - const bool clicked = ImGui::Button(icon, {ui(36), ui(36)}); + if (!enabled) ImGui::BeginDisabled(); + const bool clicked = ImGui::InvisibleButton("##action", {ui(logical_width), ui(58.0f)}); + const ImVec2 minimum = ImGui::GetItemRectMin(); + const ImVec2 maximum = ImGui::GetItemRectMax(); + ImDrawList* draw = ImGui::GetWindowDrawList(); + if (enabled && ImGui::IsItemHovered()) + draw->AddRectFilled(minimum, maximum, IM_COL32(55, 62, 74, 180), ui(3.0f)); + const ImU32 text_color = enabled ? IM_COL32(215, 220, 229, 255) : IM_COL32(105, 111, 122, 255); + const ImVec2 label_size = ImGui::CalcTextSize(label); + const ImVec2 icon_size = ImGui::CalcTextSize(icon); + draw->AddText({minimum.x + (maximum.x - minimum.x - label_size.x) * 0.5f, minimum.y + ui(3.0f)}, + text_color, label); + const float icon_x = minimum.x + (maximum.x - minimum.x - icon_size.x) * 0.5f - (dropdown ? ui(4.0f) : 0.0f); + draw->AddText({icon_x, minimum.y + ui(27.0f)}, text_color, icon); + if (dropdown) + draw->AddText({icon_x + icon_size.x + ui(8.0f), minimum.y + ui(25.0f)}, text_color, ICON_FA_CARET_DOWN); if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) { ImGui::BeginTooltip(); ImGui::TextUnformatted(tooltip); ImGui::EndTooltip(); } + if (!enabled) ImGui::EndDisabled(); + ImGui::PopID(); + return clicked; +} + +bool toolbar_selector(const char* id, const char* label, const std::string& value, + float logical_width, bool trailing_arrow = false) { + ImGui::PushID(id); + const bool clicked = ImGui::InvisibleButton("##selector", {ui(logical_width), ui(58.0f)}); + const ImVec2 minimum = ImGui::GetItemRectMin(); + const ImVec2 maximum = ImGui::GetItemRectMax(); + ImDrawList* draw = ImGui::GetWindowDrawList(); + if (ImGui::IsItemHovered()) draw->AddRectFilled(minimum, maximum, IM_COL32(55, 62, 74, 150), ui(3.0f)); + draw->AddText({minimum.x + ui(8), minimum.y + ui(3)}, IM_COL32(155, 164, 178, 255), label); + draw->AddText({minimum.x + ui(8), minimum.y + ui(27)}, IM_COL32(236, 239, 244, 255), value.c_str()); + draw->AddText({maximum.x - ui(18), minimum.y + ui(27)}, IM_COL32(148, 156, 168, 255), + trailing_arrow ? ICON_FA_ANGLE_RIGHT : ICON_FA_CARET_DOWN); ImGui::PopID(); return clicked; } @@ -695,36 +728,54 @@ void draw_app() { return; } - ImGui::BeginChild("repo_toolbar", {-1, ui(56)}, ImGuiChildFlags_Borders); - ImGui::TextDisabled("repository"); - ImGui::SameLine(ui(145)); ImGui::TextDisabled("branch"); - ImGui::SetCursorPosY(ui(26)); - ImGui::Text("%s", repo().name.c_str()); - ImGui::SameLine(ui(145)); - ImGui::SetNextItemWidth(ui(180)); - if (ImGui::BeginCombo("##branch", repo().branch.c_str())) { - for (const auto& branch : repo().local_branches) ImGui::Selectable(branch.c_str(), branch == repo().branch); - ImGui::EndCombo(); + ImGui::BeginChild("repo_toolbar", {-1, ui(64)}, ImGuiChildFlags_Borders); + ImGui::SetCursorPos({ui(5), ui(2)}); + if (toolbar_selector("repository", "repository", repo().name, 120.0f)) + g_notice = "Use repository tabs to switch repositories"; + ImGui::SameLine(0, ui(3)); + ImGui::SetCursorPosY(ui(28)); + ImGui::TextDisabled(ICON_FA_ANGLE_RIGHT); + ImGui::SameLine(0, ui(3)); + ImGui::SetCursorPosY(ui(2)); + if (toolbar_selector("branch", "branch", repo().branch, 120.0f)) ImGui::OpenPopup("branch_selector"); + if (ImGui::BeginPopup("branch_selector")) { + for (const auto& branch : repo().local_branches) { + if (ImGui::MenuItem(branch.c_str(), nullptr, branch == repo().branch) && branch != repo().branch) + g_git_manager->checkoutBranch(repo(), branch, g_notice); + } + ImGui::EndPopup(); } - constexpr int action_count = 6; - const float action_size = ui(36.0f); - const float action_spacing = ui(7.0f); - const float action_group_width = action_size * action_count + action_spacing * (action_count - 1); - const float centered_x = (ImGui::GetWindowWidth() - action_group_width) * 0.5f; - ImGui::SetCursorPos({std::max(ui(350.0f), centered_x), ui(10.0f)}); - if (toolbar_action("pull", ICON_FA_DOWNLOAD, "Pull from remote")) g_notice = "Pull is not wired yet"; + const float action_spacing = ui(3.0f); + const float action_group_width = ui(507.0f); + const float centered_x = (ImGui::GetWindowWidth() - action_group_width) * 0.5f; + ImGui::SetCursorPos({std::max(ui(300.0f), centered_x), ui(2.0f)}); + + if (toolbar_action("undo", "Undo", ICON_FA_ROTATE_LEFT, "Undo last Git action", true, false, 54)) + g_notice = "Undo is not wired yet"; ImGui::SameLine(0, action_spacing); - if (toolbar_action("push", ICON_FA_UPLOAD, "Push to remote")) g_notice = "Push is not wired yet"; + toolbar_action("redo", "Redo", ICON_FA_ROTATE_RIGHT, "Redo last Git action", false, false, 54); ImGui::SameLine(0, action_spacing); - if (toolbar_action("branch", ICON_FA_CODE_BRANCH, "Create branch")) g_notice = "Branch creation is not wired yet"; + if (toolbar_action("pull", "Pull", ICON_FA_DOWNLOAD, "Pull from remote", true, true, 58)) + g_notice = "Pull is not wired yet"; ImGui::SameLine(0, action_spacing); - if (toolbar_action("stash", ICON_FA_BOX_ARCHIVE, "Stash changes")) g_notice = "Stash is not wired yet"; + if (toolbar_action("push", "Push", ICON_FA_UPLOAD, "Push to remote", true, false, 58)) + g_notice = "Push is not wired yet"; ImGui::SameLine(0, action_spacing); - if (toolbar_action("pop", ICON_FA_BOX_OPEN, "Pop latest stash")) g_notice = "Stash pop is not wired yet"; + if (toolbar_action("branch_action", "Branch", ICON_FA_CODE_BRANCH, "Create branch", true, false, 64)) + g_notice = "Branch creation is not wired yet"; ImGui::SameLine(0, action_spacing); - if (toolbar_action("refresh", ICON_FA_ROTATE, "Refresh repository")) - g_git_manager->reload(repo(), g_notice); + toolbar_action("stash", "Stash", ICON_FA_BOX_ARCHIVE, "Stash changes", false, false, 58); + ImGui::SameLine(0, action_spacing); + toolbar_action("pop", "Pop", ICON_FA_BOX_OPEN, "Pop latest stash", false, false, 54); + ImGui::SameLine(0, ui(5)); + const ImVec2 divider = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddLine({divider.x, divider.y}, {divider.x, divider.y + ui(58)}, + IM_COL32(82, 89, 103, 255), ui(1)); + ImGui::Dummy({ui(5), ui(58)}); + ImGui::SameLine(0, ui(5)); + if (toolbar_action("terminal", "Terminal", ICON_FA_TERMINAL, "Open repository terminal", true, false, 76)) + g_notice = "Terminal is not wired yet"; ImGui::EndChild(); draw_sidebar(ui(g_sidebar_width));