mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-11-25 00:18:41 -06:00
Compare commits
10 commits
92f8975702
...
f8ee8d0e70
Author | SHA1 | Date | |
---|---|---|---|
griffi-gh | f8ee8d0e70 | ||
griffi-gh | b30fe304d1 | ||
griffi-gh | 104ac018fe | ||
griffi-gh | 7a4c4b1a29 | ||
griffi-gh | eda2ddcc0f | ||
griffi-gh | d82eb2eeb1 | ||
griffi-gh | 44b8beaa94 | ||
griffi-gh | 45829d5fef | ||
griffi-gh | 7b671d2f3d | ||
griffi-gh | cdaf4c0781 |
|
@ -32,7 +32,7 @@
|
|||
.with_align(Alignment::Center)
|
||||
.with_padding(5.)
|
||||
.with_gap(10.)
|
||||
.with_background(frame_rect! {
|
||||
.with_background(rect_frame! {
|
||||
color: (0.5, 0.5, 0.5, 1.),
|
||||
corner_radius: 10.,
|
||||
})
|
||||
|
@ -44,7 +44,7 @@
|
|||
.add_child(ui);
|
||||
Container::default()
|
||||
.with_padding((10., 20.))
|
||||
.with_background(frame_rect! {
|
||||
.with_background(rect_frame! {
|
||||
color: color::DARK_RED,
|
||||
corner_radius: (2.5, 30., 2.5, 2.5),
|
||||
})
|
||||
|
|
|
@ -9,8 +9,8 @@ use winit::{
|
|||
};
|
||||
use hui::{
|
||||
element::{
|
||||
container::Container, fill_rect::FillRect, progress_bar::ProgressBar, ElementList, UiElement
|
||||
}, frame::FrameRect, layout::{Alignment, Direction, Size}, rect::{Corners, Sides}, UiInstance
|
||||
container::Container, frame_view::FrameView, progress_bar::ProgressBar, ElementList, UiElement
|
||||
}, frame::RectFrame, layout::{Alignment, Direction, Size}, rect::{Corners, Sides}, UiInstance
|
||||
};
|
||||
use hui_glium::GliumUiRenderer;
|
||||
|
||||
|
@ -71,11 +71,11 @@ fn main() {
|
|||
padding: Sides::all(5.),
|
||||
gap: 10.,
|
||||
children: ElementList(vec![
|
||||
Box::new(FillRect {
|
||||
Box::new(FrameView {
|
||||
size: (Size::Relative(0.5), Size::Absolute(30.)).into(),
|
||||
frame: Box::new(vec4(0.75, 0., 0., 1.)),
|
||||
}),
|
||||
Box::new(FillRect {
|
||||
Box::new(FrameView {
|
||||
size: (Size::Relative(z / 2. + 0.5), Size::Absolute(30.)).into(),
|
||||
frame: Box::new(Corners::left_right(
|
||||
vec4(1., 0., 0., 1.),
|
||||
|
@ -85,19 +85,19 @@ fn main() {
|
|||
]),
|
||||
..Default::default()
|
||||
}),
|
||||
Box::new(FillRect {
|
||||
Box::new(FrameView {
|
||||
size: (Size::Relative(z / 2. + 0.5), Size::Absolute(30.)).into(),
|
||||
frame: Box::new(vec4(0., 0.75, 0., 1.)),
|
||||
}),
|
||||
Box::new(Container {
|
||||
gap: 5.,
|
||||
padding: Sides::all(5.),
|
||||
background_frame: Box::new(FrameRect::color(vec4(0., 0., 0., 0.5))),
|
||||
background_frame: Box::new(RectFrame::color(vec4(0., 0., 0., 0.5))),
|
||||
direction: Direction::Horizontal,
|
||||
children: {
|
||||
let mut x: Vec<Box<dyn UiElement>> = vec![];
|
||||
for i in 0..10 {
|
||||
x.push(Box::new(FillRect {
|
||||
x.push(Box::new(FrameView {
|
||||
size: (Size::Absolute(50.), Size::Absolute(50.)).into(),
|
||||
frame: Box::new(if i == 1 {
|
||||
vec4(0.75, 0.75, 0.75, 0.75)
|
||||
|
@ -111,7 +111,7 @@ fn main() {
|
|||
..Default::default()
|
||||
}),
|
||||
Box::new(Container {
|
||||
background_frame: Box::new(FrameRect::color((1., 0., 0.)).with_corner_radius(Corners {
|
||||
background_frame: Box::new(RectFrame::color((1., 0., 0.)).with_corner_radius(Corners {
|
||||
top_left: 0.,
|
||||
top_right: 30.,
|
||||
bottom_left: 0.,
|
||||
|
@ -124,7 +124,7 @@ fn main() {
|
|||
right: 40.,
|
||||
},
|
||||
children: ElementList(vec![
|
||||
Box::new(FillRect {
|
||||
Box::new(FrameView {
|
||||
size: (Size::Absolute(50.), Size::Absolute(50.)).into(),
|
||||
frame: Box::new(vec4(1., 1., 1., 0.75)),
|
||||
}),
|
||||
|
|
|
@ -5,7 +5,7 @@ use hui::{
|
|||
progress_bar::ProgressBar,
|
||||
text::Text,
|
||||
UiElementExt,
|
||||
}, frame::FrameRect, frame_rect, layout::{Alignment, Direction}, size
|
||||
}, frame::RectFrame, rect_frame, layout::{Alignment, Direction}, size
|
||||
};
|
||||
|
||||
#[path = "../boilerplate.rs"]
|
||||
|
@ -31,7 +31,7 @@ ui_main!{
|
|||
.with_gap(5.)
|
||||
.with_padding(10.)
|
||||
.with_size(size!(450, auto))
|
||||
.with_background(frame_rect! {
|
||||
.with_background(rect_frame! {
|
||||
color: (0.2, 0.2, 0.5),
|
||||
corner_radius: 8.
|
||||
})
|
||||
|
@ -43,11 +43,11 @@ ui_main!{
|
|||
.add_child(ui);
|
||||
ProgressBar::default()
|
||||
.with_value(mom_ratio)
|
||||
.with_background(frame_rect! {
|
||||
.with_background(rect_frame! {
|
||||
color: color::BLACK,
|
||||
corner_radius: 0.125 * ProgressBar::DEFAULT_HEIGHT
|
||||
})
|
||||
.with_foreground(frame_rect! {
|
||||
.with_foreground(rect_frame! {
|
||||
color: color::BLUE,
|
||||
corner_radius: 0.125 * ProgressBar::DEFAULT_HEIGHT
|
||||
})
|
||||
|
|
|
@ -9,8 +9,8 @@ use winit::{
|
|||
};
|
||||
use hui::{
|
||||
element::{
|
||||
container::Container, fill_rect::FillRect, spacer::Spacer, text::Text, ElementList
|
||||
}, frame::FrameRect, layout::Size, UiInstance
|
||||
container::Container, frame_view::FrameView, spacer::Spacer, text::Text, ElementList
|
||||
}, frame::RectFrame, layout::Size, UiInstance
|
||||
};
|
||||
use hui_glium::GliumUiRenderer;
|
||||
|
||||
|
@ -49,7 +49,7 @@ fn main() {
|
|||
|
||||
hui.add(Container {
|
||||
size: (Size::Relative(1.), Size::Relative(1.)).into(),
|
||||
background_frame: Box::new(FrameRect::color((0.1, 0.1, 0.1, 1.))),
|
||||
background_frame: Box::new(RectFrame::color((0.1, 0.1, 0.1, 1.))),
|
||||
children: elements(|elem| {
|
||||
elem.push(Box::new(Text {
|
||||
text: "THIS LINE SHOULD BE SHARP!".into(),
|
||||
|
@ -71,11 +71,11 @@ fn main() {
|
|||
..Default::default()
|
||||
}));
|
||||
}
|
||||
elem.push(Box::new(FillRect {
|
||||
elem.push(Box::new(FrameView {
|
||||
size: (Size::Relative(1.), Size::Absolute(10.)).into(),
|
||||
frame: Box::new(vec4(0., 0., 1., 1.)),
|
||||
}));
|
||||
elem.push(Box::new(FillRect {
|
||||
elem.push(Box::new(FrameView {
|
||||
size: (Size::Relative(1.), Size::Absolute(10.)).into(),
|
||||
frame: Box::new(vec4(1., 1., 0., 1.)),
|
||||
}));
|
||||
|
@ -86,11 +86,11 @@ fn main() {
|
|||
..Default::default()
|
||||
}));
|
||||
if instant.elapsed().as_secs() & 1 != 0 {
|
||||
elem.push(Box::new(FillRect {
|
||||
elem.push(Box::new(FrameView {
|
||||
size: (Size::Relative(1.), Size::Absolute(10.)).into(),
|
||||
frame: Box::new(vec4(1., 0., 0., 1.)),
|
||||
}));
|
||||
elem.push(Box::new(FillRect {
|
||||
elem.push(Box::new(FrameView {
|
||||
size: (Size::Relative(1.), Size::Absolute(10.)).into(),
|
||||
frame: Box::new(vec4(0., 0., 0., 1.)),
|
||||
}));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use hui::{
|
||||
color, size, frame_rect,
|
||||
color, size, rect_frame,
|
||||
element::{container::Container, text::Text, UiElementExt},
|
||||
frame::FrameRect,
|
||||
frame::RectFrame,
|
||||
layout::Alignment,
|
||||
};
|
||||
|
||||
|
@ -15,7 +15,7 @@ ui_main!(|ui, size, _| {
|
|||
.with_align(Alignment::Center)
|
||||
.with_padding(5.)
|
||||
.with_gap(10.)
|
||||
.with_background(frame_rect! {
|
||||
.with_background(rect_frame! {
|
||||
color: (0.5, 0.5, 0.5, 1.),
|
||||
corner_radius: 10.,
|
||||
})
|
||||
|
@ -27,7 +27,7 @@ ui_main!(|ui, size, _| {
|
|||
.add_child(ui);
|
||||
Container::default()
|
||||
.with_padding((10., 20.))
|
||||
.with_background(frame_rect! {
|
||||
.with_background(rect_frame! {
|
||||
color: color::DARK_RED,
|
||||
corner_radius: (2.5, 30., 2.5, 2.5),
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use glam::vec4;
|
||||
use hui::{
|
||||
size, frame_rect,
|
||||
size, rect_frame,
|
||||
color,
|
||||
element::{
|
||||
container::Container,
|
||||
|
@ -8,7 +8,7 @@ use hui::{
|
|||
text::Text,
|
||||
UiElementExt
|
||||
},
|
||||
frame::FrameRect,
|
||||
frame::RectFrame,
|
||||
layout::Alignment,
|
||||
rect::Corners,
|
||||
text::FontHandle
|
||||
|
@ -45,7 +45,7 @@ ui_main!(
|
|||
.with_children(|ui| {
|
||||
Container::default()
|
||||
.with_padding((10., 15.))
|
||||
.with_background(frame_rect! {
|
||||
.with_background(rect_frame! {
|
||||
color: (0., 0., 0., 0.5),
|
||||
corner_radius: 8.,
|
||||
})
|
||||
|
@ -70,7 +70,7 @@ ui_main!(
|
|||
.with_align((Alignment::Center, Alignment::Begin))
|
||||
.with_padding(15.)
|
||||
.with_gap(10.)
|
||||
.with_background(frame_rect! {
|
||||
.with_background(rect_frame! {
|
||||
color: (0., 0., 0., 0.5),
|
||||
corner_radius: 8.,
|
||||
})
|
||||
|
@ -111,7 +111,7 @@ ui_main!(
|
|||
.with_children(|ui| {
|
||||
Container::default()
|
||||
.with_padding(10.)
|
||||
.with_background(frame_rect!{
|
||||
.with_background(rect_frame!{
|
||||
color: (0., 0., 0., 0.5),
|
||||
corner_radius: 8.,
|
||||
})
|
||||
|
|
|
@ -7,7 +7,7 @@ use hui::{
|
|||
text::Text,
|
||||
transformer::ElementTransformExt,
|
||||
UiElementExt
|
||||
}, frame::FrameRect, frame_rect, layout::Alignment, rect::Corners, size, text::FontHandle
|
||||
}, frame::RectFrame, rect_frame, layout::Alignment, rect::Corners, size, text::FontHandle
|
||||
};
|
||||
|
||||
#[path = "../boilerplate.rs"]
|
||||
|
@ -37,7 +37,7 @@ ui_main!(
|
|||
.with_align((Alignment::Center, Alignment::Begin))
|
||||
.with_padding(15.)
|
||||
.with_gap(10.)
|
||||
.with_background(frame_rect! {
|
||||
.with_background(rect_frame! {
|
||||
color: (0., 0., 0., 0.5),
|
||||
corner_radius: 8.
|
||||
})
|
||||
|
|
|
@ -2,9 +2,9 @@ use std::time::Instant;
|
|||
use hui::{
|
||||
color, element::{
|
||||
container::Container,
|
||||
fill_rect::FillRect,
|
||||
frame_view::FrameView,
|
||||
UiElementExt
|
||||
}, frame_rect, layout::{Alignment, Direction}, size
|
||||
}, rect_frame, layout::{Alignment, Direction}, size
|
||||
};
|
||||
|
||||
#[path = "../boilerplate.rs"]
|
||||
|
@ -28,9 +28,9 @@ ui_main!(
|
|||
.with_wrap(true)
|
||||
.with_children(|ui| {
|
||||
for i in 0..10 {
|
||||
FillRect::default()
|
||||
FrameView::default()
|
||||
.with_size(size!((40 + i * 10)))
|
||||
.with_frame(frame_rect! {
|
||||
.with_frame(rect_frame! {
|
||||
color: color::DARK_RED,
|
||||
corner_radius: 8.
|
||||
})
|
||||
|
|
|
@ -3,7 +3,7 @@ use hui::{
|
|||
color,
|
||||
element::{
|
||||
container::Container,
|
||||
fill_rect::FillRect,
|
||||
frame_view::FrameView,
|
||||
slider::Slider,
|
||||
text::Text,
|
||||
UiElementExt
|
||||
|
@ -54,7 +54,7 @@ ui_main!(
|
|||
.add_child(ui);
|
||||
})
|
||||
.add_child(ui);
|
||||
FillRect::default()
|
||||
FrameView::default()
|
||||
.with_size(size!(600, 75))
|
||||
.with_frame(NinePatchFrame::from_asset(*asset).with_color(color::GREEN))
|
||||
.add_child(ui);
|
||||
|
@ -62,7 +62,7 @@ ui_main!(
|
|||
.with_color(color::BLACK)
|
||||
.with_text_size(32)
|
||||
.add_child(ui);
|
||||
FillRect::default()
|
||||
FrameView::default()
|
||||
.with_size(size!(700, 50))
|
||||
.with_frame(NinePatchFrame::from_asset(*asset).with_color((
|
||||
(1., 0., 1.),
|
||||
|
|
|
@ -6,7 +6,7 @@ use hui::{
|
|||
layout::{Alignment, Direction},
|
||||
element::{
|
||||
container::Container,
|
||||
fill_rect::FillRect,
|
||||
frame_view::FrameView,
|
||||
image::Image,
|
||||
text::Text,
|
||||
UiElementExt
|
||||
|
@ -62,7 +62,7 @@ ui_main!(
|
|||
.add_child(ui);
|
||||
})
|
||||
.add_child(ui);
|
||||
FillRect::default()
|
||||
FrameView::default()
|
||||
.with_size(size!(100%, 1))
|
||||
.with_frame(color::rgb_hex(0x2d2d30))
|
||||
.add_child(ui);
|
||||
|
@ -75,7 +75,7 @@ ui_main!(
|
|||
.with_size(size!(54, 100%))
|
||||
.with_background(color::rgb_hex(0x343334))
|
||||
.add_child(ui);
|
||||
FillRect::default()
|
||||
FrameView::default()
|
||||
.with_size(size!(1, 100%))
|
||||
.with_frame(color::rgb_hex(0x2d2d30))
|
||||
.add_child(ui);
|
||||
|
|
|
@ -58,7 +58,7 @@ pixel_perfect_text = []
|
|||
## Enable all built-in elements
|
||||
el_all = [
|
||||
"el_container",
|
||||
"el_fill_rect",
|
||||
"el_frame_view",
|
||||
"el_spacer",
|
||||
"el_br",
|
||||
"el_text",
|
||||
|
@ -72,8 +72,8 @@ el_all = [
|
|||
## Enable the built-in `Container` element
|
||||
el_container = []
|
||||
|
||||
## Enable the built-in `FillRect` element
|
||||
el_fill_rect = []
|
||||
## Enable the built-in `FrameView` element
|
||||
el_frame_view = []
|
||||
|
||||
## Enable the built-in `Spacer` element
|
||||
el_spacer = []
|
||||
|
|
|
@ -38,6 +38,8 @@ pub struct TextureAtlasMeta<'a> {
|
|||
|
||||
/// Texture handle, stores the internal index of a texture within the texture atlas and can be cheaply copied.
|
||||
///
|
||||
/// Please note that dropping a handle does not deallocate the texture from the atlas, you must do it manually.
|
||||
///
|
||||
/// Only valid for the `UiInstance` that created it.\
|
||||
/// Using it with other instances may result in panics or unexpected behavior.
|
||||
///
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
//! element API and built-in elements like `Container`, `Button`, `Text`, etc.
|
||||
|
||||
use std::any::Any;
|
||||
use crate::{
|
||||
draw::{atlas::ImageCtx, UiDrawCommandList},
|
||||
input::InputCtx,
|
||||
layout::{LayoutInfo, Size2d},
|
||||
measure::Response,
|
||||
rect::Rect,
|
||||
signal::SignalStore,
|
||||
state::StateRepo,
|
||||
text::{FontHandle, TextMeasure},
|
||||
|
@ -17,8 +17,8 @@ pub use builtin::*;
|
|||
|
||||
/// Context for the `Element::measure` function
|
||||
pub struct MeasureContext<'a> {
|
||||
pub state: &'a StateRepo,
|
||||
pub layout: &'a LayoutInfo,
|
||||
pub state: &'a StateRepo,
|
||||
pub text_measure: TextMeasure<'a>,
|
||||
pub current_font: FontHandle,
|
||||
pub images: ImageCtx<'a>,
|
||||
|
@ -29,9 +29,9 @@ pub struct MeasureContext<'a> {
|
|||
/// Context for the `Element::process` function
|
||||
pub struct ProcessContext<'a> {
|
||||
pub measure: &'a Response,
|
||||
pub state: &'a mut StateRepo,
|
||||
pub layout: &'a LayoutInfo,
|
||||
pub draw: &'a mut UiDrawCommandList,
|
||||
pub state: &'a mut StateRepo,
|
||||
pub text_measure: TextMeasure<'a>,
|
||||
pub current_font: FontHandle,
|
||||
pub images: ImageCtx<'a>,
|
||||
|
@ -50,27 +50,6 @@ pub trait UiElement {
|
|||
/// You should implement this function whenever possible, otherwise some features may not work at all, such as the `Remaining` size
|
||||
fn size(&self) -> Option<Size2d> { None }
|
||||
|
||||
/// Get the unique id used for internal state management\
|
||||
/// This value must be unique for each instance of the element
|
||||
///
|
||||
/// If the element is stateless, this function should return `None`
|
||||
fn state_id(&self) -> Option<u64> { None }
|
||||
|
||||
/// Check if the element has state.\
|
||||
/// Should not be overridden
|
||||
fn is_stateful(&self) -> bool { self.state_id().is_some() }
|
||||
|
||||
/// Check if the element has no state\
|
||||
/// Should not be overridden
|
||||
fn is_stateless(&self) -> bool { !self.is_stateful() }
|
||||
|
||||
/// Initialize the state of the element\
|
||||
/// This function should be called exactly once during the lifetime of the element,
|
||||
/// or if the state gets reset
|
||||
///
|
||||
/// This function will not get called for stateless elements
|
||||
fn init_state(&self) -> Option<Box<dyn Any>> { None }
|
||||
|
||||
/// Measure step, guaranteed to be called before the `process` step\
|
||||
/// May be called multiple times per single frame, so it should not contain any expensive calls\
|
||||
/// This function may not mutate any state.\
|
||||
|
@ -108,7 +87,7 @@ pub trait UiElementExt: UiElement {
|
|||
fn add_child(self, ui: &mut ElementList);
|
||||
|
||||
/// Add element as a ui root.
|
||||
fn add_root(self, ui: &mut UiInstance, max_size: glam::Vec2);
|
||||
fn add_root(self, ui: &mut UiInstance, max_size: impl Into<Rect>);
|
||||
}
|
||||
|
||||
impl<T: UiElement + 'static> UiElementExt for T {
|
||||
|
@ -116,7 +95,7 @@ impl<T: UiElement + 'static> UiElementExt for T {
|
|||
ui.add(self)
|
||||
}
|
||||
|
||||
fn add_root(self, ui: &mut UiInstance, max_size: glam::Vec2) {
|
||||
ui.add(self, max_size);
|
||||
fn add_root(self, ui: &mut UiInstance, rect: impl Into<Rect>) {
|
||||
ui.add(self, rect);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
#[cfg(feature = "el_container")]
|
||||
pub mod container;
|
||||
|
||||
#[cfg(feature = "el_fill_rect")]
|
||||
pub mod fill_rect;
|
||||
#[cfg(feature = "el_frame_view")]
|
||||
pub mod frame_view;
|
||||
|
||||
#[cfg(feature = "el_spacer")]
|
||||
pub mod spacer;
|
||||
|
|
|
@ -4,7 +4,7 @@ use derive_setters::Setters;
|
|||
use glam::{Vec2, vec2};
|
||||
use crate::{
|
||||
element::{ElementList, MeasureContext, ProcessContext, UiElement},
|
||||
frame::{Frame, FrameRect},
|
||||
frame::{Frame, RectFrame},
|
||||
layout::{compute_size, Alignment, Alignment2d, Direction, LayoutInfo, Size, Size2d, WrapBehavior},
|
||||
measure::{Hints, Response},
|
||||
rect::Sides,
|
||||
|
@ -82,7 +82,7 @@ impl Default for Container {
|
|||
gap: 0.,
|
||||
padding: Sides::all(0.),
|
||||
align: Alignment2d::default(),
|
||||
background_frame: Box::<FrameRect>::default(),
|
||||
background_frame: Box::<RectFrame>::default(),
|
||||
wrap: WrapBehavior::Allow,
|
||||
children: ElementList(Vec::new()),
|
||||
}
|
||||
|
@ -375,7 +375,7 @@ impl UiElement for Container {
|
|||
// });
|
||||
// }
|
||||
|
||||
self.background_frame.draw(ctx.draw, ctx.layout.position, ctx.measure.size);
|
||||
self.background_frame.draw(ctx.draw, (ctx.layout.position, ctx.measure.size).into());
|
||||
|
||||
//padding
|
||||
position += vec2(self.padding.left, self.padding.top);
|
||||
|
@ -444,8 +444,8 @@ impl UiElement for Container {
|
|||
|
||||
//measure
|
||||
let el_measure = element.measure(MeasureContext {
|
||||
state: ctx.state,
|
||||
layout: &el_layout,
|
||||
state: ctx.state,
|
||||
text_measure: ctx.text_measure,
|
||||
current_font: ctx.current_font,
|
||||
images: ctx.images,
|
||||
|
@ -486,15 +486,13 @@ impl UiElement for Container {
|
|||
//process
|
||||
element.process(ProcessContext {
|
||||
measure: &el_measure,
|
||||
state: ctx.state,
|
||||
layout: &el_layout,
|
||||
draw: ctx.draw,
|
||||
state: ctx.state,
|
||||
text_measure: ctx.text_measure,
|
||||
current_font: ctx.current_font,
|
||||
images: ctx.images,
|
||||
input: ctx.input,
|
||||
//HACK: i have no idea what to do with this
|
||||
//this sucks
|
||||
signal: ctx.signal,
|
||||
});
|
||||
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
//! Simple filled rectangle with the specified size, background and corner radius
|
||||
|
||||
use derive_setters::Setters;
|
||||
use glam::vec2;
|
||||
use crate::{
|
||||
draw::{RoundedCorners, UiDrawCommand},
|
||||
element::{MeasureContext, ProcessContext, UiElement},
|
||||
frame::{Frame, FrameRect},
|
||||
layout::{compute_size, Size, Size2d},
|
||||
measure::Response,
|
||||
size
|
||||
};
|
||||
|
||||
/// Simple filled rectangle with the specified size, background, and corner radius
|
||||
#[derive(Setters)]
|
||||
#[setters(prefix = "with_")]
|
||||
pub struct FillRect {
|
||||
/// Size of the rectangle
|
||||
#[setters(into)]
|
||||
pub size: Size2d,
|
||||
|
||||
/// Frame
|
||||
#[setters(skip)]
|
||||
pub frame: Box<dyn Frame>,
|
||||
}
|
||||
|
||||
impl FillRect {
|
||||
pub fn with_frame(mut self, frame: impl Frame + 'static) -> Self {
|
||||
self.frame = Box::new(frame);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FillRect {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
size: size!(10, 10),
|
||||
frame: Box::new(FrameRect::color((0., 0., 0., 0.5))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UiElement for FillRect {
|
||||
fn name(&self) -> &'static str {
|
||||
"fill_rect"
|
||||
}
|
||||
|
||||
fn size(&self) -> Option<Size2d> {
|
||||
Some(self.size)
|
||||
}
|
||||
|
||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||
Response {
|
||||
size: compute_size(ctx.layout, self.size, ctx.layout.max_size),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn process(&self, ctx: ProcessContext) {
|
||||
// if !self.background.is_transparent() {
|
||||
// ctx.draw.add(UiDrawCommand::Rectangle {
|
||||
// position: ctx.layout.position,
|
||||
// size: ctx.measure.size,
|
||||
// color: self.background.corners(),
|
||||
// texture: None,
|
||||
// rounded_corners: (self.corner_radius.max_f32() > 0.).then_some({
|
||||
// RoundedCorners::from_radius(self.corner_radius)
|
||||
// }),
|
||||
// });
|
||||
// }
|
||||
self.frame.draw(ctx.draw, ctx.layout.position, ctx.measure.size);
|
||||
}
|
||||
}
|
68
hui/src/element/builtin/frame_view.rs
Normal file
68
hui/src/element/builtin/frame_view.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
//! Simple element that displays the specified frame
|
||||
|
||||
use derive_setters::Setters;
|
||||
use crate::{
|
||||
element::{MeasureContext, ProcessContext, UiElement},
|
||||
frame::{Frame, RectFrame},
|
||||
layout::{compute_size, Size2d},
|
||||
measure::Response,
|
||||
size
|
||||
};
|
||||
|
||||
/// Simple rectangle that displays the specified frame
|
||||
#[derive(Setters)]
|
||||
#[setters(prefix = "with_")]
|
||||
pub struct FrameView {
|
||||
/// Size of the rectangle
|
||||
#[setters(into)]
|
||||
pub size: Size2d,
|
||||
|
||||
/// Frame
|
||||
#[setters(skip)]
|
||||
pub frame: Box<dyn Frame>,
|
||||
}
|
||||
|
||||
impl FrameView {
|
||||
pub fn new(frame: impl Frame + 'static) -> Self {
|
||||
Self {
|
||||
size: size!(10, 10),
|
||||
frame: Box::new(frame),
|
||||
}
|
||||
}
|
||||
|
||||
//setters:
|
||||
pub fn with_frame(mut self, frame: impl Frame + 'static) -> Self {
|
||||
self.frame = Box::new(frame);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FrameView {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
size: size!(10, 10),
|
||||
frame: Box::new(RectFrame::color((0., 0., 0., 0.5))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UiElement for FrameView {
|
||||
fn name(&self) -> &'static str {
|
||||
"frame_view"
|
||||
}
|
||||
|
||||
fn size(&self) -> Option<Size2d> {
|
||||
Some(self.size)
|
||||
}
|
||||
|
||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||
Response {
|
||||
size: compute_size(ctx.layout, self.size, ctx.layout.max_size),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn process(&self, ctx: ProcessContext) {
|
||||
self.frame.draw(ctx.draw, (ctx.layout.position, ctx.measure.size).into());
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ use derive_setters::Setters;
|
|||
use glam::vec2;
|
||||
use crate::{
|
||||
element::{MeasureContext, ProcessContext, UiElement},
|
||||
frame::{Frame, FrameRect},
|
||||
frame::{Frame, RectFrame},
|
||||
layout::{compute_size, Size, Size2d},
|
||||
measure::Response,
|
||||
};
|
||||
|
@ -47,8 +47,8 @@ impl Default for ProgressBar {
|
|||
Self {
|
||||
value: 0.,
|
||||
size: Size::Auto.into(),
|
||||
foreground: Box::new(FrameRect::color((0.0, 0.0, 1.0, 1.0))),
|
||||
background: Box::new(FrameRect::color((0.0, 0.0, 0.0, 1.0))),
|
||||
foreground: Box::new(RectFrame::color((0.0, 0.0, 1.0, 1.0))),
|
||||
background: Box::new(RectFrame::color((0.0, 0.0, 0.0, 1.0))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,10 +75,10 @@ impl UiElement for ProgressBar {
|
|||
|
||||
//FIXME: these optimizations may not be valid
|
||||
if value < 1. || !self.foreground.covers_opaque() {
|
||||
self.background.draw(ctx.draw, ctx.layout.position, ctx.measure.size);
|
||||
self.background.draw(ctx.draw, (ctx.layout.position, ctx.measure.size).into());
|
||||
}
|
||||
if value > 0. {
|
||||
self.foreground.draw(ctx.draw, ctx.layout.position, ctx.measure.size * vec2(value, 1.));
|
||||
self.foreground.draw(ctx.draw, (ctx.layout.position, ctx.measure.size * vec2(value, 1.)).into());
|
||||
}
|
||||
|
||||
// let rounded_corners =
|
||||
|
|
|
@ -4,7 +4,7 @@ use derive_setters::Setters;
|
|||
use glam::{Vec2, vec2};
|
||||
|
||||
use crate::{
|
||||
draw::UiDrawCommand, element::{MeasureContext, ProcessContext, UiElement}, frame::{Frame, FrameRect}, layout::{compute_size, Size2d}, measure::Response, rect::FillColor, signal::{trigger::SignalTriggerArg, Signal}
|
||||
draw::UiDrawCommand, element::{MeasureContext, ProcessContext, UiElement}, frame::{Frame, RectFrame}, layout::{compute_size, Size2d}, measure::Response, rect::FillColor, signal::{trigger::SignalTriggerArg, Signal}
|
||||
};
|
||||
|
||||
|
||||
|
@ -79,9 +79,9 @@ impl Default for Slider {
|
|||
Self {
|
||||
value: 0.0,
|
||||
size: Size2d::default(),
|
||||
handle: Box::new(FrameRect::color((0.0, 0.0, 1.))),
|
||||
track: Box::new(FrameRect::color((0.5, 0.5, 0.5))),
|
||||
track_active: Box::new(FrameRect::color((0.0, 0.0, 0.75))),
|
||||
handle: Box::new(RectFrame::color((0.0, 0.0, 1.))),
|
||||
track: Box::new(RectFrame::color((0.5, 0.5, 0.5))),
|
||||
track_active: Box::new(RectFrame::color((0.0, 0.0, 0.75))),
|
||||
track_height: 0.25,
|
||||
handle_size: (15.0, 1.),
|
||||
follow_mode: SliderFollowMode::default(),
|
||||
|
@ -156,8 +156,10 @@ impl UiElement for Slider {
|
|||
if !(self.track_active.covers_opaque() && self.handle.covers_opaque() && (self.handle_size.1 >= self.track_height) && self.value >= 1.) {
|
||||
self.track.draw(
|
||||
ctx.draw,
|
||||
ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - self.track_height / 2.),
|
||||
ctx.measure.size * vec2(1., self.track_height),
|
||||
(
|
||||
ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - self.track_height / 2.),
|
||||
ctx.measure.size * vec2(1., self.track_height),
|
||||
).into()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -168,8 +170,10 @@ impl UiElement for Slider {
|
|||
if !(self.handle.covers_opaque() && (self.handle_size.1 >= self.track_height) && self.value <= 0.) {
|
||||
self.track_active.draw(
|
||||
ctx.draw,
|
||||
ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - self.track_height / 2.),
|
||||
(ctx.measure.size - handle_size * Vec2::X) * vec2(self.value, self.track_height) + handle_size * Vec2::X / 2.,
|
||||
(
|
||||
ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - self.track_height / 2.),
|
||||
(ctx.measure.size - handle_size * Vec2::X) * vec2(self.value, self.track_height) + handle_size * Vec2::X / 2.,
|
||||
).into()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -187,10 +191,12 @@ impl UiElement for Slider {
|
|||
if (self.handle_size.0 > 0. && self.handle_size.1 > 0.) {
|
||||
self.handle.draw(
|
||||
ctx.draw,
|
||||
ctx.layout.position +
|
||||
((ctx.measure.size.x - handle_size.x) * self.value) * Vec2::X +
|
||||
ctx.measure.size.y * ((1. - self.handle_size.1) * 0.5) * Vec2::Y,
|
||||
handle_size,
|
||||
(
|
||||
ctx.layout.position +
|
||||
((ctx.measure.size.x - handle_size.x) * self.value) * Vec2::X +
|
||||
ctx.measure.size.y * ((1. - self.handle_size.1) * 0.5) * Vec2::Y,
|
||||
handle_size,
|
||||
).into()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//! modular procedural background system
|
||||
|
||||
use glam::Vec2;
|
||||
use crate::draw::UiDrawCommandList;
|
||||
use crate::{draw::UiDrawCommandList, rect::Rect};
|
||||
|
||||
pub mod point;
|
||||
mod rect;
|
||||
|
@ -9,12 +8,12 @@ pub mod stack;
|
|||
pub mod nine_patch;
|
||||
mod impls;
|
||||
|
||||
pub use rect::FrameRect;
|
||||
pub use rect::RectFrame;
|
||||
|
||||
/// Trait for a drawable frame
|
||||
pub trait Frame {
|
||||
/// Draw the frame at the given position and size
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2);
|
||||
/// Draw the frame at the given rect's position and size
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect);
|
||||
|
||||
/// Check if the frame is guaranteed to be fully opaque and fully cover the parent frame regardless of it's size
|
||||
///
|
||||
|
|
|
@ -3,14 +3,14 @@ use super::Frame;
|
|||
use crate::{
|
||||
color,
|
||||
draw::{ImageHandle, UiDrawCommand, UiDrawCommandList},
|
||||
rect::{Corners, FillColor},
|
||||
rect::{Rect, Corners, FillColor},
|
||||
};
|
||||
|
||||
impl Frame for ImageHandle {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
draw.add(UiDrawCommand::Rectangle {
|
||||
position,
|
||||
size: parent_size,
|
||||
position: rect.position,
|
||||
size: rect.size,
|
||||
color: color::WHITE.into(),
|
||||
texture: Some(*self),
|
||||
texture_uv: None,
|
||||
|
@ -24,10 +24,10 @@ impl Frame for ImageHandle {
|
|||
}
|
||||
|
||||
impl Frame for FillColor {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
draw.add(UiDrawCommand::Rectangle {
|
||||
position,
|
||||
size: parent_size,
|
||||
position: rect.position,
|
||||
size: rect.size,
|
||||
color: self.corners(),
|
||||
texture: None,
|
||||
texture_uv: None,
|
||||
|
@ -45,8 +45,8 @@ impl Frame for FillColor {
|
|||
// 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)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
|
@ -54,8 +54,8 @@ impl Frame for Corners<Vec4> {
|
|||
}
|
||||
|
||||
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)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
|
@ -63,8 +63,8 @@ impl Frame for (Vec4, Vec4, Vec4, Vec4) {
|
|||
}
|
||||
|
||||
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)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
|
@ -72,8 +72,8 @@ impl Frame for ((f32, f32, f32, f32), (f32, f32, f32, f32), (f32, f32, f32, f32)
|
|||
}
|
||||
|
||||
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)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
|
@ -83,46 +83,46 @@ impl Frame for [[f32; 4]; 4] {
|
|||
// 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)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// RGBA:
|
||||
|
||||
impl Frame for Vec4 {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||
FillColor::from(*self).draw(draw, position, parent_size)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
|
@ -130,8 +130,8 @@ impl Frame for Vec4 {
|
|||
}
|
||||
|
||||
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)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
|
@ -139,8 +139,8 @@ impl Frame for (f32, f32, f32, f32) {
|
|||
}
|
||||
|
||||
impl Frame for [f32; 4] {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||
FillColor::from(*self).draw(draw, position, parent_size)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
|
@ -150,28 +150,28 @@ impl Frame for [f32; 4] {
|
|||
// RGB:
|
||||
|
||||
impl Frame for Vec3 {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||
FillColor::from(*self).draw(draw, position, parent_size)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Frame for [f32; 3] {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||
FillColor::from(*self).draw(draw, position, parent_size)
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
FillColor::from(*self).draw(draw, rect)
|
||||
}
|
||||
fn covers_opaque(&self) -> bool {
|
||||
FillColor::from(*self).is_opaque()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
//! This is useful for creating scalable UI elements like buttons, windows, etc.
|
||||
|
||||
use glam::{vec2, UVec2, Vec2};
|
||||
use crate::{color, draw::{ImageHandle, UiDrawCommand}, rect::{Corners, FillColor, Rect}};
|
||||
use crate::{
|
||||
color,
|
||||
draw::{ImageHandle, UiDrawCommand, UiDrawCommandList},
|
||||
rect::{Rect, Corners, FillColor}
|
||||
};
|
||||
use super::Frame;
|
||||
|
||||
/// Represents a 9-patch image asset
|
||||
|
@ -49,10 +53,10 @@ impl Default for NinePatchFrame {
|
|||
}
|
||||
|
||||
impl Frame for NinePatchFrame {
|
||||
fn draw(&self, draw: &mut crate::draw::UiDrawCommandList, position: glam::Vec2, parent_size: glam::Vec2) {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
// without this, shїt gets messed up when the position is not a whole number
|
||||
//XXX: should we round the size as well?
|
||||
let position = position.round();
|
||||
let position = rect.position.round();
|
||||
|
||||
let img_sz = UVec2::from(self.asset.size).as_vec2();
|
||||
|
||||
|
@ -79,13 +83,13 @@ impl Frame for NinePatchFrame {
|
|||
|
||||
let size_h = (
|
||||
corners_image_px.top_left.x,
|
||||
parent_size.x - corners_image_px.top_left.x - (img_sz.x - corners_image_px.top_right.x),
|
||||
rect.size.x - corners_image_px.top_left.x - (img_sz.x - corners_image_px.top_right.x),
|
||||
img_sz.x - corners_image_px.top_right.x,
|
||||
);
|
||||
|
||||
let size_v = (
|
||||
corners_image_px.top_left.y,
|
||||
parent_size.y - corners_image_px.top_left.y - (img_sz.y - corners_image_px.bottom_left.y),
|
||||
rect.size.y - corners_image_px.top_left.y - (img_sz.y - corners_image_px.bottom_left.y),
|
||||
img_sz.y - corners_image_px.bottom_left.y,
|
||||
);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use glam::Vec2;
|
|||
use crate::{
|
||||
color,
|
||||
draw::{ImageHandle, RoundedCorners, UiDrawCommand, UiDrawCommandList},
|
||||
rect::{Corners, FillColor},
|
||||
rect::{Rect, Corners, FillColor},
|
||||
};
|
||||
use super::{Frame, point::FramePoint2d};
|
||||
|
||||
|
@ -10,7 +10,7 @@ use super::{Frame, point::FramePoint2d};
|
|||
///
|
||||
/// Can optionally be tinted, textured, and have rounded corners
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FrameRect {
|
||||
pub struct RectFrame {
|
||||
/// Background color of the frame\
|
||||
///
|
||||
/// If the container has a background texture, it will be multiplied by this color
|
||||
|
@ -35,26 +35,26 @@ pub struct FrameRect {
|
|||
pub corner_radius: Corners<f32>,
|
||||
}
|
||||
|
||||
// impl<T: Into<FillColor>> From<T> for FrameRect {
|
||||
// impl<T: Into<FillColor>> From<T> for RectFrame {
|
||||
// fn from(color: T) -> Self {
|
||||
// Self::from_color(color)
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<FillColor> for FrameRect {
|
||||
impl From<FillColor> for RectFrame {
|
||||
fn from(color: FillColor) -> Self {
|
||||
Self::color(color)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImageHandle> for FrameRect {
|
||||
impl From<ImageHandle> for RectFrame {
|
||||
fn from(image: ImageHandle) -> Self {
|
||||
Self::image(image)
|
||||
}
|
||||
}
|
||||
|
||||
impl FrameRect {
|
||||
/// Create a new [`FrameRect`] with the given color
|
||||
impl RectFrame {
|
||||
/// Create a new [`RectFrame`] with the given color
|
||||
pub fn color(color: impl Into<FillColor>) -> Self {
|
||||
Self {
|
||||
color: color.into(),
|
||||
|
@ -62,7 +62,7 @@ impl FrameRect {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new [`FrameRect`] with the given image\
|
||||
/// Create a new [`RectFrame`] with the given image\
|
||||
///
|
||||
/// Color will be set to [`WHITE`](crate::color::WHITE) to ensure the image is visible
|
||||
pub fn image(image: ImageHandle) -> Self {
|
||||
|
@ -73,7 +73,7 @@ impl FrameRect {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new [`FrameRect`] with the given color and image
|
||||
/// Create a new [`RectFrame`] with the given color and image
|
||||
pub fn color_image(color: impl Into<FillColor>, image: ImageHandle) -> Self {
|
||||
Self {
|
||||
color: color.into(),
|
||||
|
@ -82,7 +82,7 @@ impl FrameRect {
|
|||
}
|
||||
}
|
||||
|
||||
/// Set the corner radius of the [`FrameRect`]
|
||||
/// Set the corner radius of the [`RectFrame`]
|
||||
pub fn with_corner_radius(self, radius: impl Into<Corners<f32>>) -> Self {
|
||||
Self {
|
||||
corner_radius: radius.into(),
|
||||
|
@ -102,7 +102,7 @@ impl FrameRect {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for FrameRect {
|
||||
impl Default for RectFrame {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
color: FillColor::transparent(),
|
||||
|
@ -114,13 +114,13 @@ impl Default for FrameRect {
|
|||
}
|
||||
}
|
||||
|
||||
impl Frame for FrameRect {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) {
|
||||
impl Frame for RectFrame {
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
//TODO: handle bottom_right < top_left
|
||||
let top_left = self.top_left.resolve(parent_size);
|
||||
let bottom_right = self.bottom_right.resolve(parent_size);
|
||||
let top_left = self.top_left.resolve(rect.size);
|
||||
let bottom_right = self.bottom_right.resolve(rect.size);
|
||||
draw.add(UiDrawCommand::Rectangle {
|
||||
position: position + top_left,
|
||||
position: rect.position + top_left,
|
||||
size: bottom_right - top_left,
|
||||
color: self.color.corners(),
|
||||
texture: self.image,
|
||||
|
@ -132,14 +132,14 @@ impl Frame for FrameRect {
|
|||
}
|
||||
|
||||
fn covers_opaque(&self) -> bool {
|
||||
self.top_left.x.absolute <= 0. &&
|
||||
self.top_left.x.relative <= 0. &&
|
||||
self.top_left.y.absolute <= 0. &&
|
||||
self.top_left.x.absolute <= 0. &&
|
||||
self.top_left.y.relative <= 0. &&
|
||||
self.bottom_right.x.absolute >= 0. &&
|
||||
self.top_left.y.absolute <= 0. &&
|
||||
self.bottom_right.x.relative >= 1. &&
|
||||
self.bottom_right.y.absolute >= 0. &&
|
||||
self.bottom_right.x.absolute >= 0. &&
|
||||
self.bottom_right.y.relative >= 1. &&
|
||||
self.bottom_right.y.absolute >= 0. &&
|
||||
self.color.is_opaque() &&
|
||||
self.image.is_none() &&
|
||||
self.corner_radius.max_f32() == 0.
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
//! allows stacking two frames on top of each other
|
||||
|
||||
use glam::Vec2;
|
||||
use crate::draw::UiDrawCommandList;
|
||||
use crate::{draw::UiDrawCommandList, rect::Rect};
|
||||
use super::Frame;
|
||||
|
||||
/// A frame that draws two frames on top of each other
|
||||
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);
|
||||
fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
|
||||
self.0.draw(draw, rect);
|
||||
self.1.draw(draw, rect);
|
||||
}
|
||||
|
||||
fn covers_opaque(&self) -> bool {
|
||||
|
@ -22,10 +21,17 @@ impl Frame for FrameStack {
|
|||
pub trait FrameStackExt: Frame {
|
||||
/// Stack another frame on top of this one
|
||||
fn stack(self, other: impl Frame + 'static) -> FrameStack;
|
||||
|
||||
/// Stack another frame below this one
|
||||
fn stack_bottom(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))
|
||||
}
|
||||
|
||||
fn stack_bottom(self, other: impl Frame + 'static) -> FrameStack {
|
||||
FrameStack(Box::new(other), Box::new(self))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
use glam::Vec2;
|
||||
use crate::{
|
||||
element::{MeasureContext, ProcessContext, UiElement},
|
||||
layout::{Direction, LayoutInfo},
|
||||
text::{FontHandle, TextRenderer},
|
||||
draw::{
|
||||
ImageHandle, TextureFormat, UiDrawCall, UiDrawCommandList,
|
||||
ImageHandle,
|
||||
TextureFormat,
|
||||
UiDrawCall,
|
||||
UiDrawCommandList,
|
||||
atlas::{TextureAtlasManager, TextureAtlasMeta},
|
||||
},
|
||||
element::{MeasureContext, ProcessContext, UiElement},
|
||||
signal::{Signal, SignalStore},
|
||||
event::{EventQueue, UiEvent},
|
||||
input::UiInputState,
|
||||
layout::{Direction, LayoutInfo},
|
||||
signal::{SignalStore, Signal},
|
||||
rect::Rect,
|
||||
state::StateRepo,
|
||||
text::{FontHandle, TextRenderer}
|
||||
};
|
||||
|
||||
/// The main instance of the UI system.
|
||||
|
@ -144,16 +148,17 @@ impl UiInstance {
|
|||
|
||||
/// Add an element or an element tree to the UI
|
||||
///
|
||||
/// Use the `max_size` parameter to specify the maximum size of the element\
|
||||
/// Use the `rect` parameter to specify the position and size of the element\
|
||||
/// (usually, the size of the window/screen)
|
||||
///
|
||||
/// ## Panics:
|
||||
/// If called while the UI is not active (call [`UiInstance::begin`] first)
|
||||
pub fn add<T: UiElement>(&mut self, element: T, max_size: Vec2) {
|
||||
pub fn add(&mut self, element: impl UiElement, rect: impl Into<Rect>) {
|
||||
assert!(self.state, "must call UiInstance::begin before adding elements");
|
||||
let rect: Rect = rect.into();
|
||||
let layout = LayoutInfo {
|
||||
position: Vec2::ZERO,
|
||||
max_size,
|
||||
position: rect.position,
|
||||
max_size: rect.size,
|
||||
direction: Direction::Vertical,
|
||||
remaining_space: None,
|
||||
};
|
||||
|
|
|
@ -75,11 +75,11 @@ macro_rules! size {
|
|||
};
|
||||
}
|
||||
|
||||
/// Helper macro for constructing a `FrameRect`
|
||||
/// Helper macro for constructing a `RectFrame`
|
||||
///
|
||||
/// # Example:
|
||||
/// ```
|
||||
/// frame_rect! {
|
||||
/// _frame! {
|
||||
/// color: (0.2, 0.2, 0.3, 1.),
|
||||
/// corner_radius: 5.,
|
||||
/// };
|
||||
|
@ -89,24 +89,24 @@ macro_rules! size {
|
|||
/// - If the `image` field is set, but not `color`, the `color` field will default to [`WHITE`](crate::color::WHITE) (to ensure visibility)
|
||||
/// - If both `color` and `image` are not set, the `color` field will default to [`TRANSPARENT`](crate::color::TRANSPARENT)
|
||||
#[macro_export]
|
||||
macro_rules! frame_rect {
|
||||
macro_rules! rect_frame {
|
||||
{} => {
|
||||
$crate::frame::FrameRect::default()
|
||||
$crate::frame::RectFrame::default()
|
||||
};
|
||||
|
||||
// () => {
|
||||
// $crate::frame::FrameRect::default()
|
||||
// $crate::frame::RectFrame::default()
|
||||
// };
|
||||
|
||||
($expr:expr) => {
|
||||
{
|
||||
let _frame_rect: $crate::frame::FrameRect = $crate::frame::FrameRect::from($expr);
|
||||
_frame_rect
|
||||
let __frame: $crate::frame::RectFrame = $crate::frame::RectFrame::from($expr);
|
||||
__frame
|
||||
}
|
||||
};
|
||||
|
||||
($image:expr, $color:expr) => {
|
||||
$crate::frame::FrameRect::color_image($color, $image)
|
||||
$crate::frame::RectFrame::color_image($color, $image)
|
||||
};
|
||||
|
||||
{$($ident:ident : $expr:expr),+$(,)?} => {
|
||||
|
@ -115,58 +115,24 @@ macro_rules! frame_rect {
|
|||
#[allow(non_upper_case_globals)]
|
||||
{$(const $ident: () = ();)+}
|
||||
|
||||
// construct the FrameRect
|
||||
// construct the RectFrame
|
||||
{
|
||||
let mut frame_rect = $crate::frame::FrameRect::default();
|
||||
let mut _frame = $crate::frame::RectFrame::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;
|
||||
}
|
||||
_frame.$ident = ($expr).into();
|
||||
_image_is_set |= stringify!($ident) == "image";
|
||||
_color_is_set |= stringify!($ident) == "color";
|
||||
}
|
||||
)+
|
||||
if frame_rect.image.is_some() && _image_is_set && !_color_is_set {
|
||||
frame_rect.color = (1., 1., 1., 1.).into();
|
||||
// set color to white if image is explicitly set to Some(...) but color is left as the default
|
||||
if _frame.image.is_some() && _image_is_set && !_color_is_set {
|
||||
_frame.color = (1., 1., 1., 1.).into();
|
||||
}
|
||||
frame_rect
|
||||
_frame
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// {$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.,
|
||||
// };
|
||||
// }
|
||||
|
|
|
@ -11,6 +11,24 @@ pub struct Rect {
|
|||
}
|
||||
|
||||
impl Rect {
|
||||
pub const fn new(position: Vec2, size: Vec2) -> Self {
|
||||
Self { position, size }
|
||||
}
|
||||
|
||||
pub const fn from_position(position: Vec2) -> Self {
|
||||
Self {
|
||||
position,
|
||||
size: Vec2::ZERO,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn from_size(size: Vec2) -> Self {
|
||||
Self {
|
||||
position: Vec2::ZERO,
|
||||
size,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the rect contains a point.
|
||||
pub fn contains_point(&self, point: Vec2) -> bool {
|
||||
point.cmpge(self.position).all() && point.cmple(self.position + self.size).all()
|
||||
|
@ -63,3 +81,58 @@ impl Rect {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec2> for Rect {
|
||||
/// Create a new `Rect` from a `Vec2`, where x and y are the width and height of the rect respectively.
|
||||
fn from(size: Vec2) -> Self {
|
||||
Self::from_size(size)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(Vec2, Vec2)> for Rect {
|
||||
/// Create a new `Rect` from a tuple of two `Vec2`s, where the first `Vec2` is the position and the second `Vec2` is the size.
|
||||
fn from((position, size): (Vec2, Vec2)) -> Self {
|
||||
Self { position, size }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(f32, f32, f32, f32)> for Rect {
|
||||
/// Create a new `Rect` from a tuple of 4 `f32`s, where the first two `f32`s are the x and y positions of the top-left corner and the last two `f32`s are the width and height of the rect respectively.
|
||||
fn from((x, y, width, height): (f32, f32, f32, f32)) -> Self {
|
||||
Self {
|
||||
position: Vec2::new(x, y),
|
||||
size: Vec2::new(width, height),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[f32; 4]> for Rect {
|
||||
/// Create a new `Rect` from an array of 4 `f32`s, where the first two `f32`s are the x and y positions of the top-left corner and the last two `f32`s are the width and height of the rect respectively.
|
||||
fn from([x, y, width, height]: [f32; 4]) -> Self {
|
||||
Self {
|
||||
position: Vec2::new(x, y),
|
||||
size: Vec2::new(width, height),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rect> for (Vec2, Vec2) {
|
||||
/// Convert a `Rect` into a tuple of two `Vec2`s, where the first `Vec2` is the position and the second `Vec2` is the size.
|
||||
fn from(rect: Rect) -> Self {
|
||||
(rect.position, rect.size)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rect> for (f32, f32, f32, f32) {
|
||||
/// Convert a `Rect` into a tuple of 4 `f32`s, where the first two `f32`s are the x and y positions of the top-left corner and the last two `f32`s are the width and height of the rect respectively.
|
||||
fn from(rect: Rect) -> Self {
|
||||
(rect.position.x, rect.position.y, rect.size.x, rect.size.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rect> for [f32; 4] {
|
||||
/// Convert a `Rect` into an array of 4 `f32`s, where the first two `f32`s are the x and y positions of the top-left corner and the last two `f32`s are the width and height of the rect respectively.
|
||||
fn from(rect: Rect) -> Self {
|
||||
[rect.position.x, rect.position.y, rect.size.x, rect.size.y]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue