diff --git a/src/core/position/span.rs b/src/core/position/span.rs index 4c5bcda..0e3d53d 100644 --- a/src/core/position/span.rs +++ b/src/core/position/span.rs @@ -180,3 +180,17 @@ impl, Tag> SpanBuilder; + + fn deref(&self) -> &Self::Target { + &self.children + } +} + +impl std::ops::DerefMut for Span { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.children + } +} diff --git a/src/core/text/build.rs b/src/core/text/build.rs index 8337093..ac4468c 100644 --- a/src/core/text/build.rs +++ b/src/core/text/build.rs @@ -12,7 +12,7 @@ pub struct TextBuilder { impl TextBuilder { pub fn size(mut self, size: impl UiNum) -> Self { self.attrs.font_size = size.to_f32(); - self.attrs.line_height = self.attrs.font_size * 1.1; + self.attrs.line_height = self.attrs.font_size * LINE_HEIGHT_MULT; self } pub fn color(mut self, color: UiColor) -> Self { @@ -31,6 +31,10 @@ impl TextBuilder { self.attrs.align = align.into(); self } + pub fn center_text(mut self) -> Self { + self.attrs.align = Align::CENTER; + self + } pub fn wrap(mut self, wrap: bool) -> Self { self.attrs.wrap = wrap; self diff --git a/src/core/trait_fns.rs b/src/core/trait_fns.rs index a9b4003..f3cb5c2 100644 --- a/src/core/trait_fns.rs +++ b/src/core/trait_fns.rs @@ -1,6 +1,9 @@ use super::*; use crate::prelude::*; +// these methods should "not require any context" (require unit) because they're in core +event_ctx!(()); + pub trait CoreWidget { fn pad(self, padding: impl Into) -> impl WidgetFn; fn align(self, align: impl Into) -> impl WidgetFn; @@ -100,8 +103,6 @@ impl, Tag> CoreWidget for W { } fn scroll(self) -> impl WidgetIdFn { - event_ctx!(()); - move |ui| { Scroll::new(self.add(ui).any(), Axis::Y) .on(CursorSense::Scroll, |ctx| { diff --git a/src/layout/event.rs b/src/layout/event.rs index a17ed76..4ea16ac 100644 --- a/src/layout/event.rs +++ b/src/layout/event.rs @@ -30,6 +30,7 @@ impl) + 'static, Ctx, Data> EventFn for F { pub trait WidgetEventFn: Fn(EventIdCtx) + 'static {} impl) + 'static, Ctx, Data, W> WidgetEventFn for F {} +// TODO: naming in here is a bit weird like eventable #[macro_export] macro_rules! event_ctx { ($ty: ty) => { diff --git a/src/layout/orientation/len.rs b/src/layout/orientation/len.rs index 88d5c17..442cff3 100644 --- a/src/layout/orientation/len.rs +++ b/src/layout/orientation/len.rs @@ -41,6 +41,11 @@ impl Size { y: Len::ZERO, }; + pub const REST: Self = Self { + x: Len::REST, + y: Len::REST, + }; + pub fn abs(v: Vec2) -> Self { Self { x: Len::abs(v.x), @@ -97,6 +102,12 @@ impl Len { rest: 0.0, }; + pub const REST: Self = Self { + abs: 0.0, + rel: 0.0, + rest: 1.0, + }; + pub fn apply_rest(&self) -> UiScalar { UiScalar { rel: self.rel + if self.rest > 0.0 { 1.0 } else { 0.0 }, diff --git a/src/layout/text.rs b/src/layout/text.rs index 424a221..169d166 100644 --- a/src/layout/text.rs +++ b/src/layout/text.rs @@ -63,7 +63,7 @@ impl Default for TextAttrs { Self { color: UiColor::WHITE, font_size: size, - line_height: size * 1.2, + line_height: size * LINE_HEIGHT_MULT, family: Family::SansSerif, wrap: false, align: Align::CENTER_LEFT, @@ -71,6 +71,8 @@ impl Default for TextAttrs { } } +pub const LINE_HEIGHT_MULT: f32 = 1.1; + impl TextData { pub fn draw( &mut self, diff --git a/src/winit/mod.rs b/src/winit/mod.rs index d3b868c..774e3c2 100644 --- a/src/winit/mod.rs +++ b/src/winit/mod.rs @@ -83,23 +83,26 @@ impl AppState for DefaultState { fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) { let Self { ui, - ui_state: ui_data, - app_state: app_data, + ui_state, + app_state, } = self; - let input_changed = ui_data.input.event(&event); - let cursor_state = ui_data.cursor_state().clone(); - let old = ui_data.focus.clone(); + let input_changed = ui_state.input.event(&event); + let cursor_state = ui_state.cursor_state().clone(); + let old = ui_state.focus.clone(); if cursor_state.buttons.left.is_start() { - ui_data.focus = None; + ui_state.focus = None; } if input_changed { - let window_size = ui_data.window_size(); + let window_size = ui_state.window_size(); + // call sensors with all 3 important contexts + // TODO: allow user to specify custom contexts? + // and give them both states in case they need both ui.run_sensors(&mut (), &cursor_state, window_size); - ui.run_sensors(ui_data, &cursor_state, window_size); - ui.run_sensors(app_data, &cursor_state, window_size); + ui.run_sensors(ui_state, &cursor_state, window_size); + ui.run_sensors(app_state, &cursor_state, window_size); } - if old != ui_data.focus + if old != ui_state.focus && let Some(old) = old { ui.text(&old).deselect(); @@ -108,54 +111,54 @@ impl AppState for DefaultState { WindowEvent::CloseRequested => event_loop.exit(), WindowEvent::RedrawRequested => { ui.update(); - ui_data.renderer.update(ui); - ui_data.renderer.draw(); + ui_state.renderer.update(ui); + ui_state.renderer.draw(); } WindowEvent::Resized(size) => { ui.resize((size.width, size.height)); - ui_data.renderer.resize(size) + ui_state.renderer.resize(size) } WindowEvent::KeyboardInput { event, .. } => { - if let Some(sel) = &ui_data.focus + if let Some(sel) = &ui_state.focus && event.state.is_pressed() { let sel = &sel.clone(); let mut text = ui.text(sel); - match text.apply_event(event, &ui_data.input.modifiers) { + match text.apply_event(event, &ui_state.input.modifiers) { TextInputResult::Unfocus => { - ui_data.focus = None; - ui_data.window.set_ime_allowed(false); + ui_state.focus = None; + ui_state.window.set_ime_allowed(false); } TextInputResult::Submit => { - ui.run_event(app_data, sel, Submit, ()); + ui.run_event(app_state, sel, Submit, ()); } TextInputResult::Paste => { - if let Ok(t) = ui_data.clipboard.get_text() { + if let Ok(t) = ui_state.clipboard.get_text() { text.insert(&t); } - ui.run_event(app_data, sel, Edited, ()); + ui.run_event(app_state, sel, Edited, ()); } TextInputResult::Copy(text) => { - if let Err(err) = ui_data.clipboard.set_text(text) { + if let Err(err) = ui_state.clipboard.set_text(text) { eprintln!("failed to copy text to clipboard: {err}") } } TextInputResult::Used => { - ui.run_event(app_data, sel, Edited, ()); + ui.run_event(app_state, sel, Edited, ()); } TextInputResult::Unused => {} } } } WindowEvent::Ime(ime) => { - if let Some(sel) = &ui_data.focus { + if let Some(sel) = &ui_state.focus { let mut text = ui.text(sel); match ime { Ime::Enabled | Ime::Disabled => (), Ime::Preedit(content, _pos) => { // TODO: highlight once that's real - text.replace(ui_data.ime, content); - ui_data.ime = content.chars().count(); + text.replace(ui_state.ime, content); + ui_state.ime = content.chars().count(); } Ime::Commit(content) => { text.insert(content); @@ -165,11 +168,11 @@ impl AppState for DefaultState { } _ => (), } - app_data.window_event(event, ui, ui_data); + app_state.window_event(event, ui, ui_state); if ui.needs_redraw() { - ui_data.renderer.window().request_redraw(); + ui_state.renderer.window().request_redraw(); } - ui_data.input.end_frame(); + ui_state.input.end_frame(); } fn exit(&mut self) {