Skip to content

Commit

Permalink
Add on_create to handle and on_edit_end to textbox
Browse files Browse the repository at this point in the history
  • Loading branch information
geom3trik authored and robbert-vdh committed Apr 19, 2022
1 parent 8579fc9 commit 283a9e9
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 3 deletions.
14 changes: 14 additions & 0 deletions core/src/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ impl<'a, T> Handle<'a, T> {
self
}

pub fn on_create<F>(self, callback: F) -> Self
where
F: Fn(&mut Context),
{
let prev = self.cx.current;
self.cx.current = self.entity();
(callback)(self.cx);
self.cx.current = prev;

self
}

pub fn bind<L, F>(self, lens: L, closure: F) -> Self
where
L: Lens,
Expand Down Expand Up @@ -389,4 +401,6 @@ impl<'a, T> Handle<'a, T> {
set_style!(border_radius_top_right, Units);
set_style!(border_radius_bottom_left, Units);
set_style!(border_radius_bottom_right, Units);


}
3 changes: 3 additions & 0 deletions core/src/views/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ pub use self::image::*;

mod menu;
pub use menu::*;

mod value_slider;
pub use value_slider::*;
29 changes: 26 additions & 3 deletions core/src/views/textbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub struct TextboxData {
content_entity: Entity,
kind: TextboxKind,
on_submit: Option<Arc<dyn Fn(&mut Context, String) + Send + Sync>>,
on_edit_end: Option<Arc<dyn Fn(&mut Context) + Send + Sync>>,
}

impl TextboxData {
Expand All @@ -42,6 +43,7 @@ impl TextboxData {
content_entity: Entity::null(),
kind: TextboxKind::SingleLine,
on_submit: None,
on_edit_end: None,
}
}

Expand Down Expand Up @@ -295,6 +297,7 @@ pub enum TextEvent {
SetOnSubmit(Option<Arc<dyn Fn(&mut Context, String) + Send + Sync>>),
InitContent(Entity, TextboxKind),
GeometryChanged,
SetOnEditEnd(Option<Arc<dyn Fn(&mut Context) + Send + Sync>>),
}

impl Model for TextboxData {
Expand Down Expand Up @@ -337,11 +340,17 @@ impl Model for TextboxData {
TextEvent::StartEdit => {
if !cx.current.is_disabled(cx) {
self.edit = true;
cx.focused = cx.current;
cx.capture();
cx.current.set_checked(cx, true);
}
}

TextEvent::EndEdit => {
self.edit = false;
if let Some(callback) = &self.on_edit_end {
(callback)(cx);
}
}

TextEvent::Submit => {
Expand Down Expand Up @@ -427,6 +436,10 @@ impl Model for TextboxData {
TextEvent::SetOnSubmit(on_submit) => {
self.on_submit = on_submit.clone();
}

TextEvent::SetOnEditEnd(on_edit_end) => {
self.on_edit_end = on_edit_end.clone();
}
}
}
}
Expand Down Expand Up @@ -479,6 +492,7 @@ where
content_entity: text_data.content_entity,
kind: text_data.kind,
on_submit: text_data.on_submit.clone(),
on_edit_end: text_data.on_edit_end.clone(),
};
let real_current = cx.current;
cx.current = cx.current.parent(&cx.tree).unwrap();
Expand Down Expand Up @@ -542,6 +556,15 @@ impl<'a, L: Lens> Handle<'a, Textbox<L>> {

self
}

pub fn on_edit_end<F>(self, callback: F) -> Self
where
F: 'static + Fn(&mut Context) + Send + Sync,
{
self.cx.emit_to(self.entity, TextEvent::SetOnEditEnd(Some(Arc::new(callback))));

self
}
}

