13#include "absl/strings/str_format.h"
34#include "imgui/imgui.h"
44std::string ResolveAgentChatHistoryPath() {
47 return (*agent_dir /
"agent_chat_history.json").string();
51 return (*temp_dir /
"agent_chat_history.json").string();
53 return (std::filesystem::current_path() /
"agent_chat_history.json").string();
58 return value.
get<std::string>();
61 return value.
get<
bool>() ?
"true" :
"false";
63 if (value.is_number_integer()) {
64 return std::to_string(value.
get<
long long>());
66 if (value.is_number_unsigned()) {
67 return std::to_string(value.
get<
unsigned long long>());
69 if (value.is_number_float()) {
70 return absl::StrFormat(
"%.3f", value.
get<
double>());
79 std::string sanitized;
80 sanitized.reserve(value.size());
81 for (
unsigned char ch : value) {
82 if (std::isalnum(ch)) {
83 sanitized.push_back(
static_cast<char>(ch));
85 sanitized.push_back(
'_');
88 return sanitized.empty() ? std::string(
"entry") : sanitized;
92 if (!out || text.
empty()) {
104 if (value.is_number_unsigned()) {
105 return static_cast<uint32_t
>(value.
get<uint64_t>());
107 if (value.is_number_integer()) {
108 return static_cast<uint32_t
>(value.
get<int64_t>());
114 std::string token = value.
get<std::string>();
118 if (token[0] ==
'$') {
119 token = token.substr(1);
120 }
else if (token.size() > 2 && token[0] ==
'0' &&
121 (token[1] ==
'x' || token[1] ==
'X')) {
122 token = token.substr(2);
125 return static_cast<uint32_t
>(std::stoul(token,
nullptr, 16));
132 if (!
object.is_object()) {
135 for (
const char* key : {
"address",
"entry_address"}) {
136 if (
object.contains(key)) {
138 if (parsed.has_value()) {
147 if (!
object.is_object()) {
150 if (
object.contains(
"source") &&
object[
"source"].is_string()) {
151 return object[
"source"].get<std::string>();
153 if (
object.contains(
"file") &&
object[
"file"].is_string()) {
154 std::string reference =
object[
"file"].get<std::string>();
155 if (
object.contains(
"line") &&
object[
"line"].is_number_integer()) {
156 reference = absl::StrCat(reference,
":",
object[
"line"].get<int>());
164 if (!
object.is_object()) {
168 const std::string address =
object.contains(
"address")
171 const std::string bank =
173 const std::string name =
177 if (!source.empty() && !address.empty()) {
178 return absl::StrFormat(
"%s (%s)", source.c_str(), address.c_str());
180 if (!name.empty() && !address.empty()) {
181 return absl::StrFormat(
"%s %s", name.c_str(), address.c_str());
183 if (!name.empty() && !bank.empty()) {
184 return absl::StrFormat(
"%s %s", name.c_str(), bank.c_str());
186 if (!source.empty()) {
189 if (!address.empty()) {
202 const char* action_key,
203 const Json&
object) {
205 if (address.has_value()) {
206 return absl::StrFormat(
"%s##tool_output_%s_%06X", visible_label, action_key,
211 if (!reference.empty()) {
212 return absl::StrFormat(
"%s##tool_output_%s_%s", visible_label, action_key,
216 return absl::StrFormat(
"%s##tool_output_%s_entry", visible_label, action_key);
221 if (!
object.is_object()) {
227 bool drew_any =
false;
230 const std::string label =
232 if (ImGui::SmallButton(label.c_str())) {
241 const std::string label =
243 if (ImGui::SmallButton(label.c_str())) {
252 const std::string label =
254 if (ImGui::SmallButton(label.c_str())) {
261 for (
auto it =
object.begin(); it !=
object.end(); ++it) {
262 if (it.value().is_array() || it.value().is_object()) {
265 ImGui::BulletText(
"%s: %s", it.key().c_str(),
271 const char* label,
const Json& array,
276 if (!ImGui::CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen)) {
279 ImGui::PushID(label);
280 for (
size_t i = 0; i < array.
size(); ++i) {
281 const auto& entry = array[i];
282 ImGui::PushID(
static_cast<int>(i));
283 if (entry.is_object()) {
285 if (!title.empty()) {
289 if (!title.empty() || !entry.empty()) {
296 if (i + 1 < array.
size()) {
308 std::string context =
311 context += absl::StrFormat(
"\nName: %s", selection.
display_name);
313 if (selection.
id >= 0) {
314 context += absl::StrFormat(
"\nID: 0x%X", selection.
id);
317 context += absl::StrFormat(
"\nSecondary: 0x%X", selection.
secondary_id);
320 context +=
"\nRead Only: true";
326 const char* title,
const char* fallback_icon,
328 const std::function<
void()>& cancel_callback = {}) {
335 ImGui::TextWrapped(
"%s", status.
summary.empty() ? status.
label.c_str()
336 : status.summary.c_str());
337 if (!status.
detail.empty()) {
338 ImGui::TextWrapped(
"%s", status.
detail.c_str());
341 ImGui::TextWrapped(
"%s", status.
output_tail.c_str());
359 ImGui::TextDisabled(
"%s",
368 entry, callbacks, {.show_open_output =
true, .show_copy_log =
true});
384 return static_cast<int>(i);
400 const int next = (index + direction + size) % size;
407 return "View: Toggle Project Panel";
409 return "View: Toggle AI Agent Panel";
411 return "View: Toggle Proposals Panel";
413 return "View: Toggle Settings Panel";
415 return "View: Toggle Help Panel";
417 return "View: Toggle Notifications Panel";
419 return "View: Toggle Properties Panel";
441 return "Notifications";
447 return "Tool Output";
489 return "notifications";
495 return "tool_output";
561 if (direction == 0) {
571 const int step = direction > 0 ? 1 : -1;
572 OpenDrawer(StepRightPanel(current_panel, step));
597 ImGuiContext* context = ImGui::GetCurrentContext();
602 const ImGuiViewport* viewport = ImGui::GetMainViewport();
607 const float vp_width = viewport->WorkSize.x;
618 float viewport_width = 0.0f;
619 if (
const ImGuiViewport* viewport = ImGui::GetMainViewport()) {
620 viewport_width = viewport->WorkSize.x;
622 if (viewport_width <= 0.0f && ImGui::GetCurrentContext()) {
623 viewport_width = ImGui::GetIO().DisplaySize.x;
626 float clamped = std::max(limits.min_width, width);
627 if (viewport_width > 0.0f) {
628 const float ratio = viewport_width < 768.0f
629 ? std::max(0.88f, limits.max_width_ratio)
630 : limits.max_width_ratio;
631 const float max_width = std::max(limits.min_width, viewport_width * ratio);
632 clamped = std::clamp(clamped, limits.min_width, max_width);
635 float* target =
nullptr;
667 if (std::abs(*target - clamped) < 0.5f) {
673 "SetDrawerWidth type=%d requested=%.1f clamped=%.1f",
674 static_cast<int>(type), width, clamped);
819 float viewport_width)
const {
825 const float ratio = viewport_width < 768.0f
826 ? std::max(0.88f, limits.max_width_ratio)
827 : limits.max_width_ratio;
828 const float max_width = std::max(limits.min_width, viewport_width * ratio);
829 return std::clamp(width, limits.min_width, max_width);
838std::unordered_map<std::string, float>
853 const std::unordered_map<std::string, float>& widths) {
856 "RestoreDrawerWidths: %zu entries from settings", widths.size());
860 if (it != widths.end()) {
882 ImGui::IsKeyPressed(ImGuiKey_Escape)) {
903 float delta_time = std::clamp(ImGui::GetIO().DeltaTime, 0.0f, 1.0f / 20.0f);
940 const ImGuiViewport* viewport = ImGui::GetMainViewport();
941 const float viewport_width = viewport->WorkSize.x;
944 const float viewport_height =
945 std::max(0.0f, viewport->WorkSize.y - top_inset - bottom_safe);
948 const float full_width =
958 ImGuiWindowFlags panel_flags =
959 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove |
960 ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking |
961 ImGuiWindowFlags_NoNavFocus;
965 float panel_x = viewport->WorkPos.x + viewport_width - animated_width;
966 ImGui::SetNextWindowPos(ImVec2(panel_x, viewport->WorkPos.y + top_inset));
967 ImGui::SetNextWindowSize(ImVec2(full_width, viewport_height));
971 .border = panel_border,
972 .padding = ImVec2(0.0f, 0.0f),
973 .border_size = 1.0f},
974 nullptr, panel_flags);
986 ImGuiStyleVar_WindowPadding,
991 ImGuiChildFlags_AlwaysUseWindowPadding);
992 if (panel_content_open) {
993 switch (draw_panel) {
1027 const ImVec2 win_pos = ImGui::GetWindowPos();
1028 const float win_height = ImGui::GetWindowHeight();
1029 ImGui::SetCursorScreenPos(
1030 ImVec2(win_pos.x - handle_width * 0.5f, win_pos.y));
1031 ImGui::InvisibleButton(
"##RightPanelResizeHandle",
1032 ImVec2(handle_width, win_height));
1033 const bool handle_hovered = ImGui::IsItemHovered();
1034 const bool handle_active = ImGui::IsItemActive();
1035 if (handle_hovered || handle_active) {
1036 ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
1038 if (handle_hovered &&
1039 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
1043 if (handle_active) {
1045 ImGui::GetIO().MouseDelta.x;
1047 ImGui::SetTooltip(tr(
"Width: %.0f px"),
1052 handle_color.w = handle_active ? 0.95f : (handle_hovered ? 0.72f : 0.35f);
1053 ImGui::GetWindowDrawList()->AddLine(
1054 ImVec2(win_pos.x, win_pos.y),
1055 ImVec2(win_pos.x, win_pos.y + win_height),
1056 ImGui::GetColorU32(handle_color), handle_active ? 2.0f : 1.0f);
1066 ImVec2 header_min = ImGui::GetCursorScreenPos();
1067 ImVec2 header_max = ImVec2(header_min.x + ImGui::GetWindowWidth(),
1068 header_min.y + header_height);
1070 ImDrawList* draw_list = ImGui::GetWindowDrawList();
1071 draw_list->AddRectFilled(
1072 header_min, header_max,
1076 draw_list->AddLine(ImVec2(header_min.x, header_max.y),
1077 ImVec2(header_max.x, header_max.y),
1081 ImGui::SetCursorPosX(padding);
1082 ImGui::SetCursorPosY(ImGui::GetCursorPosY() +
1083 (header_height - ImGui::GetTextLineHeight()) * 0.5f);
1095 const std::string previous_shortcut =
1097 const std::string next_shortcut =
1099 const std::string previous_tooltip =
1100 previous_shortcut.empty() ?
"Previous right panel"
1101 : absl::StrFormat(
"Previous right panel (%s)",
1102 previous_shortcut.c_str());
1103 const std::string next_tooltip =
1104 next_shortcut.empty()
1105 ?
"Next right panel"
1106 : absl::StrFormat(
"Next right panel (%s)", next_shortcut.c_str());
1110 previous_tooltip.c_str(),
false,
1112 "switch_panel_prev")) {
1120 ImGui::OpenPopup(
"##RightPanelSwitcher");
1125 next_tooltip.c_str(),
false,
1127 "switch_panel_next")) {
1131 if (ImGui::BeginPopup(
"##RightPanelSwitcher")) {
1132 for (
PanelType panel_type : kRightPanelSwitchOrder) {
1135 const char* shortcut_action = GetPanelShortcutAction(panel_type);
1136 std::string shortcut;
1137 if (shortcut_action[0] !=
'\0') {
1139 if (shortcut ==
"Unassigned") {
1143 if (ImGui::MenuItem(label.c_str(),
1144 shortcut.empty() ?
nullptr : shortcut.c_str(),
1145 current_panel == panel_type)) {
1154 const float button_size = chrome_button_size.x;
1155 const float button_y =
1156 header_min.y + (header_height - chrome_button_size.y) * 0.5f;
1157 float current_x = ImGui::GetWindowWidth() - button_size - padding;
1160 ImGui::SetCursorScreenPos(ImVec2(header_min.x + current_x, button_y));
1163 ImVec4(0, 0, 0, 0),
"right_sidebar",
"close_panel")) {
1169 current_x -= (button_size + 4.0f);
1170 ImGui::SetCursorScreenPos(ImVec2(header_min.x + current_x, button_y));
1177 "lock_selection")) {
1183 ImGui::SetCursorPosY(header_height + 8.0f);
1191 bool default_open) {
1198 {ImGuiStyleVar_FramePadding, ImVec2(8.0f, 6.0f)},
1199 {ImGuiStyleVar_FrameRounding, 4.0f},
1203 std::string header_text;
1205 header_text = std::string(icon) +
" " + label;
1207 header_text = label;
1210 ImGuiTreeNodeFlags flags =
1211 ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth |
1212 ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_FramePadding;
1214 flags |= ImGuiTreeNodeFlags_DefaultOpen;
1217 bool is_open = ImGui::TreeNodeEx(header_text.c_str(), flags);
1221 ImGui::Indent(4.0f);
1228 ImGui::Unindent(4.0f);
1249 ImGui::TextUnformatted(value);
1254 ImGui::PushTextWrapPos(ImGui::GetContentRegionAvail().x);
1255 ImGui::TextWrapped(
"%s", text);
1256 ImGui::PopTextWrapPos();
1260 const std::string& action,
const std::string& fallback)
const {
1269 if (shortcut->
keys.empty()) {
1270 return "Unassigned";
1277 const char* description,
1278 const std::string& fallback) {
1288#ifdef YAZE_BUILD_AGENT_UI
1294 "The AI Agent is not initialized. "
1295 "Open the AI Agent from View menu or use Ctrl+Shift+A.");
1301 const float action_bar_height = ImGui::GetFrameHeightWithSpacing() + 8.0f;
1302 const float content_height =
1304 ImGui::GetContentRegionAvail().y - action_bar_height);
1306 if (ImGui::BeginChild(
"AgentChatBody", ImVec2(0, content_height),
true)) {
1313 const ImVec4 transparent_bg(0, 0, 0, 0);
1317 "Open Proposals",
false, transparent_bg,
1318 "agent_sidebar",
"open_proposals")) {
1325 "Clear Chat History",
false, transparent_bg,
1326 "agent_sidebar",
"clear_history")) {
1332 "Save Chat History",
false, transparent_bg,
1333 "agent_sidebar",
"save_history")) {
1342 "The AI Agent requires agent UI support. "
1343 "Build with YAZE_BUILD_AGENT_UI=ON to enable.");
1348#ifdef YAZE_BUILD_AGENT_UI
1355 std::string selection_context;
1361 struct QuickAction {
1366 std::vector<QuickAction> actions;
1367 if (!selection_context.empty()) {
1368 actions.push_back({
"Explain selection",
1369 "Explain this selection and how to edit it safely.\n\n" +
1370 selection_context});
1373 "Suggest improvements or checks for this selection.\n\n" +
1374 selection_context});
1379 actions.push_back({
"Summarize map",
1380 "Summarize the current overworld map and its key "
1381 "features. Use overworld tools if available."});
1382 actions.push_back({
"List sprites/items",
1383 "List notable sprites or items on the current "
1387 actions.push_back({
"Audit room",
1388 "Summarize the current dungeon room layout, doors, "
1389 "and object density."});
1390 actions.push_back({
"List sprites",
1391 "List sprites in the current dungeon room and any "
1392 "potential conflicts."});
1395 actions.push_back({
"Review tiles",
1396 "Review the current tileset usage and point out any "
1397 "obvious issues."});
1398 actions.push_back({
"Palette check",
1399 "Check palette usage for contrast/readability "
1403 actions.push_back({
"Palette audit",
1404 "Audit the active palette for hue/contrast balance "
1405 "and note risks."});
1406 actions.push_back({
"Theme ideas",
1407 "Suggest a palette variation that fits the current "
1411 actions.push_back({
"Sprite review",
1412 "Review the selected sprite properties and suggest "
1416 actions.push_back({
"Copy edit",
1417 "Review the current message text for clarity and "
1418 "style improvements."});
1421 actions.push_back({
"ASM review",
1422 "Review the current ASM changes for risks and style "
1426 actions.push_back({
"Hex context",
1427 "Explain what the current hex selection likely "
1431 actions.push_back({
"Test suggestion",
1432 "Propose a short emulator test to validate the "
1433 "current feature."});
1436 actions.push_back({
"Agent config review",
1437 "Review current agent configuration for practical "
1441 actions.push_back({
"Agent overview",
1442 "Suggest the next best agent-assisted action for the "
1443 "current editor context."});
1447 if (actions.empty()) {
1451 ImGui::TextColored(accent, tr(
"%s Editor Actions"),
ICON_MD_BOLT);
1455 int columns = ImGui::GetContentRegionAvail().x > 420.0f ? 2 : 1;
1456 if (ImGui::BeginTable(
"AgentQuickActionsTable", columns,
1457 ImGuiTableFlags_SizingStretchSame)) {
1458 for (
const auto& action : actions) {
1459 ImGui::TableNextColumn();
1460 if (ImGui::Button(action.label, ImVec2(-1, 0))) {
1485 "The proposal system is not initialized. "
1486 "Proposals will appear here when the AI Agent creates them.");
1500 "Settings will be available once initialized. "
1501 "This panel provides quick access to application settings.");
1536 const char* editor_name =
"No Editor Selected";
1541 editor_name =
"Overworld Editor";
1545 editor_name =
"Dungeon Editor";
1549 editor_name =
"Graphics Editor";
1553 editor_name =
"Palette Editor";
1557 editor_name =
"Music Editor";
1561 editor_name =
"Screen Editor";
1565 editor_name =
"Sprite Editor";
1569 editor_name =
"Message Editor";
1573 editor_name =
"Emulator";
1590 ImGui::Indent(8.0f);
1594 absl::StrFormat(
"%s+Shift+S", ctrl));
1598 absl::StrFormat(
"%s+Shift+P", ctrl));
1600 absl::StrFormat(
"%s+Shift+K", ctrl));
1602 absl::StrFormat(
"%s+B", ctrl));
1605 ImGui::Unindent(8.0f);
1614 ImGui::Indent(8.0f);
1624 ImGui::Unindent(8.0f);
1629 ImGui::Indent(8.0f);
1634 absl::StrFormat(
"%s+C", ctrl));
1636 absl::StrFormat(
"%s+V", ctrl));
1637 DrawShortcutRow(
"dungeon.object.delete",
"Delete selection",
"Delete");
1641 ImGui::Unindent(8.0f);
1646 ImGui::Indent(8.0f);
1654 absl::StrFormat(
"%s+G", ctrl));
1655 ImGui::Unindent(8.0f);
1660 ImGui::Indent(8.0f);
1664 ImGui::Unindent(8.0f);
1669 ImGui::Indent(8.0f);
1675 ImGui::Unindent(8.0f);
1680 ImGui::Indent(8.0f);
1682 "Insert Line Break");
1684 ImGui::Unindent(8.0f);
1689 ImGui::Indent(8.0f);
1693 ImGui::TextWrapped(tr(
"Select an editor to see specific shortcuts."));
1695 ImGui::Unindent(8.0f);
1704 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1706 ImGui::TextWrapped(tr(
"Paint tiles by selecting from Tile16 Selector"));
1709 tr(
"Switch between Light World, Dark World, and Special Areas"));
1712 tr(
"Use Entity Mode to place entrances, exits, items, and sprites"));
1715 tr(
"Right-click on the map to pick a tile for painting"));
1720 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1723 tr(
"Select rooms from the Room Selector or Room Matrix"));
1725 ImGui::TextWrapped(tr(
"Place objects using the Object Editor panel"));
1728 tr(
"Edit room headers for palette, GFX, and floor settings"));
1730 ImGui::TextWrapped(tr(
"Multiple rooms can be opened in separate tabs"));
1735 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1737 ImGui::TextWrapped(tr(
"Browse graphics sheets using the Sheet Browser"));
1739 ImGui::TextWrapped(tr(
"Edit pixels directly with the Pixel Editor"));
1741 ImGui::TextWrapped(tr(
"Choose palettes from Palette Controls"));
1743 ImGui::TextWrapped(tr(
"View 3D objects like rupees and crystals"));
1748 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1750 ImGui::TextWrapped(tr(
"Edit overworld, dungeon, and sprite palettes"));
1752 ImGui::TextWrapped(tr(
"Use Quick Access for color harmony tools"));
1754 ImGui::TextWrapped(tr(
"Changes update in real-time across all editors"));
1759 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1761 ImGui::TextWrapped(tr(
"Browse songs in the Song Browser"));
1763 ImGui::TextWrapped(tr(
"Use the tracker for playback control"));
1765 ImGui::TextWrapped(tr(
"Edit instruments and BRR samples"));
1770 ImGui::GetStyleColorVec4(ImGuiCol_Text));
1772 ImGui::TextWrapped(tr(
"Edit all in-game dialog messages"));
1774 ImGui::TextWrapped(tr(
"Preview text rendering with the font atlas"));
1776 ImGui::TextWrapped(tr(
"Manage the compression dictionary"));
1781 ImGui::TextWrapped(tr(
"Open a ROM file via File > Open ROM"));
1783 ImGui::TextWrapped(tr(
"Select an editor from the sidebar"));
1785 ImGui::TextWrapped(tr(
"Use panels to access tools and settings"));
1787 ImGui::TextWrapped(tr(
"Save your work via File > Save ROM"));
1793 const float button_width = ImGui::GetContentRegionAvail().x;
1796 {ImGuiStyleVar_FramePadding, ImVec2(8.0f, 6.0f)},
1797 {ImGuiStyleVar_FrameRounding, 4.0f},
1807 ImVec2(button_width, 0))) {
1821 ImVec2(button_width, 0))) {
1822 gui::OpenUrl(
"https://github.com/scawful/yaze/issues/new");
1834 if (ImGui::Button(
ICON_MD_FORUM " Join Discord", ImVec2(button_width, 0))) {
1845 "A comprehensive editor for The Legend of Zelda: "
1846 "A Link to the Past ROM files.");
1852 ImGui::Text(tr(
"Written by: scawful"));
1853 ImGui::Text(tr(
"Special Thanks: Zarby89, JaredBrian"));
1871 float avail = ImGui::GetContentRegionAvail().x;
1881 ImVec2(avail * 0.5f - 4.0f, 0))) {
1886 ImVec2(avail * 0.5f - 4.0f, 0))) {
1903 const auto cancel_build =
1906 if (build_status.visible || run_status.visible || !workflow_history.empty()) {
1908 if (build_status.visible) {
1909 DrawWorkflowSummaryCard(
"Build",
ICON_MD_BUILD, build_status,
1913 if (run_status.visible) {
1917 if (!workflow_history.empty()) {
1919 const auto preview_entries =
1921 for (
size_t i = 0; i < preview_entries.size(); ++i) {
1922 ImGui::PushID(
static_cast<int>(i));
1923 DrawWorkflowPreviewEntry(preview_entries[i], workflow_callbacks);
1925 if (i + 1 < preview_entries.size()) {
1929 if (workflow_history.size() > preview_entries.size()) {
1931 ImGui::TextDisabled(
1932 tr(
"+%zu more entries available in Workflow Output"),
1933 workflow_history.size() - preview_entries.size());
1936 " View Full History##workflow_view_full")) {
1948 if (history.empty()) {
1954 "Notifications will appear here when actions complete.");
1960 if (unread_count > 0) {
1971 ImGuiChildFlags_None, ImGuiWindowFlags_AlwaysVerticalScrollbar);
1972 if (notification_list_open) {
1974 auto now = std::chrono::system_clock::now();
1977 bool shown_today =
false;
1978 bool shown_yesterday =
false;
1979 bool shown_older =
false;
1981 for (
const auto& entry : history) {
1983 std::chrono::duration_cast<std::chrono::hours>(now - entry.timestamp)
1987 if (diff < 24 && !shown_today) {
1990 }
else if (diff >= 24 && diff < 48 && !shown_yesterday) {
1993 shown_yesterday =
true;
1994 }
else if (diff >= 48 && !shown_older) {
2001 ImGui::PushID(&entry);
2006 switch (entry.type) {
2036 ImGui::TextWrapped(
"%s", entry.message.c_str());
2039 auto diff_sec = std::chrono::duration_cast<std::chrono::seconds>(
2040 now - entry.timestamp)
2042 std::string time_str;
2043 if (diff_sec < 60) {
2044 time_str =
"just now";
2045 }
else if (diff_sec < 3600) {
2046 time_str = absl::StrFormat(
"%dm ago", diff_sec / 60);
2047 }
else if (diff_sec < 86400) {
2048 time_str = absl::StrFormat(
"%dh ago", diff_sec / 3600);
2050 time_str = absl::StrFormat(
"%dd ago", diff_sec / 86400);
2072 "Select an item in the editor to view and edit its properties here.");
2110 "Open a .yaze project file to access project management features "
2111 "including ROM versioning, snapshots, and configuration.");
2118 ImGui::TextWrapped(tr(
"Create a new project via File > New Project"));
2120 ImGui::TextWrapped(tr(
"Open existing .yaze project files"));
2122 ImGui::TextWrapped(tr(
"Projects track ROM versions and settings"));
2128 ImGui::TextWrapped(tr(
"Version snapshots with Git integration"));
2130 ImGui::TextWrapped(tr(
"ROM backup and restore"));
2132 ImGui::TextWrapped(tr(
"Project-specific settings"));
2134 ImGui::TextWrapped(tr(
"Assembly code folder integration"));
2155 "Run a project-graph query from the editor to inspect its output "
2170 ImGui::PushID(
"summary");
2172 if (!parsed.
empty()) {
2175 DrawJsonObjectFields(parsed);
2181 ImGui::PushID(
"resolved_source");
2183 if (!parsed[
"source"].empty()) {
2186 DrawJsonObjectFields(parsed[
"source"]);
2190 DrawJsonObjectArraySection(
"Matching Symbols", parsed[
"matching_symbols"],
2192 DrawJsonObjectArraySection(
"Sources", parsed[
"sources"],
2195 DrawJsonObjectArraySection(
"Writes", parsed[
"writes"],
2198 DrawJsonObjectArraySection(
"Symbols", parsed[
"symbols"],
2202 if (ImGui::CollapsingHeader(tr(
"Raw Output"),
2203 has_json ? 0 : ImGuiTreeNodeFlags_DefaultOpen)) {
2204 if (ImGui::BeginChild(
"##tool_output_result", ImVec2(0.0f, 220.0f),
true)) {
2212 bool clicked =
false;
2216 auto DrawPanelButton = [&](
const char* icon,
const char* base_tooltip,
2217 const char* shortcut_action,
PanelType type) {
2220 {ImGuiCol_Button, ImVec4(0, 0, 0, 0)},
2227 if (ImGui::SmallButton(icon)) {
2232 if (ImGui::IsItemHovered()) {
2234 if (shortcut.empty() || shortcut ==
"Unassigned") {
2235 ImGui::SetTooltip(
"%s", base_tooltip);
2237 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