mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-12-22 12:28:19 -06:00
wip slider and stuff
This commit is contained in:
parent
59a704d516
commit
6606119cc4
66
hui-examples/examples/ui_test_6.rs
Normal file
66
hui-examples/examples/ui_test_6.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use hui::{
|
||||
color, size,
|
||||
draw::TextureFormat,
|
||||
signal::UiSignal,
|
||||
layout::{Alignment, Direction},
|
||||
element::{
|
||||
container::Container,
|
||||
text::Text,
|
||||
image::Image,
|
||||
br::Br,
|
||||
interactable::ElementInteractableExt,
|
||||
slider::Slider,
|
||||
UiElementExt,
|
||||
},
|
||||
};
|
||||
|
||||
enum CounterSignal {
|
||||
Increment,
|
||||
Decrement,
|
||||
}
|
||||
impl UiSignal for CounterSignal {}
|
||||
|
||||
#[path = "../boilerplate.rs"]
|
||||
#[macro_use]
|
||||
mod boilerplate;
|
||||
|
||||
const IMAGE_DATA: &[u8] = include_bytes!("../assets/icons/visual-studio-code-icon_32x32.rgba");
|
||||
|
||||
ui_main!(
|
||||
"hUI: Internal input test",
|
||||
init: |ui| {
|
||||
let image = ui.add_image(TextureFormat::Rgba, IMAGE_DATA, 32);
|
||||
(0, image)
|
||||
},
|
||||
run: |ui, size, (ref mut counter, image)| {
|
||||
Container::default()
|
||||
.with_size(size!(100%))
|
||||
.with_padding(10.)
|
||||
.with_align((Alignment::Center, Alignment::Begin))
|
||||
.with_direction(Direction::Horizontal)
|
||||
.with_gap(5.)
|
||||
.with_background((0.1, 0.1, 0.1))
|
||||
.with_wrap(true)
|
||||
.with_children(|ui| {
|
||||
Text::new("Number of images:")
|
||||
.with_text_size(24)
|
||||
.add_child(ui);
|
||||
Br.add_child(ui);
|
||||
Slider::new(0.5)
|
||||
.with_size(size!(66%, 20))
|
||||
.add_child(ui);
|
||||
Br.add_child(ui);
|
||||
for _ in 0..*counter {
|
||||
Image::new(*image)
|
||||
.with_size(size!(48, 48))
|
||||
.add_child(ui);
|
||||
}
|
||||
})
|
||||
.add_root(ui, size);
|
||||
|
||||
ui.process_signals(|sig| match sig {
|
||||
CounterSignal::Increment => *counter += 1,
|
||||
CounterSignal::Decrement => *counter -= 1,
|
||||
});
|
||||
}
|
||||
);
|
|
@ -26,8 +26,6 @@ pub struct Interactable<C: UiSignal + 'static> {
|
|||
pub event: InteractableEvent,
|
||||
|
||||
/// Signal that will be called if the element was clicked in the current frame
|
||||
///
|
||||
/// Will be consumed after the first time it's called
|
||||
pub signal: RefCell<Option<C>>,
|
||||
}
|
||||
|
||||
|
@ -55,7 +53,8 @@ impl<C: UiSignal + 'static> UiElement for Interactable<C> {
|
|||
|
||||
//XXX: should we do this AFTER normal process call of wrapped element?
|
||||
let event_happened = match self.event {
|
||||
InteractableEvent::Click => ctx.input.check_click(rect),
|
||||
//TODO: actually pass the response
|
||||
InteractableEvent::Click => ctx.input.check_click(rect).is_some(),
|
||||
InteractableEvent::Hover => ctx.input.check_hover(rect),
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,71 @@
|
|||
use crate::element::UiElement;
|
||||
//! work in progress
|
||||
|
||||
use derive_setters::Setters;
|
||||
|
||||
use crate::{
|
||||
draw::UiDrawCommand,
|
||||
element::{MeasureContext, ProcessContext, UiElement},
|
||||
layout::{compute_size, Size2d},
|
||||
measure::Response,
|
||||
rectangle::Corners,
|
||||
signal::UiSignal,
|
||||
};
|
||||
|
||||
/// work in progress
|
||||
#[derive(Default, Debug, Clone, Copy, Setters)]
|
||||
#[setters(prefix = "with_")]
|
||||
pub struct Slider {
|
||||
pub value: f32,
|
||||
pub size: Size2d,
|
||||
}
|
||||
|
||||
impl Slider {
|
||||
pub const DEFAULT_HEIGHT: f32 = 20.0;
|
||||
|
||||
pub fn new(value: f32) -> Self {
|
||||
Self {
|
||||
value,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UiElement for Slider {
|
||||
fn name(&self) -> &'static str {
|
||||
"Slider"
|
||||
}
|
||||
|
||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||
Response {
|
||||
size: compute_size(ctx.layout, self.size, (ctx.layout.max_size.x, Self::DEFAULT_HEIGHT).into()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn process(&self, ctx: ProcessContext) {
|
||||
ctx.draw.add(UiDrawCommand::Rectangle {
|
||||
position: ctx.layout.position,
|
||||
size: ctx.measure.size,
|
||||
color: Corners::all((1., 0., 0., 1.).into()),
|
||||
texture: None,
|
||||
rounded_corners: None,
|
||||
});
|
||||
|
||||
let value = self.value.clamp(0., 1.);
|
||||
ctx.draw.add(UiDrawCommand::Rectangle {
|
||||
position: ctx.layout.position,
|
||||
size: (ctx.measure.size.x * value, ctx.measure.size.y).into(),
|
||||
color: Corners::all((0., 1., 0., 1.).into()),
|
||||
texture: None,
|
||||
rounded_corners: None,
|
||||
});
|
||||
|
||||
//handle click etc
|
||||
if let Some(res) = ctx.input.check_click(ctx.measure.rect(ctx.layout.position)) {
|
||||
let new_value = res.position_in_rect.x / ctx.measure.size.x;
|
||||
//TODO call signal with new value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
|
|
@ -234,6 +234,11 @@ impl UiInputState {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ClickCheckResponse {
|
||||
pub position_in_rect: Vec2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct InputCtx<'a>(&'a UiInputState);
|
||||
|
||||
|
@ -300,10 +305,12 @@ impl<'a> InputCtx<'a> {
|
|||
/// By default, this function only checks for the primary mouse button\
|
||||
/// This is a limitation of the current API and may change in the future\
|
||||
/// (as the current implementation of this function checks for both mouse and touch input, and the touch input quite obviously only supports one "button")
|
||||
pub fn check_click(&self, rect: Rect) -> bool {
|
||||
pub fn check_click(&self, rect: Rect) -> Option<ClickCheckResponse> {
|
||||
let pos = self.0.mouse_pointer.current_position;
|
||||
self.0.mouse_pointer.released_buttons.get(&MouseButton::Primary).map_or(false, |meta| {
|
||||
rect.contains_point(meta.start_position) && rect.contains_point(pos)
|
||||
}).then_some(ClickCheckResponse {
|
||||
position_in_rect: pos - rect.position,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,16 +56,20 @@ impl SignalStore {
|
|||
|
||||
//TODO this, simplifies handling signals
|
||||
|
||||
pub struct SignalTrigger<R: UiSignal + 'static, A = ()>(pub(crate) Box<dyn Fn(A) -> R>);
|
||||
// pub struct SignalTrigger<R: UiSignal + 'static, A = ()>(pub(crate) Box<dyn Fn(A) -> R + 'static>);
|
||||
|
||||
impl<R: UiSignal + 'static, A> SignalTrigger<R, A> {
|
||||
pub fn new<F: Fn(A) -> R + 'static>(f: F) -> Self {
|
||||
Self(Box::new(f))
|
||||
}
|
||||
}
|
||||
// impl<R: UiSignal + 'static, A> SignalTrigger<R, A> {
|
||||
// pub fn new<F: Fn(A) -> R + 'static>(f: F) -> Self {
|
||||
// Self(Box::new(f))
|
||||
// }
|
||||
|
||||
impl<R: UiSignal + 'static, A, T: Fn(A) -> R + 'static> From<T> for SignalTrigger<R, A> {
|
||||
fn from(f: T) -> Self {
|
||||
Self(Box::new(f))
|
||||
}
|
||||
}
|
||||
// pub fn call(&self, a: A) -> R {
|
||||
// (self.0)(a)
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<R: UiSignal + 'static, A, T: Fn(A) -> R + 'static> From<T> for SignalTrigger<R, A> {
|
||||
// fn from(f: T) -> Self {
|
||||
// Self(Box::new(f))
|
||||
// }
|
||||
// }
|
||||
|
|
Loading…
Reference in a new issue