mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-11-25 08:28:42 -06:00
wip slider and stuff
This commit is contained in:
parent
7d3932f139
commit
4476307482
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,
|
pub event: InteractableEvent,
|
||||||
|
|
||||||
/// Signal that will be called if the element was clicked in the current frame
|
/// 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>>,
|
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?
|
//XXX: should we do this AFTER normal process call of wrapped element?
|
||||||
let event_happened = match self.event {
|
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),
|
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 struct Slider {
|
||||||
pub value: f32,
|
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
|
//TODO
|
||||||
|
|
|
@ -234,6 +234,11 @@ impl UiInputState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct ClickCheckResponse {
|
||||||
|
pub position_in_rect: Vec2,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct InputCtx<'a>(&'a UiInputState);
|
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\
|
/// 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\
|
/// 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")
|
/// (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;
|
let pos = self.0.mouse_pointer.current_position;
|
||||||
self.0.mouse_pointer.released_buttons.get(&MouseButton::Primary).map_or(false, |meta| {
|
self.0.mouse_pointer.released_buttons.get(&MouseButton::Primary).map_or(false, |meta| {
|
||||||
rect.contains_point(meta.start_position) && rect.contains_point(pos)
|
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
|
//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> {
|
// impl<R: UiSignal + 'static, A> SignalTrigger<R, A> {
|
||||||
pub fn new<F: Fn(A) -> R + 'static>(f: F) -> Self {
|
// pub fn new<F: Fn(A) -> R + 'static>(f: F) -> Self {
|
||||||
Self(Box::new(f))
|
// Self(Box::new(f))
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: UiSignal + 'static, A, T: Fn(A) -> R + 'static> From<T> for SignalTrigger<R, A> {
|
// pub fn call(&self, a: A) -> R {
|
||||||
fn from(f: T) -> Self {
|
// (self.0)(a)
|
||||||
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))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
Loading…
Reference in a new issue