/* Crafter®.Graphics Copyright (C) 2026 Catcrafts® catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #include "vulkan/vulkan.h" export module Crafter.Graphics:UIScene; import std; import :Window; import :Types; import :DescriptorHeapVulkan; import Crafter.Event; import :UIWidget; import :UIWidgets; import :UILayout; import :UIDrawList; import :UIRenderer; import :UIHit; export namespace Crafter::UI { // The single user-facing wrapper that ties the widget tree to the // window's frame loop. Owns the renderer + draw list, optionally // owns a default descriptor heap, registers itself as a RenderPass on // the window, and routes mouse clicks through the hit tester. // // Typical usage: // // Crafter::Window window(1280, 720, "Demo"); // window.StartInit(); window.FinishInit(); // Crafter::UI::UIScene scene; // scene.Initialize(window); // scene.Root(VStack{}.children( // Button{"Play"}.onClick([&]{ ... }), // ... // )); // window.Render(); // window.StartUpdate(); // continuous rendering // window.StartSync(); class UIScene { public: UIRenderer renderer; DrawList drawList; UIScene() = default; UIScene(const UIScene&) = delete; UIScene& operator=(const UIScene&) = delete; ~UIScene(); void Initialize(Window& window, const std::filesystem::path& spvPath = "ui.comp.spv"); // Replace the widget tree. Takes ownership and clears focus // (the previously-focused widget will be destroyed with the // old tree). template requires std::derived_from, Widget> void Root(W&& root) { SetFocus(nullptr); using T = std::remove_cvref_t; auto p = std::make_unique(std::move(root)); p->parent = nullptr; root_ = std::move(p); } // Focus management. Calling with nullptr blurs whatever was focused. void SetFocus(Widget* w); Widget* Focused() const { return focused_; } // Optional surface-clearing colour. The swapchain image is // STORAGE-only (can't be vkCmdClearColorImage'd), so we paint a // full-surface rect at the start of every frame's draw list when // this is set. UIScene& background(Color c) { background_ = c; return *this; } Widget* root() { return root_.get(); } const Widget* root() const { return root_.get(); } private: Window* window_ = nullptr; std::unique_ptr root_; std::optional background_; // Auto-allocated heap for UI-only apps. If the user already attached // a heap to the window, we leave it alone and don't own one. DescriptorHeapVulkan ownedHeap_; bool ownsHeap_ = false; std::unique_ptr> mouseListener_; std::unique_ptr> updateListener_; std::unique_ptr> textListener_; std::unique_ptr> keyListener_; Widget* focused_ = nullptr; float WindowScale() const; void RebuildFrame(); }; }