stuff
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user