mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-11-22 15:18:43 -06:00
Compare commits
12 commits
bbc1d9f1ff
...
fb2f3c739e
Author | SHA1 | Date | |
---|---|---|---|
griffi-gh | fb2f3c739e | ||
griffi-gh | b12c62e06f | ||
griffi-gh | 3ac83e161a | ||
griffi-gh | d1e1325068 | ||
griffi-gh | 5ce9dda77b | ||
griffi-gh | fa994e659a | ||
griffi-gh | 328f745c39 | ||
griffi-gh | e22fa739c1 | ||
griffi-gh | 89037efebb | ||
griffi-gh | d347f8f7e9 | ||
griffi-gh | 85810a2e59 | ||
griffi-gh | 7bfd12749b |
|
@ -7,7 +7,7 @@ use hui::{
|
||||||
container::Container,
|
container::Container,
|
||||||
text::Text,
|
text::Text,
|
||||||
image::Image,
|
image::Image,
|
||||||
br::Br,
|
br::Break,
|
||||||
interactable::ElementInteractableExt,
|
interactable::ElementInteractableExt,
|
||||||
UiElementExt,
|
UiElementExt,
|
||||||
},
|
},
|
||||||
|
@ -44,7 +44,7 @@ ui_main!(
|
||||||
Text::new("Number of images:")
|
Text::new("Number of images:")
|
||||||
.with_text_size(24)
|
.with_text_size(24)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Break.add_child(ui);
|
||||||
Container::default()
|
Container::default()
|
||||||
.with_padding(10.)
|
.with_padding(10.)
|
||||||
.with_background(color::ORANGE)
|
.with_background(color::ORANGE)
|
||||||
|
@ -53,7 +53,7 @@ ui_main!(
|
||||||
.with_text_size(32)
|
.with_text_size(32)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
})
|
})
|
||||||
.on_click(CounterSignal::Decrement)
|
.on_click(|| CounterSignal::Decrement)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Container::default()
|
Container::default()
|
||||||
.with_size(size!(60, auto))
|
.with_size(size!(60, auto))
|
||||||
|
@ -72,9 +72,9 @@ ui_main!(
|
||||||
.with_text_size(32)
|
.with_text_size(32)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
})
|
})
|
||||||
.on_click(CounterSignal::Increment)
|
.on_click(|| CounterSignal::Increment)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Break.add_child(ui);
|
||||||
for _ in 0..*counter {
|
for _ in 0..*counter {
|
||||||
Image::new(*image)
|
Image::new(*image)
|
||||||
.with_size(size!(48, 48))
|
.with_size(size!(48, 48))
|
||||||
|
|
|
@ -6,7 +6,7 @@ use hui::{
|
||||||
container::Container,
|
container::Container,
|
||||||
text::Text,
|
text::Text,
|
||||||
image::Image,
|
image::Image,
|
||||||
br::Br,
|
br::Break,
|
||||||
slider::Slider,
|
slider::Slider,
|
||||||
UiElementExt,
|
UiElementExt,
|
||||||
},
|
},
|
||||||
|
@ -43,22 +43,22 @@ ui_main!(
|
||||||
Text::new(format!("Number of images: {counter}"))
|
Text::new(format!("Number of images: {counter}"))
|
||||||
.with_text_size(32)
|
.with_text_size(32)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Break.add_child(ui);
|
||||||
Text::new("Absolute tracking slider:")
|
Text::new("Absolute tracking slider:")
|
||||||
.with_text_size(16)
|
.with_text_size(16)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Break.add_child(ui);
|
||||||
Slider::new(*counter as f32 / 100.)
|
Slider::new(*counter as f32 / 100.)
|
||||||
.with_size(size!(66%, 20))
|
.with_size(size!(66%, 20))
|
||||||
.on_change(|x| {
|
.on_change(|x| {
|
||||||
CounterSignal::ChangeValue((x * 100.).round() as u32)
|
CounterSignal::ChangeValue((x * 100.).round() as u32)
|
||||||
})
|
})
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Break.add_child(ui);
|
||||||
Text::new("Relative tracking slider (Experimental):")
|
Text::new("Relative tracking slider (Experimental):")
|
||||||
.with_text_size(16)
|
.with_text_size(16)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Break.add_child(ui);
|
||||||
Slider::new(*counter as f32 / 100.)
|
Slider::new(*counter as f32 / 100.)
|
||||||
.with_size(size!(66%, 20))
|
.with_size(size!(66%, 20))
|
||||||
.with_follow_mode(hui::element::slider::SliderFollowMode::Relative)
|
.with_follow_mode(hui::element::slider::SliderFollowMode::Relative)
|
||||||
|
@ -66,7 +66,7 @@ ui_main!(
|
||||||
CounterSignal::ChangeValue((x * 100.).round() as u32)
|
CounterSignal::ChangeValue((x * 100.).round() as u32)
|
||||||
})
|
})
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Break.add_child(ui);
|
||||||
for _ in 0..*counter {
|
for _ in 0..*counter {
|
||||||
Image::new(*image)
|
Image::new(*image)
|
||||||
.with_size(size!(48, 48))
|
.with_size(size!(48, 48))
|
||||||
|
|
|
@ -55,6 +55,7 @@ pub enum UiDrawCommand {
|
||||||
PushTransform(Affine2),
|
PushTransform(Affine2),
|
||||||
/// Pop a transformation matrix from the stack
|
/// Pop a transformation matrix from the stack
|
||||||
PopTransform,
|
PopTransform,
|
||||||
|
//TODO PushClip PopClip
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List of draw commands
|
/// List of draw commands
|
||||||
|
|
|
@ -17,6 +17,12 @@ pub struct RoundedCorners {
|
||||||
pub point_count: NonZeroU16,
|
pub point_count: NonZeroU16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Corners<f32>> for RoundedCorners {
|
||||||
|
fn from(radius: Corners<f32>) -> Self {
|
||||||
|
Self::from_radius(radius)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RoundedCorners {
|
impl RoundedCorners {
|
||||||
pub fn from_radius(radius: Corners<f32>) -> Self {
|
pub fn from_radius(radius: Corners<f32>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -40,7 +40,9 @@ pub struct ProcessContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UiElement {
|
pub trait UiElement {
|
||||||
/// Get the name of the element, for example "Button" or "ProgressBar"
|
/// Get the name of the element (in lower case)
|
||||||
|
///
|
||||||
|
/// For example, "button" or "progress_bar"
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
|
|
||||||
/// Get the unique id used for internal state management\
|
/// Get the unique id used for internal state management\
|
||||||
|
|
|
@ -4,11 +4,11 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct Br;
|
pub struct Break;
|
||||||
|
|
||||||
impl UiElement for Br {
|
impl UiElement for Break {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"Br"
|
"break"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, _: MeasureContext) -> Response {
|
fn measure(&self, _: MeasureContext) -> Response {
|
||||||
|
|
|
@ -133,7 +133,7 @@ impl Container {
|
||||||
|
|
||||||
impl UiElement for Container {
|
impl UiElement for Container {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"Container"
|
"container"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
|
|
|
@ -40,7 +40,7 @@ impl Default for FillRect {
|
||||||
|
|
||||||
impl UiElement for FillRect {
|
impl UiElement for FillRect {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"FillRect"
|
"fill_rect"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl Image {
|
||||||
|
|
||||||
impl UiElement for Image {
|
impl UiElement for Image {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"Image"
|
"image"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
|
|
|
@ -5,9 +5,8 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
element::{MeasureContext, ProcessContext, UiElement},
|
element::{MeasureContext, ProcessContext, UiElement},
|
||||||
signal::Signal,
|
signal::{trigger::SignalTrigger, Signal},
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
||||||
|
@ -15,10 +14,11 @@ pub enum InteractableEvent {
|
||||||
#[default]
|
#[default]
|
||||||
Click,
|
Click,
|
||||||
Hover,
|
Hover,
|
||||||
|
Active,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper that allows adding click and hover events to any element
|
/// Wrapper that allows adding click and hover events to any element
|
||||||
pub struct Interactable<C: Signal + 'static> {
|
pub struct Interactable {
|
||||||
/// The wrapped element that will be interactable
|
/// The wrapped element that will be interactable
|
||||||
pub element: Box<dyn UiElement>,
|
pub element: Box<dyn UiElement>,
|
||||||
|
|
||||||
|
@ -26,22 +26,26 @@ pub struct Interactable<C: Signal + 'static> {
|
||||||
pub event: InteractableEvent,
|
pub event: InteractableEvent,
|
||||||
|
|
||||||
/// Signal that will be called if the element was clicked in the current frame
|
/// Signal that will be called if the element was clicked in the current frame
|
||||||
pub signal: RefCell<Option<C>>,
|
pub signal: SignalTrigger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Signal + 'static> Interactable<C> {
|
impl Interactable {
|
||||||
pub fn new(element: Box<dyn UiElement>, event: InteractableEvent, signal: C) -> Self {
|
pub fn new<S: Signal, F: Fn() -> S + 'static>(
|
||||||
|
element: Box<dyn UiElement>,
|
||||||
|
event: InteractableEvent,
|
||||||
|
signal: F
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
element,
|
element,
|
||||||
event,
|
event,
|
||||||
signal: RefCell::new(Some(signal)),
|
signal: SignalTrigger::new(signal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Signal + 'static> UiElement for Interactable<C> {
|
impl UiElement for Interactable {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"Interactable"
|
"interactable"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> crate::measure::Response {
|
fn measure(&self, ctx: MeasureContext) -> crate::measure::Response {
|
||||||
|
@ -56,12 +60,11 @@ impl<C: Signal + 'static> UiElement for Interactable<C> {
|
||||||
//TODO: actually pass the response
|
//TODO: actually pass the response
|
||||||
InteractableEvent::Click => ctx.input.check_click(rect).is_some(),
|
InteractableEvent::Click => ctx.input.check_click(rect).is_some(),
|
||||||
InteractableEvent::Hover => ctx.input.check_hover(rect),
|
InteractableEvent::Hover => ctx.input.check_hover(rect),
|
||||||
|
InteractableEvent::Active => ctx.input.check_active(rect).is_some(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if event_happened {
|
if event_happened {
|
||||||
if let Some(sig) = self.signal.take() {
|
self.signal.fire(ctx.signal);
|
||||||
ctx.signal.add(sig);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.element.process(ctx)
|
self.element.process(ctx)
|
||||||
|
@ -71,25 +74,32 @@ impl<C: Signal + 'static> UiElement for Interactable<C> {
|
||||||
/// Extension trait for [`UiElement`] that adds methods to wrap the element in an [`Interactable`]
|
/// Extension trait for [`UiElement`] that adds methods to wrap the element in an [`Interactable`]
|
||||||
pub trait ElementInteractableExt: UiElement {
|
pub trait ElementInteractableExt: UiElement {
|
||||||
/// Wrap the element in an [`Interactable`] that will call the given signal when the specified event occurs
|
/// Wrap the element in an [`Interactable`] that will call the given signal when the specified event occurs
|
||||||
fn into_interactable<C: Signal + 'static>(self, event: InteractableEvent, signal: C) -> Interactable<C>;
|
fn into_interactable<S: Signal, F: Fn() -> S + 'static>(self, event: InteractableEvent, signal: F) -> Interactable;
|
||||||
|
|
||||||
/// Wrap the element in an [`Interactable`] that will call the given signal when clicked
|
/// Wrap the element in an [`Interactable`] that will call the given signal when clicked
|
||||||
fn on_click<C: Signal + 'static>(self, signal: C) -> Interactable<C>;
|
fn on_click<S: Signal, F: Fn() -> S + 'static>(self, signal: F) -> Interactable;
|
||||||
|
|
||||||
/// Wrap the element in an [`Interactable`] that will call the given signal while hovered
|
/// Wrap the element in an [`Interactable`] that will call the given signal continuously while hovered
|
||||||
fn on_hover<C: Signal + 'static>(self, signal: C) -> Interactable<C>;
|
fn on_hover<S: Signal, F: Fn() -> S + 'static>(self, signal: F) -> Interactable;
|
||||||
|
|
||||||
|
/// Wrap the element in an [`Interactable`] that will call the given signal continuously while active
|
||||||
|
fn on_active<S: Signal, F: Fn() -> S + 'static>(self, signal: F) -> Interactable;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: UiElement + 'static> ElementInteractableExt for T {
|
impl<T: UiElement + 'static> ElementInteractableExt for T {
|
||||||
fn into_interactable<C: Signal + 'static>(self, event: InteractableEvent, signal: C) -> Interactable<C> {
|
fn into_interactable<S: Signal, F: Fn() -> S + 'static>(self, event: InteractableEvent, signal: F) -> Interactable {
|
||||||
Interactable::new(Box::new(self), event, signal)
|
Interactable::new(Box::new(self), event, signal)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_click<C: Signal + 'static>(self, signal: C) -> Interactable<C> {
|
fn on_click<S: Signal, F: Fn() -> S + 'static>(self, signal: F) -> Interactable {
|
||||||
self.into_interactable(InteractableEvent::Click, signal)
|
self.into_interactable(InteractableEvent::Click, signal)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_hover<C: Signal + 'static>(self, signal: C) -> Interactable<C> {
|
fn on_hover<S: Signal, F: Fn() -> S + 'static>(self, signal: F) -> Interactable {
|
||||||
self.into_interactable(InteractableEvent::Hover, signal)
|
self.into_interactable(InteractableEvent::Hover, signal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_active<S: Signal, F: Fn() -> S + 'static>(self, signal: F) -> Interactable {
|
||||||
|
self.into_interactable(InteractableEvent::Active, signal)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl Default for ProgressBar {
|
||||||
|
|
||||||
impl UiElement for ProgressBar {
|
impl UiElement for ProgressBar {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"ProgressBar"
|
"progress_bar"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
|
|
|
@ -103,7 +103,7 @@ impl Slider {
|
||||||
|
|
||||||
impl UiElement for Slider {
|
impl UiElement for Slider {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"Slider"
|
"slider"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
|
|
|
@ -19,7 +19,7 @@ impl Default for Spacer {
|
||||||
|
|
||||||
impl UiElement for Spacer {
|
impl UiElement for Spacer {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"Spacer"
|
"spacer"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
|
|
|
@ -71,7 +71,7 @@ impl Text {
|
||||||
|
|
||||||
impl UiElement for Text {
|
impl UiElement for Text {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"Text"
|
"text"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
|
|
|
@ -38,7 +38,7 @@ impl Transformer {
|
||||||
|
|
||||||
impl UiElement for Transformer {
|
impl UiElement for Transformer {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"Transformer"
|
"transformer"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use crate::rect::FillColor;
|
|
||||||
|
|
||||||
pub mod point;
|
pub mod point;
|
||||||
pub mod layer;
|
pub mod layer;
|
||||||
|
use glam::Vec2;
|
||||||
use layer::{FrameLayer, RectLayer};
|
use layer::{FrameLayer, FrameLayerImpl};
|
||||||
|
use crate::draw::UiDrawCommandList;
|
||||||
|
|
||||||
///XXX: this is not used yet, and also kinda a mess, simplify?
|
///XXX: this is not used yet, and also kinda a mess, simplify?
|
||||||
///Maybe limit to a single layer? (aka `Frame` will be just one of the options)
|
///Maybe limit to a single layer? (aka `Frame` will be just one of the options)
|
||||||
|
@ -20,23 +19,49 @@ pub struct Frame {
|
||||||
layers: Vec<FrameLayer>
|
layers: Vec<FrameLayer>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<FillColor>> From<T> for Frame {
|
impl<T: Into<FrameLayer>> From<T> for Frame {
|
||||||
fn from(color: T) -> Self {
|
fn from(layer: T) -> Self {
|
||||||
let mut frame = Self::default();
|
let mut frame = Self::default();
|
||||||
frame.add(RectLayer::from_color(color));
|
frame.add(layer.into());
|
||||||
frame
|
frame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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]
|
#[inline]
|
||||||
pub fn add(&mut self, layer: impl Into<FrameLayer>) -> &mut Self {
|
pub fn add(&mut self, layer: impl Into<FrameLayer>) -> &mut Self {
|
||||||
self.layers.push(layer.into());
|
self.layers.push(layer.into());
|
||||||
self
|
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]
|
#[inline]
|
||||||
pub fn finish(&mut self) -> Self {
|
pub fn finish(&mut self) -> Self {
|
||||||
self.clone()
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,25 +9,48 @@ use super::point::FramePoint2d;
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub(crate) trait FrameLayerImpl {
|
pub(crate) trait FrameLayerImpl {
|
||||||
fn draw(&self, draw: &mut UiDrawCommandList, parent_size: Vec2);
|
fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[enum_dispatch(FrameLayerImpl)]
|
#[enum_dispatch(FrameLayerImpl)]
|
||||||
pub enum FrameLayer {
|
pub enum FrameLayer {
|
||||||
Rect(RectLayer),
|
Rect(RectFrame),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct RectLayer {
|
pub struct RectFrame {
|
||||||
color: FillColor,
|
/// Background color of the frame\
|
||||||
image: Option<ImageHandle>,
|
///
|
||||||
top_left: FramePoint2d,
|
/// If the container has a background texture, it will be multiplied by this color
|
||||||
bottom_right: FramePoint2d,
|
pub color: FillColor,
|
||||||
corner_radius: Corners<f32>,
|
|
||||||
|
/// Background texture of the frame
|
||||||
|
///
|
||||||
|
/// 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\
|
||||||
|
pub image: Option<ImageHandle>,
|
||||||
|
|
||||||
|
/// Top left corner of the rectangle
|
||||||
|
pub top_left: FramePoint2d,
|
||||||
|
|
||||||
|
/// Bottom right corner of the rectangle
|
||||||
|
pub bottom_right: FramePoint2d,
|
||||||
|
|
||||||
|
/// Corner radius of the frame
|
||||||
|
pub corner_radius: Corners<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RectLayer {
|
impl<T: Into<FillColor>> From<T> for RectFrame {
|
||||||
|
fn from(color: T) -> Self {
|
||||||
|
Self::from_color(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RectFrame {
|
||||||
pub fn from_color(color: impl Into<FillColor>) -> Self {
|
pub fn from_color(color: impl Into<FillColor>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
color: color.into(),
|
color: color.into(),
|
||||||
|
@ -58,27 +81,45 @@ impl RectLayer {
|
||||||
..Self::default()
|
..Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_color_image_rounded(color: impl Into<FillColor>, image: ImageHandle, corner_radius: impl Into<Corners<f32>>) -> Self {
|
||||||
|
Self {
|
||||||
|
color: color.into(),
|
||||||
|
image: Some(image),
|
||||||
|
corner_radius: corner_radius.into(),
|
||||||
|
..Self::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RectLayer {
|
/// Inset the rectangle by the given amount
|
||||||
|
pub fn inset(self, inset: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
top_left: self.top_left + Vec2::splat(inset).into(),
|
||||||
|
bottom_right: self.bottom_right - Vec2::splat(inset).into(),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RectFrame {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
color: FillColor::default(),
|
color: FillColor::default(),
|
||||||
image: None,
|
image: None,
|
||||||
top_left: FramePoint2d::default(),
|
top_left: FramePoint2d::TOP_LEFT,
|
||||||
bottom_right: FramePoint2d::default(),
|
bottom_right: FramePoint2d::BOTTOM_RIGHT,
|
||||||
corner_radius: Corners::default(),
|
corner_radius: Corners::all(0.),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameLayerImpl for RectLayer {
|
impl FrameLayerImpl for RectFrame {
|
||||||
fn draw(&self, draw: &mut UiDrawCommandList, 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);
|
||||||
let bottom_right = self.bottom_right.resolve(parent_size);
|
let bottom_right = self.bottom_right.resolve(parent_size);
|
||||||
draw.add(UiDrawCommand::Rectangle {
|
draw.add(UiDrawCommand::Rectangle {
|
||||||
position: top_left,
|
position: position + top_left,
|
||||||
size: bottom_right - top_left,
|
size: bottom_right - top_left,
|
||||||
color: self.color.corners(),
|
color: self.color.corners(),
|
||||||
texture: self.image,
|
texture: self.image,
|
||||||
|
|
Loading…
Reference in a new issue