feat: Introduce Agent Chat History Popup for Enhanced User Interaction

- Added AgentChatHistoryPopup class to provide a sidebar for displaying recent chat messages, improving user accessibility to chat history.
- Integrated the new popup into the editor's source files, ensuring proper inclusion and functionality within the existing UI framework.
- Refactored related files to accommodate the new popup, enhancing code organization and maintainability.
- Updated CMake configuration to include the new source files, ensuring a seamless build process.
This commit is contained in:
scawful
2025-10-05 16:08:44 -04:00
parent c8d7eb3597
commit 409cf357af
8 changed files with 528 additions and 91 deletions

View File

@@ -1,71 +1,414 @@
#include "app/gui/ui_helpers.h"
#include "app/gui/theme_manager.h"
#include "absl/strings/str_format.h"
#include "app/gui/color.h"
#include "app/gui/icons.h"
#include "app/gui/theme_manager.h"
#include "imgui/imgui.h"
#include "imgui/imgui_internal.h"
namespace yaze {
namespace gui {
// ============================================================================
// Theme and Semantic Colors
// ============================================================================
ImVec4 GetThemeColor(ImGuiCol idx) {
return ImGui::GetStyle().Colors[idx];
return ImGui::GetStyle().Colors[idx];
}
ImVec4 GetSuccessColor() {
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.success);
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.success);
}
ImVec4 GetWarningColor() {
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.warning);
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.warning);
}
ImVec4 GetErrorColor() {
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.error);
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.error);
}
ImVec4 GetInfoColor() {
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.info);
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.info);
}
ImVec4 GetAccentColor() {
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.accent);
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.accent);
}
void BeginField(const char* label) {
ImGui::BeginGroup();
// Entity/Map marker colors
ImVec4 GetEntranceColor() {
return ImVec4(1.0f, 1.0f, 0.0f, 0.6f); // Yellow with transparency
}
ImVec4 GetExitColor() {
return ImVec4(1.0f, 1.0f, 1.0f, 0.6f); // White with transparency
}
ImVec4 GetItemColor() {
return ImVec4(1.0f, 0.0f, 0.0f, 0.6f); // Red with transparency
}
ImVec4 GetSpriteColor() {
return ImVec4(1.0f, 0.0f, 1.0f, 0.6f); // Magenta with transparency
}
ImVec4 GetSelectedColor() {
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.accent);
}
ImVec4 GetLockedColor() {
return ImVec4(1.0f, 0.5f, 0.0f, 1.0f); // Orange for locked items
}
// Status colors
ImVec4 GetVanillaRomColor() {
return GetWarningColor(); // Yellow from theme
}
ImVec4 GetCustomRomColor() {
return GetSuccessColor(); // Green from theme
}
ImVec4 GetModifiedColor() {
const auto& theme = ThemeManager::Get().GetCurrentTheme();
return ConvertColorToImVec4(theme.accent);
}
// ============================================================================
// Layout Helpers
// ============================================================================
void BeginField(const char* label, float label_width) {
ImGui::BeginGroup();
if (label_width > 0.0f) {
ImGui::Text("%s:", label);
ImGui::SameLine(label_width);
} else {
ImGui::TextUnformatted(label);
ImGui::SameLine();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.6f);
}
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.6f);
}
void EndField() {
ImGui::PopItemWidth();
ImGui::EndGroup();
ImGui::PopItemWidth();
ImGui::EndGroup();
}
bool BeginPropertyTable(const char* id, int columns, ImGuiTableFlags extra_flags) {
ImGuiTableFlags flags = ImGuiTableFlags_Borders |
ImGuiTableFlags_SizingFixedFit |
extra_flags;
if (ImGui::BeginTable(id, columns, flags)) {
ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, 150);
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
return true;
}
return false;
}
void EndPropertyTable() {
ImGui::EndTable();
}
void PropertyRow(const char* label, const char* value) {
ImGui::TableNextColumn();
ImGui::Text("%s", label);
ImGui::TableNextColumn();
ImGui::TextWrapped("%s", value);
}
void PropertyRow(const char* label, int value) {
ImGui::TableNextColumn();
ImGui::Text("%s", label);
ImGui::TableNextColumn();
ImGui::Text("%d", value);
}
void PropertyRowHex(const char* label, uint8_t value) {
ImGui::TableNextColumn();
ImGui::Text("%s", label);
ImGui::TableNextColumn();
ImGui::Text("0x%02X", value);
}
void PropertyRowHex(const char* label, uint16_t value) {
ImGui::TableNextColumn();
ImGui::Text("%s", label);
ImGui::TableNextColumn();
ImGui::Text("0x%04X", value);
}
void SectionHeader(const char* icon, const char* label, const ImVec4& color) {
ImGui::TextColored(color, "%s %s", icon, label);
ImGui::Separator();
}
// ============================================================================
// Common Widget Patterns
// ============================================================================
bool IconButton(const char* icon, const char* label, const ImVec2& size) {
std::string button_text = std::string(icon) + " " + std::string(label);
return ImGui::Button(button_text.c_str(), size);
std::string button_text = std::string(icon) + " " + std::string(label);
return ImGui::Button(button_text.c_str(), size);
}
bool ColoredButton(const char* label, ButtonType type, const ImVec2& size) {
ImVec4 color;
switch (type) {
case ButtonType::Success: color = GetSuccessColor(); break;
case ButtonType::Warning: color = GetWarningColor(); break;
case ButtonType::Error: color = GetErrorColor(); break;
case ButtonType::Info: color = GetInfoColor(); break;
default: color = GetThemeColor(ImGuiCol_Button); break;
}
ImGui::PushStyleColor(ImGuiCol_Button, color);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
ImVec4(color.x * 1.2f, color.y * 1.2f, color.z * 1.2f, color.w));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
ImVec4(color.x * 0.8f, color.y * 0.8f, color.z * 0.8f, color.w));
bool result = ImGui::Button(label, size);
ImGui::PopStyleColor(3);
return result;
}
bool ToggleIconButton(const char* icon_on, const char* icon_off,
bool* state, const char* tooltip) {
const char* icon = *state ? icon_on : icon_off;
ImVec4 color = *state ? GetSuccessColor() : GetThemeColor(ImGuiCol_Button);
ImGui::PushStyleColor(ImGuiCol_Button, color);
bool result = ImGui::SmallButton(icon);
ImGui::PopStyleColor();
if (result) *state = !*state;
if (tooltip && ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", tooltip);
}
return result;
}
void HelpMarker(const char* desc) {
ImGui::TextDisabled(ICON_MD_HELP_OUTLINE);
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
ImGui::TextDisabled(ICON_MD_HELP_OUTLINE);
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
void SeparatorText(const char* label) {
ImGui::SeparatorText(label);
ImGui::SeparatorText(label);
}
void StatusBadge(const char* text, ButtonType type) {
ImVec4 color;
switch (type) {
case ButtonType::Success: color = GetSuccessColor(); break;
case ButtonType::Warning: color = GetWarningColor(); break;
case ButtonType::Error: color = GetErrorColor(); break;
case ButtonType::Info: color = GetInfoColor(); break;
default: color = GetThemeColor(ImGuiCol_Text); break;
}
ImGui::PushStyleColor(ImGuiCol_Button, color);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 10.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 3));
ImGui::SmallButton(text);
ImGui::PopStyleVar(2);
ImGui::PopStyleColor();
}
// ============================================================================
// Editor-Specific Patterns
// ============================================================================
void BeginToolset(const char* id) {
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(2, 2));
ImGui::BeginTable(id, 32, ImGuiTableFlags_SizingFixedFit);
}
void EndToolset() {
ImGui::EndTable();
ImGui::PopStyleVar();
}
void ToolsetButton(const char* icon, bool selected, const char* tooltip,
std::function<void()> on_click) {
ImGui::TableNextColumn();
if (selected) {
ImGui::PushStyleColor(ImGuiCol_Button, GetAccentColor());
}
if (ImGui::Button(icon)) {
if (on_click) on_click();
}
if (selected) {
ImGui::PopStyleColor();
}
if (tooltip && ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", tooltip);
}
}
void BeginCanvasContainer(const char* id, bool scrollable) {
ImGuiWindowFlags flags = scrollable ?
ImGuiWindowFlags_AlwaysVerticalScrollbar :
ImGuiWindowFlags_None;
ImGui::BeginChild(id, ImVec2(0, 0), true, flags);
}
void EndCanvasContainer() {
ImGui::EndChild();
}
bool EditorTabItem(const char* icon, const char* label, bool* p_open) {
char tab_label[256];
snprintf(tab_label, sizeof(tab_label), "%s %s", icon, label);
return ImGui::BeginTabItem(tab_label, p_open);
}
bool ConfirmationDialog(const char* id, const char* title, const char* message,
const char* confirm_text, const char* cancel_text) {
bool confirmed = false;
if (ImGui::BeginPopupModal(id, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("%s", title);
ImGui::Separator();
ImGui::TextWrapped("%s", message);
ImGui::Separator();
if (ColoredButton(confirm_text, ButtonType::Warning, ImVec2(120, 0))) {
confirmed = true;
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button(cancel_text, ImVec2(120, 0))) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
return confirmed;
}
// ============================================================================
// Visual Indicators
// ============================================================================
void StatusIndicator(const char* label, bool active, const char* tooltip) {
ImVec4 color = active ? GetSuccessColor() : GetThemeColor(ImGuiCol_TextDisabled);
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 pos = ImGui::GetCursorScreenPos();
float radius = 5.0f;
pos.x += radius + 3;
pos.y += ImGui::GetTextLineHeight() * 0.5f;
draw_list->AddCircleFilled(pos, radius, ImGui::GetColorU32(color));
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + radius * 2 + 8);
ImGui::Text("%s", label);
if (tooltip && ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", tooltip);
}
}
void RomVersionBadge(const char* version, bool is_vanilla) {
ImVec4 color = is_vanilla ? GetWarningColor() : GetSuccessColor();
const char* icon = is_vanilla ? ICON_MD_INFO : ICON_MD_CHECK_CIRCLE;
ImGui::PushStyleColor(ImGuiCol_Text, color);
ImGui::Text("%s %s", icon, version);
ImGui::PopStyleColor();
}
void LockIndicator(bool locked, const char* label) {
if (locked) {
ImGui::TextColored(GetLockedColor(), ICON_MD_LOCK " %s (Locked)", label);
} else {
ImGui::Text(ICON_MD_LOCK_OPEN " %s", label);
}
}
// ============================================================================
// Spacing and Alignment
// ============================================================================
void VerticalSpacing(float pixels) {
ImGui::Dummy(ImVec2(0, pixels));
}
void HorizontalSpacing(float pixels) {
ImGui::Dummy(ImVec2(pixels, 0));
ImGui::SameLine();
}
void CenterText(const char* text) {
float text_width = ImGui::CalcTextSize(text).x;
ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - text_width) * 0.5f);
ImGui::Text("%s", text);
}
void RightAlign(float width) {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() +
ImGui::GetContentRegionAvail().x - width);
}
// ============================================================================
// Input Helpers
// ============================================================================
bool LabeledInputHex(const char* label, uint8_t* value) {
BeginField(label);
ImGui::PushItemWidth(60);
bool changed = ImGui::InputScalar("##hex", ImGuiDataType_U8, value, nullptr,
nullptr, "%02X",
ImGuiInputTextFlags_CharsHexadecimal);
ImGui::PopItemWidth();
EndField();
return changed;
}
bool LabeledInputHex(const char* label, uint16_t* value) {
BeginField(label);
ImGui::PushItemWidth(80);
bool changed = ImGui::InputScalar("##hex", ImGuiDataType_U16, value, nullptr,
nullptr, "%04X",
ImGuiInputTextFlags_CharsHexadecimal);
ImGui::PopItemWidth();
EndField();
return changed;
}
bool IconCombo(const char* icon, const char* label, int* current,
const char* const items[], int count) {
ImGui::Text("%s", icon);
ImGui::SameLine();
return ImGui::Combo(label, current, items, count);
}
} // namespace gui

