#include "app.hpp" #include "floormat/main.hpp" #include "compat/format.hpp" #include "src/world.hpp" #include "src/anim-atlas.hpp" #include "main/clickable.hpp" #include "imgui-raii.hpp" namespace floormat { using namespace floormat::imgui; bool popup_target::operator==(const popup_target&) const = default; void app::init_imgui(Vector2i size) { if (!_imgui.context()) _imgui = ImGuiIntegration::Context(Vector2{size}, size, size); else _imgui.relayout(Vector2{size}, size, size); } void app::render_menu() { _imgui.drawFrame(); } float app::draw_main_menu() { float main_menu_height = 0; if (auto b = begin_main_menu()) { ImGui::SetWindowFontScale(M->dpi_scale().min()); if (auto b = begin_menu("File")) { bool do_new = false, do_quickload = false, do_quit = false; ImGui::MenuItem("New", nullptr, &do_new); ImGui::Separator(); ImGui::MenuItem("Load quicksave", nullptr, &do_quickload); ImGui::Separator(); ImGui::MenuItem("Quit", "Ctrl+Q", &do_quit); if (do_new) do_key(key_new_file, kmod_none); else if (do_quickload) do_key(key_quickload, kmod_none); else if (do_quit) do_key(key_quit, kmod_none); } if (auto b = begin_menu("Editor")) { auto mode = _editor.mode(); using m = editor_mode; bool b_none = mode == m::none, b_floor = mode == m::floor, b_walls = mode == m::walls, b_scenery = mode == m::scenery, b_collisions = _render_bboxes, b_clickables = _render_clickables; ImGui::SeparatorText("Mode"); if (ImGui::MenuItem("Select", "1", &b_none)) do_key(key_mode_none); if (ImGui::MenuItem("Floor", "2", &b_floor)) do_key(key_mode_floor); if (ImGui::MenuItem("Walls", "3", &b_walls)) do_key(key_mode_walls); if (ImGui::MenuItem("Scenery", "4", &b_scenery)) do_key(key_mode_scenery); ImGui::SeparatorText("View"); if (ImGui::MenuItem("Show collisions", "Alt+C", &b_collisions)) do_key(key_render_collision_boxes); if (ImGui::MenuItem("Show clickables", "Alt+L", &b_clickables)) do_key(key_render_clickables); } main_menu_height = ImGui::GetContentRegionMax().y; } return main_menu_height; } void app::draw_ui() { const auto dpi = M->dpi_scale().min(); [[maybe_unused]] const auto style_ = style_saver{}; auto& style = ImGui::GetStyle(); auto& ctx = *ImGui::GetCurrentContext(); ImGui::StyleColorsDark(&style); style.ScaleAllSizes(dpi); ImGui::GetIO().IniFilename = nullptr; _imgui.newFrame(); if (_render_clickables) draw_clickables(); const float main_menu_height = draw_main_menu(); [[maybe_unused]] auto font = font_saver{ctx.FontSize*dpi}; if (_editor.current_tile_editor() || _editor.current_scenery_editor()) draw_editor_pane(main_menu_height); draw_fps(); draw_tile_under_cursor(); if (_editor.mode() == editor_mode::none) draw_inspector(); if (_popup_target.target != popup_target_type::none) do_popup_menu(); ImGui::EndFrame(); } void app::draw_clickables() { ImDrawList& draw = *ImGui::GetForegroundDrawList(); const auto color = ImGui::ColorConvertFloat4ToU32({0, .8f, .8f, .95f}); for (const auto& x : M->clickable_scenery()) { auto dest = Math::Range2D(x.dest); auto min = dest.min(), max = dest.max(); draw.AddRect({ min.x(), min.y() }, { max.x(), max.y() }, color, 0, ImDrawFlags_None, 2.5f); } } const StringView app::SCENERY_POPUP_NAME = "##scenery-popup"_s; void app::do_open_popup() { fm_assert(_popup_target.target != popup_target_type::none); _pending_popup = true; } bool app::check_inspector_exists(popup_target p) { if (p.target == popup_target_type::none) [[unlikely]] return true; for (const auto& p2 : inspectors) if (p2 == p) return true; return false; } void app::do_popup_menu() { fm_assert(_popup_target.target != popup_target_type::none); auto b0 = push_id(SCENERY_POPUP_NAME); const auto [sc, target] = _popup_target; //if (_popup_target.target != popup_target_type::scenery) {...} if (_pending_popup) { _pending_popup = false; fm_assert(target != popup_target_type::none); //if (type != popup_target_type::scenery) {...} if (sc) ImGui::OpenPopup(SCENERY_POPUP_NAME.data()); } if (auto b1 = begin_popup(SCENERY_POPUP_NAME)) { auto iter = sc->iter(); auto& c = sc->chunk(); if (ImGui::MenuItem("Activate", nullptr, false, sc->can_activate(iter, c))) sc->activate(iter, c); if (auto next_rot = sc->atlas->next_rotation_from(sc->r); ImGui::MenuItem("Rotate", nullptr, false, next_rot != sc->r)) sc->rotate(iter, c, next_rot); ImGui::Separator(); if (bool b_ins = sc && !check_inspector_exists(_popup_target); ImGui::MenuItem("Inspect", nullptr, false, b_ins)) inspectors.push_back(std::exchange(_popup_target, {})); } } void app::kill_popups(bool hard) { _popup_target = {}; ImGui::CloseCurrentPopup(); if (hard) { inspectors.clear(); } ImGui::FocusWindow(nullptr); } } // namespace floormat