From 31ff17c21abd5321ae104364a8b05c2d27b3ef3b Mon Sep 17 00:00:00 2001 From: shadow cat Date: Fri, 21 Nov 2025 20:18:39 -0500 Subject: [PATCH] hint gaming --- src/core/text/build.rs | 42 ++++++++++++++++++++++++++++-------------- src/core/text/edit.rs | 4 ++-- src/core/text/mod.rs | 14 +++++++++++--- src/layout/color.rs | 1 + src/layout/widget.rs | 16 ++++++++++++++++ 5 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/core/text/build.rs b/src/core/text/build.rs index 778494a..3af2065 100644 --- a/src/core/text/build.rs +++ b/src/core/text/build.rs @@ -1,20 +1,15 @@ use std::marker::{PhantomData, Sized}; - use crate::prelude::*; use cosmic_text::{Attrs, Family, Metrics}; -pub trait TextBuilderOutput: Sized { - type Output; - fn run(ui: &mut Ui, builder: TextBuilder) -> Self::Output; -} - -pub struct TextBuilder { +pub struct TextBuilder { pub content: String, pub attrs: TextAttrs, + pub hint: H, _pd: PhantomData, } -impl 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; @@ -40,29 +35,47 @@ impl TextBuilder { self.attrs.wrap = wrap; self } - pub fn editable(self) -> TextBuilder { + pub fn editable(self) -> TextBuilder { TextBuilder { content: self.content, attrs: self.attrs, + hint: self.hint, _pd: PhantomData, } } } +impl TextBuilder { + pub fn hint, Tag>(self, hint: W) -> TextBuilder { + TextBuilder { + content: self.content, + attrs: self.attrs, + hint: move |ui: &mut Ui| Some(hint.add(ui).any()), + _pd: PhantomData, + } + } +} + +pub trait TextBuilderOutput: Sized { + type Output; + fn run(ui: &mut Ui, builder: TextBuilder) -> Self::Output; +} + pub struct TextOutput; impl TextBuilderOutput for TextOutput { type Output = Text; - fn run(ui: &mut Ui, builder: TextBuilder) -> Self::Output { + fn run(ui: &mut Ui, builder: TextBuilder) -> Self::Output { let mut buf = TextBuffer::new_empty(Metrics::new( builder.attrs.font_size, builder.attrs.line_height, )); + let hint = builder.hint.get(ui); let font_system = &mut ui.data.text.font_system; buf.set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None); let mut text = Text { content: builder.content.into(), - view: TextView::new(buf, builder.attrs), + view: TextView::new(buf, builder.attrs, hint), }; text.content.changed = false; builder.attrs.apply(font_system, &mut text.view.buf, None); @@ -74,13 +87,13 @@ pub struct TextEditOutput; impl TextBuilderOutput for TextEditOutput { type Output = TextEdit; - fn run(ui: &mut Ui, builder: TextBuilder) -> Self::Output { + fn run(ui: &mut Ui, builder: TextBuilder) -> Self::Output { let buf = TextBuffer::new_empty(Metrics::new( builder.attrs.font_size, builder.attrs.line_height, )); let mut text = TextEdit { - view: TextView::new(buf, builder.attrs), + view: TextView::new(buf, builder.attrs, builder.hint.get(ui)), cursor: None, }; let font_system = &mut ui.data.text.font_system; @@ -91,7 +104,7 @@ impl TextBuilderOutput for TextEditOutput { } } -impl FnOnce<(&mut Ui,)> for TextBuilder { +impl FnOnce<(&mut Ui,)> for TextBuilder { type Output = O::Output; extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output { @@ -103,6 +116,7 @@ pub fn text(content: impl Into) -> TextBuilder { TextBuilder { content: content.into(), attrs: TextAttrs::default(), + hint: (), _pd: PhantomData, } } diff --git a/src/core/text/edit.rs b/src/core/text/edit.rs index ad8985b..88eea86 100644 --- a/src/core/text/edit.rs +++ b/src/core/text/edit.rs @@ -47,11 +47,11 @@ impl Widget for TextEdit { } fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { - Len::abs(self.view.render(ctx).size.x) + self.view.desired_width(ctx) } fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { - Len::abs(self.view.render(ctx).size.y) + self.view.desired_height(ctx) } } diff --git a/src/core/text/mod.rs b/src/core/text/mod.rs index d32a439..6484b78 100644 --- a/src/core/text/mod.rs +++ b/src/core/text/mod.rs @@ -21,18 +21,20 @@ pub struct TextView { // cache tex: Option, width: Option, + pub hint: Option, } impl TextView { - pub fn new(buf: TextBuffer, attrs: TextAttrs) -> Self { + pub fn new(buf: TextBuffer, attrs: TextAttrs, hint: Option) -> Self { Self { attrs: attrs.into(), buf: buf.into(), tex: None, width: None, + hint, } } - pub fn render(&mut self, ctx: &mut SizeCtx) -> RenderedText { + fn render(&mut self, ctx: &mut SizeCtx) -> RenderedText { let width = if self.attrs.wrap { Some(ctx.px_size().x) } else { @@ -71,6 +73,12 @@ impl TextView { let mut region = region.offset(tex.top_left_offset); region.x.end = region.x.start + UiScalar::abs(dims.x); region.y.end = region.y.start + UiScalar::abs(dims.y); + if let Some(hint) = &self.hint + && let [line] = &self.buf.lines[..] + && line.text().is_empty() + { + painter.widget(hint); + } painter.texture_within(&tex.handle, region); region } @@ -82,7 +90,7 @@ impl Text { let buf = TextBuffer::new_empty(Metrics::new(attrs.font_size, attrs.line_height)); Self { content: content.into().into(), - view: TextView::new(buf, attrs), + view: TextView::new(buf, attrs, None), } } fn update_buf(&mut self, ctx: &mut SizeCtx) { diff --git a/src/layout/color.rs b/src/layout/color.rs index 0b94b09..345ef0c 100644 --- a/src/layout/color.rs +++ b/src/layout/color.rs @@ -13,6 +13,7 @@ pub struct Color { impl Color { pub const BLACK: Self = Self::rgb(T::MIN, T::MIN, T::MIN); pub const WHITE: Self = Self::rgb(T::MAX, T::MAX, T::MAX); + pub const GRAY: Self = Self::rgb(T::MID, T::MID, T::MID); pub const RED: Self = Self::rgb(T::MAX, T::MIN, T::MIN); pub const ORANGE: Self = Self::rgb(T::MAX, T::MID, T::MIN); diff --git a/src/layout/widget.rs b/src/layout/widget.rs index 204afa7..a8d5d02 100644 --- a/src/layout/widget.rs +++ b/src/layout/widget.rs @@ -135,3 +135,19 @@ impl_widget_arr!(9;A B C D E F G H I); impl_widget_arr!(10;A B C D E F G H I J); impl_widget_arr!(11;A B C D E F G H I J K); impl_widget_arr!(12;A B C D E F G H I J K L); + +pub trait WidgetOption { + fn get(self, ui: &mut Ui) -> Option; +} + +impl WidgetOption for () { + fn get(self, _: &mut Ui) -> Option { + None + } +} + +impl Option> WidgetOption for F { + fn get(self, ui: &mut Ui) -> Option { + self(ui) + } +}