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"
4
7#include <editor/shortcuts.h>
8
11#include <engine/ecs/ecs.h>
12#include <engine/events.h>
17#include <exception>
19#include <version/version.h>
20
21#include <imgui/imgui.h>
22#include <imgui/imgui_internal.h>
24
25namespace unravel
26{
27
28namespace
29{
30auto get_debug_mode_size() -> float
31{
32 return 120.0f;
33}
34void draw_debug_mode()
35{
36 bool debugger_attached = script_system::is_debugger_attached();
37 bool debug_mode = script_system::get_script_debug_mode();
38 const char* modes[] = {ICON_MDI_BUG_CHECK " Debug", ICON_MDI_BUG " Release"};
39 const char* debug_mode_preview = modes[int(!debug_mode)];
40 ImGui::SetNextItemWidth(get_debug_mode_size());
41
42 if(debugger_attached)
43 {
44 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f));
45 }
46 if(ImGui::BeginCombo("###DebugMode", debug_mode_preview))
47 {
48 if(ImGui::Selectable(modes[0]))
49 {
50 if(!debug_mode)
51 {
54 }
55 }
56 ImGui::SetItemTooltipEx("%s",
57 "Debug mode enales C# debugging\n"
58 "but reduces C# performance.\n"
59 "Switching to Debug mode will recompile\n"
60 "and reload all scripts.");
61
62 if(ImGui::Selectable(modes[1]))
63 {
64 if(debug_mode)
65 {
68 }
69 }
70 ImGui::SetItemTooltipEx("%s",
71 "Release mode disables C# debugging\n"
72 "but improves C# performance.\n"
73 "Switching to Release mode will recompile\n"
74 "and reload all scripts.");
75
76 ImGui::EndCombo();
77 }
78
79 const char* debug_mode_tooltip = debug_mode ? "Debugger Enabled" : "Debugger Disabled";
80
81 ImGui::SetItemTooltipEx("%s", debug_mode_tooltip);
82 if(debugger_attached)
83 {
84 ImGui::SetItemTooltipEx("%s", "Debugger Attached");
85 ImGui::PopStyleColor();
86 }
87}
88} // namespace
89
90header_panel::header_panel(imgui_panels* parent) : parent_(parent)
91{
92}
93
94void header_panel::draw_menubar_child(rtti::context& ctx)
95{
96 ImGuiWindowFlags header_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar |
97 ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar |
98 ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_MenuBar;
99 ImGui::BeginChild("HEADER_menubar", ImVec2(0, ImGui::GetFrameHeight()), false, header_flags);
100
101 // Draw menu bar.
102 if(ImGui::BeginMenuBar())
103 {
104 if(ImGui::BeginMenu("File"))
105 {
106 if(ImGui::MenuItem("New Scene", ImGui::GetKeyCombinationName(shortcuts::new_scene).c_str()))
107 {
109 }
110
111 if(ImGui::MenuItem("Open Scene", ImGui::GetKeyCombinationName(shortcuts::open_scene).c_str()))
112 {
114 }
115
116 if(ImGui::MenuItem("Save Scene...", ImGui::GetKeyCombinationName(shortcuts::save_scene).c_str()))
117 {
119 }
120
121 if(ImGui::MenuItem("Save Scene As", ImGui::GetKeyCombinationName(shortcuts::save_scene_as).c_str()))
122 {
124 }
125
126 if(ImGui::MenuItem("Reload Project", nullptr))
127 {
129 }
130
131 if(ImGui::MenuItem("Close Project", nullptr))
132 {
134 }
135 ImGui::EndMenu();
136 }
137
138 if(ImGui::BeginMenu("Edit"))
139 {
140
141 auto& em = ctx.get_cached<editing_manager>();
142 auto undo = em.can_undo() ? "Undo*" : "Undo";
143 auto redo = em.can_redo() ? "Redo*" : "Redo";
144 if(ImGui::MenuItem(undo, ImGui::GetKeyCombinationName(shortcuts::undo).c_str()))
145 {
146 em.undo();
147 }
148
149 if(ImGui::MenuItem(redo, ImGui::GetKeyCombinationName(shortcuts::redo).c_str()))
150 {
151 em.redo();
152 }
153
154 if(ImGui::MenuItem("Undo History", ImGui::GetKeyCombinationName(shortcuts::undo_history).c_str()))
155 {
156 parent_->get_undo_redo_panel().show(true);
157 }
158
159 if(ImGui::MenuItem("Editor Settings..."))
160 {
161 parent_->get_editor_settings_panel().show(true);
162 }
163
164 if(ImGui::MenuItem("Project Settings..."))
165 {
166 parent_->get_project_settings_panel().show(true, "{}");
167 }
168
169 ImGui::EndMenu();
170 }
171
172 if(ImGui::BeginMenu("Deploy"))
173 {
174 if(ImGui::MenuItem("Deploy Project"))
175 {
176 parent_->get_deploy_panel().show(true);
177 }
178
179 ImGui::EndMenu();
180 }
181
182 if(ImGui::BeginMenu("Developer"))
183 {
184
185
186 if(ImGui::MenuItem("Crash(Abort)"))
187 {
188 std::abort();
189 }
190 if(ImGui::MenuItem("Crash(Terminate)"))
191 {
192 std::terminate();
193 }
194 if(ImGui::MenuItem("Crash(SIGSEGV)"))
195 {
196 *(volatile int*)0 = 0;
197 }
198
199 if(ImGui::MenuItem("Recompile Shaders"))
200 {
202 }
203
204 if(ImGui::MenuItem("Recompile Textures"))
205 {
207 }
208
209 if(ImGui::MenuItem("Recompile UI"))
210 {
212 }
213
214 if(ImGui::MenuItem("Recompile Scripts"))
215 {
217 }
218
219 if(ImGui::MenuItem("Recompile All"))
220 {
222 }
223
224 ImGui::EndMenu();
225 }
226 if(ImGui::BeginMenu("Windows"))
227 {
228 if(ImGui::MenuItem("Style"))
229 {
230 parent_->get_style_panel().show(true);
231 }
232 if(ImGui::MenuItem("Animation"))
233 {
234 parent_->get_animation_panel().show(true);
235 }
236 ImGui::EndMenu();
237 }
238
239 if(ImGui::BeginMenu("Help"))
240 {
241 if(ImGui::MenuItem("About"))
242 {
243 show_about_window_ = true;
244 }
245
246 ImGui::EndMenu();
247 }
248
249 ImGui::EndMenuBar();
250 }
251
252 if(!ImGui::IsAnyItemActive())
253 {
254 if(ImGui::IsCombinationKeyPressed(shortcuts::new_scene))
255 {
257 }
258 else if(ImGui::IsCombinationKeyPressed(shortcuts::open_scene))
259 {
261 }
262 else if(ImGui::IsCombinationKeyPressed(shortcuts::save_scene_as))
263 {
265 }
266 else if(ImGui::IsCombinationKeyPressed(shortcuts::save_scene))
267 {
269 }
270
271 else if(ImGui::IsCombinationKeyPressed(shortcuts::redo, true))
272 {
273 ctx.get_cached<editing_manager>().redo();
274 }
275 else if(ImGui::IsCombinationKeyPressed(shortcuts::redo_alt, true))
276 {
277 ctx.get_cached<editing_manager>().redo();
278 }
279 else if(ImGui::IsCombinationKeyPressed(shortcuts::undo, true))
280 {
281 ctx.get_cached<editing_manager>().undo();
282 }
283 else if(ImGui::IsCombinationKeyPressed(shortcuts::undo_history))
284 {
285 parent_->get_undo_redo_panel().show(true);
286 }
287 else if(ImGui::IsCombinationKeyPressed(shortcuts::recompile_ui))
288 {
290 }
291 }
292 ImGui::EndChild();
293}
294
295void header_panel::draw_play_toolbar(rtti::context& ctx, float header_size)
296{
297 auto& ev = ctx.get_cached<events>();
298
299 float width = ImGui::GetContentRegionAvail().x;
300
301 auto window_pos = ImGui::GetWindowPos();
302 auto window_size = ImGui::GetWindowSize();
303 // Add a poly background for the logo.
304 const ImVec2 logo_bounds = ImVec2(500, header_size * 0.5f);
305 const ImVec2 logo_pos = ImVec2(window_pos.x + window_size.x * 0.5f - logo_bounds.x * 0.5f, window_pos.y);
306
307 ImVec2 points[5] = {ImVec2(logo_pos.x, logo_pos.y),
308 ImVec2(logo_pos.x + 20, logo_pos.y + logo_bounds.y + 4),
309 ImVec2(logo_pos.x + logo_bounds.x - 20, logo_pos.y + logo_bounds.y + 4),
310 ImVec2(logo_pos.x + logo_bounds.x, logo_pos.y),
311 ImVec2(logo_pos.x, logo_pos.y)};
312
313 const ImU32 poly_background = ImGui::GetColorU32(ImGuiCol_MenuBarBg);
314 auto poly_background_border_color = poly_background;
315
316 if(ev.is_playing)
317 {
318 poly_background_border_color = ImGui::GetColorU32(ImVec4(0.0f, 0.5f, 0.0f, 0.5f));
319 }
320 if(ev.is_paused)
321 {
322 poly_background_border_color = ImGui::GetColorU32(ImVec4(0.6f, 0.3f, 0.0f, 0.5f));
323 }
324
325 ImGui::GetWindowDrawList()->AddConvexPolyFilled(&points[0], 5, poly_background_border_color);
326 // ImGui::GetWindowDrawList()->AddPolyline(&points[0], 4, poly_background_border_color, 0, 3);
327 // ImGui::GetWindowDrawList()->AddRectFilledMultiColor(logo_pos,
328 // logo_pos + logo_bounds,
329 // poly_background_border_color,
330 // poly_background_border_color,
331 // poly_background,
332 // poly_background);
333
334 auto& pm = ctx.get_cached<project_manager>();
335 auto logo = fmt::format("{}", pm.get_name());
336 auto logo_size = ImGui::CalcTextSize(logo.c_str());
337 // Add animated logo.
338 const ImVec2 logo_min = ImVec2(logo_pos.x + logo_bounds.x * 0.5f - logo_size.x * 0.5f,
339 logo_pos.y + (logo_bounds.y - logo_size.y) * 0.5f);
340 const ImVec2 logo_max = ImVec2(logo_min.x + logo_size.x, logo_min.y + logo_size.y);
341 auto logo_border_color = ImGui::GetColorU32(ImGuiCol_Text);
342 ImGui::GetWindowDrawList()->AddText(logo_min, logo_border_color, logo.c_str());
343
344 const auto& style = ImGui::GetStyle();
345 auto frame_padding = style.FramePadding;
346 auto item_spacing = style.ItemSpacing;
347 ImGui::AlignedItem(0.5f,
348 width,
349 ImGui::CalcTextSize(ICON_MDI_PLAY ICON_MDI_PAUSE ICON_MDI_SKIP_NEXT).x + frame_padding.x * 6 +
350 item_spacing.x * 3,
351 [&]()
352 {
353 ImGuiKeyChord key_chord = ev.is_playing ? shortcuts::play_toggle : shortcuts::play_toggle;
354 bool play_pressed = ImGui::IsKeyChordPressed(key_chord);
355
356 auto& scripting = ctx.get_cached<script_system>();
357 bool has_errors = scripting.has_compilation_errors();
358 ImGui::BeginDisabled(has_errors);
359 ImGui::BeginGroup();
360
361 play_pressed |= ImGui::Button(ev.is_playing ? ICON_MDI_STOP : ICON_MDI_PLAY);
362
363 if(has_errors)
364 {
365 play_pressed = false;
366 }
367 ImGui::SetItemTooltipEx("%s", ImGui::GetKeyChordName(key_chord));
368 if(play_pressed)
369 {
370 ev.toggle_play_mode(ctx);
371 ImGui::FocusWindow(ImGui::FindWindowByName(ev.is_playing ? GAME_VIEW : SCENE_VIEW));
372 }
373
374 ImGui::SameLine();
375 if(ImGui::Button(ICON_MDI_PAUSE))
376 {
377 bool was_playing = ev.is_playing;
378 ev.toggle_pause(ctx);
379 }
380
381 ImGui::SameLine();
382 ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
383 if(ImGui::Button(ICON_MDI_SKIP_NEXT))
384 {
385 ev.skip_next_frame(ctx);
386 }
387 ImGui::PopItemFlag();
388 ImGui::SameLine();
389
390 ImGui::BeginDisabled(ev.is_playing);
391 draw_debug_mode();
392 ImGui::EndDisabled();
393 ImGui::SameLine();
394
395 auto& sim = ctx.get_cached<simulation>();
396
397 auto time_scale = sim.get_time_scale();
398 ImGui::SetNextItemWidth(100);
399 if(ImGui::SliderFloat("###Time Scale", &time_scale, 0.0f, 1.0f))
400 {
401 sim.set_time_scale(time_scale);
402 }
403 ImGui::SetItemTooltipEx("%s", "Time scale.");
404 ImGui::SameLine();
405 auto& rend = ctx.get_cached<renderer>();
406 auto vsync = rend.get_vsync();
407 if(ImGui::Checkbox("Vsync", &vsync))
408 {
409 rend.set_vsync(vsync);
410 }
411
412 ImGui::EndGroup();
413 ImGui::EndDisabled();
414
415 if(has_errors)
416 {
417 ImGui::SetItemTooltipEx(
418 "%s",
419 "All compiler errors must be fixed before you can enter Play Mode!");
420 }
421 });
422}
423
424void header_panel::on_frame_ui_render(rtti::context& ctx, float header_size)
425{
426 ImGuiWindowFlags header_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBringToFrontOnFocus |
427 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
428 ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoDecoration;
429 ImGuiViewport* viewport = ImGui::GetMainViewport();
430
431 ImGui::SetNextWindowPos(ImVec2(viewport->WorkPos.x, viewport->WorkPos.y));
432 ImGui::SetNextWindowSize(ImVec2(viewport->WorkSize.x, header_size));
433 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
434 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
435
436 ImGui::SetNextWindowViewport(viewport->ID);
437
438 bool open = ImGui::Begin("HEADER", nullptr, header_flags);
439
440 ImGui::PopStyleVar();
441 ImGui::PopStyleVar();
442
443 if(open)
444 {
445 // ImGui::WindowTimeBlock block(ImGui::GetFont(ImGui::Font::Mono));
446
447 // Draw a sep. child for the menu bar.
448 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_MenuBarBg));
449 draw_menubar_child(ctx);
450 ImGui::NewLine();
451 draw_play_toolbar(ctx, header_size);
452 ImGui::PopStyleColor();
453 }
454
455 ImGui::End();
456
457 // Draw the about window (will only be visible if show_about_window_ is true)
458 draw_about_window(ctx);
459}
460
461void header_panel::draw_about_window(rtti::context& ctx)
462{
463 if (!show_about_window_)
464 return;
465
466 if(!ImGui::IsPopupOpen("About Unravel Engine"))
467 {
468 ImGui::OpenPopup("About Unravel Engine");
469 }
470
471 auto viewport = ImGui::GetMainViewport();
472 ImGui::SetNextWindowSize(ImVec2(viewport->WorkSize * 0.30f), ImGuiCond_Always);
473 ImGui::SetNextWindowPos(ImVec2(viewport->WorkSize.x * 0.5f, viewport->WorkSize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
474 if (ImGui::BeginPopupModal("About Unravel Engine", &show_about_window_, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize| ImGuiWindowFlags_NoMove))
475 {
476 // Logo and title
477 const float title_scale = 1.5f;
478 ImGui::PushFont(GetFont(ImGui::Font::Bold), GetFont(ImGui::Font::Bold)->LegacySize * title_scale); // Use default font
479 ImGui::TextColored(ImVec4(0.4f, 0.6f, 1.0f, 1.0f), "Unravel Engine");
480 ImGui::PopFont();
481
482 // Version information
483 ImGui::Text("Version %s", version::get_full().c_str());
484 ImGui::Separator();
485
486 // Engine description
487 ImGui::TextWrapped(
488 "Unravel Engine is a modern, high-performance game engine designed for creating "
489 "interactive 3D and 2D applications. It features a component-based architecture, "
490 "powerful rendering capabilities, and an intuitive editor interface.");
491
492 ImGui::Spacing();
493 ImGui::Spacing();
494
495 // Features
496 const float section_scale = 1.2f;
497 ImGui::PushFont(ImGui::GetFont(), ImGui::GetFont()->LegacySize * section_scale);
498 ImGui::Text("Key Features");
499 ImGui::PopFont();
500
501 ImGui::Columns(2);
502 ImGui::BulletText("Entity-Component-System");
503 ImGui::BulletText("PBR Rendering");
504 ImGui::BulletText("C# Scripting");
505 ImGui::BulletText("Physics Integration");
506 ImGui::NextColumn();
507 ImGui::BulletText("Real-time Editor");
508 ImGui::BulletText("Asset Management");
509 ImGui::BulletText("Cross-platform Support");
510 ImGui::BulletText("Extensible Architecture");
511 ImGui::Columns(1);
512
513 ImGui::Spacing();
514 ImGui::Spacing();
515
516 // Build information
517 ImGui::PushFont(ImGui::GetFont(), ImGui::GetFont()->LegacySize * section_scale);
518 ImGui::Text("Build Information");
519 ImGui::PopFont();
520
521 ImGui::Text("Build Date: %s", __DATE__);
522 ImGui::Text("Build Time: %s", __TIME__);
523#ifdef _DEBUG
524 ImGui::Text("Configuration: Debug");
525#else
526 ImGui::Text("Configuration: Release");
527#endif
528
529 ImGui::Spacing();
530 ImGui::Spacing();
531
532 // Copyright notice
533 ImGui::Separator();
534 ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f),
535 "Copyright © %d. All rights reserved.", 2025);
536
537
538 ImGui::EndPopup();
539 }
540}
541
542
543
544} // namespace unravel
header_panel(imgui_panels *parent)
auto get_project_settings_panel() -> project_settings_panel &
Definition panel.cpp:146
auto get_deploy_panel() -> deploy_panel &
Definition panel.cpp:141
auto get_editor_settings_panel() -> editor_settings_panel &
Definition panel.cpp:151
auto get_style_panel() -> style_panel &
Definition panel.cpp:171
auto get_animation_panel() -> animation_panel &
Definition panel.cpp:176
auto get_undo_redo_panel() -> undo_redo_panel &
Definition panel.cpp:181
#define ICON_MDI_BUG_CHECK
#define ICON_MDI_PAUSE
#define ICON_MDI_SKIP_NEXT
#define ICON_MDI_PLAY
#define ICON_MDI_BUG
void PushFont(Font::Enum _font)
Definition imgui.cpp:617
ImFont * GetFont(Font::Enum _font)
Definition imgui.cpp:623
const ImGuiKeyCombination undo_history
Definition shortcuts.h:48
const ImGuiKeyCombination new_scene
Definition shortcuts.h:15
const ImGuiKeyCombination undo
Definition shortcuts.h:45
const ImGuiKeyCombination redo
Definition shortcuts.h:46
const ImGuiKeyCombination recompile_ui
Definition shortcuts.h:49
const ImGuiKeyCombination redo_alt
Definition shortcuts.h:47
const ImGuiKeyCombination save_scene_as
Definition shortcuts.h:18
const ImGuiKeyCombination open_scene
Definition shortcuts.h:16
const ImGuiKeyCombination save_scene
Definition shortcuts.h:17
std::string get_full()
Definition version.cpp:20
float x
auto get_cached() -> T &
Definition context.hpp:49
static auto close_project(rtti::context &ctx) -> bool
static auto open_scene(rtti::context &ctx) -> bool
static auto save_scene(rtti::context &ctx) -> bool
static auto new_scene(rtti::context &ctx) -> bool
static auto reload_project(rtti::context &ctx) -> bool
static auto save_scene_as(rtti::context &ctx) -> bool
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)