mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-11-29 02:18:40 -06:00
wip Remaing
size
This commit is contained in:
parent
adc5cb5f3b
commit
4bb59b7c5f
|
@ -4,6 +4,7 @@ use hui::{
|
||||||
color, size,
|
color, size,
|
||||||
draw::{ImageHandle, TextureFormat},
|
draw::{ImageHandle, TextureFormat},
|
||||||
layout::{Alignment, Direction},
|
layout::{Alignment, Direction},
|
||||||
|
rect::Sides,
|
||||||
element::{
|
element::{
|
||||||
container::Container,
|
container::Container,
|
||||||
fill_rect::FillRect,
|
fill_rect::FillRect,
|
||||||
|
@ -38,7 +39,12 @@ ui_main!(
|
||||||
.with_size(size!(100%, auto))
|
.with_size(size!(100%, auto))
|
||||||
.with_direction(Direction::Horizontal)
|
.with_direction(Direction::Horizontal)
|
||||||
.with_align((Alignment::Begin, Alignment::Center))
|
.with_align((Alignment::Begin, Alignment::Center))
|
||||||
.with_padding(8.)
|
.with_padding(Sides {
|
||||||
|
left: 5.,
|
||||||
|
right: 0.,
|
||||||
|
top: 5.,
|
||||||
|
bottom: 5.,
|
||||||
|
})
|
||||||
.with_gap(15.)
|
.with_gap(15.)
|
||||||
.with_background(color::rgb_hex(0x3d3c3e))
|
.with_background(color::rgb_hex(0x3d3c3e))
|
||||||
.with_wrap(true) //XXX: not authentic but great for demostration
|
.with_wrap(true) //XXX: not authentic but great for demostration
|
||||||
|
@ -51,6 +57,16 @@ ui_main!(
|
||||||
.with_text_size(15)
|
.with_text_size(15)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
}
|
}
|
||||||
|
Container::default()
|
||||||
|
//HACK: due to a bug in the layout system, 100%= doesn't work as expected
|
||||||
|
.with_size(size!(94%=, 100%))
|
||||||
|
.with_align((Alignment::End, Alignment::Center))
|
||||||
|
.with_children(|ui| {
|
||||||
|
Text::new("- ×")
|
||||||
|
.with_text_size(32)
|
||||||
|
.add_child(ui);
|
||||||
|
})
|
||||||
|
.add_child(ui);
|
||||||
})
|
})
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
FillRect::default()
|
FillRect::default()
|
||||||
|
@ -58,9 +74,10 @@ ui_main!(
|
||||||
.with_frame(color::rgb_hex(0x2d2d30))
|
.with_frame(color::rgb_hex(0x2d2d30))
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Container::default()
|
Container::default()
|
||||||
.with_size(size!(100%, 100%))
|
.with_size(size!(100%, 100%=))
|
||||||
.with_direction(Direction::Horizontal)
|
.with_direction(Direction::Horizontal)
|
||||||
.with_children(|ui| {
|
.with_children(|ui| {
|
||||||
|
// Sidebar:
|
||||||
Container::default()
|
Container::default()
|
||||||
.with_size(size!(54, 100%))
|
.with_size(size!(54, 100%))
|
||||||
.with_background(color::rgb_hex(0x343334))
|
.with_background(color::rgb_hex(0x343334))
|
||||||
|
@ -69,6 +86,8 @@ ui_main!(
|
||||||
.with_size(size!(1, 100%))
|
.with_size(size!(1, 100%))
|
||||||
.with_frame(color::rgb_hex(0x2d2d30))
|
.with_frame(color::rgb_hex(0x2d2d30))
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
|
|
||||||
|
// Explorer pane:
|
||||||
Container::default()
|
Container::default()
|
||||||
.with_size(size!(200, 100%))
|
.with_size(size!(200, 100%))
|
||||||
.with_padding((15., 8.))
|
.with_padding((15., 8.))
|
||||||
|
@ -78,20 +97,16 @@ ui_main!(
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
})
|
})
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
|
|
||||||
|
// "Code" pane
|
||||||
Container::default()
|
Container::default()
|
||||||
.with_size(size!(100%, 100%))
|
.with_size(size!(100%=, 100%))
|
||||||
.with_background(color::rgb_hex(0x1f1e1f))
|
.with_background(color::rgb_hex(0x1f1e1f))
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
})
|
})
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
})
|
|
||||||
.add_root(ui, size);
|
|
||||||
|
|
||||||
//Bottom bar (yeah, it's basically fake/overlay)
|
//Status bar
|
||||||
Container::default()
|
|
||||||
.with_size(size!(100%))
|
|
||||||
.with_align((Alignment::Begin, Alignment::End))
|
|
||||||
.with_children(|ui| {
|
|
||||||
Container::default()
|
Container::default()
|
||||||
.with_size(size!(100%, auto))
|
.with_size(size!(100%, auto))
|
||||||
.with_background(color::rgb_hex(0x0079cc))
|
.with_background(color::rgb_hex(0x0079cc))
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::any::Any;
|
||||||
use crate::{
|
use crate::{
|
||||||
draw::{atlas::ImageCtx, UiDrawCommandList},
|
draw::{atlas::ImageCtx, UiDrawCommandList},
|
||||||
input::InputCtx,
|
input::InputCtx,
|
||||||
layout::LayoutInfo,
|
layout::{LayoutInfo, Size2d},
|
||||||
measure::Response,
|
measure::Response,
|
||||||
signal::SignalStore,
|
signal::SignalStore,
|
||||||
state::StateRepo,
|
state::StateRepo,
|
||||||
|
@ -45,6 +45,11 @@ pub trait UiElement {
|
||||||
/// For example, "button" or "progress_bar"
|
/// For example, "button" or "progress_bar"
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
|
|
||||||
|
/// Get the requested UiElement size
|
||||||
|
///
|
||||||
|
/// 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\
|
/// Get the unique id used for internal state management\
|
||||||
/// This value must be unique for each instance of the element
|
/// This value must be unique for each instance of the element
|
||||||
///
|
///
|
||||||
|
|
|
@ -5,7 +5,7 @@ use glam::{Vec2, vec2};
|
||||||
use crate::{
|
use crate::{
|
||||||
element::{ElementList, MeasureContext, ProcessContext, UiElement},
|
element::{ElementList, MeasureContext, ProcessContext, UiElement},
|
||||||
frame::{Frame, FrameRect},
|
frame::{Frame, FrameRect},
|
||||||
layout::{Alignment, Alignment2d, Direction, LayoutInfo, Size, Size2d, WrapBehavior},
|
layout::{compute_size, Alignment, Alignment2d, Direction, LayoutInfo, Size, Size2d, WrapBehavior},
|
||||||
measure::{Hints, Response},
|
measure::{Hints, Response},
|
||||||
rect::Sides,
|
rect::Sides,
|
||||||
};
|
};
|
||||||
|
@ -19,6 +19,7 @@ use crate::{
|
||||||
struct CudLine {
|
struct CudLine {
|
||||||
start_idx: usize,
|
start_idx: usize,
|
||||||
content_size: Vec2,
|
content_size: Vec2,
|
||||||
|
remaining_space: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContainerUserData {
|
struct ContainerUserData {
|
||||||
|
@ -90,19 +91,24 @@ impl Default for Container {
|
||||||
|
|
||||||
impl Container {
|
impl Container {
|
||||||
pub fn measure_max_inner_size(&self, layout: &LayoutInfo) -> Vec2 {
|
pub fn measure_max_inner_size(&self, layout: &LayoutInfo) -> Vec2 {
|
||||||
let outer_size_x = match self.size.width {
|
// let outer_size_x = match self.size.width {
|
||||||
Size::Auto => layout.max_size.x,
|
// Size::Auto => layout.max_size.x,
|
||||||
Size::Relative(p) => layout.max_size.x * p,
|
// Size::Relative(p) => layout.max_size.x * p,
|
||||||
Size::Absolute(p) => p,
|
// Size::Absolute(p) => p,
|
||||||
};
|
// Size::Remaining(p) => match layout.direction {
|
||||||
let outer_size_y = match self.size.height {
|
// Direction::Horizontal => layout.remaining_space.unwrap_or(layout.max_size.x) * p,
|
||||||
Size::Auto => layout.max_size.y,
|
// Direction::Vertical => layout.max_size.x,
|
||||||
Size::Relative(p) => layout.max_size.y * p,
|
// }
|
||||||
Size::Absolute(p) => p,
|
// };
|
||||||
};
|
// let outer_size_y = match self.size.height {
|
||||||
|
// Size::Auto => layout.max_size.y,
|
||||||
|
// Size::Relative(p) => layout.max_size.y * p,
|
||||||
|
// Size::Absolute(p) => p,
|
||||||
|
// };
|
||||||
|
let outer_size = compute_size(layout, self.size, layout.max_size);
|
||||||
vec2(
|
vec2(
|
||||||
outer_size_x - (self.padding.left + self.padding.right),
|
outer_size.x - (self.padding.left + self.padding.right),
|
||||||
outer_size_y - (self.padding.top + self.padding.bottom),
|
outer_size.y - (self.padding.top + self.padding.bottom),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +118,10 @@ impl UiElement for Container {
|
||||||
"container"
|
"container"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Option<Size2d> {
|
||||||
|
Some(self.size)
|
||||||
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
// XXX: If both axes are NOT set to auto, we should be able quickly return the size
|
// XXX: If both axes are NOT set to auto, we should be able quickly return the size
|
||||||
// ... but we can't, because we need to measure the children to get the inner_content_size and user_data values
|
// ... but we can't, because we need to measure the children to get the inner_content_size and user_data values
|
||||||
|
@ -126,11 +136,13 @@ impl UiElement for Container {
|
||||||
Size::Auto => ctx.layout.max_size.x,
|
Size::Auto => ctx.layout.max_size.x,
|
||||||
Size::Relative(p) => ctx.layout.max_size.x * p,
|
Size::Relative(p) => ctx.layout.max_size.x * p,
|
||||||
Size::Absolute(p) => p,
|
Size::Absolute(p) => p,
|
||||||
|
Size::Remaining(p) => ctx.layout.remaining_space.unwrap_or(ctx.layout.max_size.x) * p,
|
||||||
},
|
},
|
||||||
Direction::Vertical => match self.size.height {
|
Direction::Vertical => match self.size.height {
|
||||||
Size::Auto => ctx.layout.max_size.y,
|
Size::Auto => ctx.layout.max_size.y,
|
||||||
Size::Relative(p) => ctx.layout.max_size.y * p,
|
Size::Relative(p) => ctx.layout.max_size.y * p,
|
||||||
Size::Absolute(p) => p,
|
Size::Absolute(p) => p,
|
||||||
|
Size::Remaining(p) => ctx.layout.remaining_space.unwrap_or(ctx.layout.max_size.y) * p,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -156,10 +168,25 @@ impl UiElement for Container {
|
||||||
CudLine {
|
CudLine {
|
||||||
start_idx: 0,
|
start_idx: 0,
|
||||||
content_size: Vec2::ZERO,
|
content_size: Vec2::ZERO,
|
||||||
|
remaining_space: 0.,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
//set to true if in the current line there is an element with Remaining size (line will have to be wrapped)
|
||||||
|
// let mut has_remaining = false;
|
||||||
|
|
||||||
for (idx, element) in self.children.0.iter().enumerate() {
|
for (idx, element) in self.children.0.iter().enumerate() {
|
||||||
|
if let Some(esize) = element.size() {
|
||||||
|
let pri_size = match self.direction {
|
||||||
|
Direction::Horizontal => esize.width,
|
||||||
|
Direction::Vertical => esize.height,
|
||||||
|
};
|
||||||
|
if matches!(pri_size, Size::Remaining(_)) {
|
||||||
|
//XXX: kinda a hack?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let measure = element.measure(MeasureContext{
|
let measure = element.measure(MeasureContext{
|
||||||
state: ctx.state,
|
state: ctx.state,
|
||||||
layout: &LayoutInfo {
|
layout: &LayoutInfo {
|
||||||
|
@ -172,6 +199,7 @@ impl UiElement for Container {
|
||||||
//TODO: subtract size already taken by previous children
|
//TODO: subtract size already taken by previous children
|
||||||
max_size: self.measure_max_inner_size(ctx.layout),
|
max_size: self.measure_max_inner_size(ctx.layout),
|
||||||
direction: self.direction,
|
direction: self.direction,
|
||||||
|
remaining_space: None,
|
||||||
},
|
},
|
||||||
text_measure: ctx.text_measure,
|
text_measure: ctx.text_measure,
|
||||||
current_font: ctx.current_font,
|
current_font: ctx.current_font,
|
||||||
|
@ -193,12 +221,20 @@ impl UiElement for Container {
|
||||||
line_size -= leftover_gap;
|
line_size -= leftover_gap;
|
||||||
|
|
||||||
//update the previous line metadata
|
//update the previous line metadata
|
||||||
lines.last_mut().unwrap().content_size = line_size;
|
{
|
||||||
|
let last_line = lines.last_mut().unwrap();
|
||||||
|
last_line.content_size = line_size;
|
||||||
|
last_line.remaining_space = max_line_pri - match self.direction {
|
||||||
|
Direction::Horizontal => line_size.x,
|
||||||
|
Direction::Vertical => line_size.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//push the line metadata
|
//push the line metadata
|
||||||
lines.push(CudLine {
|
lines.push(CudLine {
|
||||||
start_idx: idx,
|
start_idx: idx,
|
||||||
content_size: Vec2::ZERO,
|
content_size: Vec2::ZERO,
|
||||||
|
remaining_space: 0.,
|
||||||
});
|
});
|
||||||
|
|
||||||
//Update the total size accordingly
|
//Update the total size accordingly
|
||||||
|
@ -249,7 +285,14 @@ impl UiElement for Container {
|
||||||
line_size -= leftover_gap;
|
line_size -= leftover_gap;
|
||||||
|
|
||||||
//Update the content size of the last line
|
//Update the content size of the last line
|
||||||
lines.last_mut().unwrap().content_size = line_size;
|
{
|
||||||
|
let cur_line = lines.last_mut().unwrap();
|
||||||
|
cur_line.content_size = line_size;
|
||||||
|
cur_line.remaining_space = max_line_pri - match self.direction {
|
||||||
|
Direction::Horizontal => line_size.x,
|
||||||
|
Direction::Vertical => line_size.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//Update the total size according to the size of the last line
|
//Update the total size according to the size of the last line
|
||||||
match self.direction {
|
match self.direction {
|
||||||
|
@ -275,17 +318,27 @@ impl UiElement for Container {
|
||||||
self.padding.top + self.padding.bottom,
|
self.padding.top + self.padding.bottom,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let computed_size = compute_size(ctx.layout, self.size, total_size);
|
||||||
match self.size.width {
|
match self.size.width {
|
||||||
Size::Auto => (),
|
Size::Auto => (),
|
||||||
Size::Relative(percentage) => total_size.x = ctx.layout.max_size.x * percentage,
|
_ => total_size.x = computed_size.x,
|
||||||
Size::Absolute(pixels) => total_size.x = pixels,
|
|
||||||
}
|
}
|
||||||
match self.size.height {
|
match self.size.height {
|
||||||
Size::Auto => (),
|
Size::Auto => (),
|
||||||
Size::Relative(percentage) => total_size.y = ctx.layout.max_size.y * percentage,
|
_ => total_size.y = computed_size.y,
|
||||||
Size::Absolute(pixels) => total_size.y = pixels,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// match self.size.width {
|
||||||
|
// Size::Auto => (),
|
||||||
|
// Size::Relative(percentage) => total_size.x = ctx.layout.max_size.x * percentage,
|
||||||
|
// Size::Absolute(pixels) => total_size.x = pixels,
|
||||||
|
// }
|
||||||
|
// match self.size.height {
|
||||||
|
// Size::Auto => (),
|
||||||
|
// Size::Relative(percentage) => total_size.y = ctx.layout.max_size.y * percentage,
|
||||||
|
// Size::Absolute(pixels) => total_size.y = pixels,
|
||||||
|
// }
|
||||||
|
|
||||||
Response {
|
Response {
|
||||||
size: total_size,
|
size: total_size,
|
||||||
hints: Hints {
|
hints: Hints {
|
||||||
|
@ -382,6 +435,7 @@ impl UiElement for Container {
|
||||||
position: local_position,
|
position: local_position,
|
||||||
max_size: self.measure_max_inner_size(ctx.layout),
|
max_size: self.measure_max_inner_size(ctx.layout),
|
||||||
direction: self.direction,
|
direction: self.direction,
|
||||||
|
remaining_space: Some(cur_line.remaining_space),
|
||||||
};
|
};
|
||||||
|
|
||||||
//measure
|
//measure
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
draw::{RoundedCorners, UiDrawCommand},
|
draw::{RoundedCorners, UiDrawCommand},
|
||||||
element::{MeasureContext, ProcessContext, UiElement},
|
element::{MeasureContext, ProcessContext, UiElement},
|
||||||
frame::{Frame, FrameRect},
|
frame::{Frame, FrameRect},
|
||||||
layout::{Size, Size2d},
|
layout::{compute_size, Size, Size2d},
|
||||||
measure::Response,
|
measure::Response,
|
||||||
size
|
size
|
||||||
};
|
};
|
||||||
|
@ -45,20 +45,13 @@ impl UiElement for FillRect {
|
||||||
"fill_rect"
|
"fill_rect"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Option<Size2d> {
|
||||||
|
Some(self.size)
|
||||||
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
Response {
|
Response {
|
||||||
size: vec2(
|
size: compute_size(ctx.layout, self.size, ctx.layout.max_size),
|
||||||
match self.size.width {
|
|
||||||
Size::Auto => ctx.layout.max_size.x,
|
|
||||||
Size::Relative(percentage) => ctx.layout.max_size.x * percentage,
|
|
||||||
Size::Absolute(pixels) => pixels,
|
|
||||||
},
|
|
||||||
match self.size.height {
|
|
||||||
Size::Auto => ctx.layout.max_size.y,
|
|
||||||
Size::Relative(percentage) => ctx.layout.max_size.y * percentage,
|
|
||||||
Size::Absolute(pixels) => pixels,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,10 @@ impl UiElement for Image {
|
||||||
"image"
|
"image"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Option<Size2d> {
|
||||||
|
Some(self.size)
|
||||||
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
let dim = ctx.images.get_size(self.image).expect("invalid image handle");
|
let dim = ctx.images.get_size(self.image).expect("invalid image handle");
|
||||||
let pre_size = compute_size(ctx.layout, self.size, dim.as_vec2());
|
let pre_size = compute_size(ctx.layout, self.size, dim.as_vec2());
|
||||||
|
|
|
@ -48,6 +48,10 @@ impl UiElement for Interactable {
|
||||||
"interactable"
|
"interactable"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Option<crate::layout::Size2d> {
|
||||||
|
self.element.size()
|
||||||
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> crate::measure::Response {
|
fn measure(&self, ctx: MeasureContext) -> crate::measure::Response {
|
||||||
self.element.measure(ctx)
|
self.element.measure(ctx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use glam::{vec2, Vec4};
|
||||||
use crate::{
|
use crate::{
|
||||||
draw::UiDrawCommand,
|
draw::UiDrawCommand,
|
||||||
element::{MeasureContext, ProcessContext, UiElement},
|
element::{MeasureContext, ProcessContext, UiElement},
|
||||||
layout::{Size, Size2d},
|
layout::{compute_size, Size, Size2d},
|
||||||
measure::Response,
|
measure::Response,
|
||||||
text::FontHandle,
|
text::FontHandle,
|
||||||
};
|
};
|
||||||
|
@ -74,6 +74,10 @@ impl UiElement for Text {
|
||||||
"text"
|
"text"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Option<Size2d> {
|
||||||
|
Some(self.size)
|
||||||
|
}
|
||||||
|
|
||||||
fn measure(&self, ctx: MeasureContext) -> Response {
|
fn measure(&self, ctx: MeasureContext) -> Response {
|
||||||
let mut size = (0., 0.);
|
let mut size = (0., 0.);
|
||||||
if matches!(self.size.width, Size::Auto) || matches!(self.size.height, Size::Auto) {
|
if matches!(self.size.width, Size::Auto) || matches!(self.size.height, Size::Auto) {
|
||||||
|
@ -83,18 +87,7 @@ impl UiElement for Text {
|
||||||
size.1 = res.height;
|
size.1 = res.height;
|
||||||
}
|
}
|
||||||
Response {
|
Response {
|
||||||
size: vec2(
|
size: compute_size(ctx.layout, self.size, size.into()),
|
||||||
match self.size.width {
|
|
||||||
Size::Auto => size.0,
|
|
||||||
Size::Relative(percentage) => ctx.layout.max_size.x * percentage,
|
|
||||||
Size::Absolute(pixels) => pixels,
|
|
||||||
},
|
|
||||||
match self.size.height {
|
|
||||||
Size::Auto => size.1,
|
|
||||||
Size::Relative(percentage) => ctx.layout.max_size.y * percentage,
|
|
||||||
Size::Absolute(pixels) => pixels,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,13 @@ impl From<f32> for FramePoint {
|
||||||
impl From<Size> for FramePoint {
|
impl From<Size> for FramePoint {
|
||||||
/// Convert a `Size` into a `FramePoint`
|
/// Convert a `Size` into a `FramePoint`
|
||||||
///
|
///
|
||||||
/// This function behaves just as you would expect, but `Auto` is always treated as `BEGIN`
|
/// This function behaves just as you would expect, but:
|
||||||
|
/// - `Auto` is always treated as `BEGIN`
|
||||||
|
/// - `Remaining` is treated as `Relative`
|
||||||
fn from(size: Size) -> Self {
|
fn from(size: Size) -> Self {
|
||||||
match size {
|
match size {
|
||||||
Size::Auto => Self::BEGIN,
|
Size::Auto => Self::BEGIN,
|
||||||
Size::Relative(value) => Self::relative(value),
|
Size::Relative(value) | Size::Remaining(value) => Self::relative(value),
|
||||||
Size::Absolute(value) => Self::absolute(value),
|
Size::Absolute(value) => Self::absolute(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,6 +157,7 @@ impl UiInstance {
|
||||||
position: Vec2::ZERO,
|
position: Vec2::ZERO,
|
||||||
max_size,
|
max_size,
|
||||||
direction: Direction::Vertical,
|
direction: Direction::Vertical,
|
||||||
|
remaining_space: None,
|
||||||
};
|
};
|
||||||
let measure = element.measure(MeasureContext {
|
let measure = element.measure(MeasureContext {
|
||||||
state: &self.stateful_state,
|
state: &self.stateful_state,
|
||||||
|
|
|
@ -134,7 +134,16 @@ pub enum Size {
|
||||||
/// Expected range: `0.0..=1.0`
|
/// Expected range: `0.0..=1.0`
|
||||||
Relative(f32),
|
Relative(f32),
|
||||||
|
|
||||||
//TODO Remaining(f32)
|
/// Size as a ratio of remaining space after all other elements have been laid out
|
||||||
|
///
|
||||||
|
/// Expected range: `0.0..=1.0`
|
||||||
|
///
|
||||||
|
/// - This feature is experimental and may not work as expected;\
|
||||||
|
/// Current `Container` implementation:
|
||||||
|
/// - Assumes that he line is fully filled if any element uses `Remaining` size, even if sum of remaining sizes is less than 1.0
|
||||||
|
/// - Does not support `Remaining` size in the secondary axis, it will be treated as `Relative`
|
||||||
|
/// - In cases where it's not applicable or not supported, it's defined to behave as `Relative`
|
||||||
|
Remaining(f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<f32> for Size {
|
impl From<f32> for Size {
|
||||||
|
@ -197,6 +206,13 @@ pub struct LayoutInfo {
|
||||||
/// Current direction of the layout\
|
/// Current direction of the layout\
|
||||||
/// (Usually matches direction of the parent container)
|
/// (Usually matches direction of the parent container)
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
|
|
||||||
|
/// Remaining space in the primary axis\
|
||||||
|
///
|
||||||
|
/// This value is only available during the layout step and is only likely to be present if the element uses `Size::Remaining`
|
||||||
|
///
|
||||||
|
/// (Make sure that LayoutInfo::direction is set to the correct direction!)
|
||||||
|
pub remaining_space: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to calculate the size of an element based on its layout and size information\
|
/// Helper function to calculate the size of an element based on its layout and size information\
|
||||||
|
@ -206,11 +222,19 @@ pub fn compute_size(layout: &LayoutInfo, size: Size2d, comfy_size: Vec2) -> Vec2
|
||||||
Size::Auto => comfy_size.x,
|
Size::Auto => comfy_size.x,
|
||||||
Size::Relative(fraction) => layout.max_size.x * fraction,
|
Size::Relative(fraction) => layout.max_size.x * fraction,
|
||||||
Size::Absolute(size) => size,
|
Size::Absolute(size) => size,
|
||||||
|
Size::Remaining(fraction) => match layout.direction {
|
||||||
|
Direction::Horizontal => layout.remaining_space.unwrap_or(layout.max_size.x) * fraction,
|
||||||
|
Direction::Vertical => layout.max_size.x * fraction,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let height = match size.height {
|
let height = match size.height {
|
||||||
Size::Auto => comfy_size.y,
|
Size::Auto => comfy_size.y,
|
||||||
Size::Relative(fraction) => layout.max_size.y * fraction,
|
Size::Relative(fraction) => layout.max_size.y * fraction,
|
||||||
Size::Absolute(size) => size,
|
Size::Absolute(size) => size,
|
||||||
|
Size::Remaining(fraction) => match layout.direction {
|
||||||
|
Direction::Horizontal => layout.max_size.y * fraction,
|
||||||
|
Direction::Vertical => layout.remaining_space.unwrap_or(layout.max_size.y) * fraction,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
vec2(width, height)
|
vec2(width, height)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
/// - `x` - `Size::Absolute(x)`
|
/// - `x` - `Size::Absolute(x)`
|
||||||
/// - `x%` - `Size::Relative(x / 100.)` *(literal only)*
|
/// - `x%` - `Size::Relative(x / 100.)` *(literal only)*
|
||||||
/// - `x/` - `Size::Relative(x)`
|
/// - `x/` - `Size::Relative(x)`
|
||||||
|
/// - `x%=` - `Size::Remaining(x / 100.)` *(literal only)*
|
||||||
|
/// - `x/=` - `Size::Remaining(x)`
|
||||||
///
|
///
|
||||||
/// ...where `x` is a literal, identifier or an expression wrapped in parentheses
|
/// ...where `x` is a literal, identifier or an expression wrapped in parentheses
|
||||||
///
|
///
|
||||||
|
@ -32,6 +34,12 @@ macro_rules! size {
|
||||||
($x:literal /) => {
|
($x:literal /) => {
|
||||||
$crate::layout::Size::Relative($x as f32)
|
$crate::layout::Size::Relative($x as f32)
|
||||||
};
|
};
|
||||||
|
($x:literal %=) => {
|
||||||
|
$crate::layout::Size::Remaining($x as f32 / 100.)
|
||||||
|
};
|
||||||
|
($x:literal /=) => {
|
||||||
|
$crate::layout::Size::Remaining($x as f32)
|
||||||
|
};
|
||||||
|
|
||||||
($x:ident) => {
|
($x:ident) => {
|
||||||
$crate::layout::Size::Absolute($x as f32)
|
$crate::layout::Size::Absolute($x as f32)
|
||||||
|
@ -39,6 +47,9 @@ macro_rules! size {
|
||||||
($x:ident /) => {
|
($x:ident /) => {
|
||||||
$crate::layout::Size::Relative($x as f32)
|
$crate::layout::Size::Relative($x as f32)
|
||||||
};
|
};
|
||||||
|
($x:ident /=) => {
|
||||||
|
$crate::layout::Size::Remaining($x as f32)
|
||||||
|
};
|
||||||
|
|
||||||
(($x:expr)) => {
|
(($x:expr)) => {
|
||||||
$crate::layout::Size::Absolute(($x) as f32)
|
$crate::layout::Size::Absolute(($x) as f32)
|
||||||
|
@ -46,6 +57,9 @@ macro_rules! size {
|
||||||
(($x:expr) /) => {
|
(($x:expr) /) => {
|
||||||
$crate::layout::Size::Relative(($x) as f32)
|
$crate::layout::Size::Relative(($x) as f32)
|
||||||
};
|
};
|
||||||
|
(($x:expr) /=) => {
|
||||||
|
$crate::layout::Size::Remaining(($x) as f32)
|
||||||
|
};
|
||||||
|
|
||||||
($x:tt , $y:tt $($ys:tt)?) => {
|
($x:tt , $y:tt $($ys:tt)?) => {
|
||||||
$crate::layout::Size2d {
|
$crate::layout::Size2d {
|
||||||
|
|
Loading…
Reference in a new issue