impl<L: Lens> View for Textbox<L>
Expand All @@ -562,9 +585,9 @@ where
if cx.current.is_over(cx) {
cx.emit(TextEvent::StartEdit);

cx.focused = cx.current;
cx.capture();
cx.current.set_checked(cx, true);
// cx.focused = cx.current;
// cx.capture();
// cx.current.set_checked(cx, true);

cx.emit(TextEvent::Hit(cx.mouse.cursorx, cx.mouse.cursory));
} else {
Expand Down
173 changes: 173 additions & 0 deletions core/src/views/value_slider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
use std::marker::PhantomData;

use crate::{
Actions, Binding, Color, Context, Element, Event, Handle, Label, Lens, LensExt, Model,
Modifiers, MouseButton, Textbox, Units::*, View, WindowEvent, ZStack,
};

use super::textbox::TextEvent;

#[derive(Lens)]
pub struct VSDataInternal {
edit: bool,
}

pub enum ValueSliderEvent {
SetEdit(bool),
OnSubmit(f32),
}

impl Model for VSDataInternal {
fn event(&mut self, _cx: &mut Context, event: &mut Event) {
if let Some(value_slider_event) = event.message.downcast() {
match value_slider_event {
ValueSliderEvent::SetEdit(flag) => {
self.edit = *flag;
}

_ => {}
}
}
}
}

pub struct ValueSlider<L> {
p: PhantomData<L>,
is_dragging: bool,
on_changing: Option<Box<dyn Fn(&mut Context, f32)>>,
}

impl<L> ValueSlider<L>
where
L: Lens<Target = f32>,
{
pub fn new(cx: &mut Context, lens: L) -> Handle<Self> {
Self { p: PhantomData::default(), is_dragging: false, on_changing: None }.build(cx, |cx| {
VSDataInternal { edit: false }.build(cx);

ZStack::new(cx, |cx| {
Element::new(cx)
.height(Stretch(1.0))
.width(Stretch(1.0))
.background_color(Color::rgb(200, 200, 200))
.bind(lens.clone(), move |handle, l| {
let val = l.get(handle.cx);
handle.width(Percentage(val * 100.0));
});
Binding::new(cx, VSDataInternal::edit, move |cx, edit| {
if edit.get(cx) {
Textbox::new(cx, lens.clone().map(|val| format!("{:.2}", val)))
.on_create(|cx| {
cx.emit(TextEvent::StartEdit);
cx.emit(TextEvent::SelectAll);
})
.on_submit(|cx, txt| {
if let Ok(val) = txt.parse::<f32>() {
let val = val.clamp(0.0, 1.0);
cx.emit(ValueSliderEvent::OnSubmit(val));
}
})
.on_edit_end(|cx| {
cx.emit(ValueSliderEvent::SetEdit(false));
})
.child_space(Stretch(1.0))
.height(Stretch(1.0))
.width(Stretch(1.0));
} else {
Label::new(cx, lens.clone().map(|val| format!("{:.2}", val)))
.child_space(Stretch(1.0))
.height(Stretch(1.0))
.width(Stretch(1.0))
.hoverable(false);
};
});
});
})
}
}

impl<L> View for ValueSlider<L>
where
L: Lens<Target = f32>,
{
fn event(&mut self, cx: &mut Context, event: &mut Event) {
if let Some(value_slider_event) = event.message.downcast() {
match value_slider_event {
ValueSliderEvent::OnSubmit(val) => {
if let Some(callback) = &self.on_changing {
(callback)(cx, *val);
}
}

_ => {}
}
}

if let Some(window_event) = event.message.downcast() {
match window_event {
WindowEvent::MouseDown(button) if *button == MouseButton::Left => {
if cx.modifiers.contains(Modifiers::ALT) {
cx.emit(ValueSliderEvent::SetEdit(true));
} else {
if let Some(vs_data) = cx.data::<VSDataInternal>() {
if !vs_data.edit {
self.is_dragging = true;
cx.capture();

let mut dx = (cx.mouse.left.pos_down.0
- cx.cache.get_posx(cx.current))
/ cx.cache.get_width(cx.current);

dx = dx.clamp(0.0, 1.0);

if let Some(callback) = self.on_changing.take() {
(callback)(cx, dx);

self.on_changing = Some(callback);
}
}
}
}
}

WindowEvent::MouseUp(button) if *button == MouseButton::Left => {
self.is_dragging = false;
cx.release();
}

WindowEvent::MouseMove(x, _) => {
if self.is_dragging {
let mut dx =
(*x - cx.cache.get_posx(cx.current)) / cx.cache.get_width(cx.current);

dx = dx.clamp(0.0, 1.0);

if let Some(callback) = &self.on_changing {
(callback)(cx, dx);
}
}
}

_ => {}
}
}
}
}

impl<'a, L> Handle<'a, ValueSlider<L>>
where
L: Lens<Target = f32>,
{
pub fn on_changing<F>(self, callback: F) -> Self
where
F: 'static + Fn(&mut Context, f32),
{
if let Some(slider) =
self.cx.views.get_mut(&self.entity).and_then(|f| f.downcast_mut::<ValueSlider<L>>())
{
slider.on_changing = Some(Box::new(callback));
}

self
}
}
37 changes: 37 additions & 0 deletions examples/value_slider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use vizia::*;

#[derive(Lens)]
pub struct AppData {
val: f32,
}

pub enum AppEvent {
SetValue(f32),
}

impl Model for AppData {
fn event(&mut self, _cx: &mut Context, event: &mut Event) {
if let Some(app_event) = event.message.downcast() {
match app_event {
AppEvent::SetValue(val) => {
self.val = *val;
}
}
}
}
}

fn main() {
let mut window_description = WindowDescription::new();
Application::new(window_description, |cx| {
AppData { val: 0.5 }.build(cx);


ValueSlider::new(cx, AppData::val)
.on_changing(|cx, val| cx.emit(AppEvent::SetValue(val)))
.width(Pixels(300.0))
.height(Pixels(50.0))
.space(Stretch(1.0));
})
.run();
}

0 comments on commit 283a9e9

Please sign in to comment.