29#include <imgui/imgui.h>
30#include <imgui/imgui_internal.h>
38auto get_debug_mode_size() ->
float
47 const char* debug_mode_preview = modes[int(!debug_mode)];
48 ImGui::SetNextItemWidth(get_debug_mode_size());
52 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f));
54 if(ImGui::BeginCombo(
"###DebugMode", debug_mode_preview))
56 if(ImGui::Selectable(modes[0]))
64 ImGui::SetItemTooltipEx(
"%s",
65 "Debug mode enales C# debugging\n"
66 "but reduces C# performance.\n"
67 "Switching to Debug mode will recompile\n"
68 "and reload all scripts.");
70 if(ImGui::Selectable(modes[1]))
78 ImGui::SetItemTooltipEx(
"%s",
79 "Release mode disables C# debugging\n"
80 "but improves C# performance.\n"
81 "Switching to Release mode will recompile\n"
82 "and reload all scripts.");
87 const char* debug_mode_tooltip = debug_mode ?
"Debugger Enabled" :
"Debugger Disabled";
89 ImGui::SetItemTooltipEx(
"%s", debug_mode_tooltip);
92 ImGui::SetItemTooltipEx(
"%s",
"Debugger Attached");
93 ImGui::PopStyleColor();
104 ImGuiWindowFlags header_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar |
105 ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar |
106 ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_MenuBar;
107 ImGui::BeginChild(
"HEADER_menubar", ImVec2(0, ImGui::GetFrameHeight()),
false, header_flags);
110 if(ImGui::BeginMenuBar())
112 if(ImGui::BeginMenu(
"File"))
134 if(ImGui::MenuItem(
"Reload Project",
nullptr))
139 if(ImGui::MenuItem(
"Close Project",
nullptr))
146 if(ImGui::BeginMenu(
"Edit"))
149 auto undo = em.can_undo() ?
"Undo*" :
"Undo";
150 auto redo = em.can_redo() ?
"Redo*" :
"Redo";
151 if(ImGui::MenuItem(undo, ImGui::GetKeyCombinationName(
shortcuts::undo).c_str()))
156 if(ImGui::MenuItem(redo, ImGui::GetKeyCombinationName(
shortcuts::redo).c_str()))
166 if(ImGui::MenuItem(
"Editor Settings..."))
171 if(ImGui::MenuItem(
"Project Settings..."))
179 if(ImGui::BeginMenu(
"Deploy"))
181 if(ImGui::MenuItem(
"Deploy Project"))
189 if(ImGui::BeginMenu(
"Build"))
196 "Rebuilding %zu reflection probe(s)",
199 ImGui::SetItemTooltip(
200 "Force all reflection probes in loaded scenes to rebuild their cubemaps.\n"
201 "Use after editing environment or static geometry.");
206 if(ImGui::MenuItem(
"Auto Rebuild Reflection Probes",
nullptr, em.auto_rebuild_reflection_probes))
208 em.auto_rebuild_reflection_probes = !em.auto_rebuild_reflection_probes;
210 ImGui::SetItemTooltip(
211 "When enabled, reflection probes are automatically refreshed whenever the scene is\n"
212 "modified (moving objects, editing materials, etc). Disable for large scenes where the\n"
213 "background bakes become noticeable; use the Build menu to rebuild manually instead.");
218 if(ImGui::BeginMenu(
"Developer"))
221 if(ImGui::MenuItem(
"Regenerate Agent Files",
nullptr,
false, pm.has_open_project()))
223 if(pm.regenerate_agent_files())
227 "Regenerated AGENTS.md and CLAUDE.md in the project root."));
233 "Failed to regenerate agent files. Check the log."));
236 ImGui::SetItemTooltip(
237 "Overwrite AGENTS.md and CLAUDE.md in the open project with the editor templates.\n"
238 "Use after updating engine agent guidance, or to restore deleted files.");
240 if(ImGui::BeginMenu(
"Assets"))
242 if(ImGui::BeginMenu(
"Regenerate"))
244 if(ImGui::MenuItem(
"Meta(Engine)"))
247 am.recreate_meta_files(ctx,
"engine:/");
249 if(ImGui::MenuItem(
"Meta(Editor)"))
252 am.recreate_meta_files(ctx,
"editor:/");
257 if(ImGui::BeginMenu(
"Recompile"))
259 if(ImGui::BeginMenu(
"Shaders"))
261 if(ImGui::MenuItem(
"Shaders (Engine)"))
266 if(ImGui::MenuItem(
"Shaders (Editor)"))
271 if(ImGui::MenuItem(
"Shaders (Project)"))
277 if(ImGui::BeginMenu(
"Textures"))
279 if(ImGui::MenuItem(
"Textures (Engine)"))
284 if(ImGui::MenuItem(
"Textures (Editor)"))
289 if(ImGui::MenuItem(
"Textures (Project)"))
297 if(ImGui::BeginMenu(
"Meshes"))
299 if(ImGui::MenuItem(
"Meshes (Engine)"))
303 if(ImGui::MenuItem(
"Meshes (Editor)"))
307 if(ImGui::MenuItem(
"Meshes (Project)"))
320 if(ImGui::BeginMenu(
"Scripts"))
322 if(ImGui::MenuItem(
"Scripts (Engine)"))
327 if(ImGui::MenuItem(
"Scripts (Editor)"))
332 if(ImGui::MenuItem(
"Scripts (Project)"))
339 if(ImGui::BeginMenu(
"All"))
341 if(ImGui::MenuItem(
"All (Engine)"))
345 if(ImGui::MenuItem(
"All (Editor)"))
350 if(ImGui::MenuItem(
"All (Project)"))
364 if(ImGui::BeginMenu(
"Crash"))
366 if(ImGui::MenuItem(
"Abort"))
370 if(ImGui::MenuItem(
"Terminate"))
374 if(ImGui::MenuItem(
"Segmentation Fault"))
376 *(
volatile int*)0 = 0;
383 if(ImGui::BeginMenu(
"Windows"))
385 if(ImGui::MenuItem(
"Style"))
389 if(ImGui::MenuItem(
"Layouts"))
393 if(ImGui::MenuItem(
"Animation"))
397 if(ImGui::MenuItem(
"MCP Server"))
401 if(ImGui::MenuItem(
"Profiler"))
409 if(ImGui::BeginMenu(
"Help"))
411 if(ImGui::MenuItem(
"Check for Updates..."))
414 vm.check_for_update_async();
417 if(ImGui::MenuItem(
"About"))
419 show_about_window_ =
true;
428 if(!ImGui::IsAnyItemActive())
457 bool any_popup_open = ImGui::IsPopupOpen((ImGuiID)0, ImGuiPopupFlags_AnyPopupId);
465 bool any_popup_open = ImGui::IsPopupOpen((ImGuiID)0, ImGuiPopupFlags_AnyPopupId);
480 const ImVec2& window_pos,
481 const ImVec2& window_size,
483 const ImVec2& item_spacing)
487 auto logo = fmt::format(
"{}", pm.get_name());
488 auto logo_size = ImGui::CalcTextSize(logo.c_str());
489 const float badge_h_pad = 30.0f;
490 const float badge_taper = 12.0f;
491 const float badge_width = logo_size.x + badge_h_pad * 2;
492 const float badge_height = header_size * 0.5f - item_spacing.y;
493 const ImVec2 badge_pos(window_pos.x + window_size.x * 0.5f - badge_width * 0.5f, window_pos.y);
494 std::array<ImVec2, 5> points = {
495 ImVec2(badge_pos.x, badge_pos.y),
496 ImVec2(badge_pos.x + badge_taper, badge_pos.y + badge_height),
497 ImVec2(badge_pos.x + badge_width - badge_taper, badge_pos.y + badge_height),
498 ImVec2(badge_pos.x + badge_width, badge_pos.y),
499 ImVec2(badge_pos.x, badge_pos.y)};
500 ImU32 badge_color = ImGui::GetColorU32(ImGuiCol_MenuBarBg);
503 badge_color = ImGui::GetColorU32(ImVec4(0.0f, 0.5f, 0.0f, 0.5f));
507 badge_color = ImGui::GetColorU32(ImVec4(0.6f, 0.3f, 0.0f, 0.5f));
509 ImGui::GetWindowDrawList()->AddConvexPolyFilled(points.data(), 5, badge_color);
510 const ImVec2 text_pos(badge_pos.x + badge_width * 0.5f - logo_size.x * 0.5f,
511 badge_pos.y + (badge_height - logo_size.y) * 0.5f);
512 ImGui::GetWindowDrawList()->AddText(text_pos, ImGui::GetColorU32(ImGuiCol_Text), logo.c_str());
519 ImGui::BeginDisabled(is_deploying);
521 ImGui::SetItemTooltipEx(
"%s",
"Deploy and Run. For more control visit Deploy/Deploy Project menu.");
522 ImGui::EndDisabled();
525 auto deploy_settings = pm.get_deploy_settings();
526 deploy_settings.deploy_and_run =
true;
527 deploy_settings.deploy_dependencies =
true;
533auto header_panel::calc_right_zone_width(
const ImVec2& frame_padding,
const ImVec2& item_spacing) ->
float
536 float slider = 100.0f;
538 float vsync_box = ImGui::CalcTextSize(
"Vsync").x + frame_padding.x * 2 + ImGui::GetFrameHeight() + item_spacing.x;
539 float max_fps_slider = 100.0f + item_spacing.x;
540 float separator = item_spacing.x * 2 + 2.0f;
541 return speed_icon + item_spacing.x + slider + item_spacing.x + reset_btn +
542 separator + vsync_box + max_fps_slider + item_spacing.x;
545auto header_panel::calc_center_zone_width(
const ImVec2& frame_padding,
const ImVec2& item_spacing) ->
float
548 frame_padding.x * 6 + item_spacing.x * 2;
549 float splash_checkbox = ImGui::CalcTextSize(
"Splash").x + frame_padding.x * 2 + ImGui::GetFrameHeight();
550 float separator = item_spacing.x * 2 + 2.0f;
551 float debug_mode = get_debug_mode_size();
552 return play_btns + splash_checkbox + item_spacing.x +
separator + debug_mode + item_spacing.x;
559 bool play_pressed = ImGui::IsKeyChordPressed(key_chord);
561 ImGui::BeginDisabled(has_errors);
565 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.18f, 0.47f, 0.18f, 1.0f));
566 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.25f, 0.58f, 0.25f, 1.0f));
567 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.12f, 0.35f, 0.12f, 1.0f));
572 ImGui::PopStyleColor(3);
574 if(has_errors && !play.is_active())
576 play_pressed =
false;
578 ImGui::SetItemTooltipEx(
"%s", ImGui::GetKeyChordName(key_chord));
587 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.60f, 0.38f, 0.08f, 1.0f));
588 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.72f, 0.48f, 0.14f, 1.0f));
589 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.48f, 0.28f, 0.04f, 1.0f));
597 ImGui::PopStyleColor(3);
600 ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat,
true);
605 ImGui::PopItemFlag();
607 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
609 ImGui::BeginDisabled(play.is_active());
611 ImGui::EndDisabled();
613 ImGui::EndDisabled();
616 ImGui::SetItemTooltipEx(
"%s",
"All compiler errors must be fixed before you can enter Play Mode!");
619 ImGui::BeginDisabled(play.is_active());
620 ImGui::Checkbox(
"Splash", &play_splash_in_editor_);
621 ImGui::SetItemTooltipEx(
"%s",
"Allow splash on play; still requires splash enabled in project settings");
622 ImGui::EndDisabled();
629 auto time_scale =
sim.get_time_scale();
631 ImGui::SetItemTooltipEx(
"%s",
"Time scale");
633 ImGui::SetNextItemWidth(100.0f);
634 if(ImGui::KnobSliderScalarT(
"###Time Scale", &time_scale, 0.0f, 3.0f))
636 sim.set_time_scale(time_scale);
638 ImGui::SetItemTooltipEx(
"%s",
"Time scale");
642 sim.set_time_scale(1.0f);
644 ImGui::SetItemTooltipEx(
"Reset time scale to 1.0");
646 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
649 auto vsync = rend.get_vsync();
650 if(ImGui::Checkbox(
"Vsync", &vsync))
652 rend.set_vsync(vsync);
655 int max_fps =
static_cast<int>(
sim.get_max_fps());
656 ImGui::SetNextItemWidth(100.0f);
657 const char* max_fps_fmt = (max_fps <= 0) ?
"Uncapped" :
"%d FPS";
658 if(ImGui::KnobSliderScalarT(
"###Max FPS", &max_fps, 0, 240, max_fps_fmt, ImGuiSliderFlags_AlwaysClamp))
660 sim.set_max_fps(
static_cast<uint32_t
>(max_fps < 0 ? 0 : max_fps));
662 ImGui::SetItemTooltipEx(
"%s",
"Max FPS (0 = uncapped)");
666void header_panel::draw_play_toolbar(
rtti::context& ctx,
float header_size)
668 auto window_pos = ImGui::GetWindowPos();
669 auto window_size = ImGui::GetWindowSize();
670 const auto& style = ImGui::GetStyle();
671 auto frame_padding = style.FramePadding;
672 auto item_spacing = style.ItemSpacing;
673 draw_project_badge(ctx, window_pos, window_size, header_size, item_spacing);
675 float avail = ImGui::GetContentRegionAvail().x;
676 float right_zone_width = calc_right_zone_width(frame_padding, item_spacing);
677 float center_zone_width = calc_center_zone_width(frame_padding, item_spacing);
678 ImGui::AlignedItem(0.5f, avail, center_zone_width,
679 [&]() ->
void { draw_center_zone(ctx); });
681 ImGui::AlignedItem(1.0f, ImGui::GetContentRegionAvail().
x, right_zone_width,
682 [&]() ->
void { draw_right_zone(ctx); });
687 ImGuiWindowFlags header_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBringToFrontOnFocus |
688 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
689 ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoDecoration;
690 ImGuiViewport* viewport = ImGui::GetMainViewport();
692 ImGui::SetNextWindowPos(ImVec2(viewport->WorkPos.x, viewport->WorkPos.y));
693 ImGui::SetNextWindowSize(ImVec2(viewport->WorkSize.x, header_size));
694 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
695 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
697 ImGui::SetNextWindowViewport(viewport->ID);
699 bool open = ImGui::Begin(
"HEADER",
nullptr, header_flags);
701 ImGui::PopStyleVar();
702 ImGui::PopStyleVar();
709 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_MenuBarBg));
710 draw_menubar_child(ctx);
712 draw_play_toolbar(ctx, header_size);
713 ImGui::PopStyleColor();
719 draw_about_window(ctx);
725 if(!show_about_window_)
728 if(!ImGui::IsPopupOpen(
"About Unravel Engine"))
730 ImGui::OpenPopup(
"About Unravel Engine");
733 auto viewport = ImGui::GetMainViewport();
734 ImGui::SetNextWindowSize(ImVec2(viewport->WorkSize * 0.30f), ImGuiCond_Always);
735 ImGui::SetNextWindowPos(ImVec2(viewport->WorkSize.x * 0.5f, viewport->WorkSize.y * 0.5f),
738 if(ImGui::BeginPopupModal(
"About Unravel Engine",
740 ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove))
743 const float title_scale = 1.5f;
746 ImGui::TextColored(ImVec4(0.4f, 0.6f, 1.0f, 1.0f),
"Unravel Engine");
754 ImGui::TextWrapped(
"Unravel Engine is a modern, high-performance game engine designed for creating "
755 "interactive 3D and 2D applications. It features a component-based architecture, "
756 "powerful rendering capabilities, and an intuitive editor interface.");
762 const float section_scale = 1.2f;
764 ImGui::Text(
"Key Features");
768 ImGui::BulletText(
"Entity-Component-System");
769 ImGui::BulletText(
"PBR Rendering");
770 ImGui::BulletText(
"C# Scripting");
771 ImGui::BulletText(
"Physics Integration");
773 ImGui::BulletText(
"Real-time Editor");
774 ImGui::BulletText(
"Asset Management");
775 ImGui::BulletText(
"Cross-platform Support");
776 ImGui::BulletText(
"Extensible Architecture");
784 ImGui::Text(
"Build Information");
787 ImGui::Text(
"Build Date: %s", __DATE__);
788 ImGui::Text(
"Build Time: %s", __TIME__);
790 ImGui::Text(
"Configuration: Debug");
792 ImGui::Text(
"Configuration: Release");
800 ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f),
"Copyright © %d. All rights reserved.", 2025);
auto get_profiler_timeline_panel() -> profiler_timeline_panel &
auto get_project_settings_panel() -> project_settings_panel &
auto get_deploy_panel() -> deploy_panel &
auto get_editor_settings_panel() -> editor_settings_panel &
auto get_layout_panel() -> layout_panel &
auto get_style_panel() -> style_panel &
auto get_animation_panel() -> animation_panel &
auto get_mcp_panel() -> mcp_panel &
auto get_undo_redo_panel() -> undo_redo_panel &
#define ICON_MDI_UNDO_VARIANT
#define ICON_MDI_BUG_CHECK
#define ICON_MDI_REFLECT_HORIZONTAL
#define ICON_MDI_SKIP_NEXT
#define ICON_MDI_PLAY_SPEED
std::vector< size_t > parent_
void PushFont(Font::Enum _font)
NOTIFY_INLINE void PushNotification(const ImGuiToast &toast)
Insert a new toast in the list.
ImFont * GetFont(Font::Enum _font)
const ImGuiKeyCombination undo_history
constexpr ImGuiKey play_toggle
const ImGuiKeyCombination new_scene
const ImGuiKeyCombination undo
const ImGuiKeyCombination redo
const ImGuiKeyCombination recompile_ui
const ImGuiKeyCombination redo_alt
const ImGuiKeyCombination save_scene_as
const ImGuiKeyCombination open_scene
const ImGuiKeyCombination save_scene
auto get_full() -> std::string
static auto close_project(rtti::context &ctx) -> bool
static auto can_enter_play(rtti::context &ctx, std::string *error=nullptr) -> bool
static auto skip_play_frame(rtti::context &ctx, std::string *error=nullptr) -> bool
static void recompile_shaders(const std::string &group="")
static void recompile_scripts(const std::string &group="")
static void recompile_ui(const std::string &group="")
static auto open_scene(rtti::context &ctx) -> bool
static void recompile_textures(const std::string &group="")
static void recompile_all(const std::string &group="")
static auto save_scene(rtti::context &ctx) -> bool
static auto new_scene(rtti::context &ctx) -> bool
static auto set_play_paused(rtti::context &ctx, bool paused, std::string *error=nullptr) -> bool
static auto reload_project(rtti::context &ctx) -> bool
static auto save_scene_as(rtti::context &ctx) -> bool
static auto rebuild_reflection_probes(rtti::context &ctx, bool force_full_first_frame=true) -> size_t
Flags every reflection probe across all loaded scenes for rebuild.
static auto toggle_play(rtti::context &ctx, bool allow_splash=true, std::string *error=nullptr) -> bool
static void recompile_meshes(const std::string &group="")
static auto is_debugger_attached() -> bool
static auto get_script_debug_mode() -> bool
static void set_script_debug_mode(bool debug)
static void set_needs_recompile(const std::string &protocol, bool now=false)