mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-11-22 07:08:42 -06:00
Compare commits
6 commits
50ea989906
...
d430996e14
Author | SHA1 | Date | |
---|---|---|---|
griffi-gh | d430996e14 | ||
griffi-gh | a0dc882799 | ||
griffi-gh | cf7919d041 | ||
griffi-gh | 8f3e04c445 | ||
griffi-gh | 2af4fd900c | ||
griffi-gh | ab5998de03 |
|
@ -44,7 +44,7 @@ fn main() {
|
||||||
gap: 5.,
|
gap: 5.,
|
||||||
padding: Sides::all(5.),
|
padding: Sides::all(5.),
|
||||||
align: (Alignment::Center, Alignment::Begin).into(),
|
align: (Alignment::Center, Alignment::Begin).into(),
|
||||||
size: (Size::Fraction(1.), Size::Fraction(1.)).into(),
|
size: (Size::Relative(1.), Size::Relative(1.)).into(),
|
||||||
children: ElementList(vec![
|
children: ElementList(vec![
|
||||||
Box::new(ProgressBar {
|
Box::new(ProgressBar {
|
||||||
value: 0.5,
|
value: 0.5,
|
||||||
|
@ -58,7 +58,7 @@ fn main() {
|
||||||
gap: 5.,
|
gap: 5.,
|
||||||
padding: Sides::all(5.),
|
padding: Sides::all(5.),
|
||||||
align: (Alignment::Center, Alignment::End).into(),
|
align: (Alignment::Center, Alignment::End).into(),
|
||||||
size: (Size::Fraction(1.), Size::Fraction(1.)).into(),
|
size: (Size::Relative(1.), Size::Relative(1.)).into(),
|
||||||
children: ElementList(vec![
|
children: ElementList(vec![
|
||||||
Box::new(ProgressBar {
|
Box::new(ProgressBar {
|
||||||
value: z,
|
value: z,
|
||||||
|
@ -66,18 +66,18 @@ fn main() {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Box::new(Container {
|
Box::new(Container {
|
||||||
size: (Size::Fraction(1.), Size::Auto).into(),
|
size: (Size::Relative(1.), Size::Auto).into(),
|
||||||
align: (Alignment::End, Alignment::Center).into(),
|
align: (Alignment::End, Alignment::Center).into(),
|
||||||
padding: Sides::all(5.),
|
padding: Sides::all(5.),
|
||||||
gap: 10.,
|
gap: 10.,
|
||||||
children: ElementList(vec![
|
children: ElementList(vec![
|
||||||
Box::new(FillRect {
|
Box::new(FillRect {
|
||||||
size: (Size::Fraction(0.5), Size::Static(30.)).into(),
|
size: (Size::Relative(0.5), Size::Absolute(30.)).into(),
|
||||||
background: vec4(0.75, 0., 0., 1.).into(),
|
background: vec4(0.75, 0., 0., 1.).into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Box::new(FillRect {
|
Box::new(FillRect {
|
||||||
size: (Size::Fraction(z / 2. + 0.5), Size::Static(30.)).into(),
|
size: (Size::Relative(z / 2. + 0.5), Size::Absolute(30.)).into(),
|
||||||
background: Corners::left_right(
|
background: Corners::left_right(
|
||||||
vec4(1., 0., 0., 1.),
|
vec4(1., 0., 0., 1.),
|
||||||
vec4(0., 1., 0., 1.)
|
vec4(0., 1., 0., 1.)
|
||||||
|
@ -88,7 +88,7 @@ fn main() {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Box::new(FillRect {
|
Box::new(FillRect {
|
||||||
size: (Size::Fraction(z / 2. + 0.5), Size::Static(30.)).into(),
|
size: (Size::Relative(z / 2. + 0.5), Size::Absolute(30.)).into(),
|
||||||
background: vec4(0., 0.75, 0., 1.).into(),
|
background: vec4(0., 0.75, 0., 1.).into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
|
@ -101,7 +101,7 @@ fn main() {
|
||||||
let mut x: Vec<Box<dyn UiElement>> = vec![];
|
let mut x: Vec<Box<dyn UiElement>> = vec![];
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
x.push(Box::new(FillRect {
|
x.push(Box::new(FillRect {
|
||||||
size: (Size::Static(50.), Size::Static(50.)).into(),
|
size: (Size::Absolute(50.), Size::Absolute(50.)).into(),
|
||||||
background: if i == 1 {
|
background: if i == 1 {
|
||||||
vec4(0.75, 0.75, 0.75, 0.75).into()
|
vec4(0.75, 0.75, 0.75, 0.75).into()
|
||||||
} else {
|
} else {
|
||||||
|
@ -130,7 +130,7 @@ fn main() {
|
||||||
},
|
},
|
||||||
children: ElementList(vec![
|
children: ElementList(vec![
|
||||||
Box::new(FillRect {
|
Box::new(FillRect {
|
||||||
size: (Size::Static(50.), Size::Static(50.)).into(),
|
size: (Size::Absolute(50.), Size::Absolute(50.)).into(),
|
||||||
background: vec4(1., 1., 1., 0.75).into(),
|
background: vec4(1., 1., 1., 0.75).into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -42,11 +42,11 @@ fn main() {
|
||||||
hui.add(Container {
|
hui.add(Container {
|
||||||
gap: 10.,
|
gap: 10.,
|
||||||
align: Alignment::Center.into(),
|
align: Alignment::Center.into(),
|
||||||
size: (Size::Fraction(1.), Size::Fraction(1.)).into(),
|
size: (Size::Relative(1.), Size::Relative(1.)).into(),
|
||||||
children: ElementList(vec![
|
children: ElementList(vec![
|
||||||
Box::new(Container {
|
Box::new(Container {
|
||||||
align: Alignment::Center.into(),
|
align: Alignment::Center.into(),
|
||||||
size: (Size::Fraction(0.5), Size::Fraction(0.5)).into(),
|
size: (Size::Relative(0.5), Size::Relative(0.5)).into(),
|
||||||
background: vec4(1., 0., 0., 1.).into(),
|
background: vec4(1., 0., 0., 1.).into(),
|
||||||
corner_radius: Corners {
|
corner_radius: Corners {
|
||||||
top_left: 10.,
|
top_left: 10.,
|
||||||
|
@ -86,7 +86,7 @@ fn main() {
|
||||||
direction: Direction::Horizontal,
|
direction: Direction::Horizontal,
|
||||||
children: ElementList(vec![
|
children: ElementList(vec![
|
||||||
Box::new(Container {
|
Box::new(Container {
|
||||||
size: (Size::Static(100.), Size::Static(100.)).into(),
|
size: (Size::Absolute(100.), Size::Absolute(100.)).into(),
|
||||||
background: Corners::left_right(
|
background: Corners::left_right(
|
||||||
vec4(1., 0., 0., 1.),
|
vec4(1., 0., 0., 1.),
|
||||||
vec4(0., 1., 0., 1.)
|
vec4(0., 1., 0., 1.)
|
||||||
|
@ -95,7 +95,7 @@ fn main() {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Box::new(Container {
|
Box::new(Container {
|
||||||
size: (Size::Static(100.), Size::Static(100.)).into(),
|
size: (Size::Absolute(100.), Size::Absolute(100.)).into(),
|
||||||
background: Corners::left_right(
|
background: Corners::left_right(
|
||||||
vec4(1., 0., 0., 1.),
|
vec4(1., 0., 0., 1.),
|
||||||
vec4(0., 1., 0., 1.)
|
vec4(0., 1., 0., 1.)
|
||||||
|
@ -104,7 +104,7 @@ fn main() {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Box::new(Container {
|
Box::new(Container {
|
||||||
size: (Size::Static(100.), Size::Static(100.)).into(),
|
size: (Size::Absolute(100.), Size::Absolute(100.)).into(),
|
||||||
background: Corners::left_right(
|
background: Corners::left_right(
|
||||||
vec4(1., 0., 0., 1.),
|
vec4(1., 0., 0., 1.),
|
||||||
vec4(0., 1., 0., 1.)
|
vec4(0., 1., 0., 1.)
|
||||||
|
@ -113,7 +113,7 @@ fn main() {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Box::new(Container {
|
Box::new(Container {
|
||||||
size: (Size::Static(100.), Size::Static(100.)).into(),
|
size: (Size::Absolute(100.), Size::Absolute(100.)).into(),
|
||||||
background: Corners::left_right(
|
background: Corners::left_right(
|
||||||
vec4(1., 0., 0., 1.),
|
vec4(1., 0., 0., 1.),
|
||||||
vec4(0., 1., 0., 1.)
|
vec4(0., 1., 0., 1.)
|
||||||
|
|
|
@ -48,7 +48,7 @@ fn main() {
|
||||||
hui.begin();
|
hui.begin();
|
||||||
|
|
||||||
hui.add(Container {
|
hui.add(Container {
|
||||||
size: (Size::Fraction(1.), Size::Fraction(1.)).into(),
|
size: (Size::Relative(1.), Size::Relative(1.)).into(),
|
||||||
background: vec4(0.1, 0.1, 0.1, 1.).into(),
|
background: vec4(0.1, 0.1, 0.1, 1.).into(),
|
||||||
children: elements(|elem| {
|
children: elements(|elem| {
|
||||||
elem.push(Box::new(Text {
|
elem.push(Box::new(Text {
|
||||||
|
@ -72,12 +72,12 @@ fn main() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
elem.push(Box::new(FillRect {
|
elem.push(Box::new(FillRect {
|
||||||
size: (Size::Fraction(1.), Size::Static(10.)).into(),
|
size: (Size::Relative(1.), Size::Absolute(10.)).into(),
|
||||||
background: vec4(0., 0., 1., 1.).into(),
|
background: vec4(0., 0., 1., 1.).into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}));
|
}));
|
||||||
elem.push(Box::new(FillRect {
|
elem.push(Box::new(FillRect {
|
||||||
size: (Size::Fraction(1.), Size::Static(10.)).into(),
|
size: (Size::Relative(1.), Size::Absolute(10.)).into(),
|
||||||
background: vec4(1., 1., 0., 1.).into(),
|
background: vec4(1., 1., 0., 1.).into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}));
|
}));
|
||||||
|
@ -89,12 +89,12 @@ fn main() {
|
||||||
}));
|
}));
|
||||||
if instant.elapsed().as_secs() & 1 != 0 {
|
if instant.elapsed().as_secs() & 1 != 0 {
|
||||||
elem.push(Box::new(FillRect {
|
elem.push(Box::new(FillRect {
|
||||||
size: (Size::Fraction(1.), Size::Static(10.)).into(),
|
size: (Size::Relative(1.), Size::Absolute(10.)).into(),
|
||||||
background: vec4(1., 0., 0., 1.).into(),
|
background: vec4(1., 0., 0., 1.).into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}));
|
}));
|
||||||
elem.push(Box::new(FillRect {
|
elem.push(Box::new(FillRect {
|
||||||
size: (Size::Fraction(1.), Size::Static(10.)).into(),
|
size: (Size::Relative(1.), Size::Absolute(10.)).into(),
|
||||||
background: vec4(0., 0., 0., 1.).into(),
|
background: vec4(0., 0., 0., 1.).into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -41,7 +41,11 @@ ui_main!(
|
||||||
.with_wrap(true)
|
.with_wrap(true)
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
Text::new(format!("Number of images: {counter}"))
|
Text::new(format!("Number of images: {counter}"))
|
||||||
.with_text_size(24)
|
.with_text_size(32)
|
||||||
|
.add_child(ui);
|
||||||
|
Br.add_child(ui);
|
||||||
|
Text::new("Absolute tracking slider:")
|
||||||
|
.with_text_size(16)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Br.add_child(ui);
|
||||||
Slider::new(*counter as f32 / 100.)
|
Slider::new(*counter as f32 / 100.)
|
||||||
|
@ -51,6 +55,18 @@ ui_main!(
|
||||||
})
|
})
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Br.add_child(ui);
|
||||||
|
Text::new("Relative tracking slider (Experimental):")
|
||||||
|
.with_text_size(16)
|
||||||
|
.add_child(ui);
|
||||||
|
Br.add_child(ui);
|
||||||
|
Slider::new(*counter as f32 / 100.)
|
||||||
|
.with_size(size!(66%, 20))
|
||||||
|
.with_follow_mode(hui::element::slider::SliderFollowMode::Relative)
|
||||||
|
.on_change(|x| {
|
||||||
|
CounterSignal::ChangeValue((x * 100.).round() as u32)
|
||||||
|
})
|
||||||
|
.add_child(ui);
|
||||||
|
Br.add_child(ui);
|
||||||
for _ in 0..*counter {
|
for _ in 0..*counter {
|
||||||
Image::new(*image)
|
Image::new(*image)
|
||||||
.with_size(size!(48, 48))
|
.with_size(size!(48, 48))
|
||||||
|
|
|
@ -116,13 +116,13 @@ impl Container {
|
||||||
pub fn measure_max_inner_size(&self, layout: &LayoutInfo) -> Vec2 {
|
pub fn measure_max_inner_size(&self, layout: &LayoutInfo) -> Vec2 {
|
||||||
let outer_size_x = match self.size.width {
|
let outer_size_x = match self.size.width {
|
||||||
Size::Auto => layout.max_size.x,
|
Size::Auto => layout.max_size.x,
|
||||||
Size::Fraction(p) => layout.max_size.x * p,
|
Size::Relative(p) => layout.max_size.x * p,
|
||||||
Size::Static(p) => p,
|
Size::Absolute(p) => p,
|
||||||
};
|
};
|
||||||
let outer_size_y = match self.size.height {
|
let outer_size_y = match self.size.height {
|
||||||
Size::Auto => layout.max_size.y,
|
Size::Auto => layout.max_size.y,
|
||||||
Size::Fraction(p) => layout.max_size.y * p,
|
Size::Relative(p) => layout.max_size.y * p,
|
||||||
Size::Static(p) => p,
|
Size::Absolute(p) => p,
|
||||||
};
|
};
|
||||||
vec2(
|
vec2(
|
||||||
outer_size_x - (self.padding.left + self.padding.right),
|
outer_size_x - (self.padding.left + self.padding.right),
|
||||||
|
@ -148,13 +148,13 @@ impl UiElement for Container {
|
||||||
let max_line_pri = match self.direction {
|
let max_line_pri = match self.direction {
|
||||||
Direction::Horizontal => match self.size.width {
|
Direction::Horizontal => match self.size.width {
|
||||||
Size::Auto => ctx.layout.max_size.x,
|
Size::Auto => ctx.layout.max_size.x,
|
||||||
Size::Fraction(p) => ctx.layout.max_size.x * p,
|
Size::Relative(p) => ctx.layout.max_size.x * p,
|
||||||
Size::Static(p) => p,
|
Size::Absolute(p) => p,
|
||||||
},
|
},
|
||||||
Direction::Vertical => match self.size.height {
|
Direction::Vertical => match self.size.height {
|
||||||
Size::Auto => ctx.layout.max_size.y,
|
Size::Auto => ctx.layout.max_size.y,
|
||||||
Size::Fraction(p) => ctx.layout.max_size.y * p,
|
Size::Relative(p) => ctx.layout.max_size.y * p,
|
||||||
Size::Static(p) => p,
|
Size::Absolute(p) => p,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -300,13 +300,13 @@ impl UiElement for Container {
|
||||||
|
|
||||||
match self.size.width {
|
match self.size.width {
|
||||||
Size::Auto => (),
|
Size::Auto => (),
|
||||||
Size::Fraction(percentage) => total_size.x = ctx.layout.max_size.x * percentage,
|
Size::Relative(percentage) => total_size.x = ctx.layout.max_size.x * percentage,
|
||||||
Size::Static(pixels) => total_size.x = pixels,
|
Size::Absolute(pixels) => total_size.x = pixels,
|
||||||
}
|
}
|
||||||
match self.size.height {
|
match self.size.height {
|
||||||
Size::Auto => (),
|
Size::Auto => (),
|
||||||
Size::Fraction(percentage) => total_size.y = ctx.layout.max_size.y * percentage,
|
Size::Relative(percentage) => total_size.y = ctx.layout.max_size.y * percentage,
|
||||||
Size::Static(pixels) => total_size.y = pixels,
|
Size::Absolute(pixels) => total_size.y = pixels,
|
||||||
}
|
}
|
||||||
|
|
||||||
Response {
|
Response {
|
||||||
|
|
|
@ -48,13 +48,13 @@ impl UiElement for FillRect {
|
||||||
size: vec2(
|
size: vec2(
|
||||||
match self.size.width {
|
match self.size.width {
|
||||||
Size::Auto => ctx.layout.max_size.x,
|
Size::Auto => ctx.layout.max_size.x,
|
||||||
Size::Fraction(percentage) => ctx.layout.max_size.x * percentage,
|
Size::Relative(percentage) => ctx.layout.max_size.x * percentage,
|
||||||
Size::Static(pixels) => pixels,
|
Size::Absolute(pixels) => pixels,
|
||||||
},
|
},
|
||||||
match self.size.height {
|
match self.size.height {
|
||||||
Size::Auto => ctx.layout.max_size.y,
|
Size::Auto => ctx.layout.max_size.y,
|
||||||
Size::Fraction(percentage) => ctx.layout.max_size.y * percentage,
|
Size::Relative(percentage) => ctx.layout.max_size.y * percentage,
|
||||||
Size::Static(pixels) => pixels,
|
Size::Absolute(pixels) => pixels,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
@ -12,6 +12,10 @@ use crate::{
|
||||||
signal::{trigger::SignalTriggerArg, Signal},
|
signal::{trigger::SignalTriggerArg, Signal},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: use state for slider?
|
||||||
|
// ^ useful if the user only hanldes the drag end event or has large step sizes with relative mode
|
||||||
|
|
||||||
/// Follow mode for the slider
|
/// Follow mode for the slider
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
||||||
pub enum SliderFollowMode {
|
pub enum SliderFollowMode {
|
||||||
|
@ -52,6 +56,11 @@ pub struct Slider {
|
||||||
#[setters(into)]
|
#[setters(into)]
|
||||||
pub track_active_color: FillColor,
|
pub track_active_color: FillColor,
|
||||||
|
|
||||||
|
/// Track height relative to the slider height\
|
||||||
|
///
|
||||||
|
/// Range: 0.0..=1.0
|
||||||
|
pub track_height_ratio: f32,
|
||||||
|
|
||||||
/// Follow mode
|
/// Follow mode
|
||||||
pub follow_mode: SliderFollowMode,
|
pub follow_mode: SliderFollowMode,
|
||||||
|
|
||||||
|
@ -64,9 +73,10 @@ impl Default for Slider {
|
||||||
Self {
|
Self {
|
||||||
value: 0.0,
|
value: 0.0,
|
||||||
size: Size2d::default(),
|
size: Size2d::default(),
|
||||||
handle_color: (0.0, 0.0, 1.0).into(),
|
handle_color: (0.0, 0.0, 1.).into(),
|
||||||
track_color: (0.5, 0.5, 0.5).into(),
|
track_color: (0.5, 0.5, 0.5).into(),
|
||||||
track_active_color: (0.0, 0.0, 0.75).into(),
|
track_active_color: (0.0, 0.0, 0.75).into(),
|
||||||
|
track_height_ratio: 0.25,
|
||||||
follow_mode: SliderFollowMode::default(),
|
follow_mode: SliderFollowMode::default(),
|
||||||
on_change: None
|
on_change: None
|
||||||
}
|
}
|
||||||
|
@ -74,7 +84,7 @@ impl Default for Slider {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Slider {
|
impl Slider {
|
||||||
pub const DEFAULT_HEIGHT: f32 = 21.0;
|
pub const DEFAULT_HEIGHT: f32 = 20.0;
|
||||||
|
|
||||||
pub fn new(value: f32) -> Self {
|
pub fn new(value: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -104,18 +114,25 @@ impl UiElement for Slider {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process(&self, ctx: ProcessContext) {
|
fn process(&self, ctx: ProcessContext) {
|
||||||
//TODO: unhardcode this
|
|
||||||
let bgrect_height_ratio = 0.33;
|
|
||||||
|
|
||||||
//XXX: some of these assumptions are wrong if the corners are rounded
|
//XXX: some of these assumptions are wrong if the corners are rounded
|
||||||
|
|
||||||
|
//Compute handle size:
|
||||||
|
// This is kinda counter-intuitive, but if the handle is transparent, we treat it as completely disabled
|
||||||
|
// To prevent confusing offset from the edge of the slider, we set the handle size to 0
|
||||||
|
let handle_size = if self.handle_color.is_transparent() {
|
||||||
|
Vec2::ZERO
|
||||||
|
} else {
|
||||||
|
vec2(15., ctx.measure.size.y)
|
||||||
|
};
|
||||||
|
|
||||||
//Draw the track
|
//Draw the track
|
||||||
//If the active part is opaque and value >= 1., we don't need to draw the background as the active part will cover it
|
//If the active part is opaque and value >= 1., we don't need to draw the background as the active part will cover it
|
||||||
|
//However, if the handle is not opaque, we need to draw the background as the active part won't quite reach the end
|
||||||
//Of corse, if it's fully transparent, we don't need to draw it either
|
//Of corse, if it's fully transparent, we don't need to draw it either
|
||||||
if !(self.track_color.is_transparent() || (self.track_active_color.is_opaque() && self.value >= 1.)) {
|
if !(self.track_color.is_transparent() || (self.track_active_color.is_opaque() && self.handle_color.is_opaque() && self.value >= 1.)) {
|
||||||
ctx.draw.add(UiDrawCommand::Rectangle {
|
ctx.draw.add(UiDrawCommand::Rectangle {
|
||||||
position: ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - bgrect_height_ratio / 2.),
|
position: ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - self.track_height_ratio / 2.),
|
||||||
size: ctx.measure.size * vec2(1., bgrect_height_ratio),
|
size: ctx.measure.size * vec2(1., self.track_height_ratio),
|
||||||
color: self.track_color.into(),
|
color: self.track_color.into(),
|
||||||
texture: None,
|
texture: None,
|
||||||
rounded_corners: None,
|
rounded_corners: None,
|
||||||
|
@ -124,10 +141,11 @@ impl UiElement for Slider {
|
||||||
|
|
||||||
//"Active" part of the track
|
//"Active" part of the track
|
||||||
//We can skip drawing it if it's fully transparent or value <= 0.
|
//We can skip drawing it if it's fully transparent or value <= 0.
|
||||||
if !(self.track_active_color.is_transparent() || self.value <= 0.) {
|
//But if the handle is not opaque, it should be visible even if value is zero
|
||||||
|
if !(self.track_active_color.is_transparent() || (self.value <= 0. && self.handle_color.is_opaque())) {
|
||||||
ctx.draw.add(UiDrawCommand::Rectangle {
|
ctx.draw.add(UiDrawCommand::Rectangle {
|
||||||
position: ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - bgrect_height_ratio / 2.),
|
position: ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - self.track_height_ratio / 2.),
|
||||||
size: ctx.measure.size * vec2(self.value, bgrect_height_ratio),
|
size: (ctx.measure.size - handle_size * Vec2::X) * vec2(self.value, self.track_height_ratio) + handle_size * Vec2::X / 2.,
|
||||||
color: self.track_active_color.into(),
|
color: self.track_active_color.into(),
|
||||||
texture: None,
|
texture: None,
|
||||||
rounded_corners: None,
|
rounded_corners: None,
|
||||||
|
@ -135,14 +153,7 @@ impl UiElement for Slider {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The handle
|
// The handle
|
||||||
// This is kinda counter-intuitive, but if the handle is transparent, we treat it as completely disabled
|
if handle_size.x != 0. && !self.handle_color.is_transparent() {
|
||||||
// To prevent confusing offset from the edge of the slider, we set the handle size to 0
|
|
||||||
let handle_size = if self.handle_color.is_transparent() {
|
|
||||||
Vec2::ZERO
|
|
||||||
} else {
|
|
||||||
vec2(15., ctx.measure.size.y)
|
|
||||||
};
|
|
||||||
if handle_size.x != 0. {
|
|
||||||
let value = self.value.clamp(0., 1.);
|
let value = self.value.clamp(0., 1.);
|
||||||
ctx.draw.add(UiDrawCommand::Rectangle {
|
ctx.draw.add(UiDrawCommand::Rectangle {
|
||||||
position: ctx.layout.position + ((ctx.measure.size.x - handle_size.x) * value) * Vec2::X,
|
position: ctx.layout.position + ((ctx.measure.size.x - handle_size.x) * value) * Vec2::X,
|
||||||
|
|
|
@ -86,13 +86,13 @@ impl UiElement for Text {
|
||||||
size: vec2(
|
size: vec2(
|
||||||
match self.size.width {
|
match self.size.width {
|
||||||
Size::Auto => size.0,
|
Size::Auto => size.0,
|
||||||
Size::Fraction(percentage) => ctx.layout.max_size.x * percentage,
|
Size::Relative(percentage) => ctx.layout.max_size.x * percentage,
|
||||||
Size::Static(pixels) => pixels,
|
Size::Absolute(pixels) => pixels,
|
||||||
},
|
},
|
||||||
match self.size.height {
|
match self.size.height {
|
||||||
Size::Auto => size.1,
|
Size::Auto => size.1,
|
||||||
Size::Fraction(percentage) => ctx.layout.max_size.y * percentage,
|
Size::Relative(percentage) => ctx.layout.max_size.y * percentage,
|
||||||
Size::Static(pixels) => pixels,
|
Size::Absolute(pixels) => pixels,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
195
hui/src/frame.rs
Normal file
195
hui/src/frame.rs
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
use glam::{Vec2, vec2};
|
||||||
|
use derive_more::{Add, AddAssign, Sub, SubAssign};
|
||||||
|
use crate::{
|
||||||
|
draw::ImageHandle,
|
||||||
|
element::fill_rect::FillRect,
|
||||||
|
layout::{Size, Size2d}
|
||||||
|
};
|
||||||
|
|
||||||
|
//TODO finish dis, slider component would be a great place to test it
|
||||||
|
|
||||||
|
/// Point inside a frame
|
||||||
|
///
|
||||||
|
/// Can be absolute, relative, or a combination of both\
|
||||||
|
/// Final coordinate is calculated as `absolute + relative * parent_size`
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Add, AddAssign, Sub, SubAssign)]
|
||||||
|
pub struct FramePoint {
|
||||||
|
/// Absolute positioning
|
||||||
|
pub absolute: f32,
|
||||||
|
|
||||||
|
/// Relative positioning
|
||||||
|
pub relative: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f32> for FramePoint {
|
||||||
|
fn from(value: f32) -> Self {
|
||||||
|
Self::absolute(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Size> for FramePoint {
|
||||||
|
/// Convert a `Size` into a `FramePoint`
|
||||||
|
///
|
||||||
|
/// This function behaves just as you would expect, but `Auto` is always treated as `BEGIN`
|
||||||
|
fn from(size: Size) -> Self {
|
||||||
|
match size {
|
||||||
|
Size::Auto => Self::BEGIN,
|
||||||
|
Size::Relative(value) => Self::relative(value),
|
||||||
|
Size::Absolute(value) => Self::absolute(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FramePoint {
|
||||||
|
pub const BEGIN: Self = Self {
|
||||||
|
absolute: 0.0,
|
||||||
|
relative: 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const CENTER: Self = Self {
|
||||||
|
absolute: 0.5,
|
||||||
|
relative: 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const END: Self = Self {
|
||||||
|
absolute: 1.0,
|
||||||
|
relative: 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const fn absolute(value: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
absolute: value,
|
||||||
|
relative: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn relative(value: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
absolute: 0.0,
|
||||||
|
relative: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn relative_absolute(relative: f32, absolute: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
absolute,
|
||||||
|
relative,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve(&self, parent_size: f32) -> f32 {
|
||||||
|
self.absolute + self.relative * parent_size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Add, AddAssign, Sub, SubAssign)]
|
||||||
|
pub struct FramePoint2d {
|
||||||
|
pub x: FramePoint,
|
||||||
|
pub y: FramePoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(FramePoint, FramePoint)> for FramePoint2d {
|
||||||
|
fn from((x, y): (FramePoint, FramePoint)) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Size> for FramePoint2d {
|
||||||
|
fn from(size: Size) -> Self {
|
||||||
|
Self {
|
||||||
|
x: size.into(),
|
||||||
|
y: size.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Size2d> for FramePoint2d {
|
||||||
|
fn from(size: Size2d) -> Self {
|
||||||
|
Self {
|
||||||
|
x: size.width.into(),
|
||||||
|
y: size.height.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(f32, f32)> for FramePoint2d {
|
||||||
|
fn from((x, y): (f32, f32)) -> Self {
|
||||||
|
Self {
|
||||||
|
x: FramePoint::absolute(x),
|
||||||
|
y: FramePoint::absolute(y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec2> for FramePoint2d {
|
||||||
|
fn from(vec: Vec2) -> Self {
|
||||||
|
Self {
|
||||||
|
x: FramePoint::absolute(vec.x),
|
||||||
|
y: FramePoint::absolute(vec.y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FramePoint2d {
|
||||||
|
pub const TOP_LEFT: Self = Self {
|
||||||
|
x: FramePoint::BEGIN,
|
||||||
|
y: FramePoint::BEGIN,
|
||||||
|
};
|
||||||
|
pub const TOP_CENTER: Self = Self {
|
||||||
|
x: FramePoint::CENTER,
|
||||||
|
y: FramePoint::BEGIN,
|
||||||
|
};
|
||||||
|
pub const TOP_RIGHT: Self = Self {
|
||||||
|
x: FramePoint::END,
|
||||||
|
y: FramePoint::BEGIN,
|
||||||
|
};
|
||||||
|
pub const CENTER_LEFT: Self = Self {
|
||||||
|
x: FramePoint::BEGIN,
|
||||||
|
y: FramePoint::CENTER,
|
||||||
|
};
|
||||||
|
pub const CENTER: Self = Self {
|
||||||
|
x: FramePoint::CENTER,
|
||||||
|
y: FramePoint::CENTER,
|
||||||
|
};
|
||||||
|
pub const CENTER_RIGHT: Self = Self {
|
||||||
|
x: FramePoint::END,
|
||||||
|
y: FramePoint::CENTER,
|
||||||
|
};
|
||||||
|
pub const BOTTOM_LEFT: Self = Self {
|
||||||
|
x: FramePoint::BEGIN,
|
||||||
|
y: FramePoint::END,
|
||||||
|
};
|
||||||
|
pub const BOTTOM_CENTER: Self = Self {
|
||||||
|
x: FramePoint::CENTER,
|
||||||
|
y: FramePoint::END,
|
||||||
|
};
|
||||||
|
pub const BOTTOM_RIGHT: Self = Self {
|
||||||
|
x: FramePoint::END,
|
||||||
|
y: FramePoint::END,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn resolve(&self, parent_size: Vec2) -> Vec2 {
|
||||||
|
let x = self.x.resolve(parent_size.x);
|
||||||
|
let y = self.y.resolve(parent_size.y);
|
||||||
|
vec2(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FrameLayer {
|
||||||
|
Rect {
|
||||||
|
color: FillRect,
|
||||||
|
image: Option<ImageHandle>,
|
||||||
|
top_left: FramePoint2d,
|
||||||
|
bottom_right: FramePoint2d,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Frame {
|
||||||
|
layers: Vec<FrameLayer>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Into<FillRect>> From<T> for Frame {
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
|
@ -91,18 +91,18 @@ pub enum Size {
|
||||||
///
|
///
|
||||||
/// Out of range values are allowed, but are not guaranteed to work as expected\
|
/// Out of range values are allowed, but are not guaranteed to work as expected\
|
||||||
/// (especially with negative values)
|
/// (especially with negative values)
|
||||||
Fraction(f32),
|
Relative(f32),
|
||||||
|
|
||||||
//TODO FractionRemaining(f32),
|
//TODO FractionRemaining(f32),
|
||||||
|
|
||||||
/// Static size in pixels
|
/// Static size in pixels
|
||||||
Static(f32),
|
Absolute(f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<f32> for Size {
|
impl From<f32> for Size {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: f32) -> Self {
|
fn from(value: f32) -> Self {
|
||||||
Self::Static(value)
|
Self::Absolute(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,13 +166,13 @@ pub struct LayoutInfo {
|
||||||
pub fn compute_size(layout: &LayoutInfo, size: Size2d, comfy_size: Vec2) -> Vec2 {
|
pub fn compute_size(layout: &LayoutInfo, size: Size2d, comfy_size: Vec2) -> Vec2 {
|
||||||
let width = match size.width {
|
let width = match size.width {
|
||||||
Size::Auto => comfy_size.x,
|
Size::Auto => comfy_size.x,
|
||||||
Size::Fraction(fraction) => layout.max_size.x * fraction,
|
Size::Relative(fraction) => layout.max_size.x * fraction,
|
||||||
Size::Static(size) => size,
|
Size::Absolute(size) => size,
|
||||||
};
|
};
|
||||||
let height = match size.height {
|
let height = match size.height {
|
||||||
Size::Auto => comfy_size.y,
|
Size::Auto => comfy_size.y,
|
||||||
Size::Fraction(fraction) => layout.max_size.y * fraction,
|
Size::Relative(fraction) => layout.max_size.y * fraction,
|
||||||
Size::Static(size) => size,
|
Size::Absolute(size) => size,
|
||||||
};
|
};
|
||||||
vec2(width, height)
|
vec2(width, height)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,5 +22,6 @@ pub mod state;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
pub mod signal;
|
pub mod signal;
|
||||||
|
pub mod frame;
|
||||||
|
|
||||||
pub use instance::UiInstance;
|
pub use instance::UiInstance;
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
///
|
///
|
||||||
/// # Syntax:
|
/// # Syntax:
|
||||||
/// - `auto` - `Size::Auto`
|
/// - `auto` - `Size::Auto`
|
||||||
/// - `x` - `Size::Static(x)`
|
/// - `x` - `Size::Absolute(x)`
|
||||||
/// - `x%` - `Size::Fraction(x / 100.)` *(literal only)*
|
/// - `x%` - `Size::Relative(x / 100.)` *(literal only)*
|
||||||
/// - `x/` - `Size::Fraction(x)`
|
/// - `x/` - `Size::Relative(x)`
|
||||||
///
|
///
|
||||||
/// ...where `x` is a literal, identifier or an expression wrapped in parentheses
|
/// ...where `x` is a literal, identifier or an expression wrapped in parentheses
|
||||||
///
|
///
|
||||||
/// # Note:
|
/// # Note:
|
||||||
/// - If a single argument is provided, it creates a `Size` using the rules specified above\
|
/// - If a single argument is provided, it creates a `Size` using the rules specified above\
|
||||||
/// - If two arguments are provided, it creates a `Size2d` with the first value as width and the second as height\
|
/// - If two arguments are provided, it creates a `Size2d` with the first value as width and the second as height\
|
||||||
/// Example: `size!(100, 50%)` creates a `Size2d` with width `100` (`Size::Static(100.)`) and height `50%` (`Size::Fraction(0.5)`)
|
/// Example: `size!(100, 50%)` creates a `Size2d` with width `100` (`Size::Absolute(100.)`) and height `50%` (`Size::Relative(0.5)`)
|
||||||
/// - `%` syntax is only valid for literals (`50%`), not expressions or identidiers.\
|
/// - `%` syntax is only valid for literals (`50%`), not expressions or identidiers.\
|
||||||
/// Use `/` instead (`(0.5 * x)/`, `x/`), but be aware of the different range (0.0-1.0) \
|
/// Use `/` instead (`(0.5 * x)/`, `x/`), but be aware of the different range (0.0-1.0) \
|
||||||
/// - Expressions must be wrapped in parentheses (for example: `(x + 5)`).\
|
/// - Expressions must be wrapped in parentheses (for example: `(x + 5)`).\
|
||||||
|
@ -24,27 +24,27 @@ macro_rules! size {
|
||||||
};
|
};
|
||||||
|
|
||||||
($x:literal) => {
|
($x:literal) => {
|
||||||
$crate::layout::Size::Static($x as f32)
|
$crate::layout::Size::Absolute($x as f32)
|
||||||
};
|
};
|
||||||
($x:literal %) => {
|
($x:literal %) => {
|
||||||
$crate::layout::Size::Fraction($x as f32 / 100.)
|
$crate::layout::Size::Relative($x as f32 / 100.)
|
||||||
};
|
};
|
||||||
($x:literal /) => {
|
($x:literal /) => {
|
||||||
$crate::layout::Size::Fraction($x as f32)
|
$crate::layout::Size::Relative($x as f32)
|
||||||
};
|
};
|
||||||
|
|
||||||
($x:ident) => {
|
($x:ident) => {
|
||||||
$crate::layout::Size::Static($x as f32)
|
$crate::layout::Size::Absolute($x as f32)
|
||||||
};
|
};
|
||||||
($x:ident /) => {
|
($x:ident /) => {
|
||||||
$crate::layout::Size::Fraction($x as f32)
|
$crate::layout::Size::Relative($x as f32)
|
||||||
};
|
};
|
||||||
|
|
||||||
(($x:expr)) => {
|
(($x:expr)) => {
|
||||||
$crate::layout::Size::Static(($x) as f32)
|
$crate::layout::Size::Absolute(($x) as f32)
|
||||||
};
|
};
|
||||||
(($x:expr) /) => {
|
(($x:expr) /) => {
|
||||||
$crate::layout::Size::Fraction(($x) as f32)
|
$crate::layout::Size::Relative(($x) as f32)
|
||||||
};
|
};
|
||||||
|
|
||||||
($x:tt , $y:tt $($ys:tt)?) => {
|
($x:tt , $y:tt $($ys:tt)?) => {
|
||||||
|
|
Loading…
Reference in a new issue