Unravel Engine C++ Reference
Loading...
Searching...
No Matches
header_panel.cpp
Go to the documentation of this file.
1#include "header_panel.h"
2#include "../panel.h"
3#include "../panels_defs.h"
5
8#include <editor/shortcuts.h>
12
15#include <engine/ecs/ecs.h>
16#include <engine/events.h>
17#include <engine/play_mode.h>
22#include <array>
23#include <exception>
25#include <version/version.h>
26
29#include <imgui/imgui.h>
30#include <imgui/imgui_internal.h>
31
32
33namespace unravel
34{
35
36namespace
37{
38auto get_debug_mode_size() -> float
39{
40 return 120.0f;
41}
42void draw_debug_mode()
43{
44 bool debugger_attached = script_system::is_debugger_attached();
45 bool debug_mode = script_system::get_script_debug_mode();
46 const char* modes[] = {ICON_MDI_BUG_CHECK " Debug", ICON_MDI_BUG " Release"};
47 const char* debug_mode_preview = modes[int(!debug_mode)];
48 ImGui::SetNextItemWidth(get_debug_mode_size());
49
50 if(debugger_attached)
51 {
52 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f));
53 }
54 if(ImGui::BeginCombo("###DebugMode", debug_mode_preview))
55 {
56 if(ImGui::Selectable(modes[0]))
57 {
58 if(!debug_mode)
59 {
62 }
63 }
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.");
69
70 if(ImGui::Selectable(modes[1]))
71 {
72 if(debug_mode)
73 {
76 }
77 }
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.");
83
84 ImGui::EndCombo();
85 }
86
87 const char* debug_mode_tooltip = debug_mode ? "Debugger Enabled" : "Debugger Disabled";
88
89 ImGui::SetItemTooltipEx("%s", debug_mode_tooltip);
90 if(debugger_attached)
91 {
92 ImGui::SetItemTooltipEx("%s", "Debugger Attached");
93 ImGui::PopStyleColor();
94 }
95}
96} // namespace
97
101
102void header_panel::draw_menubar_child(rtti::context& ctx)
103{
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);
108
109 // Draw menu bar.
110 if(ImGui::BeginMenuBar())
111 {
112 if(ImGui::BeginMenu("File"))
113 {
114 if(ImGui::MenuItem("New Scene", ImGui::GetKeyCombinationName(shortcuts::new_scene).c_str()))
115 {
117 }
118
119 if(ImGui::MenuItem("Open Scene", ImGui::GetKeyCombinationName(shortcuts::open_scene).c_str()))
120 {
122 }
123
124 if(ImGui::MenuItem("Save Scene...", ImGui::GetKeyCombinationName(shortcuts::save_scene).c_str()))
125 {
127 }
128
129 if(ImGui::MenuItem("Save Scene As", ImGui::GetKeyCombinationName(shortcuts::save_scene_as).c_str()))
130 {
132 }
133
134 if(ImGui::MenuItem("Reload Project", nullptr))
135 {
137 }
138
139 if(ImGui::MenuItem("Close Project", nullptr))
140 {
142 }
143 ImGui::EndMenu();
144 }
145
146 if(ImGui::BeginMenu("Edit"))
147 {
148 auto& em = ctx.get_cached<editing_manager>();
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()))
152 {
153 em.undo();
154 }
155
156 if(ImGui::MenuItem(redo, ImGui::GetKeyCombinationName(shortcuts::redo).c_str()))
157 {
158 em.redo();
159 }
160
161 if(ImGui::MenuItem("Undo History", ImGui::GetKeyCombinationName(shortcuts::undo_history).c_str()))
162 {
163 parent_->get_undo_redo_panel().show(true);
164 }
165
166 if(ImGui::MenuItem("Editor Settings..."))
167 {
168 parent_->get_editor_settings_panel().show(true);
169 }
170
171 if(ImGui::MenuItem("Project Settings..."))
172 {
173 parent_->get_project_settings_panel().show(true, "{}");
174 }
175
176 ImGui::EndMenu();
177 }
178
179 if(ImGui::BeginMenu("Deploy"))
180 {
181 if(ImGui::MenuItem("Deploy Project"))
182 {
183 parent_->get_deploy_panel().show(true);
184 }
185
186 ImGui::EndMenu();
187 }
188
189 if(ImGui::BeginMenu("Build"))
190 {
191 if(ImGui::MenuItem(ICON_MDI_REFLECT_HORIZONTAL " Build Reflection Captures"))
192 {
193 const auto count = editor_actions::rebuild_reflection_probes(ctx, true);
195 2000,
196 "Rebuilding %zu reflection probe(s)",
197 count));
198 }
199 ImGui::SetItemTooltip(
200 "Force all reflection probes in loaded scenes to rebuild their cubemaps.\n"
201 "Use after editing environment or static geometry.");
202
203 ImGui::Separator();
204
205 auto& em = ctx.get_cached<editing_manager>();
206 if(ImGui::MenuItem("Auto Rebuild Reflection Probes", nullptr, em.auto_rebuild_reflection_probes))
207 {
208 em.auto_rebuild_reflection_probes = !em.auto_rebuild_reflection_probes;
209 }
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.");
214
215 ImGui::EndMenu();
216 }
217
218 if(ImGui::BeginMenu("Developer"))
219 {
220 auto& pm = ctx.get_cached<project_manager>();
221 if(ImGui::MenuItem("Regenerate Agent Files", nullptr, false, pm.has_open_project()))
222 {
223 if(pm.regenerate_agent_files())
224 {
226 3000,
227 "Regenerated AGENTS.md and CLAUDE.md in the project root."));
228 }
229 else
230 {
232 4000,
233 "Failed to regenerate agent files. Check the log."));
234 }
235 }
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.");
239
240 if(ImGui::BeginMenu("Assets"))
241 {
242 if(ImGui::BeginMenu("Regenerate"))
243 {
244 if(ImGui::MenuItem("Meta(Engine)"))
245 {
246 auto& am = ctx.get_cached<asset_watcher>();
247 am.recreate_meta_files(ctx, "engine:/");
248 }
249 if(ImGui::MenuItem("Meta(Editor)"))
250 {
251 auto& am = ctx.get_cached<asset_watcher>();
252 am.recreate_meta_files(ctx, "editor:/");
253 }
254 ImGui::EndMenu();
255 }
256
257 if(ImGui::BeginMenu("Recompile"))
258 {
259 if(ImGui::BeginMenu("Shaders"))
260 {
261 if(ImGui::MenuItem("Shaders (Engine)"))
262 {
264 }
265
266 if(ImGui::MenuItem("Shaders (Editor)"))
267 {
269 }
270
271 if(ImGui::MenuItem("Shaders (Project)"))
272 {
274 }
275 ImGui::EndMenu();
276 }
277 if(ImGui::BeginMenu("Textures"))
278 {
279 if(ImGui::MenuItem("Textures (Engine)"))
280 {
282 }
283
284 if(ImGui::MenuItem("Textures (Editor)"))
285 {
287 }
288
289 if(ImGui::MenuItem("Textures (Project)"))
290 {
292 }
293
294 ImGui::EndMenu();
295 }
296
297 if(ImGui::BeginMenu("Meshes"))
298 {
299 if(ImGui::MenuItem("Meshes (Engine)"))
300 {
302 }
303 if(ImGui::MenuItem("Meshes (Editor)"))
304 {
306 }
307 if(ImGui::MenuItem("Meshes (Project)"))
308 {
310 }
311 ImGui::EndMenu();
312 }
313
314 if(ImGui::MenuItem("UI", ImGui::GetKeyCombinationName(shortcuts::recompile_ui).c_str()))
315 {
317 }
318
319
320 if(ImGui::BeginMenu("Scripts"))
321 {
322 if(ImGui::MenuItem("Scripts (Engine)"))
323 {
325 }
326
327 if(ImGui::MenuItem("Scripts (Editor)"))
328 {
330 }
331
332 if(ImGui::MenuItem("Scripts (Project)"))
333 {
335 }
336 ImGui::EndMenu();
337 }
338
339 if(ImGui::BeginMenu("All"))
340 {
341 if(ImGui::MenuItem("All (Engine)"))
342 {
344 }
345 if(ImGui::MenuItem("All (Editor)"))
346 {
348 }
349
350 if(ImGui::MenuItem("All (Project)"))
351 {
353 }
354 ImGui::EndMenu();
355 }
356
357 ImGui::EndMenu();
358 }
359 ImGui::EndMenu();
360 }
361
362
363
364 if(ImGui::BeginMenu("Crash"))
365 {
366 if(ImGui::MenuItem("Abort"))
367 {
368 std::abort();
369 }
370 if(ImGui::MenuItem("Terminate"))
371 {
372 std::terminate();
373 }
374 if(ImGui::MenuItem("Segmentation Fault"))
375 {
376 *(volatile int*)0 = 0;
377 }
378 ImGui::EndMenu();
379 }
380
381 ImGui::EndMenu();
382 }
383 if(ImGui::BeginMenu("Windows"))
384 {
385 if(ImGui::MenuItem("Style"))
386 {
387 parent_->get_style_panel().show(true);
388 }
389 if(ImGui::MenuItem("Layouts"))
390 {
391 parent_->get_layout_panel().focus();
392 }
393 if(ImGui::MenuItem("Animation"))
394 {
395 parent_->get_animation_panel().show(true);
396 }
397 if(ImGui::MenuItem("MCP Server"))
398 {
399 parent_->get_mcp_panel().show(true);
400 }
401 if(ImGui::MenuItem("Profiler"))
402 {
403 parent_->get_profiler_timeline_panel().show(true);
404 }
405
406 ImGui::EndMenu();
407 }
408
409 if(ImGui::BeginMenu("Help"))
410 {
411 if(ImGui::MenuItem("Check for Updates..."))
412 {
413 auto& vm = ctx.get_cached<version_manager>();
414 vm.check_for_update_async();
415 }
416 ImGui::Separator();
417 if(ImGui::MenuItem("About"))
418 {
419 show_about_window_ = true;
420 }
421
422 ImGui::EndMenu();
423 }
424
425 ImGui::EndMenuBar();
426 }
427
428 if(!ImGui::IsAnyItemActive())
429 {
430 if(ImGui::IsCombinationKeyPressed(shortcuts::new_scene))
431 {
433 }
434 else if(ImGui::IsCombinationKeyPressed(shortcuts::open_scene))
435 {
437 }
438 else if(ImGui::IsCombinationKeyPressed(shortcuts::save_scene_as))
439 {
441 }
442 else if(ImGui::IsCombinationKeyPressed(shortcuts::save_scene))
443 {
445 }
446
447 else if(ImGui::IsCombinationKeyPressed(shortcuts::redo, true))
448 {
449 ctx.get_cached<editing_manager>().redo();
450 }
451 else if(ImGui::IsCombinationKeyPressed(shortcuts::redo_alt, true))
452 {
453 ctx.get_cached<editing_manager>().redo();
454 }
455 else if(ImGui::IsCombinationKeyPressed(shortcuts::undo, true))
456 {
457 bool any_popup_open = ImGui::IsPopupOpen((ImGuiID)0, ImGuiPopupFlags_AnyPopupId);
458 if(!any_popup_open)
459 {
460 ctx.get_cached<editing_manager>().undo();
461 }
462 }
463 else if(ImGui::IsCombinationKeyPressed(shortcuts::undo_history))
464 {
465 bool any_popup_open = ImGui::IsPopupOpen((ImGuiID)0, ImGuiPopupFlags_AnyPopupId);
466 if(!any_popup_open)
467 {
468 parent_->get_undo_redo_panel().show(true);
469 }
470 }
471 else if(ImGui::IsCombinationKeyPressed(shortcuts::recompile_ui))
472 {
474 }
475 }
476 ImGui::EndChild();
477}
478
479void header_panel::draw_project_badge(rtti::context& ctx,
480 const ImVec2& window_pos,
481 const ImVec2& window_size,
482 float header_size,
483 const ImVec2& item_spacing)
484{
485 auto& pm = ctx.get_cached<project_manager>();
486 auto& play = ctx.get_cached<play_mode>();
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);
501 if(play.is_active())
502 {
503 badge_color = ImGui::GetColorU32(ImVec4(0.0f, 0.5f, 0.0f, 0.5f));
504 }
505 if(play.is_paused())
506 {
507 badge_color = ImGui::GetColorU32(ImVec4(0.6f, 0.3f, 0.0f, 0.5f));
508 }
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());
513}
514
515void header_panel::draw_left_zone(rtti::context& ctx)
516{
517 auto& pm = ctx.get_cached<project_manager>();
518 bool is_deploying = parent_->get_deploy_panel().is_deploying();
519 ImGui::BeginDisabled(is_deploying);
520 bool deploy_pressed = ImGui::Button(ICON_MDI_PACKAGE);
521 ImGui::SetItemTooltipEx("%s", "Deploy and Run. For more control visit Deploy/Deploy Project menu.");
522 ImGui::EndDisabled();
523 if(deploy_pressed)
524 {
525 auto deploy_settings = pm.get_deploy_settings();
526 deploy_settings.deploy_and_run = true;
527 deploy_settings.deploy_dependencies = true;
528 parent_->get_deploy_panel().deploy_and_run(ctx, deploy_settings);
529 }
530 ImGui::SameLine();
531}
532
533auto header_panel::calc_right_zone_width(const ImVec2& frame_padding, const ImVec2& item_spacing) -> float
534{
535 float speed_icon = ImGui::CalcTextSize(ICON_MDI_PLAY_SPEED).x;
536 float slider = 100.0f;
537 float reset_btn = ImGui::CalcTextSize(ICON_MDI_UNDO_VARIANT).x + frame_padding.x * 2;
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;
543}
544
545auto header_panel::calc_center_zone_width(const ImVec2& frame_padding, const ImVec2& item_spacing) -> float
546{
547 float play_btns = ImGui::CalcTextSize(ICON_MDI_PLAY ICON_MDI_PAUSE ICON_MDI_SKIP_NEXT).x +
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;
553}
554
555void header_panel::draw_center_zone(rtti::context& ctx)
556{
557 auto& play = ctx.get_cached<play_mode>();
558 ImGuiKeyChord key_chord = shortcuts::play_toggle;
559 bool play_pressed = ImGui::IsKeyChordPressed(key_chord);
560 const bool has_errors = !editor_actions::can_enter_play(ctx) && !play.is_active();
561 ImGui::BeginDisabled(has_errors);
562 ImGui::BeginGroup();
563 if(play.is_active())
564 {
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));
568 }
569 play_pressed |= ImGui::Button(play.is_active() ? ICON_MDI_STOP : ICON_MDI_PLAY);
570 if(play.is_active())
571 {
572 ImGui::PopStyleColor(3);
573 }
574 if(has_errors && !play.is_active())
575 {
576 play_pressed = false;
577 }
578 ImGui::SetItemTooltipEx("%s", ImGui::GetKeyChordName(key_chord));
579 if(play_pressed)
580 {
581 editor_actions::toggle_play(ctx, play_splash_in_editor_);
582 }
583 ImGui::SameLine();
584
585 if(play.is_paused())
586 {
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));
590 }
591 if(ImGui::Button(ICON_MDI_PAUSE))
592 {
593 editor_actions::set_play_paused(ctx, !play.is_paused());
594 }
595 if(play.is_paused())
596 {
597 ImGui::PopStyleColor(3);
598 }
599 ImGui::SameLine();
600 ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
601 if(ImGui::Button(ICON_MDI_SKIP_NEXT))
602 {
604 }
605 ImGui::PopItemFlag();
606 ImGui::SameLine();
607 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
608 ImGui::SameLine();
609 ImGui::BeginDisabled(play.is_active());
610 draw_debug_mode();
611 ImGui::EndDisabled();
612 ImGui::EndGroup();
613 ImGui::EndDisabled();
614 if(has_errors)
615 {
616 ImGui::SetItemTooltipEx("%s", "All compiler errors must be fixed before you can enter Play Mode!");
617 }
618 ImGui::SameLine();
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();
623}
624
625void header_panel::draw_right_zone(rtti::context& ctx)
626{
627 ImGui::BeginGroup();
628 auto& sim = ctx.get_cached<simulation>();
629 auto time_scale = sim.get_time_scale();
630 ImGui::Text(ICON_MDI_PLAY_SPEED);
631 ImGui::SetItemTooltipEx("%s", "Time scale");
632 ImGui::SameLine();
633 ImGui::SetNextItemWidth(100.0f);
634 if(ImGui::KnobSliderScalarT("###Time Scale", &time_scale, 0.0f, 3.0f))
635 {
636 sim.set_time_scale(time_scale);
637 }
638 ImGui::SetItemTooltipEx("%s", "Time scale");
639 ImGui::SameLine();
640 if(ImGui::Button(ICON_MDI_UNDO_VARIANT))
641 {
642 sim.set_time_scale(1.0f);
643 }
644 ImGui::SetItemTooltipEx("Reset time scale to 1.0");
645 ImGui::SameLine();
646 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
647 ImGui::SameLine();
648 auto& rend = ctx.get_cached<renderer>();
649 auto vsync = rend.get_vsync();
650 if(ImGui::Checkbox("Vsync", &vsync))
651 {
652 rend.set_vsync(vsync);
653 }
654 ImGui::SameLine();
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))
659 {
660 sim.set_max_fps(static_cast<uint32_t>(max_fps < 0 ? 0 : max_fps));
661 }
662 ImGui::SetItemTooltipEx("%s", "Max FPS (0 = uncapped)");
663 ImGui::EndGroup();
664}
665
666void header_panel::draw_play_toolbar(rtti::context& ctx, float header_size)
667{
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);
674 draw_left_zone(ctx);
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); });
680 ImGui::SameLine();
681 ImGui::AlignedItem(1.0f, ImGui::GetContentRegionAvail().x, right_zone_width,
682 [&]() -> void { draw_right_zone(ctx); });
683}
684
686{
687 ImGuiWindowFlags header_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBringToFrontOnFocus |
688 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
689 ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoDecoration;
690 ImGuiViewport* viewport = ImGui::GetMainViewport();
691
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);
696
697 ImGui::SetNextWindowViewport(viewport->ID);
698
699 bool open = ImGui::Begin("HEADER", nullptr, header_flags);
700
701 ImGui::PopStyleVar();
702 ImGui::PopStyleVar();
703
704 if(open)
705 {
706 // ImGui::WindowTimeBlock block(ImGui::GetFont(ImGui::Font::Mono));
707
708 // Draw a sep. child for the menu bar.
709 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_MenuBarBg));
710 draw_menubar_child(ctx);
711 // ImGui::NewLine();
712 draw_play_toolbar(ctx, header_size);
713 ImGui::PopStyleColor();
714 }
715
716 ImGui::End();
717
718 // Draw the about window (will only be visible if show_about_window_ is true)
719 draw_about_window(ctx);
720
721}
722
723void header_panel::draw_about_window(rtti::context& ctx)
724{
725 if(!show_about_window_)
726 return;
727
728 if(!ImGui::IsPopupOpen("About Unravel Engine"))
729 {
730 ImGui::OpenPopup("About Unravel Engine");
731 }
732
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),
736 ImGuiCond_Always,
737 ImVec2(0.5f, 0.5f));
738 if(ImGui::BeginPopupModal("About Unravel Engine",
739 &show_about_window_,
740 ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove))
741 {
742 // Logo and title
743 const float title_scale = 1.5f;
745 GetFont(ImGui::Font::Bold)->LegacySize * title_scale); // Use default font
746 ImGui::TextColored(ImVec4(0.4f, 0.6f, 1.0f, 1.0f), "Unravel Engine");
747 ImGui::PopFont();
748
749 // Version information
750 ImGui::Text("Version %s", version::get_full().c_str());
751 ImGui::Separator();
752
753 // Engine description
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.");
757
758 ImGui::Spacing();
759 ImGui::Spacing();
760
761 // Features
762 const float section_scale = 1.2f;
763 ImGui::PushFont(ImGui::GetFont(), ImGui::GetFont()->LegacySize * section_scale);
764 ImGui::Text("Key Features");
765 ImGui::PopFont();
766
767 ImGui::Columns(2);
768 ImGui::BulletText("Entity-Component-System");
769 ImGui::BulletText("PBR Rendering");
770 ImGui::BulletText("C# Scripting");
771 ImGui::BulletText("Physics Integration");
772 ImGui::NextColumn();
773 ImGui::BulletText("Real-time Editor");
774 ImGui::BulletText("Asset Management");
775 ImGui::BulletText("Cross-platform Support");
776 ImGui::BulletText("Extensible Architecture");
777 ImGui::Columns(1);
778
779 ImGui::Spacing();
780 ImGui::Spacing();
781
782 // Build information
783 ImGui::PushFont(ImGui::GetFont(), ImGui::GetFont()->LegacySize * section_scale);
784 ImGui::Text("Build Information");
785 ImGui::PopFont();
786
787 ImGui::Text("Build Date: %s", __DATE__);
788 ImGui::Text("Build Time: %s", __TIME__);
789#ifdef _DEBUG
790 ImGui::Text("Configuration: Debug");
791#else
792 ImGui::Text("Configuration: Release");
793#endif
794
795 ImGui::Spacing();
796 ImGui::Spacing();
797
798 // Copyright notice
799 ImGui::Separator();
800 ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Copyright © %d. All rights reserved.", 2025);
801
802 ImGui::EndPopup();
803 }
804}
805
806} // namespace unravel
void on_frame_ui_render(rtti::context &ctx, float header_size)
header_panel(imgui_panels *parent)
auto get_profiler_timeline_panel() -> profiler_timeline_panel &
Definition panel.cpp:236
auto get_project_settings_panel() -> project_settings_panel &
Definition panel.cpp:191
auto get_deploy_panel() -> deploy_panel &
Definition panel.cpp:186
auto get_editor_settings_panel() -> editor_settings_panel &
Definition panel.cpp:196
auto get_layout_panel() -> layout_panel &
Definition panel.cpp:286
auto get_style_panel() -> style_panel &
Definition panel.cpp:216
auto get_animation_panel() -> animation_panel &
Definition panel.cpp:226
auto get_mcp_panel() -> mcp_panel &
Definition panel.cpp:231
auto get_undo_redo_panel() -> undo_redo_panel &
Definition panel.cpp:241
float x
#define ICON_MDI_STOP
#define ICON_MDI_UNDO_VARIANT
#define ICON_MDI_PACKAGE
#define ICON_MDI_BUG_CHECK
#define ICON_MDI_REFLECT_HORIZONTAL
#define ICON_MDI_PAUSE
#define ICON_MDI_SKIP_NEXT
#define ICON_MDI_PLAY_SPEED
#define ICON_MDI_PLAY
#define ICON_MDI_BUG
@ ImGuiToastType_Error
@ ImGuiToastType_Success
@ ImGuiToastType_Info
std::vector< size_t > parent_
void PushFont(Font::Enum _font)
Definition imgui.cpp:646
NOTIFY_INLINE void PushNotification(const ImGuiToast &toast)
Insert a new toast in the list.
ImFont * GetFont(Font::Enum _font)
Definition imgui.cpp:652
const ImGuiKeyCombination undo_history
Definition shortcuts.h:50
constexpr ImGuiKey play_toggle
Definition shortcuts.h:23
const ImGuiKeyCombination new_scene
Definition shortcuts.h:17
const ImGuiKeyCombination undo
Definition shortcuts.h:47
const ImGuiKeyCombination redo
Definition shortcuts.h:48
const ImGuiKeyCombination recompile_ui
Definition shortcuts.h:51
const ImGuiKeyCombination redo_alt
Definition shortcuts.h:49
const ImGuiKeyCombination save_scene_as
Definition shortcuts.h:20
const ImGuiKeyCombination open_scene
Definition shortcuts.h:18
const ImGuiKeyCombination save_scene
Definition shortcuts.h:19
auto get_full() -> std::string
Definition version.cpp:226
emitter_sim_state sim
auto get_cached() -> T &
Definition context.hpp:49
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)