This commit is contained in:
2025-12-07 00:32:38 -05:00
parent 62aa02847a
commit 38266debb6
7 changed files with 68 additions and 32 deletions

View File

@@ -180,3 +180,17 @@ impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> SpanBuilder<LEN, Wa, Ta
self
}
}
impl std::ops::Deref for Span {
type Target = Vec<WidgetId>;
fn deref(&self) -> &Self::Target {
&self.children
}
}
impl std::ops::DerefMut for Span {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.children
}
}

View File

@@ -12,7 +12,7 @@ pub struct TextBuilder<O = TextOutput, H: WidgetOption = ()> {
impl<O, H: WidgetOption> TextBuilder<O, H> {
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<O, H: WidgetOption> TextBuilder<O, H> {
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

View File

@@ -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<W, Tag> {
fn pad(self, padding: impl Into<Padding>) -> impl WidgetFn<Pad>;
fn align(self, align: impl Into<Align>) -> impl WidgetFn<Aligned>;
@@ -100,8 +103,6 @@ impl<W: WidgetLike<Tag>, Tag> CoreWidget<W::Widget, Tag> for W {
}
fn scroll(self) -> impl WidgetIdFn<Scroll> {
event_ctx!(());
move |ui| {
Scroll::new(self.add(ui).any(), Axis::Y)
.on(CursorSense::Scroll, |ctx| {

View File

@@ -30,6 +30,7 @@ impl<F: Fn(EventCtx<Ctx, Data>) + 'static, Ctx, Data> EventFn<Ctx, Data> for F {
pub trait WidgetEventFn<Ctx, Data, W>: Fn(EventIdCtx<Ctx, Data, W>) + 'static {}
impl<F: Fn(EventIdCtx<Ctx, Data, W>) + 'static, Ctx, Data, W> WidgetEventFn<Ctx, Data, W> for F {}
// TODO: naming in here is a bit weird like eventable
#[macro_export]
macro_rules! event_ctx {
($ty: ty) => {

View File

@@ -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 },

View File

@@ -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,

View File

@@ -83,23 +83,26 @@ impl<State: DefaultAppState> AppState for DefaultState<State> {
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<State: DefaultAppState> AppState for DefaultState<State> {
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<State: DefaultAppState> AppState for DefaultState<State> {
}
_ => (),
}
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) {