diff --git a/src/ui/gitree_ui.cpp b/src/ui/gitree_ui.cpp index c01863c..5a06029 100644 --- a/src/ui/gitree_ui.cpp +++ b/src/ui/gitree_ui.cpp @@ -717,9 +717,14 @@ ImVec4 change_color(FileChangeKind kind) { void draw_file_row(const std::string& path, FileChangeKind kind, int id) { ImGui::PushID(id); - ImGui::PushStyleColor(ImGuiCol_Text, change_color(kind)); - ImGui::Selectable((std::string(change_icon(kind)) + " " + path).c_str()); - ImGui::PopStyleColor(); + ImGui::InvisibleButton("##file", {-1, ui(25.0f)}); + const ImVec2 minimum = ImGui::GetItemRectMin(); + const ImVec2 maximum = ImGui::GetItemRectMax(); + ImDrawList* draw = ImGui::GetWindowDrawList(); + if (ImGui::IsItemHovered()) draw->AddRectFilled(minimum, maximum, IM_COL32(48, 52, 60, 255)); + const float y = minimum.y + (maximum.y - minimum.y - ImGui::GetFontSize()) * 0.5f; + draw->AddText({minimum.x + ui(4.0f), y}, ImGui::ColorConvertFloat4ToU32(change_color(kind)), change_icon(kind)); + draw->AddText({minimum.x + ui(20.0f), y}, IM_COL32(174, 179, 187, 255), path.c_str()); if (ImGui::BeginPopupContextItem()) { if (ImGui::MenuItem(ICON_FA_COPY " Copy path")) ImGui::SetClipboardText(path.c_str()); ImGui::EndPopup(); @@ -729,7 +734,7 @@ void draw_file_row(const std::string& path, FileChangeKind kind, int id) { void draw_file_toolbar(bool show_view_all) { ImGui::TextDisabled(ICON_FA_ARROW_DOWN_A_Z); - const float controls_width = ui(225.0f); + const float controls_width = ui(show_view_all ? 225.0f : 227.0f); ImGui::SameLine(std::max(ImGui::GetCursorPosX() + ui(8), ImGui::GetWindowWidth() - controls_width)); const bool path_selected = g_file_view_mode == FileViewMode::path; if (path_selected) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.28f, 0.46f, 1)); @@ -779,44 +784,140 @@ void draw_working_details() { int staged = 0; for (const auto& file : repo().working_files) if (file.staged) ++staged; const int unstaged = static_cast(repo().working_files.size()) - staged; + + ImGui::BeginChild("working_header", {-1, ui(34.0f)}, ImGuiChildFlags_None, + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + ImGui::SetCursorPos({0.0f, ui(5.0f)}); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.27f, 0.10f, 0.11f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.38f, 0.13f, 0.14f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.88f, 0.36f, 0.36f, 1.0f)); - if (ImGui::SmallButton(ICON_FA_TRASH_CAN "##discard_all")) g_notice = "Discard all is not wired yet"; + if (ImGui::Button(ICON_FA_TRASH_CAN "##discard_all", {ui(23.0f), ui(23.0f)})) + g_notice = "Discard all is not wired yet"; + ImGui::PopStyleColor(3); + + const std::string changes_label = std::to_string(repo().working_files.size()) + " file changes on"; + const float branch_width = ImGui::CalcTextSize(repo().branch.c_str()).x + ui(10.0f); + const float heading_width = ImGui::CalcTextSize(changes_label.c_str()).x + ui(6.0f) + branch_width; + ImGui::SameLine(std::max(ImGui::GetCursorPosX() + ui(6.0f), + (ImGui::GetWindowWidth() - heading_width) * 0.5f)); + ImGui::AlignTextToFramePadding(); + ImGui::TextUnformatted(changes_label.c_str()); + ImGui::SameLine(0, ui(6.0f)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.06f, 0.37f, 0.43f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.08f, 0.44f, 0.51f, 1.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {ui(5.0f), ui(1.0f)}); + ImGui::Button((repo().branch + "##working_branch").c_str()); + ImGui::PopStyleVar(); ImGui::PopStyleColor(2); - ImGui::SameLine(); - ImGui::SetCursorPosX(std::max(ImGui::GetCursorPosX(), (ImGui::GetWindowWidth() - ui(165)) * 0.5f)); - ImGui::Text("%d file changes on", static_cast(repo().working_files.size())); - ImGui::SameLine(); - ImGui::TextColored(ImVec4(0.25f, 0.80f, 0.86f, 1), "%s", repo().branch.c_str()); + + ImGui::SameLine(ImGui::GetWindowWidth() - ui(27.0f)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.19f, 0.08f, 0.38f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.48f, 0.14f, 0.86f, 1.0f)); + if (ImGui::Button(ICON_FA_WAND_MAGIC_SPARKLES "##working_assist", {ui(23.0f), ui(23.0f)})) + g_notice = "Commit assistance is not wired yet"; + ImGui::PopStyleColor(2); + ImGui::EndChild(); ImGui::Separator(); + + ImGui::BeginChild("working_file_toolbar", {-1, ui(42.0f)}, ImGuiChildFlags_None, + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + ImGui::SetCursorPosY(ui(8.0f)); draw_file_toolbar(false); + ImGui::EndChild(); + + const float composer_height = ui(320.0f); + const float files_height = std::max(ui(140.0f), ImGui::GetContentRegionAvail().y - composer_height); + ImGui::BeginChild("working_files", {-1, files_height}, ImGuiChildFlags_None, + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + const float unstaged_height = files_height * 0.52f; + ImGui::BeginChild("unstaged_files", {-1, unstaged_height}, ImGuiChildFlags_None); + const bool unstaged_open = ImGui::TreeNodeEx( + (std::string("Unstaged Files (") + std::to_string(unstaged) + ")").c_str(), + ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanAvailWidth); + ImGui::SameLine(std::max(ui(145.0f), ImGui::GetWindowWidth() - ui(119.0f))); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.12f, 0.27f, 0.18f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.24f, 0.72f, 0.35f, 1.0f)); + if (ImGui::SmallButton("Stage All Changes")) g_notice = "Staging is not wired yet"; + ImGui::PopStyleColor(2); ImGui::Separator(); - const float working_files_height = std::max(ui(120.0f), ImGui::GetContentRegionAvail().y - ui(260.0f)); - ImGui::BeginChild("working_files", {-1, working_files_height}, false); - if (ImGui::TreeNodeEx((std::string("Unstaged Files (") + std::to_string(unstaged) + ")").c_str(), - ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanAvailWidth)) { - ImGui::SameLine(std::max(ui(150), ImGui::GetWindowWidth() - ui(135))); - if (ImGui::SmallButton("Stage All Changes")) g_notice = "Staging is not wired yet"; + if (unstaged_open) { draw_files(repo().working_files, false, true); ImGui::TreePop(); } - if (ImGui::TreeNodeEx((std::string("Staged Files (") + std::to_string(staged) + ")").c_str(), - ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanAvailWidth)) { + ImGui::EndChild(); + + ImGui::BeginChild("staged_files", {-1, -1}, ImGuiChildFlags_None); + const bool staged_open = ImGui::TreeNodeEx( + (std::string("Staged Files (") + std::to_string(staged) + ")").c_str(), + ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanAvailWidth); + ImGui::Separator(); + if (staged_open) { draw_files(repo().working_files, true, true); ImGui::TreePop(); } ImGui::EndChild(); - ImGui::Separator(); + ImGui::EndChild(); + + ImGui::BeginChild("commit_composer", {-1, -1}, ImGuiChildFlags_None, + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + const float handle_x = (ImGui::GetWindowWidth() - ui(90.0f)) * 0.5f; + const ImVec2 handle = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddLine( + {handle.x + handle_x, handle.y + ui(3.0f)}, + {handle.x + handle_x + ui(90.0f), handle.y + ui(3.0f)}, + IM_COL32(56, 59, 65, 255), ui(3.0f)); + ImGui::Dummy({0.0f, ui(10.0f)}); ImGui::TextUnformatted(ICON_FA_CIRCLE_DOT " Commit"); + ImGui::SameLine(0, ui(14.0f)); + ImGui::TextDisabled(ICON_FA_DOWNLOAD); + ImGui::SameLine(0, ui(14.0f)); + ImGui::TextDisabled(ICON_FA_CLOUD); ImGui::Separator(); + static bool amend = false; ImGui::Checkbox("Amend previous commit", &amend); + + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(31 / 255.0f, 34 / 255.0f, 39 / 255.0f, 1.0f)); + ImGui::BeginChild("commit_message_card", {-1, ui(165.0f)}, ImGuiChildFlags_Borders); + const float summary_controls_width = ui(60.0f); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - summary_controls_width); ImGui::InputTextWithHint("##commit_summary", "Commit summary", g_commit_summary.data(), g_commit_summary.size()); + ImGui::SameLine(); + ImGui::TextDisabled("72"); + ImGui::SameLine(0, ui(4.0f)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.12f, 0.12f, 0.29f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.35f, 0.16f, 0.62f, 1.0f)); + if (ImGui::SmallButton(ICON_FA_WAND_MAGIC_SPARKLES "##summary_assist")) + g_notice = "Summary assistance is not wired yet"; + ImGui::PopStyleColor(2); + ImGui::SetNextItemWidth(-1); ImGui::InputTextMultiline("##commit_description", g_commit_description.data(), g_commit_description.size(), - {-1, ui(115)}); + {-1, -1}); + if (g_commit_description[0] == '\0' && !ImGui::IsItemActive()) { + const ImVec2 description_minimum = ImGui::GetItemRectMin(); + ImGui::GetWindowDrawList()->AddText( + {description_minimum.x + ui(6.0f), description_minimum.y + ui(5.0f)}, + IM_COL32(154, 159, 168, 255), "Description"); + } + ImGui::EndChild(); + ImGui::PopStyleColor(); + + ImGui::TextDisabled(ICON_FA_CHEVRON_RIGHT " Commit options"); + ImGui::SameLine(std::max(ui(130.0f), ImGui::GetWindowWidth() - ui(181.0f))); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.20f, 0.06f, 0.40f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.48f, 0.12f, 0.82f, 1.0f)); + if (ImGui::SmallButton(ICON_FA_WAND_MAGIC_SPARKLES " Compose commits with AI")) + g_notice = "Commit composition is not wired yet"; + ImGui::PopStyleColor(2); + ImGui::BeginDisabled(staged == 0 || g_commit_summary[0] == '\0'); - if (ImGui::Button("Stage Changes to Commit", {-1, ui(40)})) g_notice = "Commit creation is not wired yet"; + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.12f, 0.24f, 0.18f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.24f, 0.54f, 0.32f, 1.0f)); + if (ImGui::Button(ICON_FA_CIRCLE_DOT " Stage Changes to Commit", {-1, ui(40.0f)})) + g_notice = "Commit creation is not wired yet"; + ImGui::PopStyleColor(2); ImGui::EndDisabled(); + ImGui::EndChild(); } void draw_commit_details() { @@ -875,11 +976,15 @@ void draw_commit_details() { } void draw_details(float width) { + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(39 / 255.0f, 42 / 255.0f, 49 / 255.0f, 1.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {ui(10.0f), ui(8.0f)}); ImGui::BeginChild("details", {width, -ui(28.0f)}, ImGuiChildFlags_None); + ImGui::PopStyleVar(); if (repo().selected_commit == -1) draw_working_details(); else if (!repo().commits.empty()) draw_commit_details(); else ImGui::TextDisabled("Select a repository with commits"); ImGui::EndChild(); + ImGui::PopStyleColor(); } bool toolbar_action(const char* id, const char* label, const char* icon, const char* tooltip,