208 using namespace ImGui;
210 TextDisabled(
"Lyra preview: scratch editing unavailable");
211 return absl::OkStatus();
214 TextWrapped(
"Scratch workspace retained on disk: %s",
216 if (Button(tr(
"Retry loading scratch workspace")))
218 return absl::OkStatus();
221 const auto report = [
this](absl::Status status) {
226 if (IsKeyPressed(ImGuiKey_Escape)) {
235 int current_page_idx = 0;
236 for (
size_t i = 0; i < pages.size(); ++i) {
238 current_page_idx =
static_cast<int>(i);
244 BeginDisabled(current_page_idx <= 0);
252 if (IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
253 SetTooltip(
"Previous layout");
258 SetNextItemWidth(std::max(100.0f, GetContentRegionAvail().x - 220.0f));
259 if (BeginCombo(
"##ScratchLayout", page.name.c_str())) {
260 for (
const auto& p : pages) {
261 PushID(std::to_string(p.id).c_str());
262 if (Selectable(p.name.c_str(),
276 BeginDisabled(current_page_idx >=
static_cast<int>(pages.size()) - 1);
284 if (IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
285 SetTooltip(
"Next layout");
298 if (IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
299 SetTooltip(
"New layout");
305 const bool can_capture = (active_brush && active_brush->valid());
311 if (IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
312 SetTooltip(
"Capture selection from map to scratch");
322 OpenPopup(
"ScratchMoreMenu");
324 if (IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
325 SetTooltip(
"Layout options");
328 if (BeginPopup(
"ScratchMoreMenu")) {
329 if (BeginMenu(
"Rename layout")) {
337 SetNextItemWidth(140.0f);
340 ImGuiInputTextFlags_EnterReturnsTrue)) {
349 if (BeginMenu(
"Resize layout")) {
355 SetNextItemWidth(120.0f);
356 const bool enter_pressed = InputInt2(
358 ImGuiInputTextFlags_EnterReturnsTrue);
360 const bool apply_clicked = Button(
"Apply##ScratchResize");
361 if (enter_pressed || apply_clicked) {
375 if (MenuItem(
"Duplicate layout",
nullptr,
false,
383 if (MenuItem(
"Clear layout")) {
387 if (MenuItem(
"Delete layout",
nullptr,
false, pages.size() > 1)) {
396 if (MenuItem(
"Copy layout as brush",
nullptr,
false, page.in_use)) {
400 if (MenuItem(
"Refresh preview")) {
412 const float available_width = GetContentRegionAvail().x;
420 options.
canvas_size = ImVec2(page.width * 16 + 4, page.height * 16 + 4);
428 "##ScratchSpaceScrollRegion",
429 ImVec2(0, std::max(150.0f, GetContentRegionAvail().y - 28)));
435 const float scale = canvas.scale;
436 const float cell_size = 16.0f * scale;
437 const ImVec2 grid_min(origin.x + scroll.x + 2.0f, origin.y + scroll.y + 2.0f);
438 const ImVec2 grid_max(grid_min.x + page.width * cell_size,
439 grid_min.y + page.height * cell_size);
443 constexpr ImU32 kGridColor = IM_COL32(200, 200, 200, 45);
444 for (
int col = 0; col <= page.width; ++col) {
445 const float x = grid_min.x + col * cell_size;
446 canvas.draw_list->AddLine(ImVec2(x, grid_min.y), ImVec2(x, grid_max.y),
449 for (
int row = 0; row <= page.height; ++row) {
450 const float y = grid_min.y + row * cell_size;
451 canvas.draw_list->AddLine(ImVec2(grid_min.x, y), ImVec2(grid_max.x, y),
454 canvas.draw_list->AddRect(grid_min, grid_max, IM_COL32(255, 255, 255, 60));
463 canvas.draw_list->AddRectFilled(ImVec2(x0, y0), ImVec2(x1, y1),
464 IM_COL32(80, 140, 240, 50));
465 canvas.draw_list->AddRect(ImVec2(x0, y0), ImVec2(x1, y1),
466 IM_COL32(255, 255, 255, 220), 0.0f, 0, 2.0f);
471 const int x =
static_cast<int>(std::floor(cursor.x / 16.0f));
472 const int y =
static_cast<int>(std::floor(cursor.y / 16.0f));
476 IsMouseClicked(ImGuiMouseButton_Right) && x >= 0 && y >= 0 &&
477 x < page.width && y < page.height) {
485 int cur_x = std::clamp(x, 0, page.width - 1);
486 int cur_y = std::clamp(y, 0, page.height - 1);
495 const float x0 = grid_min.x + min_x * cell_size;
496 const float y0 = grid_min.y + min_y * cell_size;
497 const float x1 = grid_min.x + (max_x + 1.0f) * cell_size;
498 const float y1 = grid_min.y + (max_y + 1.0f) * cell_size;
499 canvas.draw_list->AddRectFilled(ImVec2(x0, y0), ImVec2(x1, y1),
500 IM_COL32(100, 160, 255, 70));
501 canvas.draw_list->AddRect(ImVec2(x0, y0), ImVec2(x1, y1),
502 IM_COL32(255, 255, 255, 255), 0.0f, 0, 2.0f);
509 int end_x = std::clamp(x, 0, page.width - 1);
510 int end_y = std::clamp(y, 0, page.height - 1);
512 if (start_x == end_x && start_y == end_y) {
517 int min_x = std::min(start_x, end_x);
518 int max_x = std::max(start_x, end_x);
519 int min_y = std::min(start_y, end_y);
520 int max_y = std::max(start_y, end_y);
522 brush.
width = max_x - min_x + 1;
523 brush.
height = max_y - min_y + 1;
525 for (
int row = min_y; row <= max_y; ++row) {
526 for (
int col = min_x; col <= max_x; ++col) {
527 brush.
tile_ids.push_back(page.tile_data[col][row]);
539 if (x >= 0 && y >= 0 && x < page.width && y < page.height) {
540 if (active_brush && active_brush->valid()) {
542 const float bx0 = grid_min.x + x * cell_size;
543 const float by0 = grid_min.y + y * cell_size;
544 const float bx1 = grid_min.x + (x + active_brush->width) * cell_size;
545 const float by1 = grid_min.y + (y + active_brush->height) * cell_size;
549 const float atlas_w =
551 const float atlas_h =
553 if (atlas_w > 0.0f && atlas_h > 0.0f) {
554 for (
int by = 0; by < active_brush->height; ++by) {
555 for (
int bx = 0; bx < active_brush->width; ++bx) {
556 if (x + bx < 0 || x + bx >= page.width || y + by < 0 ||
557 y + by >= page.height)
559 const int brush_idx = by * active_brush->width + bx;
561 static_cast<int>(active_brush->tile_ids.size()))
563 const int tile_id = active_brush->tile_ids[brush_idx];
564 const int tile_col = tile_id % cols;
565 const int tile_row = tile_id / cols;
566 const float uv0_x = (tile_col * 16.0f) / atlas_w;
567 const float uv0_y = (tile_row * 16.0f) / atlas_h;
568 const float uv1_x = ((tile_col + 1) * 16.0f) / atlas_w;
569 const float uv1_y = ((tile_row + 1) * 16.0f) / atlas_h;
570 const float tx0 = grid_min.x + (x + bx) * cell_size;
571 const float ty0 = grid_min.y + (y + by) * cell_size;
572 canvas.draw_list->AddImage(
575 ImVec2(tx0 + cell_size, ty0 + cell_size),
576 ImVec2(uv0_x, uv0_y), ImVec2(uv1_x, uv1_y),
577 IM_COL32(255, 255, 255, 170));
582 canvas.draw_list->AddRect(ImVec2(bx0, by0), ImVec2(bx1, by1),
583 IM_COL32(255, 220, 50, 220), 0.0f, 0, 2.0f);
585 if (IsMouseClicked(ImGuiMouseButton_Left)) {
596 const float hx0 = grid_min.x + x * cell_size;
597 const float hy0 = grid_min.y + y * cell_size;
598 canvas.draw_list->AddRect(
599 ImVec2(hx0, hy0), ImVec2(hx0 + cell_size, hy0 + cell_size),
600 IM_COL32(255, 255, 255, 180), 0.0f, 0, 1.5f);
602 if (IsMouseClicked(ImGuiMouseButton_Left)) {
607 IsMouseDown(ImGuiMouseButton_Left))
613 !IsMouseDown(ImGuiMouseButton_Right) && page.in_use) {
614 const int tile_id = page.tile_data[x][y];
615 if (ImGui::BeginTooltip()) {
616 ImGui::Text(tr(
"Tile %d (0x%03X)"), tile_id, tile_id);
617 ImGui::TextDisabled(
"Scratch: (%d, %d)", x, y);
620 ImGui::Text(tr(
"Placed %d times (%s)"), usage,
625 const int tile_col = tile_id % cols;
626 const int tile_row = tile_id / cols;
627 const float atlas_w =
629 const float atlas_h =
631 if (atlas_w > 0 && atlas_h > 0) {
632 const float uv0_x = (tile_col * 16.0f) / atlas_w;
633 const float uv0_y = (tile_row * 16.0f) / atlas_h;
634 const float uv1_x = ((tile_col + 1) * 16.0f) / atlas_w;
635 const float uv1_y = ((tile_row + 1) * 16.0f) / atlas_h;
638 ImVec2(64.0f, 64.0f), ImVec2(uv0_x, uv0_y),
639 ImVec2(uv1_x, uv1_y));
650 if (!IsMouseDown(ImGuiMouseButton_Left)) {
656 TextWrapped(
"Scratch action: %s",
659 TextWrapped(
"Unsaved scratch layouts: %s",
661 if (Button(tr(
"Retry scratch save")))
664 return absl::OkStatus();