View File

@@ -3,43 +3,147 @@
#include "imgui/imgui.h"
#include <string>
#include <functional>
namespace yaze {
namespace gui {
// A collection of helper functions and widgets to standardize UI development
// and reduce boilerplate ImGui code.
// and reduce boilerplate ImGui code across all editors.
// --- Theming and Colors ---
// ============================================================================
// Theme and Semantic Colors
// ============================================================================
// Gets a color from the current theme.
// Gets a color from the current theme
ImVec4 GetThemeColor(ImGuiCol idx);
// Gets a semantic color from the current theme.
// Semantic colors from current theme
ImVec4 GetSuccessColor();
ImVec4 GetWarningColor();
ImVec4 GetErrorColor();
ImVec4 GetInfoColor();
ImVec4 GetAccentColor();
// --- Layout Helpers ---
// Entity/Map marker colors (for overworld, dungeon)
ImVec4 GetEntranceColor();
ImVec4 GetExitColor();
ImVec4 GetItemColor();
ImVec4 GetSpriteColor();
ImVec4 GetSelectedColor();
ImVec4 GetLockedColor();
// Begins a standard row for a label and a widget.
void BeginField(const char* label);
// Ends a field row.
// Status colors
ImVec4 GetVanillaRomColor();
ImVec4 GetCustomRomColor();
ImVec4 GetModifiedColor();
// ============================================================================
// Layout Helpers
// ============================================================================
// Label + widget field pattern
void BeginField(const char* label, float label_width = 0.0f);
void EndField();
// --- Widget Wrappers ---
// Property table pattern (common in editors)
bool BeginPropertyTable(const char* id, int columns = 2,
ImGuiTableFlags extra_flags = 0);
void EndPropertyTable();
// A button with an icon from the Material Design icon font.
bool IconButton(const char* icon, const char* label, const ImVec2& size = ImVec2(0, 0));
// Property row helpers
void PropertyRow(const char* label, const char* value);
void PropertyRow(const char* label, int value);
void PropertyRowHex(const char* label, uint8_t value);
void PropertyRowHex(const char* label, uint16_t value);
// A help marker that shows a tooltip on hover.
// Section headers with icons
void SectionHeader(const char* icon, const char* label,
const ImVec4& color = ImVec4(1, 1, 1, 1));
// ============================================================================
// Common Widget Patterns
// ============================================================================
// Button with icon
bool IconButton(const char* icon, const char* label,
const ImVec2& size = ImVec2(0, 0));
// Colored button for status actions
enum class ButtonType { Default, Success, Warning, Error, Info };
bool ColoredButton(const char* label, ButtonType type,
const ImVec2& size = ImVec2(0, 0));
// Toggle button with visual state
bool ToggleIconButton(const char* icon_on, const char* icon_off,
bool* state, const char* tooltip = nullptr);
// Help marker with tooltip
void HelpMarker(const char* desc);
// A separator with centered text.
// Separator with text
void SeparatorText(const char* label);
// Status badge (pill-shaped colored label)
void StatusBadge(const char* text, ButtonType type = ButtonType::Default);
// ============================================================================
// Editor-Specific Patterns
// ============================================================================
// Toolset table (horizontal button bar)
void BeginToolset(const char* id);
void EndToolset();
void ToolsetButton(const char* icon, bool selected, const char* tooltip,
std::function<void()> on_click);
// Canvas container patterns
void BeginCanvasContainer(const char* id, bool scrollable = true);
void EndCanvasContainer();
// Tab pattern for editor modes
bool EditorTabItem(const char* icon, const char* label, bool* p_open = nullptr);
// Modal confirmation dialog
bool ConfirmationDialog(const char* id, const char* title, const char* message,
const char* confirm_text = "OK",
const char* cancel_text = "Cancel");
// ============================================================================
// Visual Indicators
// ============================================================================
// Status indicator dot + label
void StatusIndicator(const char* label, bool active,
const char* tooltip = nullptr);
// ROM version badge
void RomVersionBadge(const char* version, bool is_vanilla);
// Locked/Unlocked indicator
void LockIndicator(bool locked, const char* label);
// ============================================================================
// Spacing and Alignment
// ============================================================================
void VerticalSpacing(float pixels = 8.0f);
void HorizontalSpacing(float pixels = 8.0f);
void CenterText(const char* text);
void RightAlign(float width);
// ============================================================================
// Input Helpers (complement existing gui::InputHex functions)
// ============================================================================
// Labeled hex input with automatic formatting
bool LabeledInputHex(const char* label, uint8_t* value);
bool LabeledInputHex(const char* label, uint16_t* value);
// Combo with icon
bool IconCombo(const char* icon, const char* label, int* current,
const char* const items[], int count);
} // namespace gui
} // namespace yaze