stuff
This commit is contained in:
@@ -180,3 +180,17 @@ impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> SpanBuilder<LEN, Wa, Ta
|
|||||||
self
|
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> {
|
impl<O, H: WidgetOption> TextBuilder<O, H> {
|
||||||
pub fn size(mut self, size: impl UiNum) -> Self {
|
pub fn size(mut self, size: impl UiNum) -> Self {
|
||||||
self.attrs.font_size = size.to_f32();
|
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
|
self
|
||||||
}
|
}
|
||||||
pub fn color(mut self, color: UiColor) -> 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.attrs.align = align.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
pub fn center_text(mut self) -> Self {
|
||||||
|
self.attrs.align = Align::CENTER;
|
||||||
|
self
|
||||||
|
}
|
||||||
pub fn wrap(mut self, wrap: bool) -> Self {
|
pub fn wrap(mut self, wrap: bool) -> Self {
|
||||||
self.attrs.wrap = wrap;
|
self.attrs.wrap = wrap;
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
// these methods should "not require any context" (require unit) because they're in core
|
||||||
|
event_ctx!(());
|
||||||
|
|
||||||
pub trait CoreWidget<W, Tag> {
|
pub trait CoreWidget<W, Tag> {
|
||||||
fn pad(self, padding: impl Into<Padding>) -> impl WidgetFn<Pad>;
|
fn pad(self, padding: impl Into<Padding>) -> impl WidgetFn<Pad>;
|
||||||
fn align(self, align: impl Into<Align>) -> impl WidgetFn<Aligned>;
|
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> {
|
fn scroll(self) -> impl WidgetIdFn<Scroll> {
|
||||||
event_ctx!(());
|
|
||||||
|
|
||||||
move |ui| {
|
move |ui| {
|
||||||
Scroll::new(self.add(ui).any(), Axis::Y)
|
Scroll::new(self.add(ui).any(), Axis::Y)
|
||||||
.on(CursorSense::Scroll, |ctx| {
|
.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 {}
|
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 {}
|
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_export]
|
||||||
macro_rules! event_ctx {
|
macro_rules! event_ctx {
|
||||||
($ty: ty) => {
|
($ty: ty) => {
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ impl Size {
|
|||||||
y: Len::ZERO,
|
y: Len::ZERO,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const REST: Self = Self {
|
||||||
|
x: Len::REST,
|
||||||
|
y: Len::REST,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn abs(v: Vec2) -> Self {
|
pub fn abs(v: Vec2) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: Len::abs(v.x),
|
x: Len::abs(v.x),
|
||||||
@@ -97,6 +102,12 @@ impl Len {
|
|||||||
rest: 0.0,
|
rest: 0.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const REST: Self = Self {
|
||||||
|
abs: 0.0,
|
||||||
|
rel: 0.0,
|
||||||
|
rest: 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn apply_rest(&self) -> UiScalar {
|
pub fn apply_rest(&self) -> UiScalar {
|
||||||
UiScalar {
|
UiScalar {
|
||||||
rel: self.rel + if self.rest > 0.0 { 1.0 } else { 0.0 },
|
rel: self.rel + if self.rest > 0.0 { 1.0 } else { 0.0 },
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ impl Default for TextAttrs {
|
|||||||
Self {
|
Self {
|
||||||
color: UiColor::WHITE,
|
color: UiColor::WHITE,
|
||||||
font_size: size,
|
font_size: size,
|
||||||
line_height: size * 1.2,
|
line_height: size * LINE_HEIGHT_MULT,
|
||||||
family: Family::SansSerif,
|
family: Family::SansSerif,
|
||||||
wrap: false,
|
wrap: false,
|
||||||
align: Align::CENTER_LEFT,
|
align: Align::CENTER_LEFT,
|
||||||
@@ -71,6 +71,8 @@ impl Default for TextAttrs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const LINE_HEIGHT_MULT: f32 = 1.1;
|
||||||
|
|
||||||
impl TextData {
|
impl TextData {
|
||||||
pub fn draw(
|
pub fn draw(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
@@ -83,23 +83,26 @@ impl<State: DefaultAppState> AppState for DefaultState<State> {
|
|||||||
fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) {
|
fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) {
|
||||||
let Self {
|
let Self {
|
||||||
ui,
|
ui,
|
||||||
ui_state: ui_data,
|
ui_state,
|
||||||
app_state: app_data,
|
app_state,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let input_changed = ui_data.input.event(&event);
|
let input_changed = ui_state.input.event(&event);
|
||||||
let cursor_state = ui_data.cursor_state().clone();
|
let cursor_state = ui_state.cursor_state().clone();
|
||||||
let old = ui_data.focus.clone();
|
let old = ui_state.focus.clone();
|
||||||
if cursor_state.buttons.left.is_start() {
|
if cursor_state.buttons.left.is_start() {
|
||||||
ui_data.focus = None;
|
ui_state.focus = None;
|
||||||
}
|
}
|
||||||
if input_changed {
|
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(&mut (), &cursor_state, window_size);
|
||||||
ui.run_sensors(ui_data, &cursor_state, window_size);
|
ui.run_sensors(ui_state, &cursor_state, window_size);
|
||||||
ui.run_sensors(app_data, &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
|
&& let Some(old) = old
|
||||||
{
|
{
|
||||||
ui.text(&old).deselect();
|
ui.text(&old).deselect();
|
||||||
@@ -108,54 +111,54 @@ impl<State: DefaultAppState> AppState for DefaultState<State> {
|
|||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
ui.update();
|
ui.update();
|
||||||
ui_data.renderer.update(ui);
|
ui_state.renderer.update(ui);
|
||||||
ui_data.renderer.draw();
|
ui_state.renderer.draw();
|
||||||
}
|
}
|
||||||
WindowEvent::Resized(size) => {
|
WindowEvent::Resized(size) => {
|
||||||
ui.resize((size.width, size.height));
|
ui.resize((size.width, size.height));
|
||||||
ui_data.renderer.resize(size)
|
ui_state.renderer.resize(size)
|
||||||
}
|
}
|
||||||
WindowEvent::KeyboardInput { event, .. } => {
|
WindowEvent::KeyboardInput { event, .. } => {
|
||||||
if let Some(sel) = &ui_data.focus
|
if let Some(sel) = &ui_state.focus
|
||||||
&& event.state.is_pressed()
|
&& event.state.is_pressed()
|
||||||
{
|
{
|
||||||
let sel = &sel.clone();
|
let sel = &sel.clone();
|
||||||
let mut text = ui.text(sel);
|
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 => {
|
TextInputResult::Unfocus => {
|
||||||
ui_data.focus = None;
|
ui_state.focus = None;
|
||||||
ui_data.window.set_ime_allowed(false);
|
ui_state.window.set_ime_allowed(false);
|
||||||
}
|
}
|
||||||
TextInputResult::Submit => {
|
TextInputResult::Submit => {
|
||||||
ui.run_event(app_data, sel, Submit, ());
|
ui.run_event(app_state, sel, Submit, ());
|
||||||
}
|
}
|
||||||
TextInputResult::Paste => {
|
TextInputResult::Paste => {
|
||||||
if let Ok(t) = ui_data.clipboard.get_text() {
|
if let Ok(t) = ui_state.clipboard.get_text() {
|
||||||
text.insert(&t);
|
text.insert(&t);
|
||||||
}
|
}
|
||||||
ui.run_event(app_data, sel, Edited, ());
|
ui.run_event(app_state, sel, Edited, ());
|
||||||
}
|
}
|
||||||
TextInputResult::Copy(text) => {
|
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}")
|
eprintln!("failed to copy text to clipboard: {err}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TextInputResult::Used => {
|
TextInputResult::Used => {
|
||||||
ui.run_event(app_data, sel, Edited, ());
|
ui.run_event(app_state, sel, Edited, ());
|
||||||
}
|
}
|
||||||
TextInputResult::Unused => {}
|
TextInputResult::Unused => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowEvent::Ime(ime) => {
|
WindowEvent::Ime(ime) => {
|
||||||
if let Some(sel) = &ui_data.focus {
|
if let Some(sel) = &ui_state.focus {
|
||||||
let mut text = ui.text(sel);
|
let mut text = ui.text(sel);
|
||||||
match ime {
|
match ime {
|
||||||
Ime::Enabled | Ime::Disabled => (),
|
Ime::Enabled | Ime::Disabled => (),
|
||||||
Ime::Preedit(content, _pos) => {
|
Ime::Preedit(content, _pos) => {
|
||||||
// TODO: highlight once that's real
|
// TODO: highlight once that's real
|
||||||
text.replace(ui_data.ime, content);
|
text.replace(ui_state.ime, content);
|
||||||
ui_data.ime = content.chars().count();
|
ui_state.ime = content.chars().count();
|
||||||
}
|
}
|
||||||
Ime::Commit(content) => {
|
Ime::Commit(content) => {
|
||||||
text.insert(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() {
|
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) {
|
fn exit(&mut self) {
|
||||||
|
|||||||
Reference in New Issue
Block a user