Initial public khodo snapshot
publish / publish (push) Successful in 27m4s

This commit is contained in:
khodowany
2026-09-04 19:30:11 -05:00
commit 51339606a2
38 changed files with 8989 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <luma/application.hpp>
#include <luma/animation.hpp>
#include <luma/assets.hpp>
#include <luma/config.hpp>
#include <luma/control.hpp>
#include <luma/controls.hpp>
#include <luma/geometry.hpp>
#include <luma/input.hpp>
#include <luma/overlays.hpp>
#include <luma/render.hpp>
#include <luma/routing.hpp>
#include <luma/theme.hpp>
#include <luma/window.hpp>
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include <chrono>
#include <expected>
#include <functional>
#include <vector>
#include <modulus.hpp>
namespace luma {
enum class easing {
LINEAR,
EASE_OUT,
EASE_IN_OUT,
};
struct animation {
std::float32_t from{};
std::float32_t to{};
std::chrono::milliseconds duration{200};
luma::easing easing{luma::easing::EASE_OUT};
std::function<void(std::float32_t)> apply{};
std::function<void()> finished{};
};
class animation_graph {
public:
auto add(luma::animation animation) -> std::expected<void, modulus::error>;
auto tick(std::chrono::steady_clock::duration delta) -> std::expected<void, modulus::error>;
auto empty() const -> std::bool_t;
auto clear() -> void;
private:
struct running_animation {
luma::animation animation{};
std::chrono::steady_clock::duration elapsed{};
};
enum class pending_kind {
ADD,
CLEAR,
};
struct pending_operation {
luma::animation_graph::pending_kind kind{luma::animation_graph::pending_kind::CLEAR};
luma::animation_graph::running_animation animation{};
};
std::vector<luma::animation_graph::running_animation> animations_{};
std::vector<luma::animation_graph::pending_operation> pending_{};
std::bool_t ticking_{false};
std::bool_t clear_requested_{false};
};
auto interpolate(std::float32_t from, std::float32_t to, std::float32_t progress, luma::easing easing) -> std::expected<std::float32_t, modulus::error>;
}
+81
View File
@@ -0,0 +1,81 @@
#pragma once
#include <chrono>
#include <cstdint>
#include <expected>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <type_traits>
#include <utility>
#include <modulus.hpp>
#include <luma/animation.hpp>
#include <luma/config.hpp>
#include <luma/control.hpp>
#include <luma/geometry.hpp>
#include <luma/overlays.hpp>
#include <luma/render.hpp>
#include <luma/window.hpp>
namespace luma {
namespace detail {
struct application_core;
}
struct frame_stats {
std::uint64_t frame{};
std::chrono::steady_clock::duration delta{};
};
class application {
public:
explicit application(luma::application_config config = {});
application(luma::application const&) = delete;
application(luma::application&&) noexcept;
~application();
auto operator=(luma::application const&) -> luma::application& = delete;
auto operator=(luma::application&&) noexcept -> luma::application&;
auto dispatch(std::function<std::expected<void, modulus::error>()> task) -> std::expected<void, modulus::error>;
auto register_route(std::string name, std::function<std::expected<std::unique_ptr<luma::control>, modulus::error>()> factory) -> std::expected<void, modulus::error>;
auto replace_route(std::string name) -> std::expected<void, modulus::error>;
auto push_route(std::string name) -> std::expected<void, modulus::error>;
auto pop_route() -> std::expected<void, modulus::error>;
auto current_route() const -> std::expected<std::string, modulus::error>;
auto add_animation(luma::animation animation) -> std::expected<void, modulus::error>;
auto clear_animations() -> std::expected<void, modulus::error>;
auto animations_empty() const -> std::expected<std::bool_t, modulus::error>;
auto open_window(luma::window_options options, std::unique_ptr<luma::control> content) -> std::expected<std::uint64_t, modulus::error>;
auto close_window(std::uint64_t id) -> std::expected<void, modulus::error>;
auto bring_window_to_front(std::uint64_t id) -> std::expected<void, modulus::error>;
auto set_window_bounds(std::uint64_t id, luma::rect bounds) -> std::expected<void, modulus::error>;
auto set_window_visible(std::uint64_t id, std::bool_t visible) -> std::expected<void, modulus::error>;
auto load_texture(std::string path) -> std::expected<std::shared_ptr<luma::texture>, modulus::error>;
auto request_layout() -> std::expected<void, modulus::error>;
auto set_root(std::expected<std::unique_ptr<luma::control>, modulus::error> root) -> std::expected<void, modulus::error>;
auto set_root(std::unique_ptr<luma::control> root) -> std::expected<void, modulus::error>;
template <typename CONTROL>
requires (std::is_base_of_v<luma::control, CONTROL> && !std::is_same_v<luma::control, CONTROL>)
auto set_root(std::unique_ptr<CONTROL> root) -> std::expected<void, modulus::error>;
auto show_dialog(luma::dialog_options options) -> std::expected<void, modulus::error>;
auto close_dialog(luma::dialog_result result) -> std::expected<void, modulus::error>;
auto show_toast(luma::toast toast) -> std::expected<void, modulus::error>;
auto request_stop() -> void;
auto should_stop() const -> std::bool_t;
auto run() -> std::expected<void, modulus::error>;
private:
auto core_snapshot() const -> std::shared_ptr<luma::detail::application_core>;
mutable std::mutex core_mutex_{};
std::shared_ptr<luma::detail::application_core> core_{};
};
template <typename CONTROL>
requires (std::is_base_of_v<luma::control, CONTROL> && !std::is_same_v<luma::control, CONTROL>)
auto application::set_root(std::unique_ptr<CONTROL> root) -> std::expected<void, modulus::error> {
return set_root(std::unique_ptr<luma::control>{std::move(root)});
}
}
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include <cstdint>
#include <expected>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <modulus.hpp>
#include <luma/render.hpp>
namespace luma {
class renderer_resources {
public:
virtual ~renderer_resources() = default;
virtual auto load_texture(std::string const& path) -> std::expected<std::shared_ptr<luma::texture>, modulus::error> = 0;
};
class asset_cache {
public:
explicit asset_cache(luma::renderer_resources& resources);
auto texture(std::string const& path) -> std::expected<std::shared_ptr<luma::texture>, modulus::error>;
auto clear() -> void;
private:
struct in_flight_load;
luma::renderer_resources* resources_{};
mutable std::mutex mutex_{};
std::uint64_t generation_{};
std::unordered_map<std::string, std::shared_ptr<luma::texture>> textures_{};
std::unordered_map<std::string, std::shared_ptr<luma::asset_cache::in_flight_load>> loading_{};
};
}
+45
View File
@@ -0,0 +1,45 @@
#pragma once
#include <cstdint>
#include <expected>
#include <string>
#include <boost/json/value.hpp>
#include <modulus.hpp>
#include <luma/theme.hpp>
namespace luma {
struct display_config {
std::int32_t width{1024};
std::int32_t height{600};
std::int32_t target_fps{60};
std::int32_t idle_fps{15};
std::bool_t fullscreen{true};
};
struct touch_config {
std::int32_t max_points{5};
};
struct application_config {
std::string title{"Luma"};
luma::display_config display{};
luma::touch_config touch{};
luma::theme theme{luma::default_theme()};
};
auto validate(luma::display_config const& config) -> std::expected<void, modulus::error>;
auto validate(luma::touch_config const& config) -> std::expected<void, modulus::error>;
auto validate(luma::application_config const& config) -> std::expected<void, modulus::error>;
auto parse_display_config(boost::json::value const& value) -> std::expected<luma::display_config, modulus::error>;
auto parse_touch_config(boost::json::value const& value) -> std::expected<luma::touch_config, modulus::error>;
auto parse_application_config(boost::json::value const& value) -> std::expected<luma::application_config, modulus::error>;
auto load_application_config(std::string const& path) -> std::expected<luma::application_config, modulus::error>;
auto to_json(luma::display_config const& config) -> boost::json::value;
auto to_json(luma::touch_config const& config) -> boost::json::value;
auto to_json(luma::application_config const& config) -> boost::json::value;
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <functional>
#include <modulus.hpp>
#include <luma/geometry.hpp>
namespace luma {
class draw_context;
struct theme;
struct touch_event;
class control {
public:
virtual ~control();
virtual auto measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size = 0;
virtual auto arrange(luma::rect bounds) -> void;
virtual auto draw(luma::draw_context& context, luma::theme const& theme) const -> void = 0;
virtual auto handle_touch(luma::touch_event const& event) -> std::bool_t;
virtual auto invalidate_layout() -> void;
virtual auto bind_layout_invalidator(std::function<void()> invalidator) -> void;
virtual auto focusable() const -> std::bool_t;
virtual auto set_focused(std::bool_t value) -> void;
auto focused() const -> std::bool_t;
auto set_enabled(std::bool_t value) -> void;
auto enabled() const -> std::bool_t;
auto bounds() const -> luma::rect;
protected:
auto notify_layout_changed() const -> void;
auto layout_invalidator() const -> std::function<void()>;
private:
luma::rect bounds_{};
std::function<void()> layout_invalidator_{};
std::bool_t focused_{false};
std::bool_t enabled_{true};
};
}
+185
View File
@@ -0,0 +1,185 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <expected>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include <vector>
#include <modulus.hpp>
#include <luma/control.hpp>
#include <luma/detail/errors.hpp>
#include <luma/render.hpp>
namespace luma {
enum class direction {
ROW,
COLUMN,
};
enum class alignment {
START,
CENTER,
END,
STRETCH,
};
enum class text_input_mode {
TEXT,
INTEGER,
DECIMAL,
};
enum class image_fit {
CONTAIN,
COVER,
FILL,
CENTER,
};
enum class keyboard_key_kind {
CHARACTER,
BACKSPACE,
SPACE,
ENTER,
};
struct keyboard_key {
std::string label{};
std::string value{};
luma::keyboard_key_kind kind{luma::keyboard_key_kind::CHARACTER};
};
struct keyboard_layout {
std::vector<std::vector<luma::keyboard_key>> rows{};
};
struct text_field_options {
std::string text{};
std::string placeholder{};
luma::text_input_mode mode{luma::text_input_mode::TEXT};
std::bool_t password{false};
std::size_t max_length{256};
};
class text_input_state {
public:
struct layout_listener {
std::weak_ptr<void> lifetime{};
std::function<void()> callback{};
};
text_input_state(luma::text_field_options options, std::function<void(std::string)> on_change);
auto snapshot() const -> luma::text_field_options;
auto text() const -> std::string;
auto focused() const -> std::bool_t;
auto set_focused(std::bool_t value) -> void;
auto version() const -> std::uint64_t;
auto add_layout_listener(std::weak_ptr<void> lifetime, std::function<void()> callback) -> void;
auto append(std::string_view value) -> std::expected<void, modulus::error>;
auto backspace() -> std::expected<void, modulus::error>;
auto set_text(std::string value) -> std::expected<void, modulus::error>;
private:
mutable std::mutex mutex_{};
luma::text_field_options options_{};
std::function<void(std::string)> on_change_{};
std::vector<luma::text_input_state::layout_listener> layout_listeners_{};
std::bool_t focused_{false};
std::uint64_t version_{};
};
auto default_text_keyboard() -> luma::keyboard_layout;
auto numeric_keyboard() -> luma::keyboard_layout;
auto make_text_input(luma::text_field_options options, std::function<void(std::string)> on_change) -> std::expected<std::shared_ptr<luma::text_input_state>, modulus::error>;
template <typename... CONTROLS>
auto children(CONTROLS&&... controls) -> std::expected<std::vector<std::unique_ptr<luma::control>>, modulus::error>;
auto label(std::string text) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto button(std::string text, std::function<void()> on_click) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto text_field(luma::text_field_options options, std::function<void(std::string)> on_change) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto text_field(std::shared_ptr<luma::text_input_state> input) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto soft_keyboard(luma::keyboard_layout layout, std::shared_ptr<luma::text_input_state> input, std::function<void()> on_enter = {}) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto soft_keyboard(luma::keyboard_layout layout, std::function<void(std::string)> on_text, std::function<void()> on_enter = {}) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto panel(std::expected<std::vector<std::unique_ptr<luma::control>>, modulus::error> children = luma::children()) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto panel(std::vector<std::unique_ptr<luma::control>> children) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto spacer(luma::size value) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto progress_bar(std::float32_t value) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto image(std::shared_ptr<luma::texture> texture, luma::image_fit fit = luma::image_fit::CONTAIN) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto row(std::expected<std::vector<std::unique_ptr<luma::control>>, modulus::error> children, std::float32_t gap = 8.0F, luma::alignment align = luma::alignment::CENTER) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto row(std::vector<std::unique_ptr<luma::control>> children, std::float32_t gap = 8.0F, luma::alignment align = luma::alignment::CENTER) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto column(std::expected<std::vector<std::unique_ptr<luma::control>>, modulus::error> children, std::float32_t gap = 8.0F, luma::alignment align = luma::alignment::STRETCH) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto column(std::vector<std::unique_ptr<luma::control>> children, std::float32_t gap = 8.0F, luma::alignment align = luma::alignment::STRETCH) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto stack(std::expected<std::vector<std::unique_ptr<luma::control>>, modulus::error> children) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto stack(std::vector<std::unique_ptr<luma::control>> children) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto scroll_view(std::expected<std::unique_ptr<luma::control>, modulus::error> child, std::bool_t vertical = true, std::bool_t horizontal = false) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto scroll_view(std::unique_ptr<luma::control> child, std::bool_t vertical = true, std::bool_t horizontal = false) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
template <typename CONTROL>
requires (std::is_base_of_v<luma::control, CONTROL> && !std::is_same_v<luma::control, CONTROL>)
auto scroll_view(std::unique_ptr<CONTROL> child, std::bool_t vertical = true, std::bool_t horizontal = false) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto list(std::expected<std::vector<std::unique_ptr<luma::control>>, modulus::error> children, std::float32_t gap = 4.0F) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
auto list(std::vector<std::unique_ptr<luma::control>> children, std::float32_t gap = 4.0F) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
}
namespace luma::detail {
template <typename CONTROL>
requires std::is_base_of_v<luma::control, CONTROL>
auto normalize_child(std::unique_ptr<CONTROL> child) -> std::expected<std::unique_ptr<luma::control>, modulus::error> {
if (child == nullptr) {
return luma::detail::fail<std::unique_ptr<luma::control>>(luma::detail::error_invalid_argument, "child control must not be null");
}
return modulus::success(std::unique_ptr<luma::control>{std::move(child)});
}
template <typename CONTROL>
requires std::is_base_of_v<luma::control, CONTROL>
auto normalize_child(std::expected<std::unique_ptr<CONTROL>, modulus::error> child) -> std::expected<std::unique_ptr<luma::control>, modulus::error> {
if (!child) {
return modulus::fail<std::unique_ptr<luma::control>>(child.error());
}
return luma::detail::normalize_child(std::move(*child));
}
}
template <typename CONTROL>
requires (std::is_base_of_v<luma::control, CONTROL> && !std::is_same_v<luma::control, CONTROL>)
auto luma::scroll_view(std::unique_ptr<CONTROL> child, std::bool_t vertical, std::bool_t horizontal) -> std::expected<std::unique_ptr<luma::control>, modulus::error> {
return luma::scroll_view(std::unique_ptr<luma::control>{std::move(child)}, vertical, horizontal);
}
template <typename... CONTROLS>
auto luma::children(CONTROLS&&... controls) -> std::expected<std::vector<std::unique_ptr<luma::control>>, modulus::error> {
auto result = std::vector<std::unique_ptr<luma::control>>{};
result.reserve(sizeof...(controls));
auto append = [&result](auto&& input) -> std::expected<void, modulus::error> {
auto child = luma::detail::normalize_child(std::forward<decltype(input)>(input));
if (!child) {
return modulus::fail<void>(child.error());
}
result.push_back(std::move(*child));
return {};
};
auto status = std::expected<void, modulus::error>{};
([&] {
if (status) {
status = append(std::forward<CONTROLS>(controls));
}
}(), ...);
if (!status) {
return modulus::fail<std::vector<std::unique_ptr<luma::control>>>(status.error());
}
return modulus::success(std::move(result));
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
#include <expected>
#include <string>
#include <utility>
#include <modulus.hpp>
namespace luma::detail {
constexpr std::int32_t error_invalid_argument{1};
constexpr std::int32_t error_not_found{2};
constexpr std::int32_t error_unavailable{3};
constexpr std::int32_t error_timeout{4};
constexpr std::int32_t error_internal{5};
auto make_error(std::int32_t code, std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> modulus::error;
template <typename VALUE>
auto fail(std::int32_t code, std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected<VALUE, modulus::error>;
}
template <typename VALUE>
auto luma::detail::fail(std::int32_t code, std::string message, modulus::source_location location) -> std::expected<VALUE, modulus::error> {
return modulus::fail<VALUE>(luma::detail::make_error(code, std::move(message), location));
}
+70
View File
@@ -0,0 +1,70 @@
#pragma once
#include <algorithm>
#include <limits>
#include <modulus.hpp>
namespace luma {
struct point {
std::float32_t x{};
std::float32_t y{};
};
struct size {
std::float32_t width{};
std::float32_t height{};
};
struct rect {
std::float32_t x{};
std::float32_t y{};
std::float32_t width{};
std::float32_t height{};
};
struct edge_insets {
std::float32_t left{};
std::float32_t top{};
std::float32_t right{};
std::float32_t bottom{};
};
struct constraints {
luma::size min{};
luma::size max{.width = std::numeric_limits<std::float32_t>::max(), .height = std::numeric_limits<std::float32_t>::max()};
};
constexpr auto right(luma::rect value) -> std::float32_t;
constexpr auto bottom(luma::rect value) -> std::float32_t;
constexpr auto contains(luma::rect area, luma::point value) -> std::bool_t;
constexpr auto inset(luma::rect area, luma::edge_insets value) -> luma::rect;
constexpr auto clamp(luma::size value, luma::constraints limits) -> luma::size;
constexpr auto deflate(luma::constraints limits, luma::edge_insets value) -> luma::constraints;
}
constexpr auto luma::right(luma::rect value) -> std::float32_t {
return value.x + value.width;
}
constexpr auto luma::bottom(luma::rect value) -> std::float32_t {
return value.y + value.height;
}
constexpr auto luma::contains(luma::rect area, luma::point value) -> std::bool_t {
return value.x >= area.x && value.x <= luma::right(area) && value.y >= area.y && value.y <= luma::bottom(area);
}
constexpr auto luma::inset(luma::rect area, luma::edge_insets value) -> luma::rect {
return {.x = area.x + value.left, .y = area.y + value.top, .width = std::max(std::float32_t{}, area.width - value.left - value.right), .height = std::max(std::float32_t{}, area.height - value.top - value.bottom)};
}
constexpr auto luma::clamp(luma::size value, luma::constraints limits) -> luma::size {
return {.width = std::clamp(value.width, limits.min.width, limits.max.width), .height = std::clamp(value.height, limits.min.height, limits.max.height)};
}
constexpr auto luma::deflate(luma::constraints limits, luma::edge_insets value) -> luma::constraints {
return {.min = {.width = std::max(std::float32_t{}, limits.min.width - value.left - value.right), .height = std::max(std::float32_t{}, limits.min.height - value.top - value.bottom)}, .max = {.width = std::max(std::float32_t{}, limits.max.width - value.left - value.right), .height = std::max(std::float32_t{}, limits.max.height - value.top - value.bottom)}};
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include <chrono>
#include <cstdint>
#include <vector>
#include <luma/geometry.hpp>
namespace luma {
enum class touch_phase {
DOWN,
MOVE,
UP,
CANCEL,
};
struct touch_point {
std::int32_t id{};
luma::point position{};
luma::touch_phase phase{luma::touch_phase::MOVE};
};
struct touch_event {
std::vector<luma::touch_point> points{};
std::chrono::steady_clock::time_point time{std::chrono::steady_clock::now()};
};
}
+67
View File
@@ -0,0 +1,67 @@
#pragma once
#include <chrono>
#include <cstdint>
#include <deque>
#include <expected>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <modulus.hpp>
#include <luma/control.hpp>
namespace luma {
enum class dialog_result {
NONE,
ACCEPTED,
CANCELLED,
};
struct dialog_options {
std::string title{};
std::unique_ptr<luma::control> body{};
std::string accept_text{"OK"};
std::string cancel_text{"Cancel"};
std::function<void(luma::dialog_result)> on_close{};
};
struct toast {
std::string message{};
std::chrono::milliseconds duration{2500};
};
class overlay_host final : public luma::control {
public:
auto show_dialog(luma::dialog_options options) -> std::expected<void, modulus::error>;
auto close_dialog(luma::dialog_result result) -> std::expected<void, modulus::error>;
auto show_toast(luma::toast toast) -> std::expected<void, modulus::error>;
auto tick(std::chrono::steady_clock::duration delta) -> std::bool_t;
auto measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size override;
auto arrange(luma::rect bounds) -> void override;
auto draw(luma::draw_context& context, luma::theme const& theme) const -> void override;
auto handle_touch(luma::touch_event const& event) -> std::bool_t override;
auto invalidate_layout() -> void override;
auto bind_layout_invalidator(std::function<void()> invalidator) -> void override;
private:
friend auto overlays(std::unique_ptr<luma::control> content) -> std::expected<std::unique_ptr<luma::overlay_host>, modulus::error>;
explicit overlay_host(std::unique_ptr<luma::control> content);
auto begin_traversal() const -> void;
auto end_traversal() const -> void;
auto retire_dialog_body(std::unique_ptr<luma::control> body) -> void;
auto flush_retired_dialog_bodies() const -> void;
std::unique_ptr<luma::control> content_{};
std::optional<luma::dialog_options> dialog_{};
std::deque<luma::toast> toasts_{};
std::chrono::steady_clock::duration toast_elapsed_{};
mutable std::vector<std::unique_ptr<luma::control>> retired_dialog_bodies_{};
mutable std::uint32_t traversal_depth_{};
};
auto overlays(std::unique_ptr<luma::control> content) -> std::expected<std::unique_ptr<luma::overlay_host>, modulus::error>;
}
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include <cstdint>
#include <string_view>
#include <modulus.hpp>
#include <luma/geometry.hpp>
#include <luma/theme.hpp>
namespace luma {
struct texture_info {
std::int32_t width{};
std::int32_t height{};
};
class texture {
public:
virtual ~texture() = default;
virtual auto info() const -> luma::texture_info = 0;
};
class draw_context {
public:
virtual ~draw_context() = default;
virtual auto fill_rect(luma::rect bounds, luma::color color) -> void = 0;
virtual auto stroke_rect(luma::rect bounds, std::float32_t thickness, luma::color color) -> void = 0;
virtual auto stroke_line(luma::point from, luma::point to, std::float32_t thickness, luma::color color) -> void = 0;
virtual auto fill_ellipse(luma::rect bounds, luma::color color) -> void = 0;
virtual auto stroke_ellipse(luma::rect bounds, std::float32_t thickness, luma::color color) -> void = 0;
virtual auto draw_text(std::string_view text, luma::point origin, luma::text_style const& style, luma::color color) -> void = 0;
virtual auto draw_texture(luma::texture const& texture, luma::rect source, luma::rect destination, luma::color tint) -> void = 0;
virtual auto push_clip(luma::rect bounds) -> void = 0;
virtual auto pop_clip() -> void = 0;
virtual auto measure_text(std::string_view text, luma::text_style const& style) const -> luma::size = 0;
};
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <expected>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <modulus.hpp>
#include <luma/control.hpp>
namespace luma {
class router {
public:
auto register_route(std::string name, std::function<std::expected<std::unique_ptr<luma::control>, modulus::error>()> factory) -> std::expected<void, modulus::error>;
auto set_retire_handler(std::function<void(std::unique_ptr<luma::control>)> handler) -> void;
auto replace(std::string const& name) -> std::expected<void, modulus::error>;
auto push(std::string const& name) -> std::expected<void, modulus::error>;
auto pop() -> std::expected<void, modulus::error>;
auto clear_stack() -> void;
auto current() -> luma::control*;
auto current() const -> luma::control const*;
auto current_route() const -> std::string const&;
private:
struct entry {
std::string name{};
std::unique_ptr<luma::control> view{};
};
auto retire(std::unique_ptr<luma::control> view) -> void;
auto retire_stack() -> void;
std::unordered_map<std::string, std::function<std::expected<std::unique_ptr<luma::control>, modulus::error>()>> routes_{};
std::vector<luma::router::entry> stack_{};
std::string empty_route_{};
std::function<void(std::unique_ptr<luma::control>)> retire_handler_{};
};
}
+49
View File
@@ -0,0 +1,49 @@
#pragma once
#include <cstdint>
#include <expected>
#include <string>
#include <boost/json/value.hpp>
#include <modulus.hpp>
namespace luma {
struct color {
std::uint8_t r{};
std::uint8_t g{};
std::uint8_t b{};
std::uint8_t a{255};
};
struct text_style {
std::string font{"default"};
std::float32_t size{24.0F};
std::float32_t line_height{30.0F};
};
struct theme {
luma::color background{18, 19, 22, 255};
luma::color surface{32, 34, 38, 255};
luma::color surface_active{46, 94, 170, 255};
luma::color text{242, 244, 248, 255};
luma::color text_muted{170, 176, 186, 255};
luma::color border{82, 88, 99, 255};
luma::color accent{84, 160, 255, 255};
luma::text_style body{};
luma::text_style title{.font = "default", .size = 32.0F, .line_height = 40.0F};
std::float32_t radius{4.0F};
std::float32_t spacing{8.0F};
};
auto default_theme() -> luma::theme;
auto validate(luma::text_style const& style) -> std::expected<void, modulus::error>;
auto validate(luma::theme const& theme) -> std::expected<void, modulus::error>;
auto parse_color(boost::json::value const& value) -> std::expected<luma::color, modulus::error>;
auto parse_theme(boost::json::value const& value) -> std::expected<luma::theme, modulus::error>;
auto to_json(luma::color const& color) -> boost::json::value;
auto to_json(luma::text_style const& style) -> boost::json::value;
auto to_json(luma::theme const& theme) -> boost::json::value;
}
+94
View File
@@ -0,0 +1,94 @@
#pragma once
#include <cstdint>
#include <expected>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <modulus.hpp>
#include <luma/control.hpp>
#include <luma/geometry.hpp>
namespace luma {
class window_manager;
struct window_options {
std::string title{};
luma::rect bounds{};
std::bool_t modal{false};
std::bool_t decorated{true};
std::bool_t visible{true};
};
class window {
public:
window(luma::window const&) = delete;
window(luma::window&&) noexcept = default;
auto operator=(luma::window const&) -> luma::window& = delete;
auto operator=(luma::window&&) noexcept -> luma::window& = default;
auto id() const -> std::uint64_t;
auto options() const -> luma::window_options const&;
auto set_bounds(luma::rect bounds) -> std::expected<void, modulus::error>;
auto set_visible(std::bool_t value) -> void;
auto visible() const -> std::bool_t;
auto content() -> luma::control*;
auto content() const -> luma::control const*;
private:
friend class luma::window_manager;
window(std::uint64_t id, luma::window_options options, std::unique_ptr<luma::control> content);
std::uint64_t id_{};
luma::window_options options_{};
std::unique_ptr<luma::control> content_{};
};
class window_manager final : public luma::control {
public:
auto open(luma::window_options options, std::unique_ptr<luma::control> content) -> std::expected<std::uint64_t, modulus::error>;
auto close(std::uint64_t id) -> std::expected<void, modulus::error>;
auto bring_to_front(std::uint64_t id) -> std::expected<void, modulus::error>;
auto set_bounds(std::uint64_t id, luma::rect bounds) -> std::expected<void, modulus::error>;
auto set_visible(std::uint64_t id, std::bool_t visible) -> std::expected<void, modulus::error>;
auto find(std::uint64_t id) -> luma::window*;
auto clear() -> void;
auto measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size override;
auto arrange(luma::rect bounds) -> void override;
auto draw(luma::draw_context& context, luma::theme const& theme) const -> void override;
auto handle_touch(luma::touch_event const& event) -> std::bool_t override;
auto invalidate_layout() -> void override;
auto bind_layout_invalidator(std::function<void()> invalidator) -> void override;
private:
enum class pending_kind {
OPEN,
CLOSE,
BRING_TO_FRONT,
SET_BOUNDS,
SET_VISIBLE,
CLEAR,
};
struct pending_operation {
luma::window_manager::pending_kind kind{luma::window_manager::pending_kind::CLEAR};
std::uint64_t id{};
std::unique_ptr<luma::window> window{};
luma::rect bounds{};
std::bool_t visible{};
};
auto contains_effective(std::uint64_t id) const -> std::bool_t;
auto close_now(std::uint64_t id) const -> void;
auto bring_to_front_now(std::uint64_t id) const -> void;
auto set_bounds_now(std::uint64_t id, luma::rect bounds) const -> void;
auto set_visible_now(std::uint64_t id, std::bool_t visible) const -> void;
auto apply_pending_operations() const -> void;
std::uint64_t next_id_{1};
mutable std::float32_t title_line_height_{30.0F};
mutable std::vector<std::unique_ptr<luma::window>> windows_{};
mutable std::unordered_map<std::int32_t, std::uint64_t> active_touches_{};
mutable std::vector<luma::window_manager::pending_operation> pending_operations_{};
mutable std::uint32_t mutation_depth_{};
};
}