feat(ui): wire Git actions and operation dialogs
This commit is contained in:
@@ -40,9 +40,21 @@ std::string g_notice;
|
||||
bool g_init_popup = false;
|
||||
bool g_about_popup = false;
|
||||
bool g_licenses_popup = false;
|
||||
bool g_branch_create_popup = false;
|
||||
bool g_tag_create_popup = false;
|
||||
bool g_remote_add_popup = false;
|
||||
bool g_worktree_add_popup = false;
|
||||
bool g_submodule_add_popup = false;
|
||||
bool g_discard_all_popup = false;
|
||||
std::array<char, 256> g_git_name{};
|
||||
std::array<char, 1024> g_git_value{};
|
||||
std::array<char, 1024> g_git_path{};
|
||||
std::string g_git_target;
|
||||
enum class FileViewMode { path, tree };
|
||||
FileViewMode g_file_view_mode = FileViewMode::path;
|
||||
bool g_view_all_files = false;
|
||||
bool g_sidebar_workspace_view = false;
|
||||
bool g_request_branch_selector = false;
|
||||
std::array<char, 128> g_commit_summary{};
|
||||
std::array<char, 1024> g_commit_description{};
|
||||
float g_ui_scale = 1.0f;
|
||||
@@ -289,7 +301,17 @@ bool sidebar_section_header(const char* label, int count, const char* add_toolti
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.43f, 0.90f, 0.51f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.25f, 0.72f, 0.35f, 1.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {ui(5.0f), ui(1.0f)});
|
||||
if (ImGui::SmallButton(ICON_FA_PLUS "##add")) g_notice = add_notice;
|
||||
if (ImGui::SmallButton(ICON_FA_PLUS "##add")) {
|
||||
const std::string section = label;
|
||||
if (section.find("LOCAL") != std::string::npos) {
|
||||
g_git_target.clear();
|
||||
g_branch_create_popup = true;
|
||||
}
|
||||
else if (section.find("REMOTE") != std::string::npos) g_remote_add_popup = true;
|
||||
else if (section.find("WORKTREES") != std::string::npos) g_worktree_add_popup = true;
|
||||
else if (section.find("SUBMODULES") != std::string::npos) g_submodule_add_popup = true;
|
||||
else g_notice = add_notice;
|
||||
}
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) ImGui::SetTooltip("%s", add_tooltip);
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor(2);
|
||||
@@ -344,7 +366,8 @@ void section(const char* label, const std::vector<std::string>& items, const cha
|
||||
const bool open = sidebar_section_header(label, static_cast<int>(items.size()), add_tooltip, add_notice);
|
||||
if (open && body_height >= ui(1.0f)) {
|
||||
ImGui::BeginChild((std::string(label) + "##body").c_str(), {-1, body_height});
|
||||
for (const auto& item : items) {
|
||||
const std::vector<std::string> snapshot = items;
|
||||
for (const auto& item : snapshot) {
|
||||
sidebar_item_row(item_icon, item, item);
|
||||
sidebar_item_context(item, kind);
|
||||
}
|
||||
@@ -379,7 +402,10 @@ void branch_context(const std::string& branch, bool remote) {
|
||||
if (!ImGui::BeginPopupContextItem()) return;
|
||||
if (!remote && ImGui::MenuItem(ICON_FA_CODE_BRANCH " Checkout"))
|
||||
g_git_manager->checkoutBranch(repo(), branch, g_notice);
|
||||
if (remote && ImGui::MenuItem(ICON_FA_DOWNLOAD " Fetch")) g_notice = "Remote fetch is not wired yet";
|
||||
if (remote && ImGui::MenuItem(ICON_FA_DOWNLOAD " Fetch")) {
|
||||
const size_t slash = branch.find('/');
|
||||
g_git_manager->fetch(repo(), slash == std::string::npos ? branch : branch.substr(0, slash), g_notice);
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem(ICON_FA_COPY " Copy branch name")) ImGui::SetClipboardText(branch.c_str());
|
||||
ImGui::EndPopup();
|
||||
@@ -434,12 +460,26 @@ void draw_sidebar(float width) {
|
||||
ImGui::BeginChild("sidebar", {width, -ui(28.0f)}, ImGuiChildFlags_None,
|
||||
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||
const float mode_button_width = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||
if (ImGui::Button(ICON_FA_LIST " List", {mode_button_width, ui(30)})) {}
|
||||
const bool list_selected = !g_sidebar_workspace_view;
|
||||
if (list_selected)
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.25f, 0.40f, 1.0f));
|
||||
if (ImGui::Button(ICON_FA_LIST " List", {mode_button_width, ui(30)})) g_sidebar_workspace_view = false;
|
||||
if (list_selected) ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_FA_LAYER_GROUP " Workspace", {mode_button_width, ui(30)})) {}
|
||||
ImGui::TextDisabled(ICON_FA_EYE " VIEWING %d", static_cast<int>(repo().local_branches.size() + repo().remote_branches.size()));
|
||||
const bool workspace_selected = g_sidebar_workspace_view;
|
||||
if (workspace_selected)
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.25f, 0.40f, 1.0f));
|
||||
if (ImGui::Button(ICON_FA_LAYER_GROUP " Workspace", {mode_button_width, ui(30)}))
|
||||
g_sidebar_workspace_view = true;
|
||||
if (workspace_selected) ImGui::PopStyleColor();
|
||||
const int viewing_count = g_sidebar_workspace_view
|
||||
? static_cast<int>(repo().worktrees.size() + repo().submodules.size())
|
||||
: static_cast<int>(repo().local_branches.size() + repo().remote_branches.size());
|
||||
ImGui::TextDisabled(ICON_FA_EYE " VIEWING %d", viewing_count);
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
ImGui::InputTextWithHint("##filter", ICON_FA_MAGNIFYING_GLASS " Search branches...", g_filter.data(), g_filter.size());
|
||||
ImGui::InputTextWithHint("##filter", g_sidebar_workspace_view
|
||||
? ICON_FA_MAGNIFYING_GLASS " Search workspace..."
|
||||
: ICON_FA_MAGNIFYING_GLASS " Search branches...", g_filter.data(), g_filter.size());
|
||||
ImGui::Spacing();
|
||||
ImGui::BeginChild("sidebar_sections", {-1, -1}, ImGuiChildFlags_None,
|
||||
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||
@@ -455,11 +495,15 @@ void draw_sidebar(float width) {
|
||||
std::array<bool, 4> section_open{};
|
||||
int open_count = 0;
|
||||
for (size_t index = 0; index < section_open.size(); ++index) {
|
||||
if (g_sidebar_workspace_view ? index < 2 : index >= 2) {
|
||||
section_open[index] = false;
|
||||
continue;
|
||||
}
|
||||
section_open[index] = sidebar_section_is_open(section_ids[index]);
|
||||
if (!section_open[index]) continue;
|
||||
++open_count;
|
||||
}
|
||||
const float header_space = (ui(22.0f) + 1.0f) * static_cast<float>(section_open.size());
|
||||
const float header_space = (ui(22.0f) + 1.0f) * 2.0f;
|
||||
const float splitter_space = ui(5.0f) * open_count;
|
||||
const float body_space = std::max(0.0f, ImGui::GetContentRegionAvail().y - header_space - splitter_space);
|
||||
std::array<float, 4> section_heights{};
|
||||
@@ -488,13 +532,16 @@ void draw_sidebar(float width) {
|
||||
maximum_heights[index] = std::max(1.0f, logical_body_space - other_heights);
|
||||
}
|
||||
|
||||
branch_section(ICON_FA_HOUSE " LOCAL", repo().local_branches, ICON_FA_CODE_BRANCH, ICON_FA_FOLDER,
|
||||
"Create local branch", "Branch creation is not wired yet", false, 0, section_heights[0], maximum_heights[0]);
|
||||
branch_section(ICON_FA_CLOUD " REMOTE", repo().remote_branches, ICON_FA_CODE_BRANCH, ICON_FA_GLOBE,
|
||||
"Add remote", "Remote creation is not wired yet", true, 1, section_heights[1], maximum_heights[1]);
|
||||
section(ICON_FA_DIAGRAM_PROJECT " WORKTREES", repo().worktrees, ICON_FA_COMPUTER,
|
||||
"Add worktree", "Worktree creation is not wired yet", SidebarItemKind::worktree, 2,
|
||||
section_heights[2], maximum_heights[2]);
|
||||
if (!g_sidebar_workspace_view) {
|
||||
branch_section(ICON_FA_HOUSE " LOCAL", repo().local_branches, ICON_FA_CODE_BRANCH, ICON_FA_FOLDER,
|
||||
"Create local branch", "Create local branch", false, 0, section_heights[0], maximum_heights[0]);
|
||||
branch_section(ICON_FA_CLOUD " REMOTE", repo().remote_branches, ICON_FA_CODE_BRANCH, ICON_FA_GLOBE,
|
||||
"Add remote", "Add remote", true, 1, section_heights[1], maximum_heights[1]);
|
||||
} else {
|
||||
section(ICON_FA_DIAGRAM_PROJECT " WORKTREES", repo().worktrees, ICON_FA_COMPUTER,
|
||||
"Add worktree", "Add worktree", SidebarItemKind::worktree, 2,
|
||||
section_heights[2], maximum_heights[2]);
|
||||
}
|
||||
|
||||
const float submodules_body_height = section_open[3] && section_heights[3] >= ui(1.0f)
|
||||
? section_heights[3] + ui(5.0f)
|
||||
@@ -502,9 +549,11 @@ void draw_sidebar(float width) {
|
||||
const float submodules_block_height = ui(22.0f) + submodules_body_height;
|
||||
ImGui::SetCursorPosY(std::max(ImGui::GetCursorPosY(),
|
||||
ImGui::GetContentRegionMax().y - submodules_block_height));
|
||||
section(ICON_FA_CUBES " SUBMODULES", repo().submodules, ICON_FA_CUBES,
|
||||
"Add submodule", "Submodule creation is not wired yet", SidebarItemKind::submodule, 3,
|
||||
section_heights[3], maximum_heights[3]);
|
||||
if (g_sidebar_workspace_view) {
|
||||
section(ICON_FA_CUBES " SUBMODULES", repo().submodules, ICON_FA_CUBES,
|
||||
"Add submodule", "Add submodule", SidebarItemKind::submodule, 3,
|
||||
section_heights[3], maximum_heights[3]);
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::EndChild();
|
||||
ImGui::EndChild();
|
||||
@@ -680,8 +729,18 @@ void draw_commit_table() {
|
||||
if (ImGui::MenuItem(ICON_FA_COPY " Copy commit message"))
|
||||
ImGui::SetClipboardText(commit.summary.c_str());
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem(ICON_FA_TAG " Create tag here")) g_notice = "Tag creation is not wired yet";
|
||||
if (ImGui::MenuItem(ICON_FA_CODE_BRANCH " Create branch here")) g_notice = "Branch creation is not wired yet";
|
||||
if (ImGui::MenuItem(ICON_FA_TAG " Create tag here")) {
|
||||
char target[GIT_OID_SHA1_HEXSIZE + 1]{};
|
||||
git_oid_tostr(target, sizeof(target), &commit.oid);
|
||||
g_git_target = target;
|
||||
g_tag_create_popup = true;
|
||||
}
|
||||
if (ImGui::MenuItem(ICON_FA_CODE_BRANCH " Create branch here")) {
|
||||
char target[GIT_OID_SHA1_HEXSIZE + 1]{};
|
||||
git_oid_tostr(target, sizeof(target), &commit.oid);
|
||||
g_git_target = target;
|
||||
g_branch_create_popup = true;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
float chip_x = reference_origin.x + ui(3.0f);
|
||||
@@ -722,7 +781,8 @@ ImVec4 change_color(FileChangeKind kind) {
|
||||
return {0.94f, 0.66f, 0.25f, 1};
|
||||
}
|
||||
|
||||
void draw_file_row(const std::string& path, FileChangeKind kind, int id) {
|
||||
void draw_file_row(const std::string& path, FileChangeKind kind, int id,
|
||||
bool working_file = false, bool staged = false, const std::string& action_path = {}) {
|
||||
ImGui::PushID(id);
|
||||
ImGui::InvisibleButton("##file", {-1, ui(25.0f)});
|
||||
const ImVec2 minimum = ImGui::GetItemRectMin();
|
||||
@@ -732,7 +792,15 @@ void draw_file_row(const std::string& path, FileChangeKind kind, int id) {
|
||||
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());
|
||||
const std::string& git_path = action_path.empty() ? path : action_path;
|
||||
if (ImGui::BeginPopupContextItem()) {
|
||||
if (working_file && !staged && ImGui::MenuItem(ICON_FA_PLUS " Stage file"))
|
||||
g_git_manager->stageFile(repo(), git_path, g_notice);
|
||||
if (working_file && staged && ImGui::MenuItem(ICON_FA_MINUS " Unstage file"))
|
||||
g_git_manager->unstageFile(repo(), git_path, g_notice);
|
||||
if (working_file && !staged && ImGui::MenuItem(ICON_FA_TRASH_CAN " Discard changes"))
|
||||
g_git_manager->discardFile(repo(), git_path, g_notice);
|
||||
if (working_file) ImGui::Separator();
|
||||
if (ImGui::MenuItem(ICON_FA_COPY " Copy path")) ImGui::SetClipboardText(path.c_str());
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
@@ -760,16 +828,19 @@ void draw_file_toolbar(bool show_view_all) {
|
||||
|
||||
template <typename File>
|
||||
void draw_files(const std::vector<File>& files, bool staged_filter = false, bool filter_by_stage = false) {
|
||||
// Git actions reload repository data immediately, so render from a stable snapshot.
|
||||
const std::vector<File> snapshot = files;
|
||||
if (g_file_view_mode == FileViewMode::path) {
|
||||
int id = 0;
|
||||
for (const auto& file : files) {
|
||||
for (const auto& file : snapshot) {
|
||||
if constexpr (requires { file.staged; }) if (filter_by_stage && file.staged != staged_filter) continue;
|
||||
draw_file_row(file.path, file.kind, id++);
|
||||
if constexpr (requires { file.staged; }) draw_file_row(file.path, file.kind, id++, true, file.staged);
|
||||
else draw_file_row(file.path, file.kind, id++);
|
||||
}
|
||||
return;
|
||||
}
|
||||
std::map<std::string, std::vector<const File*>> groups;
|
||||
for (const auto& file : files) {
|
||||
for (const auto& file : snapshot) {
|
||||
if constexpr (requires { file.staged; }) if (filter_by_stage && file.staged != staged_filter) continue;
|
||||
const size_t slash = file.path.find('/');
|
||||
const std::string group = slash == std::string::npos ? "Files" : file.path.substr(0, slash);
|
||||
@@ -780,7 +851,10 @@ void draw_files(const std::vector<File>& files, bool staged_filter = false, bool
|
||||
if (ImGui::TreeNodeEx((std::string(ICON_FA_FOLDER) + " " + group).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
for (const File* file : entries) {
|
||||
const size_t slash = file->path.find('/');
|
||||
draw_file_row(slash == std::string::npos ? file->path : file->path.substr(slash + 1), file->kind, id++);
|
||||
const std::string display = slash == std::string::npos ? file->path : file->path.substr(slash + 1);
|
||||
if constexpr (requires { file->staged; })
|
||||
draw_file_row(display, file->kind, id++, true, file->staged, file->path);
|
||||
else draw_file_row(display, file->kind, id++);
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
@@ -799,7 +873,7 @@ void draw_working_details() {
|
||||
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::Button(ICON_FA_TRASH_CAN "##discard_all", {ui(23.0f), ui(23.0f)}))
|
||||
g_notice = "Discard all is not wired yet";
|
||||
g_discard_all_popup = true;
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
const std::string changes_label = std::to_string(repo().working_files.size()) + " file changes on";
|
||||
@@ -813,15 +887,18 @@ void draw_working_details() {
|
||||
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());
|
||||
if (ImGui::Button((repo().branch + "##working_branch").c_str()))
|
||||
g_request_branch_selector = true;
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
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";
|
||||
if (ImGui::Button(ICON_FA_WAND_MAGIC_SPARKLES "##working_assist", {ui(23.0f), ui(23.0f)})) {
|
||||
const std::string suggestion = "Update " + std::to_string(repo().working_files.size()) + " files";
|
||||
std::snprintf(g_commit_summary.data(), g_commit_summary.size(), "%s", suggestion.c_str());
|
||||
}
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::EndChild();
|
||||
ImGui::Separator();
|
||||
@@ -844,7 +921,7 @@ void draw_working_details() {
|
||||
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";
|
||||
if (ImGui::SmallButton("Stage All Changes")) g_git_manager->stageAll(repo(), g_notice);
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::Separator();
|
||||
if (unstaged_open) {
|
||||
@@ -894,8 +971,10 @@ void draw_working_details() {
|
||||
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";
|
||||
if (ImGui::SmallButton(ICON_FA_WAND_MAGIC_SPARKLES "##summary_assist")) {
|
||||
const std::string suggestion = "Update " + std::to_string(repo().working_files.size()) + " files";
|
||||
std::snprintf(g_commit_summary.data(), g_commit_summary.size(), "%s", suggestion.c_str());
|
||||
}
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
ImGui::InputTextMultiline("##commit_description", g_commit_description.data(), g_commit_description.size(),
|
||||
@@ -913,15 +992,25 @@ void draw_working_details() {
|
||||
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";
|
||||
if (ImGui::SmallButton(ICON_FA_WAND_MAGIC_SPARKLES " Compose commits with AI")) {
|
||||
const std::string suggestion = "Update " + std::to_string(repo().working_files.size()) + " files";
|
||||
std::snprintf(g_commit_summary.data(), g_commit_summary.size(), "%s", suggestion.c_str());
|
||||
if (g_commit_description[0] == '\0')
|
||||
std::snprintf(g_commit_description.data(), g_commit_description.size(),
|
||||
"Update the current working tree changes.");
|
||||
}
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
ImGui::BeginDisabled(staged == 0 || g_commit_summary[0] == '\0');
|
||||
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";
|
||||
if (ImGui::Button(ICON_FA_CIRCLE_DOT " Stage Changes to Commit", {-1, ui(40.0f)})) {
|
||||
if (g_git_manager->commit(repo(), g_commit_summary.data(), g_commit_description.data(), amend, g_notice)) {
|
||||
g_commit_summary.fill('\0');
|
||||
g_commit_description.fill('\0');
|
||||
amend = false;
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::EndDisabled();
|
||||
ImGui::EndChild();
|
||||
@@ -1179,6 +1268,150 @@ void draw_licenses_popup() {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
void draw_git_action_popups() {
|
||||
if (g_branch_create_popup) {
|
||||
g_git_name.fill('\0');
|
||||
g_branch_create_popup = false;
|
||||
ImGui::OpenPopup("Create branch");
|
||||
}
|
||||
if (ImGui::BeginPopupModal("Create branch", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
static bool checkout_branch = true;
|
||||
ImGui::TextUnformatted("Branch name");
|
||||
ImGui::SetNextItemWidth(ui(360.0f));
|
||||
ImGui::InputText("##branch_name", g_git_name.data(), g_git_name.size());
|
||||
ImGui::TextDisabled("Start point: %s", g_git_target.empty() ? "HEAD" : g_git_target.c_str());
|
||||
ImGui::Checkbox("Check out new branch", &checkout_branch);
|
||||
const bool valid = g_git_name[0] != '\0';
|
||||
ImGui::BeginDisabled(!valid);
|
||||
if (ImGui::Button("Create", {ui(90.0f), 0}) &&
|
||||
g_git_manager->createBranch(repo(), g_git_name.data(), g_git_target,
|
||||
checkout_branch, g_notice)) {
|
||||
g_git_target.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", {ui(90.0f), 0})) {
|
||||
g_git_target.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (g_tag_create_popup) {
|
||||
g_git_name.fill('\0');
|
||||
g_tag_create_popup = false;
|
||||
ImGui::OpenPopup("Create tag");
|
||||
}
|
||||
if (ImGui::BeginPopupModal("Create tag", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextUnformatted("Tag name");
|
||||
ImGui::SetNextItemWidth(ui(360.0f));
|
||||
ImGui::InputText("##tag_name", g_git_name.data(), g_git_name.size());
|
||||
ImGui::TextDisabled("Target: %s", g_git_target.empty() ? "HEAD" : g_git_target.c_str());
|
||||
ImGui::BeginDisabled(g_git_name[0] == '\0');
|
||||
if (ImGui::Button("Create", {ui(90.0f), 0}) &&
|
||||
g_git_manager->createTag(repo(), g_git_name.data(), g_git_target, g_notice)) {
|
||||
g_git_target.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", {ui(90.0f), 0})) {
|
||||
g_git_target.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (g_remote_add_popup) {
|
||||
g_git_name.fill('\0');
|
||||
g_git_value.fill('\0');
|
||||
std::snprintf(g_git_name.data(), g_git_name.size(), "%s",
|
||||
std::find(repo().remotes.begin(), repo().remotes.end(), "origin") == repo().remotes.end()
|
||||
? "origin" : "upstream");
|
||||
g_remote_add_popup = false;
|
||||
ImGui::OpenPopup("Add remote");
|
||||
}
|
||||
if (ImGui::BeginPopupModal("Add remote", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextUnformatted("Remote name");
|
||||
ImGui::SetNextItemWidth(ui(420.0f));
|
||||
ImGui::InputText("##remote_name", g_git_name.data(), g_git_name.size());
|
||||
ImGui::TextUnformatted("Remote URL");
|
||||
ImGui::SetNextItemWidth(ui(420.0f));
|
||||
ImGui::InputText("##remote_url", g_git_value.data(), g_git_value.size());
|
||||
ImGui::BeginDisabled(g_git_name[0] == '\0' || g_git_value[0] == '\0');
|
||||
if (ImGui::Button("Add remote", {ui(110.0f), 0}) &&
|
||||
g_git_manager->addRemote(repo(), g_git_name.data(), g_git_value.data(), g_notice))
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", {ui(90.0f), 0})) ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (g_worktree_add_popup) {
|
||||
g_git_path.fill('\0');
|
||||
g_git_value.fill('\0');
|
||||
g_worktree_add_popup = false;
|
||||
ImGui::OpenPopup("Add worktree");
|
||||
}
|
||||
if (ImGui::BeginPopupModal("Add worktree", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextUnformatted("Worktree folder");
|
||||
ImGui::SetNextItemWidth(ui(460.0f));
|
||||
ImGui::InputText("##worktree_path", g_git_path.data(), g_git_path.size());
|
||||
ImGui::TextUnformatted("Branch or commit (optional)");
|
||||
ImGui::SetNextItemWidth(ui(460.0f));
|
||||
ImGui::InputText("##worktree_branch", g_git_value.data(), g_git_value.size());
|
||||
ImGui::BeginDisabled(g_git_path[0] == '\0');
|
||||
if (ImGui::Button("Add worktree", {ui(120.0f), 0}) &&
|
||||
g_git_manager->addWorktree(repo(), g_git_path.data(), g_git_value.data(), g_notice))
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", {ui(90.0f), 0})) ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (g_submodule_add_popup) {
|
||||
g_git_value.fill('\0');
|
||||
g_git_path.fill('\0');
|
||||
g_submodule_add_popup = false;
|
||||
ImGui::OpenPopup("Add submodule");
|
||||
}
|
||||
if (ImGui::BeginPopupModal("Add submodule", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextUnformatted("Repository URL");
|
||||
ImGui::SetNextItemWidth(ui(460.0f));
|
||||
ImGui::InputText("##submodule_url", g_git_value.data(), g_git_value.size());
|
||||
ImGui::TextUnformatted("Local path (optional)");
|
||||
ImGui::SetNextItemWidth(ui(460.0f));
|
||||
ImGui::InputText("##submodule_path", g_git_path.data(), g_git_path.size());
|
||||
ImGui::BeginDisabled(g_git_value[0] == '\0');
|
||||
if (ImGui::Button("Add submodule", {ui(125.0f), 0}) &&
|
||||
g_git_manager->addSubmodule(repo(), g_git_value.data(), g_git_path.data(), g_notice))
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", {ui(90.0f), 0})) ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (g_discard_all_popup) {
|
||||
g_discard_all_popup = false;
|
||||
ImGui::OpenPopup("Discard all changes?");
|
||||
}
|
||||
if (ImGui::BeginPopupModal("Discard all changes?", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextWrapped("This permanently discards tracked changes and removes untracked files and folders.");
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.42f, 0.12f, 0.13f, 1.0f));
|
||||
if (ImGui::Button("Discard all", {ui(110.0f), 0})) {
|
||||
if (g_git_manager->discardAll(repo(), g_notice)) ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", {ui(90.0f), 0})) ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void draw_popups() {
|
||||
if (g_init_popup) { ImGui::OpenPopup("Create repository"); g_init_popup = false; }
|
||||
if (ImGui::BeginPopupModal("Create repository", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
@@ -1195,6 +1428,7 @@ void draw_popups() {
|
||||
}
|
||||
draw_about_popup();
|
||||
draw_licenses_popup();
|
||||
draw_git_action_popups();
|
||||
}
|
||||
|
||||
void draw_footer() {
|
||||
@@ -1272,7 +1506,10 @@ void draw_app() {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Edit")) { ImGui::MenuItem("Preferences", nullptr, false, false); ImGui::EndMenu(); }
|
||||
if (ImGui::BeginMenu("View")) { ImGui::MenuItem("Refresh", "F5"); ImGui::EndMenu(); }
|
||||
if (ImGui::BeginMenu("View")) {
|
||||
if (ImGui::MenuItem("Refresh", "F5")) g_git_manager->reload(repo(), g_notice);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Help")) {
|
||||
if (ImGui::MenuItem("About Gitree")) g_about_popup = true;
|
||||
ImGui::EndMenu();
|
||||
@@ -1377,12 +1614,26 @@ void draw_app() {
|
||||
const float repository_width = std::clamp(
|
||||
ImGui::CalcTextSize(repo().name.c_str()).x / g_ui_scale + 42.0f, 120.0f, 220.0f);
|
||||
if (toolbar_selector("repository", "repository", repo().name, repository_width))
|
||||
g_notice = "Use repository tabs to switch repositories";
|
||||
ImGui::OpenPopup("repository_selector");
|
||||
if (ImGui::BeginPopup("repository_selector")) {
|
||||
for (size_t index = 0; index < g_tabs.size(); ++index) {
|
||||
if (ImGui::MenuItem(g_tabs[index]->name.c_str(), nullptr, index == g_active_tab)) {
|
||||
g_active_tab = index;
|
||||
g_tab_to_select = g_tabs[index].get();
|
||||
persist_repository_session();
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::SameLine(0, ui(3));
|
||||
ImGui::SetCursorPosY(ui(19));
|
||||
ImGui::TextDisabled(ICON_FA_ANGLE_RIGHT);
|
||||
ImGui::SameLine(0, ui(3));
|
||||
ImGui::SetCursorPosY(ui(1));
|
||||
if (g_request_branch_selector) {
|
||||
ImGui::OpenPopup("branch_selector");
|
||||
g_request_branch_selector = false;
|
||||
}
|
||||
if (toolbar_selector("branch", "branch", repo().branch, 150.0f)) ImGui::OpenPopup("branch_selector");
|
||||
const float selectors_right = ImGui::GetItemRectMax().x - ImGui::GetWindowPos().x;
|
||||
ImGui::SetNextWindowSize({ui(320.0f), ui(370.0f)}, ImGuiCond_Appearing);
|
||||
@@ -1413,26 +1664,31 @@ void draw_app() {
|
||||
ImGui::SetCursorPos({std::max(selectors_right + ui(10.0f), centered_x), ui(1.0f)});
|
||||
|
||||
if (toolbar_action("undo", "Undo", ICON_FA_ROTATE_LEFT, "Undo last Git action", true, false, 54))
|
||||
g_notice = "Undo is not wired yet";
|
||||
g_git_manager->undoCommit(repo(), g_notice);
|
||||
ImGui::SameLine(0, action_spacing);
|
||||
toolbar_action("redo", "Redo", ICON_FA_ROTATE_RIGHT, "Redo last Git action", false, false, 54);
|
||||
if (toolbar_action("redo", "Redo", ICON_FA_ROTATE_RIGHT, "Redo last Git action", true, false, 54))
|
||||
g_git_manager->redoCommit(repo(), g_notice);
|
||||
ImGui::SameLine(0, action_spacing);
|
||||
bool pull_dropdown_clicked = false;
|
||||
if (toolbar_action("pull", "Pull", ICON_FA_DOWNLOAD, pull_mode_name(g_user_data->pullMode()),
|
||||
true, true, 58, &pull_dropdown_clicked))
|
||||
g_notice = std::string(pull_mode_name(g_user_data->pullMode())) + " is not wired yet";
|
||||
g_git_manager->pull(repo(), g_user_data->pullMode(), g_notice);
|
||||
if (pull_dropdown_clicked) ImGui::OpenPopup("pull_options");
|
||||
draw_pull_options();
|
||||
ImGui::SameLine(0, action_spacing);
|
||||
if (toolbar_action("push", "Push", ICON_FA_UPLOAD, "Push to remote", true, false, 58))
|
||||
g_notice = "Push is not wired yet";
|
||||
g_git_manager->push(repo(), g_notice);
|
||||
ImGui::SameLine(0, action_spacing);
|
||||
if (toolbar_action("branch_action", "Branch", ICON_FA_CODE_BRANCH, "Create branch", true, false, 64))
|
||||
g_notice = "Branch creation is not wired yet";
|
||||
if (toolbar_action("branch_action", "Branch", ICON_FA_CODE_BRANCH, "Create branch", true, false, 64)) {
|
||||
g_git_target.clear();
|
||||
g_branch_create_popup = true;
|
||||
}
|
||||
ImGui::SameLine(0, action_spacing);
|
||||
toolbar_action("stash", "Stash", ICON_FA_BOX_ARCHIVE, "Stash changes", false, false, 58);
|
||||
if (toolbar_action("stash", "Stash", ICON_FA_BOX_ARCHIVE, "Stash changes", true, false, 58))
|
||||
g_git_manager->stash(repo(), g_notice);
|
||||
ImGui::SameLine(0, action_spacing);
|
||||
toolbar_action("pop", "Pop", ICON_FA_BOX_OPEN, "Pop latest stash", false, false, 54);
|
||||
if (toolbar_action("pop", "Pop", ICON_FA_BOX_OPEN, "Pop latest stash", true, false, 54))
|
||||
g_git_manager->popStash(repo(), g_notice);
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user