12#include "absl/strings/str_format.h"
33#include "imgui/imgui.h"
43std::string ResolveAgentChatHistoryPath() {
46 return (*agent_dir /
"agent_chat_history.json").string();
50 return (*temp_dir /
"agent_chat_history.json").string();
52 return (std::filesystem::current_path() /
"agent_chat_history.json").string();
57 return value.
get<std::string>();
60 return value.
get<
bool>() ?
"true" :
"false";
62 if (value.is_number_integer()) {
63 return std::to_string(value.
get<
long long>());
65 if (value.is_number_unsigned()) {
66 return std::to_string(value.
get<
unsigned long long>());
68 if (value.is_number_float()) {
69 return absl::StrFormat(
"%.3f", value.
get<
double>());
78 std::string sanitized;
79 sanitized.reserve(value.size());
80 for (
unsigned char ch : value) {
81 if (std::isalnum(ch)) {
82 sanitized.push_back(
static_cast<char>(ch));
84 sanitized.push_back(
'_');
87 return sanitized.empty() ? std::string(
"entry") : sanitized;
91 if (!out || text.
empty()) {
103 if (value.is_number_unsigned()) {
104 return static_cast<uint32_t
>(value.
get<uint64_t>());
106 if (value.is_number_integer()) {
107 return static_cast<uint32_t
>(value.
get<int64_t>());
113 std::string token = value.
get<std::string>();
117 if (token[0] ==
'$') {
118 token = token.substr(1);
119 }
else if (token.size() > 2 && token[0] ==
'0' &&
120 (token[1] ==
'x' || token[1] ==
'X')) {
121 token = token.substr(2);
124 return static_cast<uint32_t
>(std::stoul(token,
nullptr, 16));
131 if (!
object.is_object()) {
134 for (
const char* key : {
"address",
"entry_address"}) {
135 if (
object.contains(key)) {
137 if (parsed.has_value()) {
146 if (!
object.is_object()) {
149 if (
object.contains(
"source") &&
object[
"source"].is_string()) {
150 return object[
"source"].get<std::string>();
152 if (
object.contains(
"file") &&
object[
"file"].is_string()) {
153 std::string reference =
object[
"file"].get<std::string>();
154 if (
object.contains(
"line") &&
object[
"line"].is_number_integer()) {
155 reference = absl::StrCat(reference,
":",
object[
"line"].get<int>());
163 if (!
object.is_object()) {
167 const std::string address =
object.contains(
"address")
170 const std::string bank =
172 const std::string name =
176 if (!source.empty() && !address.empty()) {
177 return absl::StrFormat(
"%s (%s)", source.c_str(), address.c_str());
179 if (!name.empty() && !address.empty()) {
180 return absl::StrFormat(
"%s %s", name.c_str(), address.c_str());
182 if (!name.empty() && !bank.empty()) {
183 return absl::StrFormat(
"%s %s", name.c_str(), bank.c_str());
185 if (!source.empty()) {
188 if (!address.empty()) {
201 const char* action_key,
202 const Json&
object) {
204 if (address.has_value()) {
205 return absl::StrFormat(
"%s##tool_output_%s_%06X", visible_label, action_key,
210 if (!reference.empty()) {
211 return absl::StrFormat(
"%s##tool_output_%s_%s", visible_label, action_key,
215 return absl::StrFormat(
"%s##tool_output_%s_entry", visible_label, action_key);
220 if (!
object.is_object()) {
226 bool drew_any =
false;
229 const std::string label =
231 if (ImGui::SmallButton(label.c_str())) {
240 const std::string label =
242 if (ImGui::SmallButton(label.c_str())) {
251 const std::string label =
253 if (ImGui::SmallButton(label.c_str())) {
260 for (
auto it =
object.begin(); it !=
object.end(); ++it) {
261 if (it.value().is_array() || it.value().is_object()) {
264 ImGui::BulletText(
"%s: %s", it.key().c_str(),
270 const char* label,
const Json& array,
275 if (!ImGui::CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen)) {
278 ImGui::PushID(label);
279 for (
size_t i = 0; i < array.
size(); ++i) {
280 const auto& entry = array[i];
281 ImGui::PushID(
static_cast<int>(i));
282 if (entry.is_object()) {
284 if (!title.empty()) {
288 if (!title.empty() || !entry.empty()) {
295 if (i + 1 < array.
size()) {
307 std::string context =
310 context += absl::StrFormat(
"\nName: %s", selection.
display_name);
312 if (selection.
id >= 0) {
313 context += absl::StrFormat(
"\nID: 0x%X", selection.
id);
316 context += absl::StrFormat(
"\nSecondary: 0x%X", selection.
secondary_id);
319 context +=
"\nRead Only: true";
325 const char* title,
const char* fallback_icon,
327 const std::function<
void()>& cancel_callback = {}) {
334 ImGui::TextWrapped(
"%s", status.
summary.empty() ? status.
label.c_str()
335 : status.summary.c_str());
336 if (!status.
detail.empty()) {
337 ImGui::TextWrapped(
"%s", status.
detail.c_str());
340 ImGui::TextWrapped(
"%s", status.
output_tail.c_str());
358 ImGui::TextDisabled(
"%s",
367 entry, callbacks, {.show_open_output =
true, .show_copy_log =
true});
383 return static_cast<int>(i);
399 const int next = (index + direction + size) % size;
406 return "View: Toggle Project Panel";
408 return "View: Toggle AI Agent Panel";
410 return "View: Toggle Proposals Panel";
412 return "View: Toggle Settings Panel";
414 return "View: Toggle Help Panel";
416 return "View: Toggle Notifications Panel";
418 return "View: Toggle Properties Panel";
440 return "Notifications";
446 return "Tool Output";
488 return "notifications";
494 return "tool_output";
560 if (direction == 0) {
570 const int step = direction > 0 ? 1 : -1;
571 OpenDrawer(StepRightPanel(current_panel, step));
596 ImGuiContext* context = ImGui::GetCurrentContext();
601 const ImGuiViewport* viewport = ImGui::GetMainViewport();
606 const float vp_width = viewport->WorkSize.x;
617 float viewport_width = 0.0f;
618 if (
const ImGuiViewport* viewport = ImGui::GetMainViewport()) {
619 viewport_width = viewport->WorkSize.x;
621 if (viewport_width <= 0.0f && ImGui::GetCurrentContext()) {
622 viewport_width = ImGui::GetIO().DisplaySize.x;
625 float clamped = std::max(limits.min_width, width);
626 if (viewport_width > 0.0f) {
627 const float ratio = viewport_width < 768.0f
628 ? std::max(0.88f, limits.max_width_ratio)
629 : limits.max_width_ratio;
630 const float max_width = std::max(limits.min_width, viewport_width * ratio);
631 clamped = std::clamp(clamped, limits.min_width, max_width);
634 float* target =
nullptr;
666 if (std::abs(*target - clamped) < 0.5f) {
672 "SetDrawerWidth type=%d requested=%.1f clamped=%.1f",
673 static_cast<int>(type), width, clamped);
818 float viewport_width)
const {
824 const float ratio = viewport_width < 768.0f
825 ? std::max(0.88f, limits.max_width_ratio)
826 : limits.max_width_ratio;
827 const float max_width = std::max(limits.min_width, viewport_width * ratio);
828 return std::clamp(width, limits.min_width, max_width);
837std::unordered_map<std::string, float>
852 const std::unordered_map<std::string, float>& widths) {
855 "RestoreDrawerWidths: %zu entries from settings", widths.size());
859 if (it != widths.end()) {
881 ImGui::IsKeyPressed(ImGuiKey_Escape)) {
902 float delta_time = std::clamp(ImGui::GetIO().DeltaTime, 0.0f, 1.0f / 20.0f);
939 const ImGuiViewport* viewport = ImGui::GetMainViewport();
940 const float viewport_width = viewport->WorkSize.x;
943 const float viewport_height =
944 std::max(0.0f, viewport->WorkSize.y - top_inset - bottom_safe);
947 const float full_width =
957 ImGuiWindowFlags panel_flags =
958 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove |
959 ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking |
960 ImGuiWindowFlags_NoNavFocus;
964 float panel_x = viewport->WorkPos.x + viewport_width - animated_width;
965 ImGui::SetNextWindowPos(ImVec2(panel_x, viewport->WorkPos.y + top_inset));
966 ImGui::SetNextWindowSize(ImVec2(full_width, viewport_height));
970 .border = panel_border,
971 .padding = ImVec2(0.0f, 0.0f),
972 .border_size = 1.0f},
973 nullptr, panel_flags);
985 ImGuiStyleVar_WindowPadding,
990 ImGuiChildFlags_AlwaysUseWindowPadding);
991 if (panel_content_open) {
992 switch (draw_panel) {
1026 const ImVec2 win_pos = ImGui::GetWindowPos();
1027 const float win_height = ImGui::GetWindowHeight();
1028 ImGui::SetCursorScreenPos(
1029 ImVec2(win_pos.x - handle_width * 0.5f, win_pos.y));
1030 ImGui::InvisibleButton(
"##RightPanelResizeHandle",
1031 ImVec2(handle_width, win_height));
1032 const bool handle_hovered = ImGui::IsItemHovered();
1033 const bool handle_active = ImGui::IsItemActive();
1034 if (handle_hovered || handle_active) {
1035 ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
1037 if (handle_hovered &&
1038 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
1042 if (handle_active) {
1044 ImGui::GetIO().MouseDelta.x;
1046 ImGui::SetTooltip(
"Width: %.0f px",
1051 handle_color.w = handle_active ? 0.95f : (handle_hovered ? 0.72f : 0.35f);
1052 ImGui::GetWindowDrawList()->AddLine(
1053 ImVec2(win_pos.x, win_pos.y),
1054 ImVec2(win_pos.x, win_pos.y + win_height),
1055 ImGui::GetColorU32(handle_color), handle_active ? 2.0f : 1.0f);
1065 ImVec2 header_min = ImGui::GetCursorScreenPos();
1066 ImVec2 header_max = ImVec2(header_min.x + ImGui::GetWindowWidth(),
1067 header_min.y + header_height);
1069 ImDrawList* draw_list = ImGui::GetWindowDrawList();
1070 draw_list->AddRectFilled(
1071 header_min, header_max,
1075 draw_list->AddLine(ImVec2(header_min.x, header_max.y),
1076 ImVec2(header_max.x, header_max.y),
1080 ImGui::SetCursorPosX(padding);
1081 ImGui::SetCursorPosY(ImGui::GetCursorPosY() +
1082 (header_height - ImGui::GetTextLineHeight()) * 0.5f);
1094 const std::string previous_shortcut =
1096 const std::string next_shortcut =
1098 const std::string previous_tooltip =
1099 previous_shortcut.empty() ?
"Previous right panel"
1100 : absl::StrFormat(
"Previous right panel (%s)",
1101 previous_shortcut.c_str());
1102 const std::string next_tooltip =
1103 next_shortcut.empty()
1104 ?
"Next right panel"
1105 : absl::StrFormat(
"Next right panel (%s)", next_shortcut.c_str());
1109 previous_tooltip.c_str(),
false,
1111 "switch_panel_prev")) {
1119 ImGui::OpenPopup(
"##RightPanelSwitcher");
1124 next_tooltip.c_str(),
false,
1126 "switch_panel_next")) {
1130 if (ImGui::BeginPopup(
"##RightPanelSwitcher")) {
1131 for (
PanelType panel_type : kRightPanelSwitchOrder) {
1134 const char* shortcut_action = GetPanelShortcutAction(panel_type);
1135 std::string shortcut;
1136 if (shortcut_action[0] !=
'\0') {
1138 if (shortcut ==
"Unassigned") {
1142 if (ImGui::MenuItem(label.c_str(),
1143 shortcut.empty() ?
nullptr : shortcut.c_str(),
1144 current_panel == panel_type)) {
1153 const float button_size = chrome_button_size.x;
1154 const float button_y =
1155 header_min.y + (header_height - chrome_button_size.y) * 0.5f;
1156 float current_x = ImGui::GetWindowWidth() - button_size - padding;
1159 ImGui::SetCursorScreenPos(ImVec2(header_min.x + current_x, button_y));
1162 ImVec4(0, 0, 0, 0),
"right_sidebar",
"close_panel")) {
1168 current_x -= (button_size + 4.0f);
1169 ImGui::SetCursorScreenPos(ImVec2(header_min.x + current_x, button_y));
1176 "lock_selection")) {
1182 ImGui::SetCursorPosY(header_height + 8.0f);
1190 bool default_open) {
1197 {ImGuiStyleVar_FramePadding, ImVec2(8.0f, 6.0f)},
1198 {ImGuiStyleVar_FrameRounding, 4.0f},
1202 std::string header_text;
1204 header_text = std::string(icon) +
" " + label;
1206 header_text = label;
1209 ImGuiTreeNodeFlags flags =
1210 ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth |
1211 ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_FramePadding;
1213 flags |= ImGuiTreeNodeFlags_DefaultOpen;
1216 bool is_open = ImGui::TreeNodeEx(header_text.c_str(), flags);
1220 ImGui::Indent(4.0f);
1227 ImGui::Unindent(4.0f);
1248 ImGui::TextUnformatted(value);
1253 ImGui::PushTextWrapPos(ImGui::GetContentRegionAvail().x);
1254 ImGui::TextWrapped(
"%s", text);
1255 ImGui::PopTextWrapPos();
1259 const std::string& action,
const std::string& fallback)
const {
1268 if (shortcut->
keys.empty()) {
1269 return "Unassigned";
1276 const char* description,
1277 const std::string& fallback) {
1287#ifdef YAZE_BUILD_AGENT_UI
1293 "The AI Agent is not initialized. "
1294 "Open the AI Agent from View menu or use Ctrl+Shift+A.");
1300 const float action_bar_height = ImGui::GetFrameHeightWithSpacing() + 8.0f;
1301 const float content_height =
1303 ImGui::GetContentRegionAvail().y - action_bar_height);
1305 if (ImGui::BeginChild(
"AgentChatBody", ImVec2(0, content_height),
true)) {
1312 const ImVec4 transparent_bg(0, 0, 0, 0);
1316 "Open Proposals",
false, transparent_bg,
1317 "agent_sidebar",
"open_proposals")) {
1324 "Clear Chat History",
false, transparent_bg,
1325 "agent_sidebar",
"clear_history")) {
1331 "Save Chat History",
false, transparent_bg,
1332 "agent_sidebar",
"save_history")) {
1341 "The AI Agent requires agent UI support. "
1342 "Build with YAZE_BUILD_AGENT_UI=ON to enable.");
1347#ifdef YAZE_BUILD_AGENT_UI
1354 std::string selection_context;
1360 struct QuickAction {
1365 std::vector<QuickAction> actions;
1366 if (!selection_context.empty()) {
1367 actions.push_back({
"Explain selection",
1368 "Explain this selection and how to edit it safely.\n\n" +
1369 selection_context});
1372 "Suggest improvements or checks for this selection.\n\n" +
1373 selection_context});
1378 actions.push_back({
"Summarize map",
1379 "Summarize the current overworld map and its key "
1380 "features. Use overworld tools if available."});
1381 actions.push_back({
"List sprites/items",
1382 "List notable sprites or items on the current "
1386 actions.push_back({
"Audit room",
1387 "Summarize the current dungeon room layout, doors, "
1388 "and object density."});
1389 actions.push_back({
"List sprites",
1390 "List sprites in the current dungeon room and any "
1391 "potential conflicts."});
1394 actions.push_back({
"Review tiles",
1395 "Review the current tileset usage and point out any "
1396 "obvious issues."});
1397 actions.push_back({
"Palette check",
1398 "Check palette usage for contrast/readability "
1402 actions.push_back({
"Palette audit",
1403 "Audit the active palette for hue/contrast balance "
1404 "and note risks."});
1405 actions.push_back({
"Theme ideas",
1406 "Suggest a palette variation that fits the current "
1410 actions.push_back({
"Sprite review",
1411 "Review the selected sprite properties and suggest "
1415 actions.push_back({
"Copy edit",
1416 "Review the current message text for clarity and "
1417 "style improvements."});
1420 actions.push_back({
"ASM review",
1421 "Review the current ASM changes for risks and style "
1425 actions.push_back({
"Hex context",
1426 "Explain what the current hex selection likely "
1430 actions.push_back({
"Test suggestion",
1431 "Propose a short emulator test to validate the "
1432 "current feature."});
1435 actions.push_back({
"Agent config review",
1436 "Review current agent configuration for practical "
1440 actions.push_back({
"Agent overview",
1441 "Suggest the next best agent-assisted action for the "
1442 "current editor context."});
1446 if (actions.empty()) {
1450 ImGui::TextColored(accent,
"%s Editor Actions",
ICON_MD_BOLT);
1454 int columns = ImGui::GetContentRegionAvail().x > 420.0f ? 2 : 1;
1455 if (ImGui::BeginTable(
"AgentQuickActionsTable", columns,
1456 ImGuiTableFlags_SizingStretchSame)) {
1457 for (
const auto& action : actions) {
1458 ImGui::TableNextColumn();
1459 if (ImGui::Button(action.label, ImVec2(-1, 0))) {
1484 "The proposal system is not initialized. "
1485 "Proposals will appear here when the AI Agent creates them.");
1499 "Settings will be available once initialized. "
1500 "This panel provides quick access to application settings.");
1535 const char* editor_name =
"No Editor Selected";
1540 editor_name =
"Overworld Editor";
1544 editor_name =
"Dungeon Editor";
1548 editor_name =
"Graphics Editor";
1552 editor_name =
"Palette Editor";
1556 editor_name =
"Music Editor";
1560 editor_name =
"Screen Editor";
1564 editor_name =
"Sprite Editor";
1568 editor_name =
"Message Editor";
1572 editor_name =
"Emulator";
1589 ImGui::Indent(8.0f);
1593 absl::StrFormat(
"%s+Shift+S", ctrl));
1597 absl::StrFormat(
"%s+Shift+P", ctrl));
1599 absl::StrFormat(
"%s+Shift+K", ctrl));
1601 absl::StrFormat(
"%s+B", ctrl));
1604 ImGui::Unindent(8.0f);
1613 ImGui::Indent(8.0f);
1623 ImGui::Unindent(8.0f);
1628 ImGui::Indent(8.0f);
1633 absl::StrFormat(
"%s+C", ctrl));
1635 absl::StrFormat(
"%s+V", ctrl));
1636 DrawShortcutRow(
"dungeon.object.delete",
"Delete selection",
"Delete");
1640 ImGui::Unindent(8.0f);
1645 ImGui::Indent(8.0f);
1653 absl::StrFormat(
"%s+G", ctrl));
1654 ImGui::Unindent(8.0f);
1659 ImGui::Indent(8.0f);
1663 ImGui::Unindent(8.0f);
1668 ImGui::Indent(8.0f);
1674 ImGui::Unindent(8.0f);
1679 ImGui::Indent(8.0f);
1681 "Insert Line Break");
1683 ImGui::Unindent(8.0f);
1688 ImGui::Indent(8.0f);
1692 ImGui::TextWrapped(
"Select an editor to see specific shortcuts.");
1694 ImGui::Unindent(8.0f);
1703 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1705 ImGui::TextWrapped(
"Paint tiles by selecting from Tile16 Selector");
1708 "Switch between Light World, Dark World, and Special Areas");
1711 "Use Entity Mode to place entrances, exits, items, and sprites");
1713 ImGui::TextWrapped(
"Right-click on the map to pick a tile for painting");
1718 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1720 ImGui::TextWrapped(
"Select rooms from the Room Selector or Room Matrix");
1722 ImGui::TextWrapped(
"Place objects using the Object Editor panel");
1725 "Edit room headers for palette, GFX, and floor settings");
1727 ImGui::TextWrapped(
"Multiple rooms can be opened in separate tabs");
1732 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1734 ImGui::TextWrapped(
"Browse graphics sheets using the Sheet Browser");
1736 ImGui::TextWrapped(
"Edit pixels directly with the Pixel Editor");
1738 ImGui::TextWrapped(
"Choose palettes from Palette Controls");
1740 ImGui::TextWrapped(
"View 3D objects like rupees and crystals");
1745 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1747 ImGui::TextWrapped(
"Edit overworld, dungeon, and sprite palettes");
1749 ImGui::TextWrapped(
"Use Quick Access for color harmony tools");
1751 ImGui::TextWrapped(
"Changes update in real-time across all editors");
1756 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1758 ImGui::TextWrapped(
"Browse songs in the Song Browser");
1760 ImGui::TextWrapped(
"Use the tracker for playback control");
1762 ImGui::TextWrapped(
"Edit instruments and BRR samples");
1767 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1769 ImGui::TextWrapped(
"Edit all in-game dialog messages");
1771 ImGui::TextWrapped(
"Preview text rendering with the font atlas");
1773 ImGui::TextWrapped(
"Manage the compression dictionary");
1778 ImGui::TextWrapped(
"Open a ROM file via File > Open ROM");
1780 ImGui::TextWrapped(
"Select an editor from the sidebar");
1782 ImGui::TextWrapped(
"Use panels to access tools and settings");
1784 ImGui::TextWrapped(
"Save your work via File > Save ROM");
1790 const float button_width = ImGui::GetContentRegionAvail().x;
1793 {ImGuiStyleVar_FramePadding, ImVec2(8.0f, 6.0f)},
1794 {ImGuiStyleVar_FrameRounding, 4.0f},
1804 ImVec2(button_width, 0))) {
1818 ImVec2(button_width, 0))) {
1819 gui::OpenUrl(
"https://github.com/scawful/yaze/issues/new");
1831 if (ImGui::Button(
ICON_MD_FORUM " Join Discord", ImVec2(button_width, 0))) {
1842 "A comprehensive editor for The Legend of Zelda: "
1843 "A Link to the Past ROM files.");
1849 ImGui::Text(
"Written by: scawful");
1850 ImGui::Text(
"Special Thanks: Zarby89, JaredBrian");
1868 float avail = ImGui::GetContentRegionAvail().x;
1878 ImVec2(avail * 0.5f - 4.0f, 0))) {
1883 ImVec2(avail * 0.5f - 4.0f, 0))) {
1900 const auto cancel_build =
1903 if (build_status.visible || run_status.visible || !workflow_history.empty()) {
1905 if (build_status.visible) {
1906 DrawWorkflowSummaryCard(
"Build",
ICON_MD_BUILD, build_status,
1910 if (run_status.visible) {
1914 if (!workflow_history.empty()) {
1916 const auto preview_entries =
1918 for (
size_t i = 0; i < preview_entries.size(); ++i) {
1919 ImGui::PushID(
static_cast<int>(i));
1920 DrawWorkflowPreviewEntry(preview_entries[i], workflow_callbacks);
1922 if (i + 1 < preview_entries.size()) {
1926 if (workflow_history.size() > preview_entries.size()) {
1928 ImGui::TextDisabled(
"+%zu more entries available in Workflow Output",
1929 workflow_history.size() - preview_entries.size());
1932 " View Full History##workflow_view_full")) {
1944 if (history.empty()) {
1950 "Notifications will appear here when actions complete.");
1956 if (unread_count > 0) {
1967 ImGuiChildFlags_None, ImGuiWindowFlags_AlwaysVerticalScrollbar);
1968 if (notification_list_open) {
1970 auto now = std::chrono::system_clock::now();
1973 bool shown_today =
false;
1974 bool shown_yesterday =
false;
1975 bool shown_older =
false;
1977 for (
const auto& entry : history) {
1979 std::chrono::duration_cast<std::chrono::hours>(now - entry.timestamp)
1983 if (diff < 24 && !shown_today) {
1986 }
else if (diff >= 24 && diff < 48 && !shown_yesterday) {
1989 shown_yesterday =
true;
1990 }
else if (diff >= 48 && !shown_older) {
1997 ImGui::PushID(&entry);
2002 switch (entry.type) {
2032 ImGui::TextWrapped(
"%s", entry.message.c_str());
2035 auto diff_sec = std::chrono::duration_cast<std::chrono::seconds>(
2036 now - entry.timestamp)
2038 std::string time_str;
2039 if (diff_sec < 60) {
2040 time_str =
"just now";
2041 }
else if (diff_sec < 3600) {
2042 time_str = absl::StrFormat(
"%dm ago", diff_sec / 60);
2043 }
else if (diff_sec < 86400) {
2044 time_str = absl::StrFormat(
"%dh ago", diff_sec / 3600);
2046 time_str = absl::StrFormat(
"%dd ago", diff_sec / 86400);
2068 "Select an item in the editor to view and edit its properties here.");
2106 "Open a .yaze project file to access project management features "
2107 "including ROM versioning, snapshots, and configuration.");
2114 ImGui::TextWrapped(
"Create a new project via File > New Project");
2116 ImGui::TextWrapped(
"Open existing .yaze project files");
2118 ImGui::TextWrapped(
"Projects track ROM versions and settings");
2124 ImGui::TextWrapped(
"Version snapshots with Git integration");
2126 ImGui::TextWrapped(
"ROM backup and restore");
2128 ImGui::TextWrapped(
"Project-specific settings");
2130 ImGui::TextWrapped(
"Assembly code folder integration");
2151 "Run a project-graph query from the editor to inspect its output "
2166 ImGui::PushID(
"summary");
2168 if (!parsed.
empty()) {
2171 DrawJsonObjectFields(parsed);
2177 ImGui::PushID(
"resolved_source");
2179 if (!parsed[
"source"].empty()) {
2182 DrawJsonObjectFields(parsed[
"source"]);
2186 DrawJsonObjectArraySection(
"Matching Symbols", parsed[
"matching_symbols"],
2188 DrawJsonObjectArraySection(
"Sources", parsed[
"sources"],
2191 DrawJsonObjectArraySection(
"Writes", parsed[
"writes"],
2194 DrawJsonObjectArraySection(
"Symbols", parsed[
"symbols"],
2198 if (ImGui::CollapsingHeader(
"Raw Output",
2199 has_json ? 0 : ImGuiTreeNodeFlags_DefaultOpen)) {
2200 if (ImGui::BeginChild(
"##tool_output_result", ImVec2(0.0f, 220.0f),
true)) {
2208 bool clicked =
false;
2212 auto DrawPanelButton = [&](
const char* icon,
const char* base_tooltip,
2213 const char* shortcut_action,
PanelType type) {
2216 {ImGuiCol_Button, ImVec4(0, 0, 0, 0)},
2223 if (ImGui::SmallButton(icon)) {
2228 if (ImGui::IsItemHovered()) {
2230 if (shortcut.empty() || shortcut ==
"Unassigned") {
2231 ImGui::SetTooltip(
"%s", base_tooltip);
2233 ImGui::SetTooltip(
"%s (%s)", base_tooltip, shortcut.c_str());
static Json parse(const std::string &)
std::string dump(int=-1, char=' ', bool=false, int=0) const
bool contains(const std::string &) const
void SendMessage(const std::string &message)
void Draw(float available_height=0.0f)
void set_active(bool active)
absl::Status SaveHistory(const std::string &filepath)
void CycleDrawer(int direction)
Cycle to the next/previous right drawer in header order.
bool DrawDrawerToggleButtons()
Draw drawer toggle buttons for the status cluster.
void DrawPanelDescription(const char *text)
void DrawEditorContextHeader()
static std::string PanelTypeKey(PanelType type)
void NotifyPanelWidthChanged(PanelType type, float width)
EditorType active_editor_type_
void DrawEditorSpecificShortcuts()
void DrawShortcutRow(const std::string &action, const char *description, const std::string &fallback)
std::string GetShortcutLabel(const std::string &action, const std::string &fallback) const
float GetClampedPanelWidth(PanelType type, float viewport_width) const
void OpenDrawer(DrawerType type)
Open a specific drawer.
void SetDrawerWidth(DrawerType type, float width)
Set drawer width for a specific drawer type.
void SetToolOutput(std::string title, std::string query, std::string content, ToolOutputActions actions={})
ToolOutputActions tool_output_actions_
void DrawPanelValue(const char *label, const char *value)
void Draw()
Draw the drawer and its contents.
std::function< void(PanelType, float)> on_panel_width_changed_
void DrawGlobalShortcuts()
void ResetDrawerWidths()
Reset all drawer widths to their defaults.
void DrawPanelHeader(const char *title, const char *icon)
void DrawEditorSpecificHelp()
SelectionPropertiesPanel * properties_panel_
bool BeginPanelSection(const char *label, const char *icon=nullptr, bool default_open=true)
void ToggleDrawer(DrawerType type)
Toggle a specific drawer on/off.
float notifications_width_
void DrawProposalsPanel()
static float GetDefaultDrawerWidth(DrawerType type, EditorType editor=EditorType::kUnknown)
Get the default width for a specific drawer type.
ShortcutManager * shortcut_manager_
std::string tool_output_title_
float GetConfiguredPanelWidth(PanelType type) const
void DrawQuickActionButtons()
std::unordered_map< std::string, PanelSizeLimits > panel_size_limits_
void DrawPropertiesPanel()
void DrawAgentChatPanel()
SettingsPanel * settings_panel_
void DrawNotificationsPanel()
ToastManager * toast_manager_
bool IsDrawerActive(DrawerType type) const
Check if a specific drawer is active.
bool IsDrawerExpanded() const
Check if any drawer is currently expanded (or animating closed)
float GetDrawerWidth() const
Get the width of the drawer when expanded.
std::string tool_output_content_
void OnHostVisibilityChanged(bool visible)
Snap transient animations when host visibility changes.
void DrawPanelLabel(const char *label)
bool DrawAgentQuickActions()
void CloseDrawer()
Close the currently active drawer.
void RestoreDrawerWidths(const std::unordered_map< std::string, float > &widths)
std::unordered_map< std::string, float > SerializeDrawerWidths() const
Persist/restore per-drawer widths for user settings.
ProposalDrawer * proposal_drawer_
std::string tool_output_query_
void CycleToPreviousDrawer()
ProjectManagementPanel * project_panel_
void DrawToolOutputPanel()
PanelSizeLimits GetPanelSizeLimits(PanelType type) const
void SetPanelSizeLimits(PanelType type, const PanelSizeLimits &limits)
Set sizing constraints for an individual right panel.
const SelectionContext & GetSelection() const
Get the current selection context.
bool HasSelection() const
Check if there's an active selection.
void Draw()
Draw the properties panel content.
const Shortcut * FindShortcut(const std::string &name) const
size_t GetUnreadCount() const
const std::deque< NotificationEntry > & GetHistory() const
static bool BeginContentChild(const char *id, const ImVec2 &min_size, bool border=false, ImGuiWindowFlags flags=0)
static void EndContentChild()
static SafeAreaInsets GetSafeAreaInsets()
static float GetTopInset()
RAII guard for ImGui style colors.
RAII guard for ImGui style vars.
RAII compound guard for window-level style setup.
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_ROCKET_LAUNCH
#define ICON_MD_NOTIFICATIONS
#define ICON_MD_ACCOUNT_TREE
#define ICON_MD_LANDSCAPE
#define ICON_MD_LOCK_OPEN
#define ICON_MD_FOLDER_SPECIAL
#define ICON_MD_CHECKLIST
#define ICON_MD_PLAY_ARROW
#define ICON_MD_FILE_DOWNLOAD
#define ICON_MD_SWAP_HORIZ
#define ICON_MD_VIDEOGAME_ASSET
#define ICON_MD_BUG_REPORT
#define ICON_MD_MUSIC_NOTE
#define ICON_MD_CHEVRON_LEFT
#define ICON_MD_CHECK_CIRCLE
#define ICON_MD_DESCRIPTION
#define ICON_MD_HELP_OUTLINE
#define ICON_MD_STRAIGHTEN
#define ICON_MD_NOTIFICATIONS_OFF
#define ICON_MD_SELECT_ALL
#define ICON_MD_OPEN_IN_NEW
#define ICON_MD_CONTENT_COPY
#define ICON_MD_DELETE_FOREVER
#define ICON_MD_CHEVRON_RIGHT
#define ICON_MD_FIBER_MANUAL_RECORD
#define ICON_MD_SMART_TOY
#define ICON_MD_DELETE_SWEEP
#define LOG_INFO(category, format,...)
std::vector< ProjectWorkflowHistoryEntry > workflow_history()
std::function< void()> cancel_build_workflow_callback()
ProjectWorkflowStatus build_workflow_status()
std::function< void()> run_project_workflow_callback()
std::function< void()> show_workflow_output_callback()
std::function< void()> start_build_workflow_callback()
ProjectWorkflowStatus run_workflow_status()
std::string JsonValueToDisplayString(const Json &value)
void DrawWorkflowPreviewEntry(const ProjectWorkflowHistoryEntry &entry, const workflow::WorkflowActionCallbacks &callbacks)
void DrawWorkflowSummaryCard(const char *title, const char *fallback_icon, const ProjectWorkflowStatus &status, const std::function< void()> &cancel_callback={})
int FindRightPanelIndex(RightDrawerManager::PanelType type)
const std::array< RightDrawerManager::PanelType, 7 > kRightPanelSwitchOrder
std::string ExtractToolOutputReference(const Json &object)
bool TryParseToolOutputJson(const std::string &text, Json *out)
const char * GetPanelShortcutAction(RightDrawerManager::PanelType type)
std::string BuildSelectionContextSummary(const SelectionContext &selection)
std::string BuildToolOutputEntryTitle(const Json &object)
std::string SanitizeToolOutputIdFragment(const std::string &value)
void DrawJsonObjectArraySection(const char *label, const Json &array, const RightDrawerManager::ToolOutputActions &actions)
void DrawJsonObjectFields(const Json &object)
RightDrawerManager::PanelType StepRightPanel(RightDrawerManager::PanelType current, int direction)
std::optional< uint32_t > ParseToolOutputAddress(const Json &value)
std::optional< uint32_t > ExtractToolOutputAddress(const Json &object)
void DrawToolOutputEntryActions(const Json &object, const RightDrawerManager::ToolOutputActions &actions)
std::string BuildToolOutputActionLabel(const char *visible_label, const char *action_key, const Json &object)
std::string FormatHistoryTime(std::chrono::system_clock::time_point timestamp)
const char * WorkflowIcon(const ProjectWorkflowStatus &status, const char *fallback_icon)
WorkflowActionRowResult DrawHistoryActionRow(const ProjectWorkflowHistoryEntry &entry, const WorkflowActionCallbacks &callbacks, const WorkflowActionRowOptions &options)
std::vector< ProjectWorkflowHistoryEntry > SelectWorkflowPreviewEntries(const std::vector< ProjectWorkflowHistoryEntry > &history, size_t max_entries)
ImVec4 WorkflowColor(ProjectWorkflowState state)
const char * GetPanelTypeName(RightDrawerManager::PanelType type)
Get the name of a panel type.
const char * GetSelectionTypeName(SelectionType type)
Get a human-readable name for a selection type.
std::string PrintShortcut(const std::vector< ImGuiKey > &keys)
const char * GetPanelTypeIcon(RightDrawerManager::PanelType type)
Get the icon for a panel type.
bool TransparentIconButton(const char *icon, const ImVec2 &size, const char *tooltip, bool is_active, const ImVec4 &active_color, const char *panel_id, const char *anim_id)
Draw a transparent icon button (hover effect only).
const char * GetCtrlDisplayName()
Get the display name for the primary modifier key.
ImVec4 ConvertColorToImVec4(const Color &color)
void ColoredText(const char *text, const ImVec4 &color)
ImVec4 GetSurfaceContainerHighestVec4()
bool OpenUrl(const std::string &url)
ImVec4 GetTextDisabledVec4()
ImVec4 GetTextSecondaryVec4()
void ColoredTextF(const ImVec4 &color, const char *fmt,...)
ImVec4 GetSurfaceContainerHighVec4()
ImVec4 GetOnSurfaceVec4()
ImVec4 GetSurfaceContainerVec4()
ProjectWorkflowStatus status
std::chrono::system_clock::time_point timestamp
ProjectWorkflowState state
Holds information about the current selection.
std::vector< ImGuiKey > keys
std::function< void()> run_project
std::function< void()> show_output
std::function< void()> start_build
static constexpr float kPanelWidthSettings
static constexpr float kPanelWidthHelp
static constexpr float kPanelMinWidthProject
static constexpr float kHeaderButtonSpacing
static constexpr float kPanelMinWidthHelp
static constexpr float kPanelWidthNotifications
static constexpr float kPanelWidthMedium
static constexpr float kAnimationSnapThreshold
static constexpr float kPanelMinWidthNotifications
static constexpr float kPanelMinWidthAgentChat
static constexpr float kContentMinHeightChat
static constexpr float kPanelPaddingLarge
static constexpr float kHeaderButtonGap
static constexpr float kAnimationSpeed
static constexpr float kPanelMinWidthSettings
static constexpr float kPanelPaddingMedium
static constexpr float kPanelWidthProject
static constexpr float kSplitterWidth
static constexpr float kPanelMinWidthProposals
static constexpr float kPanelHeaderHeight
static constexpr float kPanelMinWidthAbsolute
static constexpr float kContentMinHeightList
static constexpr float kPanelMinWidthProperties
static constexpr float kPanelWidthProposals
static constexpr float kPanelWidthProperties
static constexpr float kPanelWidthAgentChat