From afab5900f7d4dee1e34ebaa7ce854f792d59b5ef Mon Sep 17 00:00:00 2001 From: scawful Date: Thu, 17 Apr 2025 21:50:01 -0400 Subject: [PATCH] Add color conversion utility and editable palette display functionality; implement color picker and context menu options for palette colors in the GUI. --- src/app/gui/color.cc | 103 ++++++++++++++++++++++++++++++++++++++++++- src/app/gui/color.h | 10 ++++- 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/src/app/gui/color.cc b/src/app/gui/color.cc index fc1bd5ed..4fc2d6d0 100644 --- a/src/app/gui/color.cc +++ b/src/app/gui/color.cc @@ -16,6 +16,10 @@ ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor& color) { ); } +gfx::SnesColor ConvertImVec4ToSnesColor(const ImVec4& color) { + return gfx::SnesColor(color.x, color.y, color.z); +} + IMGUI_API bool SnesColorButton(absl::string_view id, gfx::SnesColor& color, ImGuiColorEditFlags flags, const ImVec2& size_arg) { @@ -58,7 +62,7 @@ absl::Status DisplayPalette(gfx::SnesPalette& palette, bool loaded) { static ImVec4 saved_palette[32] = {}; if (loaded && !init) { for (int n = 0; n < palette.size(); n++) { - ASSIGN_OR_RETURN(auto color, palette.GetColor(n)); + auto color = palette[n]; saved_palette[n].x = color.rgb().x / 255; saved_palette[n].y = color.rgb().y / 255; saved_palette[n].z = color.rgb().z / 255; @@ -163,5 +167,102 @@ void SelectablePalettePipeline(uint64_t& palette_id, bool& refresh_graphics, ImGui::EndChild(); } +absl::Status DisplayEditablePalette(gfx::SnesPalette& palette, + const std::string& title, + bool show_color_picker, int colors_per_row, + ImGuiColorEditFlags flags) { + // Default flags if none provided + if (flags == 0) { + flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | + ImGuiColorEditFlags_NoTooltip; + } + + // Display title if provided + if (!title.empty()) { + ImGui::Text("%s", title.c_str()); + } + static int selected_color = 0; + + if (show_color_picker) { + ImGui::Separator(); + static ImVec4 current_color = ImVec4(0, 0, 0, 1.0f); + + if (ImGui::ColorPicker4("Color Picker", (float*)¤t_color, + ImGuiColorEditFlags_NoSidePreview | + ImGuiColorEditFlags_NoSmallPreview)) { + // Convert the selected color to SNES format and add it to the palette + gfx::SnesColor snes_color(current_color); + palette.UpdateColor(selected_color, snes_color); + } + } + + // Display the palette colors in a grid + ImGui::BeginGroup(); // Lock X position + for (int n = 0; n < palette.size(); n++) { + ImGui::PushID(n); + if ((n % colors_per_row) != 0) { + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + } + + // Create a unique ID for this color button + std::string button_id = "##palette_" + std::to_string(n); + + // Display the color button + if (SnesColorButton(button_id, palette[n], flags, ImVec2(20, 20))) { + // Color was clicked, could be used to select this color + selected_color = n; + } + + if (ImGui::BeginPopupContextItem()) { + if (ImGui::MenuItem("Edit Color")) { + // Open color picker for this color + ImGui::OpenPopup(("Edit Color##" + std::to_string(n)).c_str()); + } + + if (ImGui::MenuItem("Copy as SNES Value")) { + std::string clipboard = absl::StrFormat("$%04X", palette[n].snes()); + ImGui::SetClipboardText(clipboard.c_str()); + } + + if (ImGui::MenuItem("Copy as RGB")) { + auto rgb = palette[n].rgb(); + std::string clipboard = + absl::StrFormat("(%d,%d,%d)", (int)(rgb.x * 255), + (int)(rgb.y * 255), (int)(rgb.z * 255)); + ImGui::SetClipboardText(clipboard.c_str()); + } + + if (ImGui::MenuItem("Copy as Hex")) { + auto rgb = palette[n].rgb(); + std::string clipboard = + absl::StrFormat("#%02X%02X%02X", (int)(rgb.x * 255), + (int)(rgb.y * 255), (int)(rgb.z * 255)); + ImGui::SetClipboardText(clipboard.c_str()); + } + + ImGui::EndPopup(); + } + + // Color picker popup + if (ImGui::BeginPopup(("Edit Color##" + std::to_string(n)).c_str())) { + ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoSidePreview | + ImGuiColorEditFlags_NoSmallPreview; + + ImVec4 color = ConvertSnesColorToImVec4(palette[n]); + if (ImGui::ColorPicker4("##picker", (float*)&color, picker_flags)) { + // Update the SNES color when the picker changes + palette[n] = ConvertImVec4ToSnesColor(color); + } + + ImGui::EndPopup(); + } + + ImGui::PopID(); + } + ImGui::EndGroup(); + + return absl::OkStatus(); +} + } // namespace gui } // namespace yaze diff --git a/src/app/gui/color.h b/src/app/gui/color.h index a14413a1..554ba968 100644 --- a/src/app/gui/color.h +++ b/src/app/gui/color.h @@ -7,7 +7,6 @@ #include #include "absl/status/status.h" -#include "absl/strings/str_format.h" #include "app/gfx/snes_palette.h" #include "imgui/imgui.h" @@ -43,6 +42,9 @@ inline std::string ColorToHexString(const Color &color) { // normalized color values ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor &color); +// A utility function to convert an ImVec4 to an SnesColor object +gfx::SnesColor ConvertImVec4ToSnesColor(const ImVec4 &color); + // The wrapper function for ImGui::ColorButton that takes a SnesColor reference IMGUI_API bool SnesColorButton(absl::string_view id, gfx::SnesColor &color, ImGuiColorEditFlags flags = 0, @@ -53,6 +55,12 @@ IMGUI_API bool SnesColorEdit4(absl::string_view label, gfx::SnesColor *color, absl::Status DisplayPalette(gfx::SnesPalette &palette, bool loaded); +absl::Status DisplayEditablePalette(gfx::SnesPalette &palette, + const std::string &title = "", + bool show_color_picker = false, + int colors_per_row = 8, + ImGuiColorEditFlags flags = 0); + void SelectablePalettePipeline(uint64_t &palette_id, bool &refresh_graphics, gfx::SnesPalette &palette);