aboutsummaryrefslogtreecommitdiff
path: root/src/ui/ui_layer.h
blob: 4479844179b394d945f07eb441d481f6dec9c991 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#pragma once

#include "workspace.h"          // AppActions, UIContext
#include "rendering/view.h"

#include <string>

struct ImFont;

namespace Donut
{
    // the workspaces and the panels they're built from.
    enum class Tab   { Simulation, SceneEditor, Export };
    enum class Panel { Outliner, Properties, BlackHole, Settings, Export, Stats };
    inline constexpr int kTabCount   = 3;
    inline constexpr int kPanelCount = 6;

    // the application's docking shell: a main menu bar, a workspace tab strip
    // ([ Simulation ] [ Scene Editor ] [ Export ]), a bottom status bar, and one
    // full-viewport dock space per workspace with a pass-through centre so the
    // live 3D render shows through. every workspace keeps its own dock tree and
    // its own panel instances, so rearranging one never touches the others, and
    // ImGui persists all of them in imgui.ini. draw() returns the View the
    // RenderPath should draw this frame.
    class UILayer
    {
    public:
        UILayer();

        // loads the Inter faces and registers the workspace ini section on the
        // live ImGui context. call once after the device's init_imgui() and before
        // the first draw(): ImGui reads imgui.ini on its first NewFrame.
        auto init() -> void;
        auto draw(const UIContext& ctx) -> View;

    private:
        // one workspace: a fixed centre view, its own dock tree, its own window
        // instances of the panels it owns.
        struct TabState
        {
            Tab          id    = Tab::Simulation;
            const char*  label = nullptr;             // "Scene Editor"
            const char*  key   = nullptr;             // "scene": the ### suffix and dock-id salt
            View         view  = View::BlackHole;
            unsigned int dock_id = 0;                 // ImHashStr("donut.dock.<key>")
            std::string  name[kPanelCount];           // "Black Hole###scene.black_hole"
            bool         allowed[kPanelCount]  = {};  // belongs to this workspace
            bool         defaults[kPanelCount] = {};  // open after a seed / reset
            bool         show[kPanelCount]     = {};  // open right now
            bool         reset     = false;           // rebuild the tree before it's next submitted
            bool         appearing = false;           // first frame back: panels mustn't grab focus
        };

        auto draw_menu_bar(const UIContext& ctx) -> void;
        auto draw_tab_strip() -> void;
        auto draw_status_bar(const UIContext& ctx) -> void;
        auto build_layout(TabState& tab) -> void;       // DockBuilder seed for one workspace
        auto request_tab(int index) -> void { m_tab_request = index; }
        auto sync_persisted() -> void;

        auto begin_panel(TabState& tab, Panel p) -> bool;
        auto draw_panel(const UIContext& ctx, TabState& tab, Panel p) -> void;
        auto panel_outliner(const UIContext& ctx, TabState& tab) -> void;
        auto panel_properties(const UIContext& ctx, TabState& tab) -> void;
        auto panel_black_hole(const UIContext& ctx, TabState& tab) -> void;
        auto panel_settings(const UIContext& ctx, TabState& tab) -> void;
        auto panel_export(const UIContext& ctx, TabState& tab) -> void;
        auto panel_stats(const UIContext& ctx, TabState& tab) -> void;

        // styled building blocks the panels share (they need the fonts, hence members)
        auto section(const char* title, bool default_open = true) -> bool;   // collapsible heading
        auto caption(const char* text) -> void;                               // muted helper text
        auto segmented(const char* id, const char* const* labels, int count, int& value) -> bool;

        TabState m_tabs[kTabCount];
        int      m_active_tab  = 0;      // index into m_tabs; the source of truth
        int      m_tab_request = -1;     // one-frame programmatic strip selection
        bool     m_first_frame = true;

        // properties-panel gizmo op (0 = translate, 1 = scale); cast in the .cpp.
        int   m_gizmo_op = 0;

        // settings panel.
        float m_ui_scale = 1.0f;

        // export panel.
        bool m_exp_color = true, m_exp_redshift = false, m_exp_temperature = false, m_exp_impact = false;
        int  m_exp_resolution = 1, m_exp_format = 0;
        int  m_exp_written = 0; bool m_exp_reported = false;

        // typography: two faces, sized at PushFont time (ImGui 1.92 rasterises on demand).
        ImFont* m_font_body    = nullptr;   // Inter Regular
        ImFont* m_font_heading = nullptr;   // Inter SemiBold

        // rolling frame-time history (ms) for the diagnostics graph.
        static constexpr int kFrameHist = 120;
        float m_frame_hist[kFrameHist] = {};
        int   m_frame_hist_i = 0;
    };
}