#include "detail/control_types.hpp" auto luma::label(std::string text) -> std::expected, modulus::error> { if (text.empty()) { return luma::detail::invalid>("label text must not be empty"); } return modulus::success(std::unique_ptr{std::make_unique(std::move(text))}); } auto luma::button(std::string text, std::function on_click) -> std::expected, modulus::error> { if (text.empty()) { return luma::detail::invalid>("button text must not be empty"); } if (!on_click) { return luma::detail::invalid>("button click callback must not be empty"); } return modulus::success(std::unique_ptr{std::make_unique(std::move(text), std::move(on_click))}); } auto luma::text_field(luma::text_field_options options, std::function on_change) -> std::expected, modulus::error> { auto input = luma::make_text_input(std::move(options), std::move(on_change)); if (!input) { return modulus::fail>(input.error()); } return luma::text_field(std::move(*input)); } auto luma::text_field(std::shared_ptr input) -> std::expected, modulus::error> { if (input == nullptr) { return luma::detail::invalid>("text input state must not be null"); } return modulus::success(std::unique_ptr{std::make_unique(std::move(input))}); } auto luma::soft_keyboard(luma::keyboard_layout layout, std::shared_ptr input, std::function on_enter) -> std::expected, modulus::error> { if (auto status = luma::detail::valid_keyboard_layout(layout); !status) { return modulus::fail>(status.error()); } if (input == nullptr) { return luma::detail::invalid>("text input state must not be null"); } return modulus::success(std::unique_ptr{std::make_unique(std::move(layout), std::move(input), std::move(on_enter))}); } auto luma::soft_keyboard(luma::keyboard_layout layout, std::function on_text, std::function on_enter) -> std::expected, modulus::error> { if (auto status = luma::detail::valid_keyboard_layout(layout); !status) { return modulus::fail>(status.error()); } if (!on_text) { return luma::detail::invalid>("keyboard text callback must not be empty"); } return modulus::success(std::unique_ptr{std::make_unique(std::move(layout), std::move(on_text), std::move(on_enter))}); } auto luma::panel(std::expected>, modulus::error> children) -> std::expected, modulus::error> { if (!children) { return modulus::fail>(children.error()); } return luma::panel(std::move(*children)); } auto luma::panel(std::vector> children) -> std::expected, modulus::error> { if (auto status = luma::detail::validate_children(children); !status) { return modulus::fail>(status.error()); } return modulus::success(std::unique_ptr{std::make_unique(std::move(children))}); } auto luma::spacer(luma::size value) -> std::expected, modulus::error> { if (!luma::detail::finite_size(value)) { return luma::detail::invalid>("spacer size must be finite and non-negative"); } return modulus::success(std::unique_ptr{std::make_unique(value)}); } auto luma::progress_bar(std::float32_t value) -> std::expected, modulus::error> { if (!std::isfinite(value)) { return luma::detail::invalid>("progress value must be finite"); } return modulus::success(std::unique_ptr{std::make_unique(value)}); } auto luma::image(std::shared_ptr texture, luma::image_fit fit) -> std::expected, modulus::error> { if (texture == nullptr) { return luma::detail::invalid>("image texture must not be null"); } auto info = texture->info(); if (info.width <= 0 || info.height <= 0) { return luma::detail::invalid>("image texture dimensions must be positive"); } return modulus::success(std::unique_ptr{std::make_unique(std::move(texture), fit)}); } auto luma::row(std::expected>, modulus::error> children, std::float32_t gap, luma::alignment align) -> std::expected, modulus::error> { if (!children) { return modulus::fail>(children.error()); } return luma::row(std::move(*children), gap, align); } auto luma::row(std::vector> children, std::float32_t gap, luma::alignment align) -> std::expected, modulus::error> { if (auto status = luma::detail::validate_children(children); !status) { return modulus::fail>(status.error()); } if (!std::isfinite(gap) || gap < 0.0F) { return luma::detail::invalid>("row gap must be finite and non-negative"); } return modulus::success(std::unique_ptr{std::make_unique(luma::direction::ROW, std::move(children), gap, align)}); } auto luma::column(std::expected>, modulus::error> children, std::float32_t gap, luma::alignment align) -> std::expected, modulus::error> { if (!children) { return modulus::fail>(children.error()); } return luma::column(std::move(*children), gap, align); } auto luma::column(std::vector> children, std::float32_t gap, luma::alignment align) -> std::expected, modulus::error> { if (auto status = luma::detail::validate_children(children); !status) { return modulus::fail>(status.error()); } if (!std::isfinite(gap) || gap < 0.0F) { return luma::detail::invalid>("column gap must be finite and non-negative"); } return modulus::success(std::unique_ptr{std::make_unique(luma::direction::COLUMN, std::move(children), gap, align)}); } auto luma::stack(std::expected>, modulus::error> children) -> std::expected, modulus::error> { if (!children) { return modulus::fail>(children.error()); } return luma::stack(std::move(*children)); } auto luma::stack(std::vector> children) -> std::expected, modulus::error> { if (auto status = luma::detail::validate_children(children); !status) { return modulus::fail>(status.error()); } return modulus::success(std::unique_ptr{std::make_unique(std::move(children))}); } auto luma::scroll_view(std::expected, modulus::error> child, std::bool_t vertical, std::bool_t horizontal) -> std::expected, modulus::error> { if (!child) { return modulus::fail>(child.error()); } return luma::scroll_view(std::move(*child), vertical, horizontal); } auto luma::scroll_view(std::unique_ptr child, std::bool_t vertical, std::bool_t horizontal) -> std::expected, modulus::error> { if (child == nullptr) { return luma::detail::invalid>("scroll view child must not be null"); } if (!vertical && !horizontal) { return luma::detail::invalid>("scroll view must enable at least one axis"); } return modulus::success(std::unique_ptr{std::make_unique(std::move(child), vertical, horizontal)}); } auto luma::list(std::expected>, modulus::error> children, std::float32_t gap) -> std::expected, modulus::error> { if (!children) { return modulus::fail>(children.error()); } return luma::list(std::move(*children), gap); } auto luma::list(std::vector> children, std::float32_t gap) -> std::expected, modulus::error> { if (!std::isfinite(gap) || gap < 0.0F) { return luma::detail::invalid>("list gap must be finite and non-negative"); } return luma::column(std::move(children), gap, luma::alignment::STRETCH); }