Formatting
publish / publish (push) Successful in 15m37s

This commit is contained in:
khodowany
2026-09-14 23:56:06 -05:00
parent 86cf029ad7
commit bb96aaf95d
30 changed files with 1030 additions and 950 deletions
+177 -161
View File
@@ -27,21 +27,21 @@
#include <luma/render.hpp>
#include <luma/theme.hpp>
namespace {
constexpr auto panel_padding = luma::edge_insets{
.left = 8.0F,
.top = 8.0F,
.right = 8.0F,
.bottom = 8.0F
};
.bottom = 8.0F};
constexpr auto scroll_drag_threshold = std::float32_t{6.0F};
class label_control final : public luma::control {
public:
explicit label_control(std::string text);
auto measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size override;
auto draw(luma::draw_context& context, luma::theme const& theme) const -> void override;
auto measure(luma::draw_context &context, luma::theme const &theme, luma::constraints limits) -> luma::size override;
auto draw(luma::draw_context &context, luma::theme const &theme) const -> void override;
private:
std::string text_;
};
@@ -49,9 +49,9 @@ private:
class button_control final : public luma::control {
public:
button_control(std::string text, std::function<void()> on_click);
auto measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size 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 measure(luma::draw_context &context, luma::theme const &theme, luma::constraints limits) -> luma::size 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 focusable() const -> std::bool_t override;
private:
std::string text_;
@@ -62,9 +62,9 @@ private:
class text_field_control final : public luma::control {
public:
explicit text_field_control(std::shared_ptr<luma::text_input_state> input);
auto measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size 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 measure(luma::draw_context &context, luma::theme const &theme, luma::constraints limits) -> luma::size 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;
auto focusable() const -> std::bool_t override;
@@ -81,9 +81,9 @@ class soft_keyboard_control final : public luma::control {
public:
soft_keyboard_control(luma::keyboard_layout layout, std::function<void(std::string)> on_text, std::function<void()> on_enter);
soft_keyboard_control(luma::keyboard_layout layout, std::shared_ptr<luma::text_input_state> input, std::function<void()> on_enter);
auto measure(luma::draw_context&, luma::theme const&, luma::constraints limits) -> luma::size 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 measure(luma::draw_context &, luma::theme const &, luma::constraints limits) -> luma::size 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;
private:
luma::keyboard_layout layout_;
std::function<void(std::string)> on_text_;
@@ -94,10 +94,10 @@ private:
class panel_control final : public luma::control {
public:
explicit panel_control(std::vector<std::unique_ptr<luma::control>> children);
auto measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size override;
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 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:
@@ -107,8 +107,8 @@ private:
class spacer_control final : public luma::control {
public:
explicit spacer_control(luma::size value);
auto measure(luma::draw_context&, luma::theme const&, luma::constraints limits) -> luma::size override;
auto draw(luma::draw_context&, luma::theme const&) const -> void override;
auto measure(luma::draw_context &, luma::theme const &, luma::constraints limits) -> luma::size override;
auto draw(luma::draw_context &, luma::theme const &) const -> void override;
private:
luma::size value_;
};
@@ -116,8 +116,8 @@ private:
class progress_bar_control final : public luma::control {
public:
explicit progress_bar_control(std::float32_t value);
auto measure(luma::draw_context&, luma::theme const&, luma::constraints limits) -> luma::size override;
auto draw(luma::draw_context& context, luma::theme const& theme) const -> void override;
auto measure(luma::draw_context &, luma::theme const &, luma::constraints limits) -> luma::size override;
auto draw(luma::draw_context &context, luma::theme const &theme) const -> void override;
private:
std::float32_t value_;
};
@@ -125,8 +125,8 @@ private:
class image_control final : public luma::control {
public:
image_control(std::shared_ptr<luma::texture> texture, luma::image_fit fit);
auto measure(luma::draw_context&, luma::theme const&, luma::constraints limits) -> luma::size override;
auto draw(luma::draw_context& context, luma::theme const& theme) const -> void override;
auto measure(luma::draw_context &, luma::theme const &, luma::constraints limits) -> luma::size override;
auto draw(luma::draw_context &context, luma::theme const &theme) const -> void override;
private:
std::shared_ptr<luma::texture> texture_;
luma::image_fit fit_;
@@ -135,10 +135,10 @@ private:
class linear_control final : public luma::control {
public:
linear_control(luma::direction direction, std::vector<std::unique_ptr<luma::control>> children, std::float32_t gap, luma::alignment align);
auto measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size override;
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 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:
@@ -152,10 +152,10 @@ private:
class stack_control final : public luma::control {
public:
explicit stack_control(std::vector<std::unique_ptr<luma::control>> children);
auto measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size override;
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 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:
@@ -165,10 +165,10 @@ private:
class scroll_view_control final : public luma::control {
public:
scroll_view_control(std::unique_ptr<luma::control> child, std::bool_t vertical, std::bool_t horizontal);
auto measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size override;
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 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:
@@ -177,7 +177,7 @@ private:
luma::point last{};
std::bool_t child_active{false};
};
auto handle_point(luma::touch_event const& event, luma::touch_point const& point) -> std::bool_t;
auto handle_point(luma::touch_event const &event, luma::touch_point const &point) -> std::bool_t;
auto invalidate_child_measure() -> void;
auto arrange_child() -> void;
auto clamp_offset() -> void;
@@ -202,9 +202,9 @@ auto finite_size(luma::size value) -> std::bool_t {
auto finite_rect(luma::rect value) -> std::bool_t {
return std::isfinite(value.x) && std::isfinite(value.y) && finite_size({
.width = value.width,
.height = value.height,
});
.width = value.width,
.height = value.height,
});
}
auto finite_constraints(luma::constraints value) -> std::bool_t {
@@ -219,11 +219,11 @@ auto same_constraints(luma::constraints left, luma::constraints right) -> std::b
return same_size(left.min, right.min) && same_size(left.max, right.max);
}
auto same_text_style(luma::text_style const& left, luma::text_style const& right) -> std::bool_t {
auto same_text_style(luma::text_style const &left, luma::text_style const &right) -> std::bool_t {
return left.font == right.font && left.size == right.size && left.line_height == right.line_height;
}
auto same_theme_metrics(luma::theme const& left, luma::theme const& right) -> std::bool_t {
auto same_theme_metrics(luma::theme const &left, luma::theme const &right) -> std::bool_t {
return same_text_style(left.body, right.body) && same_text_style(left.title, right.title) && left.radius == right.radius && left.spacing == right.spacing;
}
@@ -232,26 +232,26 @@ auto invalid(std::string message) -> std::expected<VALUE, modulus::error> {
return luma::detail::fail<VALUE>(luma::detail::error_invalid_argument, std::move(message));
}
auto throw_error(modulus::error const& error) -> void {
auto throw_error(modulus::error const &error) -> void {
throw std::runtime_error(error.describe());
}
auto throw_if_failed(std::expected<void, modulus::error> const& status) -> void {
auto throw_if_failed(std::expected<void, modulus::error> const &status) -> void {
if (!status) {
throw_error(status.error());
}
}
auto make_event(luma::touch_event const& event, luma::touch_point point) -> luma::touch_event {
auto make_event(luma::touch_event const &event, luma::touch_point point) -> luma::touch_event {
return {
.points = {point},
.time = event.time,
};
}
auto dispatch_to_children(std::vector<std::unique_ptr<luma::control>>& children, luma::touch_event const& event) -> std::bool_t {
auto dispatch_to_children(std::vector<std::unique_ptr<luma::control>> &children, luma::touch_event const &event) -> std::bool_t {
auto handled = false;
for (auto const& point : event.points) {
for (auto const &point : event.points) {
auto single = make_event(event, point);
for (auto current = children.rbegin(); current != children.rend(); ++current) {
assert(*current != nullptr);
@@ -264,8 +264,8 @@ auto dispatch_to_children(std::vector<std::unique_ptr<luma::control>>& children,
return handled;
}
auto find_point(luma::touch_event const& event, std::int32_t id) -> luma::touch_point const* {
for (auto const& point : event.points) {
auto find_point(luma::touch_event const &event, std::int32_t id) -> luma::touch_point const * {
for (auto const &point : event.points) {
if (point.id == id) {
return &point;
}
@@ -273,8 +273,8 @@ auto find_point(luma::touch_event const& event, std::int32_t id) -> luma::touch_
return nullptr;
}
auto first_point_with_phase(luma::touch_event const& event, luma::touch_phase phase) -> luma::touch_point const* {
for (auto const& point : event.points) {
auto first_point_with_phase(luma::touch_event const &event, luma::touch_phase phase) -> luma::touch_point const * {
for (auto const &point : event.points) {
if (point.phase == phase) {
return &point;
}
@@ -282,8 +282,8 @@ auto first_point_with_phase(luma::touch_event const& event, luma::touch_phase ph
return nullptr;
}
auto first_point_inside(luma::touch_event const& event, luma::rect bounds, luma::touch_phase phase) -> luma::touch_point const* {
for (auto const& point : event.points) {
auto first_point_inside(luma::touch_event const &event, luma::rect bounds, luma::touch_phase phase) -> luma::touch_point const * {
for (auto const &point : event.points) {
if (point.phase == phase && luma::contains(bounds, point.position)) {
return &point;
}
@@ -291,13 +291,13 @@ auto first_point_inside(luma::touch_event const& event, luma::rect bounds, luma:
return nullptr;
}
auto valid_keyboard_layout(luma::keyboard_layout const& layout) -> std::expected<void, modulus::error> {
auto valid_keyboard_layout(luma::keyboard_layout const &layout) -> std::expected<void, modulus::error> {
if (layout.rows.empty()) {
return luma::detail::fail<void>(luma::detail::error_invalid_argument, "keyboard layout must contain at least one row");
}
auto has_key = false;
for (auto const& row : layout.rows) {
for (auto const& key : row) {
for (auto const &row : layout.rows) {
for (auto const &key : row) {
has_key = true;
if (key.label.empty()) {
return luma::detail::fail<void>(luma::detail::error_invalid_argument, "keyboard key label must not be empty");
@@ -310,8 +310,8 @@ auto valid_keyboard_layout(luma::keyboard_layout const& layout) -> std::expected
return {};
}
auto validate_children(std::vector<std::unique_ptr<luma::control>> const& children) -> std::expected<void, modulus::error> {
for (auto const& child : children) {
auto validate_children(std::vector<std::unique_ptr<luma::control>> const &children) -> std::expected<void, modulus::error> {
for (auto const &child : children) {
if (child == nullptr) {
return luma::detail::fail<void>(luma::detail::error_invalid_argument, "child control must not be null");
}
@@ -319,7 +319,7 @@ auto validate_children(std::vector<std::unique_ptr<luma::control>> const& childr
return {};
}
auto centered_text_origin(luma::draw_context& context, std::string const& text, luma::rect bounds, luma::text_style const& style) -> luma::point {
auto centered_text_origin(luma::draw_context &context, std::string const &text, luma::rect bounds, luma::text_style const &style) -> luma::point {
assert(finite_rect(bounds));
auto measured = context.measure_text(text, style);
assert(finite_size(measured));
@@ -359,52 +359,56 @@ auto fit_rect(luma::rect bounds, luma::texture_info info, luma::image_fit fit) -
};
}
label_control::label_control(std::string text) : text_{std::move(text)} {
label_control::label_control(std::string text)
: text_{std::move(text)} {
assert(!text_.empty());
}
auto label_control::measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size {
auto label_control::measure(luma::draw_context &context, luma::theme const &theme, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
auto measured = context.measure_text(text_, theme.body);
assert(finite_size(measured));
return luma::clamp(measured, limits);
}
auto label_control::draw(luma::draw_context& context, luma::theme const& theme) const -> void {
auto label_control::draw(luma::draw_context &context, luma::theme const &theme) const -> void {
assert(!text_.empty());
context.draw_text(text_, {
.x = bounds().x,
.y = bounds().y,
}, theme.body, enabled() ? theme.text : theme.text_muted);
.x = bounds().x,
.y = bounds().y,
},
theme.body, enabled() ? theme.text : theme.text_muted);
}
button_control::button_control(std::string text, std::function<void()> on_click) : text_{std::move(text)}, on_click_{std::move(on_click)} {
button_control::button_control(std::string text, std::function<void()> on_click)
: text_{std::move(text)}, on_click_{std::move(on_click)} {
assert(!text_.empty());
assert(on_click_);
}
auto button_control::measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size {
auto button_control::measure(luma::draw_context &context, luma::theme const &theme, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
auto text_size = context.measure_text(text_, theme.body);
assert(finite_size(text_size));
return luma::clamp({
.width = text_size.width + 32.0F,
.height = std::max(std::float32_t{48}, text_size.height + std::float32_t{16}),
}, limits);
.width = text_size.width + 32.0F,
.height = std::max(std::float32_t{48}, text_size.height + std::float32_t{16}),
},
limits);
}
auto button_control::draw(luma::draw_context& context, luma::theme const& theme) const -> void {
auto button_control::draw(luma::draw_context &context, luma::theme const &theme) const -> void {
auto fill = pressed_id_.has_value() ? theme.surface_active : theme.surface;
context.fill_rect(bounds(), fill);
context.stroke_rect(bounds(), 1.0F, focused() ? theme.accent : theme.border);
context.draw_text(text_, centered_text_origin(context, text_, bounds(), theme.body), theme.body, enabled() ? theme.text : theme.text_muted);
}
auto button_control::handle_touch(luma::touch_event const& event) -> std::bool_t {
auto button_control::handle_touch(luma::touch_event const &event) -> std::bool_t {
if (!enabled()) {
return false;
}
auto const* point = pressed_id_ ? find_point(event, *pressed_id_) : first_point_inside(event, bounds(), luma::touch_phase::DOWN);
auto const *point = pressed_id_ ? find_point(event, *pressed_id_) : first_point_inside(event, bounds(), luma::touch_phase::DOWN);
if (point == nullptr) {
return false;
}
@@ -434,11 +438,12 @@ auto button_control::focusable() const -> std::bool_t {
return true;
}
text_field_control::text_field_control(std::shared_ptr<luma::text_input_state> input) : input_{std::move(input)} {
text_field_control::text_field_control(std::shared_ptr<luma::text_input_state> input)
: input_{std::move(input)} {
assert(input_ != nullptr);
}
auto text_field_control::measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size {
auto text_field_control::measure(luma::draw_context &context, luma::theme const &theme, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
auto version = input_->version();
if (cached_limits_ && cached_style_ && same_constraints(*cached_limits_, limits) && same_text_style(*cached_style_, theme.body) && cached_version_ == version) {
@@ -451,13 +456,14 @@ auto text_field_control::measure(luma::draw_context& context, luma::theme const&
cached_style_ = theme.body;
cached_version_ = version;
cached_size_ = luma::clamp({
.width = std::max(std::float32_t{240}, measured.width + std::float32_t{24}),
.height = std::max(std::float32_t{48}, measured.height + std::float32_t{16}),
}, limits);
.width = std::max(std::float32_t{240}, measured.width + std::float32_t{24}),
.height = std::max(std::float32_t{48}, measured.height + std::float32_t{16}),
},
limits);
return cached_size_;
}
auto text_field_control::draw(luma::draw_context& context, luma::theme const& theme) const -> void {
auto text_field_control::draw(luma::draw_context &context, luma::theme const &theme) const -> void {
context.fill_rect(bounds(), theme.surface);
context.stroke_rect(bounds(), 1.0F, input_->focused() ? theme.accent : theme.border);
auto options = input_->snapshot();
@@ -468,16 +474,17 @@ auto text_field_control::draw(luma::draw_context& context, luma::theme const& th
text = std::string(options.text.size(), '*');
}
context.draw_text(text, {
.x = bounds().x + 12.0F,
.y = bounds().y + 8.0F,
}, theme.body, options.text.empty() ? theme.text_muted : theme.text);
.x = bounds().x + 12.0F,
.y = bounds().y + 8.0F,
},
theme.body, options.text.empty() ? theme.text_muted : theme.text);
}
auto text_field_control::handle_touch(luma::touch_event const& event) -> std::bool_t {
auto text_field_control::handle_touch(luma::touch_event const &event) -> std::bool_t {
if (!enabled()) {
return false;
}
auto const* point = first_point_inside(event, bounds(), luma::touch_phase::DOWN);
auto const *point = first_point_inside(event, bounds(), luma::touch_phase::DOWN);
if (point == nullptr) {
point = first_point_with_phase(event, luma::touch_phase::DOWN);
}
@@ -513,28 +520,31 @@ auto text_field_control::focusable() const -> std::bool_t {
return true;
}
soft_keyboard_control::soft_keyboard_control(luma::keyboard_layout layout, std::function<void(std::string)> on_text, std::function<void()> on_enter) : layout_{std::move(layout)}, on_text_{std::move(on_text)}, on_enter_{std::move(on_enter)} {
soft_keyboard_control::soft_keyboard_control(luma::keyboard_layout layout, std::function<void(std::string)> on_text, std::function<void()> on_enter)
: layout_{std::move(layout)}, on_text_{std::move(on_text)}, on_enter_{std::move(on_enter)} {
assert(!layout_.rows.empty());
assert(on_text_);
}
soft_keyboard_control::soft_keyboard_control(luma::keyboard_layout layout, std::shared_ptr<luma::text_input_state> input, std::function<void()> on_enter) : layout_{std::move(layout)}, on_enter_{std::move(on_enter)}, input_{std::move(input)} {
soft_keyboard_control::soft_keyboard_control(luma::keyboard_layout layout, std::shared_ptr<luma::text_input_state> input, std::function<void()> on_enter)
: layout_{std::move(layout)}, on_enter_{std::move(on_enter)}, input_{std::move(input)} {
assert(!layout_.rows.empty());
assert(input_ != nullptr);
}
auto soft_keyboard_control::measure(luma::draw_context&, luma::theme const&, luma::constraints limits) -> luma::size {
auto soft_keyboard_control::measure(luma::draw_context &, luma::theme const &, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
return luma::clamp({
.width = 640.0F,
.height = static_cast<std::float32_t>(layout_.rows.size()) * 56.0F,
}, limits);
.width = 640.0F,
.height = static_cast<std::float32_t>(layout_.rows.size()) * 56.0F,
},
limits);
}
auto soft_keyboard_control::draw(luma::draw_context& context, luma::theme const& theme) const -> void {
auto soft_keyboard_control::draw(luma::draw_context &context, luma::theme const &theme) const -> void {
auto key_height = bounds().height / static_cast<std::float32_t>(layout_.rows.size());
for (auto row_index = std::size_t{}; row_index < layout_.rows.size(); ++row_index) {
auto const& row = layout_.rows[row_index];
auto const &row = layout_.rows[row_index];
if (row.empty()) {
continue;
}
@@ -549,27 +559,28 @@ auto soft_keyboard_control::draw(luma::draw_context& context, luma::theme const&
context.fill_rect(rect, theme.surface);
context.stroke_rect(rect, 1.0F, theme.border);
context.draw_text(row[column_index].label, {
.x = rect.x + 12.0F,
.y = rect.y + 10.0F,
}, theme.body, theme.text);
.x = rect.x + 12.0F,
.y = rect.y + 10.0F,
},
theme.body, theme.text);
}
}
}
auto soft_keyboard_control::handle_touch(luma::touch_event const& event) -> std::bool_t {
auto const* point = first_point_inside(event, bounds(), luma::touch_phase::UP);
auto soft_keyboard_control::handle_touch(luma::touch_event const &event) -> std::bool_t {
auto const *point = first_point_inside(event, bounds(), luma::touch_phase::UP);
if (point == nullptr) {
return false;
}
auto row_count = layout_.rows.size();
assert(row_count > 0);
auto row_index = std::min(row_count - 1, static_cast<std::size_t>((point->position.y - bounds().y) / (bounds().height / static_cast<std::float32_t>(row_count))));
auto const& row = layout_.rows[row_index];
auto const &row = layout_.rows[row_index];
if (row.empty()) {
return true;
}
auto column_index = std::min(row.size() - 1, static_cast<std::size_t>((point->position.x - bounds().x) / (bounds().width / static_cast<std::float32_t>(row.size()))));
auto const& key = row[column_index];
auto const &key = row[column_index];
switch (key.kind) {
case luma::keyboard_key_kind::CHARACTER:
if (input_) {
@@ -604,13 +615,14 @@ auto soft_keyboard_control::handle_touch(luma::touch_event const& event) -> std:
return true;
}
panel_control::panel_control(std::vector<std::unique_ptr<luma::control>> children) : children_{std::move(children)} {}
panel_control::panel_control(std::vector<std::unique_ptr<luma::control>> children)
: children_{std::move(children)} {}
auto panel_control::measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size {
auto panel_control::measure(luma::draw_context &context, luma::theme const &theme, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
auto child_limits = luma::deflate(limits, panel_padding);
auto result = child_limits.min;
for (auto& child : children_) {
for (auto &child : children_) {
assert(child != nullptr);
auto measured = child->measure(context, theme, child_limits);
result.width = std::max(result.width, measured.width);
@@ -625,26 +637,26 @@ auto panel_control::arrange(luma::rect bounds) -> void {
assert(finite_rect(bounds));
luma::control::arrange(bounds);
auto content = luma::inset(bounds, panel_padding);
for (auto& child : children_) {
for (auto &child : children_) {
assert(child != nullptr);
child->arrange(content);
}
}
auto panel_control::draw(luma::draw_context& context, luma::theme const& theme) const -> void {
auto panel_control::draw(luma::draw_context &context, luma::theme const &theme) const -> void {
context.fill_rect(bounds(), theme.surface);
for (auto const& child : children_) {
for (auto const &child : children_) {
assert(child != nullptr);
child->draw(context, theme);
}
}
auto panel_control::handle_touch(luma::touch_event const& event) -> std::bool_t {
auto panel_control::handle_touch(luma::touch_event const &event) -> std::bool_t {
return dispatch_to_children(children_, event);
}
auto panel_control::invalidate_layout() -> void {
for (auto& child : children_) {
for (auto &child : children_) {
assert(child != nullptr);
child->invalidate_layout();
}
@@ -652,62 +664,68 @@ auto panel_control::invalidate_layout() -> void {
auto panel_control::bind_layout_invalidator(std::function<void()> invalidator) -> void {
luma::control::bind_layout_invalidator(invalidator);
for (auto& child : children_) {
for (auto &child : children_) {
assert(child != nullptr);
child->bind_layout_invalidator(invalidator);
}
}
spacer_control::spacer_control(luma::size value) : value_{value} {
spacer_control::spacer_control(luma::size value)
: value_{value} {
assert(finite_size(value_));
}
auto spacer_control::measure(luma::draw_context&, luma::theme const&, luma::constraints limits) -> luma::size {
auto spacer_control::measure(luma::draw_context &, luma::theme const &, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
return luma::clamp(value_, limits);
}
auto spacer_control::draw(luma::draw_context&, luma::theme const&) const -> void {}
auto spacer_control::draw(luma::draw_context &, luma::theme const &) const -> void {}
progress_bar_control::progress_bar_control(std::float32_t value) : value_{std::clamp(value, std::float32_t{}, std::float32_t{1})} {
progress_bar_control::progress_bar_control(std::float32_t value)
: value_{std::clamp(value, std::float32_t{}, std::float32_t{1})} {
assert(std::isfinite(value));
}
auto progress_bar_control::measure(luma::draw_context&, luma::theme const&, luma::constraints limits) -> luma::size {
auto progress_bar_control::measure(luma::draw_context &, luma::theme const &, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
return luma::clamp({
.width = 160.0F,
.height = 16.0F,
}, limits);
.width = 160.0F,
.height = 16.0F,
},
limits);
}
auto progress_bar_control::draw(luma::draw_context& context, luma::theme const& theme) const -> void {
auto progress_bar_control::draw(luma::draw_context &context, luma::theme const &theme) const -> void {
context.fill_rect(bounds(), theme.surface);
context.fill_rect({
.x = bounds().x,
.y = bounds().y,
.width = bounds().width * value_,
.height = bounds().height,
}, theme.accent);
.x = bounds().x,
.y = bounds().y,
.width = bounds().width * value_,
.height = bounds().height,
},
theme.accent);
}
image_control::image_control(std::shared_ptr<luma::texture> texture, luma::image_fit fit) : texture_{std::move(texture)}, fit_{fit} {
image_control::image_control(std::shared_ptr<luma::texture> texture, luma::image_fit fit)
: texture_{std::move(texture)}, fit_{fit} {
assert(texture_ != nullptr);
}
auto image_control::measure(luma::draw_context&, luma::theme const&, luma::constraints limits) -> luma::size {
auto image_control::measure(luma::draw_context &, luma::theme const &, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
auto info = texture_->info();
if (info.width <= 0 || info.height <= 0) {
return luma::clamp({}, limits);
}
return luma::clamp({
.width = static_cast<std::float32_t>(info.width),
.height = static_cast<std::float32_t>(info.height),
}, limits);
.width = static_cast<std::float32_t>(info.width),
.height = static_cast<std::float32_t>(info.height),
},
limits);
}
auto image_control::draw(luma::draw_context& context, luma::theme const& theme) const -> void {
auto image_control::draw(luma::draw_context &context, luma::theme const &theme) const -> void {
auto info = texture_->info();
if (info.width <= 0 || info.height <= 0) {
return;
@@ -721,18 +739,19 @@ auto image_control::draw(luma::draw_context& context, luma::theme const& theme)
context.draw_texture(*texture_, source, fit_rect(bounds(), info, fit_), theme.text);
}
linear_control::linear_control(luma::direction direction, std::vector<std::unique_ptr<luma::control>> children, std::float32_t gap, luma::alignment align) : direction_{direction}, children_{std::move(children)}, gap_{gap}, align_{align} {
linear_control::linear_control(luma::direction direction, std::vector<std::unique_ptr<luma::control>> children, std::float32_t gap, luma::alignment align)
: direction_{direction}, children_{std::move(children)}, gap_{gap}, align_{align} {
assert(std::isfinite(gap_));
assert(gap_ >= 0.0F);
}
auto linear_control::measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size {
auto linear_control::measure(luma::draw_context &context, luma::theme const &theme, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
measured_.clear();
measured_.reserve(children_.size());
auto result = luma::size{};
for (auto index = std::size_t{}; index < children_.size(); ++index) {
auto& child = children_[index];
auto &child = children_[index];
assert(child != nullptr);
auto child_limits = limits;
if (direction_ == luma::direction::ROW) {
@@ -762,7 +781,7 @@ auto linear_control::arrange(luma::rect bounds) -> void {
luma::control::arrange(bounds);
auto cursor = direction_ == luma::direction::ROW ? bounds.x : bounds.y;
for (auto index = std::size_t{}; index < children_.size(); ++index) {
auto& child = children_[index];
auto &child = children_[index];
assert(child != nullptr);
auto measured = index < measured_.size() ? measured_[index] : luma::size{};
auto child_bounds = bounds;
@@ -791,20 +810,20 @@ auto linear_control::arrange(luma::rect bounds) -> void {
}
}
auto linear_control::draw(luma::draw_context& context, luma::theme const& theme) const -> void {
for (auto const& child : children_) {
auto linear_control::draw(luma::draw_context &context, luma::theme const &theme) const -> void {
for (auto const &child : children_) {
assert(child != nullptr);
child->draw(context, theme);
}
}
auto linear_control::handle_touch(luma::touch_event const& event) -> std::bool_t {
auto linear_control::handle_touch(luma::touch_event const &event) -> std::bool_t {
return dispatch_to_children(children_, event);
}
auto linear_control::invalidate_layout() -> void {
measured_.clear();
for (auto& child : children_) {
for (auto &child : children_) {
assert(child != nullptr);
child->invalidate_layout();
}
@@ -812,19 +831,19 @@ auto linear_control::invalidate_layout() -> void {
auto linear_control::bind_layout_invalidator(std::function<void()> invalidator) -> void {
luma::control::bind_layout_invalidator(invalidator);
for (auto& child : children_) {
for (auto &child : children_) {
assert(child != nullptr);
child->bind_layout_invalidator(invalidator);
}
}
stack_control::stack_control(std::vector<std::unique_ptr<luma::control>> children)
: children_{std::move(children)} {}
stack_control::stack_control(std::vector<std::unique_ptr<luma::control>> children) : children_{std::move(children)} {}
auto stack_control::measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size {
auto stack_control::measure(luma::draw_context &context, luma::theme const &theme, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
auto result = limits.min;
for (auto& child : children_) {
for (auto &child : children_) {
assert(child != nullptr);
auto measured = child->measure(context, theme, limits);
result.width = std::max(result.width, measured.width);
@@ -836,25 +855,25 @@ auto stack_control::measure(luma::draw_context& context, luma::theme const& them
auto stack_control::arrange(luma::rect bounds) -> void {
assert(finite_rect(bounds));
luma::control::arrange(bounds);
for (auto& child : children_) {
for (auto &child : children_) {
assert(child != nullptr);
child->arrange(bounds);
}
}
auto stack_control::draw(luma::draw_context& context, luma::theme const& theme) const -> void {
for (auto const& child : children_) {
auto stack_control::draw(luma::draw_context &context, luma::theme const &theme) const -> void {
for (auto const &child : children_) {
assert(child != nullptr);
child->draw(context, theme);
}
}
auto stack_control::handle_touch(luma::touch_event const& event) -> std::bool_t {
auto stack_control::handle_touch(luma::touch_event const &event) -> std::bool_t {
return dispatch_to_children(children_, event);
}
auto stack_control::invalidate_layout() -> void {
for (auto& child : children_) {
for (auto &child : children_) {
assert(child != nullptr);
child->invalidate_layout();
}
@@ -862,19 +881,19 @@ auto stack_control::invalidate_layout() -> void {
auto stack_control::bind_layout_invalidator(std::function<void()> invalidator) -> void {
luma::control::bind_layout_invalidator(invalidator);
for (auto& child : children_) {
for (auto &child : children_) {
assert(child != nullptr);
child->bind_layout_invalidator(invalidator);
}
}
scroll_view_control::scroll_view_control(std::unique_ptr<luma::control> child, std::bool_t vertical, std::bool_t horizontal) : child_{std::move(child)}, vertical_{vertical}, horizontal_{horizontal} {
scroll_view_control::scroll_view_control(std::unique_ptr<luma::control> child, std::bool_t vertical, std::bool_t horizontal)
: child_{std::move(child)}, vertical_{vertical}, horizontal_{horizontal} {
assert(child_ != nullptr);
assert(vertical_ || horizontal_);
}
auto scroll_view_control::measure(luma::draw_context& context, luma::theme const& theme, luma::constraints limits) -> luma::size {
auto scroll_view_control::measure(luma::draw_context &context, luma::theme const &theme, luma::constraints limits) -> luma::size {
assert(finite_constraints(limits));
auto max = std::numeric_limits<std::float32_t>::max();
auto child_limits = luma::constraints{
@@ -903,21 +922,21 @@ auto scroll_view_control::arrange(luma::rect bounds) -> void {
arrange_child();
}
auto scroll_view_control::draw(luma::draw_context& context, luma::theme const& theme) const -> void {
auto scroll_view_control::draw(luma::draw_context &context, luma::theme const &theme) const -> void {
context.push_clip(bounds());
child_->draw(context, theme);
context.pop_clip();
}
auto scroll_view_control::handle_touch(luma::touch_event const& event) -> std::bool_t {
auto scroll_view_control::handle_touch(luma::touch_event const &event) -> std::bool_t {
auto handled = false;
for (auto const& point : event.points) {
for (auto const &point : event.points) {
handled = handle_point(event, point) || handled;
}
return handled;
}
auto scroll_view_control::handle_point(luma::touch_event const& event, luma::touch_point const& point) -> std::bool_t {
auto scroll_view_control::handle_point(luma::touch_event const &event, luma::touch_point const &point) -> std::bool_t {
if (point.phase == luma::touch_phase::DOWN) {
if (!luma::contains(bounds(), point.position)) {
return false;
@@ -938,13 +957,11 @@ auto scroll_view_control::handle_point(luma::touch_event const& event, luma::tou
}
return true;
}
auto found = touches_.find(point.id);
if (found == touches_.end()) {
return false;
}
auto& state = found->second;
auto &state = found->second;
if (point.phase == luma::touch_phase::MOVE) {
auto delta = luma::point{
.x = point.position.x - state.last.x,
@@ -994,7 +1011,6 @@ auto scroll_view_control::handle_point(luma::touch_event const& event, luma::tou
}
return true;
}
if (point.phase == luma::touch_phase::UP || point.phase == luma::touch_phase::CANCEL) {
auto const scrolling = scroll_id_ == point.id && dragging_;
if (state.child_active) {
@@ -1015,7 +1031,6 @@ auto scroll_view_control::handle_point(luma::touch_event const& event, luma::tou
touches_.erase(found);
return true;
}
return true;
}
@@ -1073,7 +1088,7 @@ auto accepts_text(luma::text_input_mode mode, std::string_view current, std::str
return true;
}
auto validate_text_options(luma::text_field_options const& options) -> std::expected<void, modulus::error> {
auto validate_text_options(luma::text_field_options const &options) -> std::expected<void, modulus::error> {
if (options.max_length == 0) {
return luma::detail::fail<void>(luma::detail::error_invalid_argument, "text field max length must be positive");
}
@@ -1090,13 +1105,13 @@ auto callback_failure(std::string message) -> std::expected<void, modulus::error
return luma::detail::fail<void>(luma::detail::error_internal, std::move(message));
}
auto notify_text_changed(std::function<void(std::string)> const& callback, std::string value) -> std::expected<void, modulus::error> {
auto notify_text_changed(std::function<void(std::string)> const &callback, std::string value) -> std::expected<void, modulus::error> {
if (!callback) {
return {};
}
try {
callback(std::move(value));
} catch (std::exception const& error) {
} catch (std::exception const &error) {
return callback_failure(std::string{"text change callback failed: "} + error.what());
} catch (...) {
return callback_failure("text change callback failed with an unknown exception");
@@ -1104,8 +1119,8 @@ auto notify_text_changed(std::function<void(std::string)> const& callback, std::
return {};
}
auto notify_layout_listeners(std::vector<std::function<void()>> const& listeners) -> void {
for (auto const& listener : listeners) {
auto notify_layout_listeners(std::vector<std::function<void()>> const &listeners) -> void {
for (auto const &listener : listeners) {
if (!listener) {
continue;
}
@@ -1116,7 +1131,7 @@ auto notify_layout_listeners(std::vector<std::function<void()>> const& listeners
}
}
auto collect_layout_listeners(std::vector<luma::text_input_state::layout_listener>& listeners) -> std::vector<std::function<void()>> {
auto collect_layout_listeners(std::vector<luma::text_input_state::layout_listener> &listeners) -> std::vector<std::function<void()>> {
auto callbacks = std::vector<std::function<void()>>{};
auto write = listeners.begin();
for (auto read = listeners.begin(); read != listeners.end(); ++read) {
@@ -1135,7 +1150,8 @@ auto collect_layout_listeners(std::vector<luma::text_input_state::layout_listene
}
luma::text_input_state::text_input_state(luma::text_field_options options, std::function<void(std::string)> on_change) : options_{std::move(options)}, on_change_{std::move(on_change)} {
luma::text_input_state::text_input_state(luma::text_field_options options, std::function<void(std::string)> on_change)
: options_{std::move(options)}, on_change_{std::move(on_change)} {
assert(options_.max_length > 0);
assert(on_change_);
}