Min size layout constraints
This commit is contained in:
@@ -11,19 +11,19 @@ use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::iter;
|
||||
use std::time::Instant;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use std::time::Instant;
|
||||
|
||||
use ruin_reactivity::effect;
|
||||
use ruin_runtime::queue_future;
|
||||
use ruin_ui::{
|
||||
Border, Color, CursorIcon, DisplayItem, Edges, Element, ElementId, HitTarget, InteractionTree,
|
||||
KeyboardEvent, KeyboardEventKind, KeyboardKey, LayoutCache, LayoutSnapshot, PlatformEvent,
|
||||
PointerButton, PointerEvent, PointerEventKind, PointerRouter, Quad, RoutedPointerEvent,
|
||||
RoutedPointerEventKind, ScrollbarStyle, TextFontFamily, TextSpan, TextSpanWeight, TextStyle,
|
||||
TextSystem, TextWrap, UiSize, WindowController, WindowSpec, WindowUpdate,
|
||||
layout_snapshot_with_cache,
|
||||
Border, BoxShadow, Color, CursorIcon, DisplayItem, Edges, Element, ElementId, HitTarget,
|
||||
InteractionTree, KeyboardEvent, KeyboardEventKind, KeyboardKey, LayoutCache, LayoutSnapshot,
|
||||
PlatformEvent, PointerButton, PointerEvent, PointerEventKind, PointerRouter, Quad,
|
||||
RoutedPointerEvent, RoutedPointerEventKind, ScrollbarStyle, TextFontFamily, TextSpan,
|
||||
TextSpanWeight, TextStyle, TextSystem, TextWrap, UiSize, WindowController, WindowSpec,
|
||||
WindowUpdate, layout_snapshot_with_cache,
|
||||
};
|
||||
use ruin_ui_platform_wayland::start_wayland_ui;
|
||||
|
||||
@@ -59,6 +59,11 @@ impl Window {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn min_size(mut self, min_width: f32, min_height: f32) -> Self {
|
||||
self.spec = self.spec.min_inner_size(UiSize::new(min_width, min_height));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn base_color(mut self, color: Color) -> Self {
|
||||
self.spec = self.spec.base_color(color);
|
||||
self
|
||||
@@ -169,6 +174,8 @@ impl<M: Mountable> MountedApp<M> {
|
||||
let bindings = Rc::new(RefCell::new(EventBindings::default()));
|
||||
let shortcuts = Rc::new(RefCell::new(Vec::<ShortcutBinding>::new()));
|
||||
let current_title = Rc::new(RefCell::new(None::<String>));
|
||||
let last_min_size = Rc::new(RefCell::new(None::<UiSize>));
|
||||
let explicit_min_size = app_window.spec.min_inner_size;
|
||||
let mut input_state = InputState::new();
|
||||
let mut pointer_router = PointerRouter::new();
|
||||
|
||||
@@ -181,6 +188,7 @@ impl<M: Mountable> MountedApp<M> {
|
||||
let bindings = Rc::clone(&bindings);
|
||||
let shortcuts = Rc::clone(&shortcuts);
|
||||
let current_title = Rc::clone(¤t_title);
|
||||
let last_min_size = Rc::clone(&last_min_size);
|
||||
let root = Rc::clone(&root);
|
||||
let render_state = Rc::clone(&render_state);
|
||||
let text_selection = Rc::clone(&input_state.text_selection);
|
||||
@@ -208,6 +216,7 @@ impl<M: Mountable> MountedApp<M> {
|
||||
let LayoutSnapshot {
|
||||
mut scene,
|
||||
interaction_tree: next_interaction_tree,
|
||||
root_min_size,
|
||||
} = layout_snapshot_with_cache(
|
||||
version,
|
||||
viewport,
|
||||
@@ -216,6 +225,21 @@ impl<M: Mountable> MountedApp<M> {
|
||||
&mut layout_cache.borrow_mut(),
|
||||
);
|
||||
let layout_us = t_layout.elapsed().as_micros();
|
||||
|
||||
// Compute and send min-size hint: max of layout min and explicit window min.
|
||||
let desired_min = UiSize::new(
|
||||
root_min_size
|
||||
.width
|
||||
.max(explicit_min_size.map_or(0.0, |s| s.width)),
|
||||
root_min_size
|
||||
.height
|
||||
.max(explicit_min_size.map_or(0.0, |s| s.height)),
|
||||
);
|
||||
let current_min = *last_min_size.borrow();
|
||||
if current_min != Some(desired_min) {
|
||||
let _ = window.update(WindowUpdate::new().min_inner_size(Some(desired_min)));
|
||||
*last_min_size.borrow_mut() = Some(desired_min);
|
||||
}
|
||||
let effect_us = t_effect.elapsed().as_micros();
|
||||
|
||||
tracing::debug!(
|
||||
@@ -716,6 +740,16 @@ impl IntoBorder for (f32, Color) {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoShadow {
|
||||
fn into_shadow(self) -> BoxShadow;
|
||||
}
|
||||
|
||||
impl IntoShadow for BoxShadow {
|
||||
fn into_shadow(self) -> BoxShadow {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum TextRole {
|
||||
Body,
|
||||
@@ -862,6 +896,25 @@ impl ContainerBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn shadow(mut self, shadow: impl IntoShadow) -> Self {
|
||||
self.element = self.element.shadow(shadow.into_shadow());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn min_width(mut self, min_width: f32) -> Self {
|
||||
self.element = self.element.min_width(min_width);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn min_height(mut self, min_height: f32) -> Self {
|
||||
self.element = self.element.min_height(min_height);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn min_size(self, min_width: f32, min_height: f32) -> Self {
|
||||
self.min_width(min_width).min_height(min_height)
|
||||
}
|
||||
|
||||
pub fn widget_ref<T>(mut self, widget_ref: WidgetRef<T>) -> Self {
|
||||
self.widget_ref = Some(widget_ref.element_id.clone());
|
||||
self
|
||||
@@ -921,6 +974,20 @@ impl ScrollBoxBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn min_width(mut self, min_width: f32) -> Self {
|
||||
self.element = self.element.min_width(min_width);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn min_height(mut self, min_height: f32) -> Self {
|
||||
self.element = self.element.min_height(min_height);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn min_size(self, min_width: f32, min_height: f32) -> Self {
|
||||
self.min_width(min_width).min_height(min_height)
|
||||
}
|
||||
|
||||
pub fn scrollbar_style(mut self, style: ScrollbarStyle) -> Self {
|
||||
self.element = self.element.scrollbar_style(style);
|
||||
self
|
||||
@@ -1121,6 +1188,8 @@ impl TextBuilder {
|
||||
#[derive(Default)]
|
||||
pub struct ButtonBuilder {
|
||||
on_press: Option<PressHandler>,
|
||||
background: Option<Color>,
|
||||
color: Option<Color>,
|
||||
}
|
||||
|
||||
impl ButtonBuilder {
|
||||
@@ -1129,26 +1198,43 @@ impl ButtonBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn background(mut self, color: Color) -> Self {
|
||||
self.background = Some(color);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn color(mut self, color: Color) -> Self {
|
||||
self.color = Some(color);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn children(self, children: impl TextChildren) -> View {
|
||||
let id = allocate_element_id();
|
||||
let label = children.into_text();
|
||||
let view = View::from_element(
|
||||
Element::column()
|
||||
let view = View::from_element({
|
||||
let elt = Element::column()
|
||||
.id(id)
|
||||
.padding(Edges::symmetric(14.0, 10.0))
|
||||
.background(surfaces::interactive())
|
||||
.corner_radius(10.0)
|
||||
.padding(Edges::symmetric(14.0, 10.0));
|
||||
|
||||
let elt = if let Some(background) = self.background {
|
||||
elt.background(background)
|
||||
} else {
|
||||
elt.background(surfaces::interactive())
|
||||
};
|
||||
|
||||
elt.corner_radius(10.0)
|
||||
.cursor(CursorIcon::Pointer)
|
||||
.focusable(true)
|
||||
.child(
|
||||
Element::spans(
|
||||
[TextSpan::new(label).weight(TextSpanWeight::Medium)],
|
||||
TextStyle::new(18.0, colors::text()).with_line_height(21.6),
|
||||
TextStyle::new(18.0, self.color.unwrap_or(colors::text()))
|
||||
.with_line_height(21.6),
|
||||
)
|
||||
.pointer_events(false)
|
||||
.focusable(false),
|
||||
),
|
||||
);
|
||||
)
|
||||
});
|
||||
|
||||
match self.on_press {
|
||||
Some(handler) => view.with_press_handler(id, handler),
|
||||
@@ -1988,8 +2074,9 @@ pub mod prelude {
|
||||
Pending, Ready, Resource, ResourceState, Result, ScrollBoxBuilder, ScrollBoxWidget,
|
||||
Shortcut, ShortcutScope, Signal, TextBuilder, TextChildren, TextRole, TextValue, View,
|
||||
WidgetRef, Window, block, button, colors, column, component, context_provider, provide,
|
||||
row, scroll_box, surfaces, text, use_context, use_effect, use_memo, use_resource, use_shortcut,
|
||||
use_shortcut_with_context, use_signal, use_widget_ref, use_window_title, view,
|
||||
row, scroll_box, surfaces, text, use_context, use_effect, use_memo, use_resource,
|
||||
use_shortcut, use_shortcut_with_context, use_signal, use_widget_ref, use_window_title,
|
||||
view,
|
||||
};
|
||||
pub use ruin_ui::{
|
||||
Border, Color, CursorIcon, Edges, Element, ElementId, InteractionTree, PointerButton,
|
||||
|
||||
Reference in New Issue
Block a user