mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-11-25 16:38:42 -06:00
Compare commits
14 commits
fb2f3c739e
...
2a4af1aa35
Author | SHA1 | Date | |
---|---|---|---|
griffi-gh | 2a4af1aa35 | ||
griffi-gh | 8a52fe1d67 | ||
griffi-gh | 7a64a6b750 | ||
griffi-gh | 9ba0a7e762 | ||
griffi-gh | 91668e575c | ||
griffi-gh | b89a277aa9 | ||
griffi-gh | f5f3dd9ad3 | ||
griffi-gh | 03a49791fa | ||
griffi-gh | d2598f8a20 | ||
griffi-gh | d44a2bae53 | ||
griffi-gh | 3c680ea294 | ||
griffi-gh | 899774a7e1 | ||
griffi-gh | 9acdacaa32 | ||
griffi-gh | f8b80040f3 |
|
@ -9,8 +9,8 @@ use winit::{
|
||||||
};
|
};
|
||||||
use hui::{
|
use hui::{
|
||||||
element::{
|
element::{
|
||||||
container::Container, progress_bar::ProgressBar, fill_rect::FillRect, ElementList, UiElement
|
container::Container, fill_rect::FillRect, progress_bar::ProgressBar, ElementList, UiElement
|
||||||
}, layout::{Alignment, Direction, Size}, rect::{Corners, Sides}, UiInstance
|
}, frame::FrameRect, layout::{Alignment, Direction, Size}, rect::{Corners, Sides}, UiInstance
|
||||||
};
|
};
|
||||||
use hui_glium::GliumUiRenderer;
|
use hui_glium::GliumUiRenderer;
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ fn main() {
|
||||||
Box::new(Container {
|
Box::new(Container {
|
||||||
gap: 5.,
|
gap: 5.,
|
||||||
padding: Sides::all(5.),
|
padding: Sides::all(5.),
|
||||||
background: vec4(0., 0., 0., 0.5).into(),
|
background_frame: Box::new(FrameRect::color(vec4(0., 0., 0., 0.5))),
|
||||||
direction: Direction::Horizontal,
|
direction: Direction::Horizontal,
|
||||||
children: {
|
children: {
|
||||||
let mut x: Vec<Box<dyn UiElement>> = vec![];
|
let mut x: Vec<Box<dyn UiElement>> = vec![];
|
||||||
|
@ -115,19 +115,18 @@ fn main() {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Box::new(Container {
|
Box::new(Container {
|
||||||
background: vec4(1., 0., 0., 1.).into(),
|
background_frame: Box::new(FrameRect::color((1., 0., 0.)).with_corner_radius(Corners {
|
||||||
|
top_left: 0.,
|
||||||
|
top_right: 30.,
|
||||||
|
bottom_left: 0.,
|
||||||
|
bottom_right: 0.,
|
||||||
|
})),
|
||||||
padding: Sides {
|
padding: Sides {
|
||||||
top: 10.,
|
top: 10.,
|
||||||
bottom: 20.,
|
bottom: 20.,
|
||||||
left: 30.,
|
left: 30.,
|
||||||
right: 40.,
|
right: 40.,
|
||||||
},
|
},
|
||||||
corner_radius: Corners {
|
|
||||||
top_left: 0.,
|
|
||||||
top_right: 30.,
|
|
||||||
bottom_left: 0.,
|
|
||||||
bottom_right: 0.,
|
|
||||||
},
|
|
||||||
children: ElementList(vec![
|
children: ElementList(vec![
|
||||||
Box::new(FillRect {
|
Box::new(FillRect {
|
||||||
size: (Size::Absolute(50.), Size::Absolute(50.)).into(),
|
size: (Size::Absolute(50.), Size::Absolute(50.)).into(),
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use hui::{
|
use hui::{
|
||||||
size,
|
|
||||||
layout::{Alignment, Direction},
|
|
||||||
element::{
|
element::{
|
||||||
container::Container,
|
container::Container,
|
||||||
progress_bar::ProgressBar,
|
progress_bar::ProgressBar,
|
||||||
text::Text,
|
text::Text,
|
||||||
UiElementExt,
|
UiElementExt,
|
||||||
},
|
}, frame::FrameRect, frame_rect, layout::{Alignment, Direction}, size
|
||||||
};
|
};
|
||||||
|
|
||||||
#[path = "../boilerplate.rs"]
|
#[path = "../boilerplate.rs"]
|
||||||
|
@ -33,8 +31,10 @@ ui_main!{
|
||||||
.with_gap(5.)
|
.with_gap(5.)
|
||||||
.with_padding(10.)
|
.with_padding(10.)
|
||||||
.with_size(size!(450, auto))
|
.with_size(size!(450, auto))
|
||||||
.with_background((0.2, 0.2, 0.5))
|
.with_background(frame_rect! {
|
||||||
.with_corner_radius(8.)
|
color: (0.2, 0.2, 0.5),
|
||||||
|
corner_radius: 8.
|
||||||
|
})
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
if instant.elapsed().as_secs_f32() < 5. {
|
if instant.elapsed().as_secs_f32() < 5. {
|
||||||
Text::default()
|
Text::default()
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
//WARNING: THIS EXAMPLE IS EXTREMELY OUTDATED AND USES DEPRECATED API
|
|
||||||
|
|
||||||
use glam::{vec4, UVec2};
|
|
||||||
use glium::{backend::glutin::SimpleWindowBuilder, Surface};
|
|
||||||
use winit::{
|
|
||||||
event::{Event, WindowEvent},
|
|
||||||
event_loop::{EventLoopBuilder, ControlFlow}
|
|
||||||
};
|
|
||||||
use hui::{
|
|
||||||
element::{
|
|
||||||
container::Container,
|
|
||||||
text::Text, ElementList
|
|
||||||
},
|
|
||||||
layout::{Alignment, Direction, Size},
|
|
||||||
rect::{Corners, Sides},
|
|
||||||
UiInstance
|
|
||||||
};
|
|
||||||
use hui_glium::GliumUiRenderer;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
kubi_logging::init();
|
|
||||||
|
|
||||||
let event_loop = EventLoopBuilder::new().build().unwrap();
|
|
||||||
let (_window, display) = SimpleWindowBuilder::new().build(&event_loop);
|
|
||||||
|
|
||||||
let mut hui = UiInstance::new();
|
|
||||||
let mut backend = GliumUiRenderer::new(&display);
|
|
||||||
event_loop.run(|event, window_target| {
|
|
||||||
window_target.set_control_flow(ControlFlow::Poll);
|
|
||||||
match event {
|
|
||||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
|
||||||
window_target.exit();
|
|
||||||
},
|
|
||||||
Event::AboutToWait => {
|
|
||||||
let mut frame = display.draw();
|
|
||||||
frame.clear_color_srgb(0.5, 0.5, 0.5, 0.);
|
|
||||||
|
|
||||||
let resolution = UVec2::from(display.get_framebuffer_dimensions()).as_vec2();
|
|
||||||
|
|
||||||
hui.begin();
|
|
||||||
|
|
||||||
hui.add(Container {
|
|
||||||
gap: 10.,
|
|
||||||
align: Alignment::Center.into(),
|
|
||||||
size: (Size::Relative(1.), Size::Relative(1.)).into(),
|
|
||||||
children: ElementList(vec![
|
|
||||||
Box::new(Container {
|
|
||||||
align: Alignment::Center.into(),
|
|
||||||
size: (Size::Relative(0.5), Size::Relative(0.5)).into(),
|
|
||||||
background: vec4(1., 0., 0., 1.).into(),
|
|
||||||
corner_radius: Corners {
|
|
||||||
top_left: 10.,
|
|
||||||
top_right: 20.,
|
|
||||||
bottom_left: 50.,
|
|
||||||
bottom_right: 80.
|
|
||||||
},
|
|
||||||
children: ElementList(vec![
|
|
||||||
Box::new(Container {
|
|
||||||
padding: Sides::all(20.),
|
|
||||||
direction: Direction::Horizontal,
|
|
||||||
align: Alignment::Center.into(),
|
|
||||||
size: (Size::Auto, Size::Auto).into(),
|
|
||||||
background: vec4(0.1, 0.1, 0.1, 0.5).into(),
|
|
||||||
corner_radius: Corners::all(8.),
|
|
||||||
children: ElementList(vec![
|
|
||||||
Box::new(Text {
|
|
||||||
text: "Corners".into(),
|
|
||||||
text_size: 50,
|
|
||||||
color: vec4(1., 1., 1., 1.),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
Box::new(Text {
|
|
||||||
text: "!".into(),
|
|
||||||
text_size: 50,
|
|
||||||
color: vec4(1., 1., 0., 1.),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
Box::new(Container {
|
|
||||||
gap: 10.,
|
|
||||||
direction: Direction::Horizontal,
|
|
||||||
children: ElementList(vec![
|
|
||||||
Box::new(Container {
|
|
||||||
size: (Size::Absolute(100.), Size::Absolute(100.)).into(),
|
|
||||||
background: Corners::left_right(
|
|
||||||
vec4(1., 0., 0., 1.),
|
|
||||||
vec4(0., 1., 0., 1.)
|
|
||||||
).into(),
|
|
||||||
corner_radius: Corners::all(0.),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
Box::new(Container {
|
|
||||||
size: (Size::Absolute(100.), Size::Absolute(100.)).into(),
|
|
||||||
background: Corners::left_right(
|
|
||||||
vec4(1., 0., 0., 1.),
|
|
||||||
vec4(0., 1., 0., 1.)
|
|
||||||
).into(),
|
|
||||||
corner_radius: Corners::all(10.),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
Box::new(Container {
|
|
||||||
size: (Size::Absolute(100.), Size::Absolute(100.)).into(),
|
|
||||||
background: Corners::left_right(
|
|
||||||
vec4(1., 0., 0., 1.),
|
|
||||||
vec4(0., 1., 0., 1.)
|
|
||||||
).into(),
|
|
||||||
corner_radius: Corners::all(20.),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
Box::new(Container {
|
|
||||||
size: (Size::Absolute(100.), Size::Absolute(100.)).into(),
|
|
||||||
background: Corners::left_right(
|
|
||||||
vec4(1., 0., 0., 1.),
|
|
||||||
vec4(0., 1., 0., 1.)
|
|
||||||
).into(),
|
|
||||||
corner_radius: Corners::all(30.),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
..Default::default()
|
|
||||||
}, resolution);
|
|
||||||
|
|
||||||
hui.end();
|
|
||||||
|
|
||||||
backend.update(&hui);
|
|
||||||
backend.draw(&mut frame, resolution);
|
|
||||||
|
|
||||||
frame.finish().unwrap();
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}).unwrap();
|
|
||||||
}
|
|
|
@ -10,7 +10,7 @@ use winit::{
|
||||||
use hui::{
|
use hui::{
|
||||||
element::{
|
element::{
|
||||||
container::Container, fill_rect::FillRect, spacer::Spacer, text::Text, ElementList
|
container::Container, fill_rect::FillRect, spacer::Spacer, text::Text, ElementList
|
||||||
}, layout::Size, UiInstance
|
}, frame::FrameRect, layout::Size, UiInstance
|
||||||
};
|
};
|
||||||
use hui_glium::GliumUiRenderer;
|
use hui_glium::GliumUiRenderer;
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ fn main() {
|
||||||
|
|
||||||
hui.add(Container {
|
hui.add(Container {
|
||||||
size: (Size::Relative(1.), Size::Relative(1.)).into(),
|
size: (Size::Relative(1.), Size::Relative(1.)).into(),
|
||||||
background: vec4(0.1, 0.1, 0.1, 1.).into(),
|
background_frame: Box::new(FrameRect::color((0.1, 0.1, 0.1, 1.))),
|
||||||
children: elements(|elem| {
|
children: elements(|elem| {
|
||||||
elem.push(Box::new(Text {
|
elem.push(Box::new(Text {
|
||||||
text: "THIS LINE SHOULD BE SHARP!".into(),
|
text: "THIS LINE SHOULD BE SHARP!".into(),
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use hui::{
|
use hui::{
|
||||||
color, size,
|
color, element::{container::Container, text::Text, UiElementExt}, frame::FrameRect, layout::Alignment, size
|
||||||
layout::Alignment,
|
|
||||||
element::{UiElementExt, container::Container, text::Text},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[path = "../boilerplate.rs"]
|
#[path = "../boilerplate.rs"]
|
||||||
|
@ -14,8 +12,10 @@ ui_main!(|ui, size, _| {
|
||||||
.with_align(Alignment::Center)
|
.with_align(Alignment::Center)
|
||||||
.with_padding(5.)
|
.with_padding(5.)
|
||||||
.with_gap(10.)
|
.with_gap(10.)
|
||||||
.with_corner_radius(10.)
|
.with_background(
|
||||||
.with_background(color::WHITE)
|
FrameRect::color(color::WHITE)
|
||||||
|
.with_corner_radius(10.)
|
||||||
|
)
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
Text::default()
|
Text::default()
|
||||||
.with_text("Hello, world")
|
.with_text("Hello, world")
|
||||||
|
@ -24,8 +24,10 @@ ui_main!(|ui, size, _| {
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Container::default()
|
Container::default()
|
||||||
.with_padding((10., 20.))
|
.with_padding((10., 20.))
|
||||||
.with_corner_radius((2.5, 30., 2.5, 2.5))
|
.with_background(
|
||||||
.with_background(color::DARK_RED)
|
FrameRect::color(color::DARK_RED)
|
||||||
|
.with_corner_radius((2.5, 30., 2.5, 2.5))
|
||||||
|
)
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
Text::default()
|
Text::default()
|
||||||
.with_text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
|
.with_text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
use glam::vec4;
|
use glam::vec4;
|
||||||
use hui::{
|
use hui::{
|
||||||
color, size,
|
size, frame_rect,
|
||||||
element::{container::Container, progress_bar::ProgressBar, text::Text, UiElementExt},
|
color,
|
||||||
|
element::{
|
||||||
|
container::Container,
|
||||||
|
progress_bar::ProgressBar,
|
||||||
|
text::Text,
|
||||||
|
UiElementExt
|
||||||
|
},
|
||||||
|
frame::FrameRect,
|
||||||
layout::Alignment,
|
layout::Alignment,
|
||||||
rect::Corners,
|
rect::Corners,
|
||||||
text::FontHandle,
|
text::FontHandle
|
||||||
};
|
};
|
||||||
|
|
||||||
#[path = "../boilerplate.rs"]
|
#[path = "../boilerplate.rs"]
|
||||||
|
@ -38,8 +45,10 @@ ui_main!(
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
Container::default()
|
Container::default()
|
||||||
.with_padding((10., 15.))
|
.with_padding((10., 15.))
|
||||||
.with_corner_radius(8.)
|
.with_background(
|
||||||
.with_background((0., 0., 0., 0.5))
|
FrameRect::color((0., 0., 0., 0.5))
|
||||||
|
.with_corner_radius(8.)
|
||||||
|
)
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
let flash = 1. - 0.5 * (4. * instant.elapsed().as_secs_f32()).sin().powi(2);
|
let flash = 1. - 0.5 * (4. * instant.elapsed().as_secs_f32()).sin().powi(2);
|
||||||
Text::default()
|
Text::default()
|
||||||
|
@ -61,8 +70,10 @@ ui_main!(
|
||||||
.with_align((Alignment::Center, Alignment::Begin))
|
.with_align((Alignment::Center, Alignment::Begin))
|
||||||
.with_padding(15.)
|
.with_padding(15.)
|
||||||
.with_gap(10.)
|
.with_gap(10.)
|
||||||
.with_corner_radius(8.)
|
.with_background(frame_rect! {
|
||||||
.with_background((0., 0., 0., 0.5))
|
color: (0., 0., 0., 0.5),
|
||||||
|
corner_radius: 8.,
|
||||||
|
})
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
Text::default()
|
Text::default()
|
||||||
.with_text("Did you know?")
|
.with_text("Did you know?")
|
||||||
|
@ -100,8 +111,10 @@ ui_main!(
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
Container::default()
|
Container::default()
|
||||||
.with_padding(10.)
|
.with_padding(10.)
|
||||||
.with_corner_radius(8.)
|
.with_background(
|
||||||
.with_background((0., 0., 0., 0.5))
|
FrameRect::color((0., 0., 0., 0.5))
|
||||||
|
.with_corner_radius(8.)
|
||||||
|
)
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
Text::default()
|
Text::default()
|
||||||
.with_text("Level 5")
|
.with_text("Level 5")
|
||||||
|
|
|
@ -7,11 +7,7 @@ use hui::{
|
||||||
text::Text,
|
text::Text,
|
||||||
transformer::ElementTransformExt,
|
transformer::ElementTransformExt,
|
||||||
UiElementExt
|
UiElementExt
|
||||||
},
|
}, frame::FrameRect, frame_rect, layout::Alignment, rect::Corners, size, text::FontHandle
|
||||||
layout::Alignment,
|
|
||||||
rect::Corners,
|
|
||||||
text::FontHandle,
|
|
||||||
size,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[path = "../boilerplate.rs"]
|
#[path = "../boilerplate.rs"]
|
||||||
|
@ -41,8 +37,10 @@ ui_main!(
|
||||||
.with_align((Alignment::Center, Alignment::Begin))
|
.with_align((Alignment::Center, Alignment::Begin))
|
||||||
.with_padding(15.)
|
.with_padding(15.)
|
||||||
.with_gap(10.)
|
.with_gap(10.)
|
||||||
.with_corner_radius(8.)
|
.with_background(frame_rect! {
|
||||||
.with_background((0., 0., 0., 0.5))
|
color: (0., 0., 0., 0.5),
|
||||||
|
corner_radius: 8.
|
||||||
|
})
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
Text::default()
|
Text::default()
|
||||||
.with_text("Did you know?")
|
.with_text("Did you know?")
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
use hui::{
|
use hui::{
|
||||||
draw::TextureFormat,
|
draw::TextureFormat,
|
||||||
signal::Signal,
|
|
||||||
layout::{Alignment, Direction},
|
|
||||||
element::{
|
element::{
|
||||||
container::Container,
|
|
||||||
text::Text,
|
|
||||||
image::Image,
|
|
||||||
br::Break,
|
br::Break,
|
||||||
|
container::Container,
|
||||||
|
image::Image,
|
||||||
slider::Slider,
|
slider::Slider,
|
||||||
|
text::Text,
|
||||||
UiElementExt,
|
UiElementExt,
|
||||||
},
|
},
|
||||||
|
frame::FrameRect,
|
||||||
|
layout::{Alignment, Direction},
|
||||||
|
signal::Signal,
|
||||||
size,
|
size,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ document-features = "0.2"
|
||||||
derive_setters = "0.1"
|
derive_setters = "0.1"
|
||||||
derive_more = "0.99"
|
derive_more = "0.99"
|
||||||
tinyset = "0.4"
|
tinyset = "0.4"
|
||||||
enum_dispatch = "0.3"
|
#enum_dispatch = "0.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["builtin_elements", "builtin_font", "pixel_perfect_text"]
|
default = ["builtin_elements", "builtin_font", "pixel_perfect_text"]
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::rect::Corners;
|
||||||
|
|
||||||
//TODO uneven corners (separate width/height for each corner)
|
//TODO uneven corners (separate width/height for each corner)
|
||||||
|
|
||||||
|
/// Calculate the number of points based on the maximum corner radius
|
||||||
fn point_count(corners: Corners<f32>) -> NonZeroU16 {
|
fn point_count(corners: Corners<f32>) -> NonZeroU16 {
|
||||||
//Increase for higher quality
|
//Increase for higher quality
|
||||||
const VTX_PER_CORER_RADIUS_PIXEL: f32 = 0.5;
|
const VTX_PER_CORER_RADIUS_PIXEL: f32 = 0.5;
|
||||||
|
@ -11,19 +12,31 @@ fn point_count(corners: Corners<f32>) -> NonZeroU16 {
|
||||||
).unwrap()
|
).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Low-level options for rendering rounded corners
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct RoundedCorners {
|
pub struct RoundedCorners {
|
||||||
|
/// Corner radius of each corner
|
||||||
pub radius: Corners<f32>,
|
pub radius: Corners<f32>,
|
||||||
|
|
||||||
|
/// Number of points to use for each corner
|
||||||
|
///
|
||||||
|
/// This value affects all corners, regardless of their individual radius
|
||||||
pub point_count: NonZeroU16,
|
pub point_count: NonZeroU16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Corners<f32>> for RoundedCorners {
|
impl From<Corners<f32>> for RoundedCorners {
|
||||||
|
/// Create a new `RoundedCorners` from [`Corners<f32>`](crate::rect::Corners)
|
||||||
|
///
|
||||||
|
/// Point count will be calculated automatically based on the maximum radius
|
||||||
fn from(radius: Corners<f32>) -> Self {
|
fn from(radius: Corners<f32>) -> Self {
|
||||||
Self::from_radius(radius)
|
Self::from_radius(radius)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoundedCorners {
|
impl RoundedCorners {
|
||||||
|
/// Create a new `RoundedCorners` from [`Corners<f32>`](crate::rect::Corners)
|
||||||
|
///
|
||||||
|
/// Point count will be calculated automatically based on the maximum radius
|
||||||
pub fn from_radius(radius: Corners<f32>) -> Self {
|
pub fn from_radius(radius: Corners<f32>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
radius,
|
radius,
|
||||||
|
|
|
@ -3,18 +3,13 @@
|
||||||
use derive_setters::Setters;
|
use derive_setters::Setters;
|
||||||
use glam::{Vec2, vec2};
|
use glam::{Vec2, vec2};
|
||||||
use crate::{
|
use crate::{
|
||||||
draw::{ImageHandle, RoundedCorners, UiDrawCommand},
|
|
||||||
element::{ElementList, MeasureContext, ProcessContext, UiElement},
|
element::{ElementList, MeasureContext, ProcessContext, UiElement},
|
||||||
layout::{Alignment, Alignment2d, Direction, LayoutInfo, Size, Size2d},
|
layout::{Alignment, Alignment2d, Direction, LayoutInfo, Size, Size2d},
|
||||||
|
frame::{Frame, FrameRect},
|
||||||
measure::{Hints, Response},
|
measure::{Hints, Response},
|
||||||
rect::{Corners, FillColor, Sides},
|
rect::{Sides, FillColor},
|
||||||
};
|
};
|
||||||
|
|
||||||
// pub struct Border {
|
|
||||||
// pub color: Vec4,
|
|
||||||
// pub width: f32,
|
|
||||||
// }
|
|
||||||
|
|
||||||
//XXX: add Order/Direction::Forward/Reverse or sth?
|
//XXX: add Order/Direction::Forward/Reverse or sth?
|
||||||
//TODO: clip children flag
|
//TODO: clip children flag
|
||||||
//TODO: borders
|
//TODO: borders
|
||||||
|
@ -54,26 +49,8 @@ pub struct Container {
|
||||||
#[setters(into)]
|
#[setters(into)]
|
||||||
pub align: Alignment2d,
|
pub align: Alignment2d,
|
||||||
|
|
||||||
/// Background color of the container\
|
#[setters(skip)]
|
||||||
///
|
pub background_frame: Box<dyn Frame>,
|
||||||
/// If the container has a background texture, it will be multiplied by this color
|
|
||||||
#[setters(into)]
|
|
||||||
pub background: FillColor,
|
|
||||||
|
|
||||||
/// Background texture of the container
|
|
||||||
///
|
|
||||||
/// Can be used in conjunction with the background color\
|
|
||||||
/// In this case, the texture will be shaded by the color
|
|
||||||
///
|
|
||||||
/// Please note that if the background color is NOT set (or set to transparent), the texture will NOT be visible\
|
|
||||||
/// This is because the texture is multiplied by the color, and if the color is transparent, the texture will be too\
|
|
||||||
//TODO: fix this flaw, if background_image is called for the first time, bg wasnt explicitly set and background is transparent, set it to white
|
|
||||||
#[setters(into)]
|
|
||||||
pub background_image: Option<ImageHandle>,
|
|
||||||
|
|
||||||
/// Corner radius of the background rectangle
|
|
||||||
#[setters(into)]
|
|
||||||
pub corner_radius: Corners<f32>,
|
|
||||||
|
|
||||||
/// Set this to `true` to allow the elements wrap automatically
|
/// Set this to `true` to allow the elements wrap automatically
|
||||||
///
|
///
|
||||||
|
@ -93,6 +70,11 @@ impl Container {
|
||||||
self.children.0.extend(ElementList::from_callback(ui).0);
|
self.children.0.extend(ElementList::from_callback(ui).0);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_background(mut self, frame: impl Frame + 'static) -> Self {
|
||||||
|
self.background_frame = Box::new(frame);
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Container {
|
impl Default for Container {
|
||||||
|
@ -103,11 +85,9 @@ impl Default for Container {
|
||||||
gap: 0.,
|
gap: 0.,
|
||||||
padding: Sides::all(0.),
|
padding: Sides::all(0.),
|
||||||
align: Alignment2d::default(),
|
align: Alignment2d::default(),
|
||||||
background: FillColor::transparent(),
|
background_frame: Box::<FrameRect>::default(),
|
||||||
background_image: None,
|
|
||||||
children: ElementList(Vec::new()),
|
|
||||||
wrap: false,
|
wrap: false,
|
||||||
corner_radius: Corners::all(0.),
|
children: ElementList(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,18 +308,20 @@ impl UiElement for Container {
|
||||||
let mut position = ctx.layout.position;
|
let mut position = ctx.layout.position;
|
||||||
|
|
||||||
//background
|
//background
|
||||||
if !self.background.is_transparent() {
|
// if !self.background.is_transparent() {
|
||||||
let corner_colors = self.background.corners();
|
// let corner_colors = self.background.corners();
|
||||||
ctx.draw.add(UiDrawCommand::Rectangle {
|
// ctx.draw.add(UiDrawCommand::Rectangle {
|
||||||
position,
|
// position,
|
||||||
size: ctx.measure.size,
|
// size: ctx.measure.size,
|
||||||
color: corner_colors,
|
// color: corner_colors,
|
||||||
texture: self.background_image,
|
// texture: self.background_image,
|
||||||
rounded_corners: (self.corner_radius.max_f32() > 0.).then_some({
|
// rounded_corners: (self.corner_radius.max_f32() > 0.).then_some({
|
||||||
RoundedCorners::from_radius(self.corner_radius)
|
// RoundedCorners::from_radius(self.corner_radius)
|
||||||
}),
|
// }),
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
self.background_frame.draw(ctx.draw, ctx.layout.position, ctx.measure.size);
|
||||||
|
|
||||||
//padding
|
//padding
|
||||||
position += vec2(self.padding.left, self.padding.top);
|
position += vec2(self.padding.left, self.padding.top);
|
||||||
|
|
|
@ -16,6 +16,8 @@ use crate::{
|
||||||
//TODO: use state for slider?
|
//TODO: use state for slider?
|
||||||
// ^ useful if the user only hanldes the drag end event or has large step sizes with relative mode
|
// ^ useful if the user only hanldes the drag end event or has large step sizes with relative mode
|
||||||
|
|
||||||
|
//TODO: adopt frame api here
|
||||||
|
|
||||||
/// 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 {
|
||||||
|
|
|
@ -1,67 +1,13 @@
|
||||||
pub mod point;
|
|
||||||
pub mod layer;
|
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use layer::{FrameLayer, FrameLayerImpl};
|
|
||||||
use crate::draw::UiDrawCommandList;
|
use crate::draw::UiDrawCommandList;
|
||||||
|
|
||||||
///XXX: this is not used yet, and also kinda a mess, simplify?
|
pub mod point;
|
||||||
///Maybe limit to a single layer? (aka `Frame` will be just one of the options)
|
mod rect;
|
||||||
///Because currently, this is just a duplicate of the dormal draw command system, but with a different name...
|
pub mod stack;
|
||||||
///Then, there's no need for the positioning stuff too, which is a bit overkill and is kinda code duplication too!
|
mod impls;
|
||||||
///aka Frame::Rectangle, Frame::NinePatch, ...
|
|
||||||
|
|
||||||
/// A frame, which can contain multiple layers
|
pub use rect::FrameRect;
|
||||||
///
|
|
||||||
/// Use these to construct complex backgrounds
|
pub trait Frame {
|
||||||
#[derive(Default, Clone)]
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2);
|
||||||
pub struct Frame {
|
|
||||||
/// Layers of the frame
|
|
||||||
layers: Vec<FrameLayer>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Into<FrameLayer>> From<T> for Frame {
|
|
||||||
fn from(layer: T) -> Self {
|
|
||||||
let mut frame = Self::default();
|
|
||||||
frame.add(layer.into());
|
|
||||||
frame
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
/// Get the layer with the given index
|
|
||||||
#[inline]
|
|
||||||
pub fn layer(&self, index: usize) -> Option<&FrameLayer> {
|
|
||||||
self.layers.get(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a mutable reference to the layer with the given index
|
|
||||||
#[inline]
|
|
||||||
pub fn layer_mut(&mut self, index: usize) -> Option<&mut FrameLayer> {
|
|
||||||
self.layers.get_mut(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a layer to the frame
|
|
||||||
#[inline]
|
|
||||||
pub fn add(&mut self, layer: impl Into<FrameLayer>) -> &mut Self {
|
|
||||||
self.layers.push(layer.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a layer to the back of the frame
|
|
||||||
#[inline]
|
|
||||||
pub fn add_back(&mut self, layer: impl Into<FrameLayer>) -> &mut Self {
|
|
||||||
self.layers.insert(0, layer.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn finish(&mut self) -> Self {
|
|
||||||
self.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
|
||||||
for layer in &self.layers {
|
|
||||||
layer.draw(draw, position, parent_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
125
hui/src/frame/impls.rs
Normal file
125
hui/src/frame/impls.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
use glam::{Vec2, Vec3, Vec4};
|
||||||
|
use super::Frame;
|
||||||
|
use crate::{
|
||||||
|
color,
|
||||||
|
draw::{ImageHandle, UiDrawCommand, UiDrawCommandList},
|
||||||
|
rect::{Corners, FillColor},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Frame for ImageHandle {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
draw.add(UiDrawCommand::Rectangle {
|
||||||
|
position,
|
||||||
|
size: parent_size,
|
||||||
|
color: color::WHITE.into(),
|
||||||
|
texture: Some(*self),
|
||||||
|
rounded_corners: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for FillColor {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
draw.add(UiDrawCommand::Rectangle {
|
||||||
|
position,
|
||||||
|
size: parent_size,
|
||||||
|
color: self.corners(),
|
||||||
|
texture: None,
|
||||||
|
rounded_corners: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl for various types resembling colors
|
||||||
|
|
||||||
|
// Corners (RGBA):
|
||||||
|
|
||||||
|
impl Frame for Corners<Vec4> {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for (Vec4, Vec4, Vec4, Vec4) {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for ((f32, f32, f32, f32), (f32, f32, f32, f32), (f32, f32, f32, f32), (f32, f32, f32, f32)) {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for [[f32; 4]; 4] {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Corners (RGB):
|
||||||
|
|
||||||
|
impl Frame for Corners<Vec3> {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for (Vec3, Vec3, Vec3, Vec3) {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for ((f32, f32, f32), (f32, f32, f32), (f32, f32, f32), (f32, f32, f32)) {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for [[f32; 3]; 4] {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RGBA:
|
||||||
|
|
||||||
|
impl Frame for Vec4 {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for (f32, f32, f32, f32) {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for [f32; 4] {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RGB:
|
||||||
|
|
||||||
|
impl Frame for Vec3 {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for (f32, f32, f32) {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame for [f32; 3] {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
FillColor::from(*self).draw(draw, position, parent_size)
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,14 +43,14 @@ impl FramePoint {
|
||||||
|
|
||||||
/// Center of the frame axis
|
/// Center of the frame axis
|
||||||
pub const CENTER: Self = Self {
|
pub const CENTER: Self = Self {
|
||||||
absolute: 0.5,
|
absolute: 0.0,
|
||||||
relative: 0.0,
|
relative: 0.5,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// End of the frame axis
|
/// End of the frame axis
|
||||||
pub const END: Self = Self {
|
pub const END: Self = Self {
|
||||||
absolute: 1.0,
|
absolute: 0.0,
|
||||||
relative: 0.0,
|
relative: 1.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Create a new absolutely positioned `FramePoint`
|
/// Create a new absolutely positioned `FramePoint`
|
||||||
|
|
|
@ -1,25 +1,13 @@
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use enum_dispatch::enum_dispatch;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color,
|
color,
|
||||||
draw::{ImageHandle, RoundedCorners, UiDrawCommand, UiDrawCommandList},
|
draw::{ImageHandle, RoundedCorners, UiDrawCommand, UiDrawCommandList},
|
||||||
rect::{Corners, FillColor},
|
rect::{Corners, FillColor},
|
||||||
};
|
};
|
||||||
use super::point::FramePoint2d;
|
use super::{Frame, point::FramePoint2d};
|
||||||
|
|
||||||
#[enum_dispatch]
|
|
||||||
pub(crate) trait FrameLayerImpl {
|
|
||||||
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[enum_dispatch(FrameLayerImpl)]
|
pub struct FrameRect {
|
||||||
pub enum FrameLayer {
|
|
||||||
Rect(RectFrame),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct RectFrame {
|
|
||||||
/// Background color of the frame\
|
/// Background color of the frame\
|
||||||
///
|
///
|
||||||
/// If the container has a background texture, it will be multiplied by this color
|
/// If the container has a background texture, it will be multiplied by this color
|
||||||
|
@ -44,29 +32,35 @@ pub struct RectFrame {
|
||||||
pub corner_radius: Corners<f32>,
|
pub corner_radius: Corners<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<FillColor>> From<T> for RectFrame {
|
// impl<T: Into<FillColor>> From<T> for FrameRect {
|
||||||
fn from(color: T) -> Self {
|
// fn from(color: T) -> Self {
|
||||||
Self::from_color(color)
|
// Self::from_color(color)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
impl From<FillColor> for FrameRect {
|
||||||
|
fn from(color: FillColor) -> Self {
|
||||||
|
Self::color(color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RectFrame {
|
impl From<ImageHandle> for FrameRect {
|
||||||
pub fn from_color(color: impl Into<FillColor>) -> Self {
|
fn from(image: ImageHandle) -> Self {
|
||||||
|
Self::image(image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameRect {
|
||||||
|
/// Create a new [`FrameRect`] with the given color
|
||||||
|
pub fn color(color: impl Into<FillColor>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
color: color.into(),
|
color: color.into(),
|
||||||
..Self::default()
|
..Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_color_rounded(color: impl Into<FillColor>, corner_radius: impl Into<Corners<f32>>) -> Self {
|
/// Create a new [`FrameRect`] with the given image
|
||||||
Self {
|
pub fn image(image: ImageHandle) -> Self {
|
||||||
color: color.into(),
|
|
||||||
corner_radius: corner_radius.into(),
|
|
||||||
..Self::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_image(image: ImageHandle) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
color: color::WHITE.into(),
|
color: color::WHITE.into(),
|
||||||
image: Some(image),
|
image: Some(image),
|
||||||
|
@ -74,7 +68,8 @@ impl RectFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_color_image(color: impl Into<FillColor>, image: ImageHandle) -> Self {
|
/// Create a new [`FrameRect`] with the given color and image
|
||||||
|
pub fn color_image(color: impl Into<FillColor>, image: ImageHandle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
color: color.into(),
|
color: color.into(),
|
||||||
image: Some(image),
|
image: Some(image),
|
||||||
|
@ -82,17 +77,18 @@ impl RectFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_color_image_rounded(color: impl Into<FillColor>, image: ImageHandle, corner_radius: impl Into<Corners<f32>>) -> Self {
|
/// Set the corner radius of the [`FrameRect`]
|
||||||
|
pub fn with_corner_radius(self, radius: impl Into<Corners<f32>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
color: color.into(),
|
corner_radius: radius.into(),
|
||||||
image: Some(image),
|
..self
|
||||||
corner_radius: corner_radius.into(),
|
|
||||||
..Self::default()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inset the rectangle by the given amount
|
//TODO: deprecate and replace
|
||||||
pub fn inset(self, inset: f32) -> Self {
|
|
||||||
|
/// Inset the rectangle by the given amount in pixels
|
||||||
|
pub fn with_inset(self, inset: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
top_left: self.top_left + Vec2::splat(inset).into(),
|
top_left: self.top_left + Vec2::splat(inset).into(),
|
||||||
bottom_right: self.bottom_right - Vec2::splat(inset).into(),
|
bottom_right: self.bottom_right - Vec2::splat(inset).into(),
|
||||||
|
@ -101,10 +97,10 @@ impl RectFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RectFrame {
|
impl Default for FrameRect {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
color: FillColor::default(),
|
color: FillColor::transparent(),
|
||||||
image: None,
|
image: None,
|
||||||
top_left: FramePoint2d::TOP_LEFT,
|
top_left: FramePoint2d::TOP_LEFT,
|
||||||
bottom_right: FramePoint2d::BOTTOM_RIGHT,
|
bottom_right: FramePoint2d::BOTTOM_RIGHT,
|
||||||
|
@ -113,7 +109,7 @@ impl Default for RectFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameLayerImpl for RectFrame {
|
impl Frame for FrameRect {
|
||||||
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
//TODO: handle bottom_right < top_left
|
//TODO: handle bottom_right < top_left
|
||||||
let top_left = self.top_left.resolve(parent_size);
|
let top_left = self.top_left.resolve(parent_size);
|
22
hui/src/frame/stack.rs
Normal file
22
hui/src/frame/stack.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use glam::Vec2;
|
||||||
|
use crate::draw::UiDrawCommandList;
|
||||||
|
use super::Frame;
|
||||||
|
|
||||||
|
pub struct FrameStack(pub Box<dyn Frame>, pub Box<dyn Frame>);
|
||||||
|
|
||||||
|
impl Frame for FrameStack {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||||
|
self.0.draw(draw, position, parent_size);
|
||||||
|
self.1.draw(draw, position, parent_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FrameStackExt: Frame {
|
||||||
|
fn stack(self, other: impl Frame + 'static) -> FrameStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Frame + 'static> FrameStackExt for T {
|
||||||
|
fn stack(self, other: impl Frame + 'static) -> FrameStack {
|
||||||
|
FrameStack(Box::new(self), Box::new(other))
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,3 +60,87 @@ macro_rules! size {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper macro for constructing a `FrameRect`
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! frame_rect {
|
||||||
|
{} => {
|
||||||
|
$crate::frame::FrameRect::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// () => {
|
||||||
|
// $crate::frame::FrameRect::default()
|
||||||
|
// };
|
||||||
|
|
||||||
|
($expr:expr) => {
|
||||||
|
{
|
||||||
|
let _frame_rect: $crate::frame::FrameRect = $crate::frame::FrameRect::from($expr);
|
||||||
|
_frame_rect
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($image:expr, $color:expr) => {
|
||||||
|
$crate::frame::FrameRect::color_image($color, $image)
|
||||||
|
};
|
||||||
|
|
||||||
|
{$($ident:ident : $expr:expr),+$(,)?} => {
|
||||||
|
{
|
||||||
|
// ensure all identifiers are unique
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
{$(const $ident: () = ();)+}
|
||||||
|
|
||||||
|
// construct the FrameRect
|
||||||
|
{
|
||||||
|
let mut frame_rect = $crate::frame::FrameRect::default();
|
||||||
|
let mut _color_is_set = false;
|
||||||
|
let mut _image_is_set = false;
|
||||||
|
$(
|
||||||
|
{
|
||||||
|
frame_rect.$ident = ($expr).into();
|
||||||
|
if stringify!($ident) == "image" {
|
||||||
|
_image_is_set = true;
|
||||||
|
}
|
||||||
|
if stringify!($ident) == "color" {
|
||||||
|
_color_is_set = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
if frame_rect.image.is_some() && _image_is_set && !_color_is_set {
|
||||||
|
frame_rect.color = (1., 1., 1., 1.).into();
|
||||||
|
}
|
||||||
|
frame_rect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// {$from:expr, $($ident:ident : $expr:expr),+$(,)?} => {
|
||||||
|
// {
|
||||||
|
// // ensure all identifiers are unique
|
||||||
|
// #[allow(non_upper_case_globals)]
|
||||||
|
// {
|
||||||
|
// $(
|
||||||
|
// const $ident: () = ();
|
||||||
|
// )+
|
||||||
|
// }
|
||||||
|
// // construct the FrameRect
|
||||||
|
// {
|
||||||
|
// let mut _frame_rect: $crate::frame::FrameRect = ($from).into();
|
||||||
|
// $(
|
||||||
|
// let $ident = ($expr).into();
|
||||||
|
// _frame_rect.$ident = $ident;
|
||||||
|
// )+
|
||||||
|
// _frame_rect
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[allow(unused)]
|
||||||
|
// fn test() {
|
||||||
|
// // let _ = frame_rect!(5, 6);
|
||||||
|
|
||||||
|
// let _ = frame_rect! {
|
||||||
|
// color: (0.2, 0.2, 0.3, 1.),
|
||||||
|
// corner_radius: 5.,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
|
@ -153,6 +153,17 @@ impl From<[[f32; 4]; 4]> for FillColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Corners<Vec3>> for FillColor {
|
||||||
|
fn from(corners: Corners<Vec3>) -> Self {
|
||||||
|
Self(Corners {
|
||||||
|
top_left: corners.top_left.extend(1.),
|
||||||
|
top_right: corners.top_right.extend(1.),
|
||||||
|
bottom_left: corners.bottom_left.extend(1.),
|
||||||
|
bottom_right: corners.bottom_right.extend(1.),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<(Vec3, Vec3, Vec3, Vec3)> for FillColor {
|
impl From<(Vec3, Vec3, Vec3, Vec3)> for FillColor {
|
||||||
fn from((top_left, top_right, bottom_left, bottom_right): (Vec3, Vec3, Vec3, Vec3)) -> Self {
|
fn from((top_left, top_right, bottom_left, bottom_right): (Vec3, Vec3, Vec3, Vec3)) -> Self {
|
||||||
Self(Corners {
|
Self(Corners {
|
||||||
|
|
|
@ -8,6 +8,7 @@ mod font;
|
||||||
mod ftm;
|
mod ftm;
|
||||||
mod stack;
|
mod stack;
|
||||||
|
|
||||||
|
/// Built-in font handle
|
||||||
#[cfg(feature="builtin_font")]
|
#[cfg(feature="builtin_font")]
|
||||||
pub use font::BUILTIN_FONT;
|
pub use font::BUILTIN_FONT;
|
||||||
pub use font::FontHandle;
|
pub use font::FontHandle;
|
||||||
|
@ -17,7 +18,7 @@ use ftm::FontTextureManager;
|
||||||
use ftm::GlyphCacheEntry;
|
use ftm::GlyphCacheEntry;
|
||||||
use stack::FontStack;
|
use stack::FontStack;
|
||||||
|
|
||||||
pub struct TextRenderer {
|
pub(crate) struct TextRenderer {
|
||||||
manager: FontManager,
|
manager: FontManager,
|
||||||
ftm: FontTextureManager,
|
ftm: FontTextureManager,
|
||||||
stack: FontStack,
|
stack: FontStack,
|
||||||
|
@ -63,15 +64,18 @@ impl Default for TextRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Size of measured text
|
||||||
pub struct TextMeasureResponse {
|
pub struct TextMeasureResponse {
|
||||||
pub max_width: f32,
|
pub max_width: f32,
|
||||||
pub height: f32,
|
pub height: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Context for measuring text
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct TextMeasure<'a>(&'a TextRenderer);
|
pub struct TextMeasure<'a>(&'a TextRenderer);
|
||||||
|
|
||||||
impl<'a> TextMeasure<'a> {
|
impl<'a> TextMeasure<'a> {
|
||||||
|
/// Measure the given string of text with the given font and size
|
||||||
pub fn measure(&self, font: FontHandle, size: u16, text: &str) -> TextMeasureResponse {
|
pub fn measure(&self, font: FontHandle, size: u16, text: &str) -> TextMeasureResponse {
|
||||||
use fontdue::layout::{Layout, CoordinateSystem, TextStyle};
|
use fontdue::layout::{Layout, CoordinateSystem, TextStyle};
|
||||||
let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
|
let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
|
||||||
|
|
Loading…
Reference in a new issue