The beginnings of a simple library...

This commit is contained in:
2023-10-28 15:00:15 -04:00
parent 2d7df265d0
commit 140a6ad043
16 changed files with 765 additions and 66 deletions

View File

@@ -9,12 +9,8 @@ edition = "2021"
name = "nytegearui" name = "nytegearui"
path = "src/lib.rs" path = "src/lib.rs"
[[bin]]
name = "demo"
path = "src/main.rs"
[dependencies] [dependencies]
winit = "0.29" winit = "0.29"
glutin = "0.31.0" glutin = "0.31.0"
gl = "0.14" gl = "0.14"
raw-gl-context = { git = "https://github.com/Aargonian/raw-gl-context.git", branch = "master" } raw-gl-context = { git = "https://github.com/Aargonian/raw-gl-context.git", branch = "master" }

View File

@@ -0,0 +1,82 @@
//TODO: Remove this
#![allow(dead_code)]
#![allow(unused_variables)]
use nytegearui::widget::{
Position, Sizing,
style::Style,
};
use nytegearui::window::{Renderer, Widget};
use nytegearui::window::Window;
pub struct RectangleWidget {
position: Position,
sizing: Sizing,
style: Style,
}
impl RectangleWidget {
pub fn new(width: u32, height: u32) -> Self {
Self {
position: Default::default(),
sizing: Sizing {
size: (width, height).into(),
..Default::default()
},
style: Default::default(),
}
}
}
impl Widget for RectangleWidget {
fn draw(&self, renderer: &mut dyn Renderer) {
//renderer.set_style();
/*
renderer.fill_rect(self.position.x,
self.position.y,
self.sizing.size.width,
self.sizing.size.height,
self.style.foreground_color);
*/
}
}
fn main() {
let window = Window::new();
let rect_widget = RectangleWidget::new(50, 50);
/*
event_loop.run(move |event, window_target| {
match event {
Event::WindowEvent {
event: winit::event::WindowEvent::CloseRequested,
..
} => {
window_target.exit();
}
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..
} => {
unsafe {
context.make_current();
}
unsafe {
gl::ClearColor(0.2, 0.1, 0.5, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
}
context.swap_buffers();
unsafe {
context.make_not_current();
}
}
_ => {}
}
}).expect("TODO: panic message");
*/
}

View File

@@ -0,0 +1,6 @@
use nytegearui::window::Window;
fn main() {
let mut window = Window::new();
window.run();
}

View File

@@ -1,7 +1,9 @@
use crate::window::Renderer; use gl::types::GLfloat;
use raw_gl_context::{GlConfig, GlContext}; use raw_gl_context::{GlConfig, GlContext};
use winit::window::Window as WinitWindow; use winit::window::Window as WinitWindow;
use winit::raw_window_handle::HasRawWindowHandle;
use crate::widget::color::Color;
use crate::window::Renderer;
pub struct OpenGLRenderer { pub struct OpenGLRenderer {
context: GlContext, context: GlContext,
@@ -11,14 +13,21 @@ impl OpenGLRenderer
{ {
pub fn try_create(window: &WinitWindow) -> Option<OpenGLRenderer> pub fn try_create(window: &WinitWindow) -> Option<OpenGLRenderer>
{ {
let context = unsafe { GlContext::create(window, GlConfig::default()).unwrap() }; let gl_context = unsafe {
let potential_context = GlContext::create(window, GlConfig::default());
if let Ok(context) = potential_context {
context.make_current();
unsafe { gl::load_with(|symbol| context.get_proc_address(symbol) as *const _);
context.make_current();
} context
} else {
return None;
}
};
Some(OpenGLRenderer { Some(OpenGLRenderer {
context, context: gl_context,
}) })
} }
} }
@@ -33,7 +42,31 @@ impl Renderer for OpenGLRenderer
todo!() todo!()
} }
fn fill_rect(&mut self, x: u32, y: u32, width: u32, height: u32, value: u32) { fn fill_rect(&mut self, x: u32, y: u32, width: u32, height: u32, color: Color) {
todo!() todo!()
} }
fn clear_background(&mut self, background_color: Color) {
let red: GLfloat = ((background_color.r as f64) / 255.0) as GLfloat;
let green: GLfloat = ((background_color.g as f64) / 255.0) as GLfloat;
let blue: GLfloat = ((background_color.b as f64) / 255.0) as GLfloat;
let alpha: GLfloat = ((background_color.a as f64) / 255.0) as GLfloat;
unsafe {
gl::ClearColor(red, green, blue, alpha);
gl::Clear(gl::COLOR_BUFFER_BIT);
}
}
fn begin(&mut self) {
unsafe {
self.context.make_current();
}
}
fn end(&mut self) {
self.context.swap_buffers();
unsafe {
self.context.make_not_current();
}
}
} }

View File

@@ -1,2 +1,4 @@
pub mod window; pub mod window;
pub mod backends; pub mod widget;
mod backends;

View File

@@ -1,50 +0,0 @@
use raw_gl_context::{GlConfig, GlContext};
use winit::event_loop::EventLoop;
use winit::window::WindowBuilder;
use winit::event::{Event, WindowEvent};
fn main() {
let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap();
let context = unsafe { GlContext::create(&window, GlConfig::default()).unwrap() };
unsafe {
context.make_current();
}
gl::load_with(|symbol| context.get_proc_address(symbol) as *const _);
event_loop.run(move |event, window_target| {
match event {
Event::WindowEvent {
event: winit::event::WindowEvent::CloseRequested,
..
} => {
window_target.exit();
}
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..
} => {
unsafe {
context.make_current();
}
unsafe {
gl::ClearColor(0.2, 0.1, 0.5, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
}
context.swap_buffers();
unsafe {
context.make_not_current();
}
}
_ => {}
}
}).expect("TODO: panic message");
}

46
src/widget/color.rs Normal file
View File

@@ -0,0 +1,46 @@
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Color {
pub a: u8,
pub r: u8,
pub g: u8,
pub b: u8,
}
impl Color {
pub const fn new(a: u8, r: u8, g: u8, b: u8) -> Self {
Self { a, r, g, b }
}
}
impl From<u32> for Color {
fn from(argb: u32) -> Self {
Self {
a: ((argb >> 24) & 0xff) as u8,
r: ((argb >> 16) & 0xff) as u8,
g: ((argb >> 8) & 0xff) as u8,
b: (argb & 0xff) as u8,
}
}
}
impl Into<u32> for Color {
fn into(self) -> u32 {
((self.a as u32) << 24)
| ((self.r as u32) << 16)
| ((self.g as u32) << 8)
| (self.b as u32)
}
}
// Constants for common colors
pub const BLACK: Color = Color::new(255, 0, 0, 0);
pub const WHITE: Color = Color::new(255, 255, 255, 255);
pub const RED: Color = Color::new(255, 255, 0, 0);
pub const GREEN: Color = Color::new(255, 0, 255, 0);
pub const BLUE: Color = Color::new(255, 0, 0, 255);
pub const YELLOW: Color = Color::new(255, 255, 255, 0);
pub const ORANGE: Color = Color::new(255, 255, 165, 0);
pub const PURPLE: Color = Color::new(255, 128, 0, 128);
pub const GRAY: Color = Color::new(255, 128, 128, 128);
pub const LIGHT_GRAY: Color = Color::new(255, 192, 192, 192);
pub const DARK_GRAY: Color = Color::new(255, 64, 64, 64);

7
src/widget/mod.rs Normal file
View File

@@ -0,0 +1,7 @@
pub use util::*;
pub mod color;
pub mod style;
pub mod widget;
mod util;

16
src/widget/style.rs Normal file
View File

@@ -0,0 +1,16 @@
use crate::widget::color::Color;
#[derive(Default)]
pub struct Border {
pub thickness: u32,
pub color: Color,
}
#[derive(Default)]
pub struct Style {
pub background_color: Color,
pub foreground_color: Color,
pub border: Border,
pub corner_radius: (u32, u32, u32, u32),
}

View File

@@ -0,0 +1,32 @@
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Dimension {
Percent(f64),
Pixel(u32),
}
impl Default for Dimension {
fn default() -> Self {
Dimension::Pixel(0)
}
}
impl Into<Dimension> for u32 {
fn into(self) -> Dimension {
Dimension::Pixel(self)
}
}
impl Into<Dimension> for f64 {
fn into(self) -> Dimension {
Dimension::Percent(self)
}
}
impl Dimension {
pub fn calculate_dimension_size(&self, available_space: u32) -> u32 {
match self {
Self::Pixel(value) => *value,
Self::Percent(percent) => ((percent * available_space as f64)/100.0) as u32
}
}
}

7
src/widget/util/mod.rs Normal file
View File

@@ -0,0 +1,7 @@
mod sizing;
mod dimension;
mod position;
pub use dimension::*;
pub use sizing::*;
pub use position::*;

View File

@@ -0,0 +1,5 @@
#[derive(Default, Clone, Copy, Debug, PartialEq)]
pub struct Position {
pub x: u32,
pub y: u32
}

197
src/widget/util/sizing.rs Normal file
View File

@@ -0,0 +1,197 @@
use crate::widget::Dimension;
#[derive(Default, Clone, Copy, Debug, PartialEq)]
pub struct Size {
pub width: Dimension,
pub height: Dimension,
}
impl From<(u32, u32)> for Size {
fn from(value: (u32, u32)) -> Size {
Size {
width: Dimension::Pixel(value.0),
height: Dimension::Pixel(value.1),
}
}
}
impl From<(f64, f64)> for Size {
fn from(value: (f64, f64)) -> Size {
Size {
width: Dimension::Percent(value.0),
height: Dimension::Percent(value.1),
}
}
}
#[derive(Default, Clone, Copy, Debug, PartialEq)]
pub struct AbsoluteSize {
pub width: u32,
pub height: u32,
}
impl From<AbsoluteSize> for Size {
fn from(value: AbsoluteSize) -> Size {
Size {
width: Dimension::Pixel(value.width),
height: Dimension::Pixel(value.height),
}
}
}
impl From<(u32, u32)> for AbsoluteSize {
fn from(value: (u32, u32)) -> AbsoluteSize {
AbsoluteSize {
width: value.0,
height: value.1,
}
}
}
#[derive(Default, Clone, Copy, Debug, PartialEq)]
pub struct Margin {
pub top: Dimension,
pub right: Dimension,
pub bottom: Dimension,
pub left: Dimension,
}
#[derive(Default, Clone, Copy, Debug, PartialEq)]
pub struct Padding {
pub top: Dimension,
pub right: Dimension,
pub bottom: Dimension,
pub left: Dimension,
}
/// The Sizing and Positional information for a Widget
///
/// Use this struct to position your widget within the parent element and provide sizing hints for
/// the layout engine. Positional information may be ignored by the layout engine depending on the
/// layout used by the parent widget, and sizing information will be used for a hint-style system.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct Sizing {
pub margin: Margin,
pub padding: Padding,
pub min_size: Option<Size>,
pub max_size: Option<Size>,
pub size: Size,
}
impl Sizing {
/// Calculates the size this widget will take up given an available amount of space.
///
/// This calculation will use a combination of the margin, padding, and sizing values to
/// determine the final size of the widget. If the available space is less than the combination
/// of margin, padding, and the minimum size of this widget, the return value will be greater
/// than the available space. If the available space is larger than the combination of padding,
/// margin, and the max size of this Sizing, it will be less than the available space. For all
/// other situations, the returned Spacing value will be the calculated margin, padding, and
/// size of this widget sizing within the available space.
///
/// In cases where the size has (likely incorrectly) been configured to be larger than the max
/// size, or smaller than the min size, the larger or smaller of the two will be used,
/// respectively.
///
/// The returned size from this function will always have a `None` value for the `min_size` and
/// `max_size` fields. The returned `Sizing` object will have the margin, padding, and inner
/// size value to reserve for this widget.
pub fn calculate_sizing(&self, available_space: AbsoluteSize) -> Sizing {
// Helper function for converting dimensions to u32
fn calculate_dimension_size(dimension: Dimension, available_space: u32) -> u32 {
match dimension {
Dimension::Pixel(value) => value,
Dimension::Percent(percent) => (available_space as f64 * percent) as u32
}
}
let top_pad = calculate_dimension_size(self.padding.top, available_space.height);
let right_pad = calculate_dimension_size(self.padding.right, available_space.width);
let bottom_pad = calculate_dimension_size(self.padding.bottom, available_space.height);
let left_pad = calculate_dimension_size(self.padding.left, available_space.width);
let top_margin = calculate_dimension_size(self.margin.top, available_space.height);
let right_margin = calculate_dimension_size(self.margin.right, available_space.width);
let bottom_margin = calculate_dimension_size(self.margin.bottom, available_space.height);
let left_margin = calculate_dimension_size(self.margin.left, available_space.width);
// We use box-model sizing, so min/max are calculated to the border not including padding
let remaining_height = available_space.height - (top_margin + bottom_margin);
let remaining_width = available_space.width - (left_margin + right_margin);
// Calculate our minimum sizes in case min size is greater than declared size
let possible_min_width = calculate_dimension_size(self.size.width, remaining_width);
let possible_min_height = calculate_dimension_size(self.size.height, remaining_height);
let min_width = if let Some(min_size) = self.min_size {
let declared_min_width = calculate_dimension_size(min_size.width, remaining_width);
declared_min_width.min(possible_min_width)
} else {
possible_min_width
};
let min_height = if let Some(min_size) = self.min_size {
let declared_min_height = calculate_dimension_size(min_size.height, remaining_height);
declared_min_height.min(possible_min_height)
} else {
possible_min_height
};
// Calculate our maximum sizes in case max size is greater than declared size
let possible_max_width = calculate_dimension_size(self.size.width, remaining_width);
let possible_max_height = calculate_dimension_size(self.size.height, remaining_height);
let max_width = if let Some(max_size) = self.max_size {
let declared_max_width = calculate_dimension_size(max_size.width, remaining_width);
declared_max_width.max(possible_max_width)
} else {
possible_max_width
};
let max_height = if let Some(max_size) = self.max_size {
let declared_max_height = calculate_dimension_size(max_size.height, remaining_height);
declared_max_height.max(possible_max_height)
} else {
possible_max_height
};
// Determine final sizes.
let final_width = if remaining_width < min_width {
min_width
} else if remaining_width > max_width {
max_width
} else {
remaining_width
};
let final_height = if remaining_height < min_height {
min_height
} else if remaining_height > max_height {
max_height
} else {
remaining_height
};
let size = Size {
width: final_width.into(),
height: final_height.into(),
};
let padding = Padding {
top: top_pad.into(),
right: right_pad.into(),
bottom: bottom_pad.into(),
left: left_pad.into(),
};
let margin = Margin {
top: top_margin.into(),
right: right_margin.into(),
bottom: bottom_margin.into(),
left: left_margin.into(),
};
Sizing {
min_size: None,
max_size: None,
padding,
margin,
size,
}
}
}

11
src/widget/widget.rs Normal file
View File

@@ -0,0 +1,11 @@
use crate::widget::Position;
use crate::widget::style::Style;
use crate::window::Renderer;
trait Widget {
fn style(&self) -> Option<Style>;
fn position(&self) -> Position;
fn draw(&self, renderer: &dyn Renderer);
}

View File

@@ -1,16 +1,23 @@
use std::collections::VecDeque;
use winit::{ use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
window::{Window as WinitWindow, WindowBuilder}, window::{Window as WinitWindow, WindowBuilder},
}; };
use winit::event::{Event, WindowEvent};
use winit::platform::pump_events::EventLoopExtPumpEvents;
use crate::backends::OpenGLRenderer; use crate::backends::OpenGLRenderer;
use crate::widget::color::Color;
pub trait Renderer pub trait Renderer
{ {
fn draw_pixel(&mut self, x: u32, y: u32, value: u32); fn draw_pixel(&mut self, x: u32, y: u32, value: u32);
fn draw_rect(&mut self, x: u32, y: u32, width: u32, height: u32, value: u32); fn draw_rect(&mut self, x: u32, y: u32, width: u32, height: u32, value: u32);
fn fill_rect(&mut self, x: u32, y: u32, width: u32, height: u32, value: u32); fn fill_rect(&mut self, x: u32, y: u32, width: u32, height: u32, color: Color);
fn clear_background(&mut self, background_color: Color);
fn begin(&mut self);
fn end(&mut self);
} }
pub trait Widget pub trait Widget
@@ -49,6 +56,51 @@ impl Window
} }
} }
pub fn run(&mut self) {
let timeout = None;
let mut exit_loop = false;
let mut event_queue = VecDeque::new();
while !exit_loop {
self.event_loop.pump_events(timeout, |event, elwt| {
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == self.window.id() => {
elwt.exit();
exit_loop = true;
}
_ => event_queue.push_back(event)
}
});
while let Some(event) = event_queue.pop_front() {
match event {
Event::AboutToWait => {
self.window.request_redraw();
}
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..
} => {
self.redraw();
}
_ => (),
}
}
}
}
fn redraw(&mut self) {
self.renderer.begin();
self.renderer.clear_background(Color::new(255, 51, 25, 128));
self.renderer.end();
}
fn resolve_rendering_backend(window: &WinitWindow) -> Option<Box<dyn Renderer>> fn resolve_rendering_backend(window: &WinitWindow) -> Option<Box<dyn Renderer>>
{ {
//TODO: Expand this to allow for Metal and DirectX Renderers //TODO: Expand this to allow for Metal and DirectX Renderers

257
tests/test_sizing.rs Normal file
View File

@@ -0,0 +1,257 @@
extern crate nytegearui;
use nytegearui::widget::{AbsoluteSize, Dimension, Margin, Padding, Size, Sizing};
#[test]
fn test_desired_size_only() {
let width = 500;
let height = 300;
let child_size = Sizing {
padding: Default::default(),
margin: Default::default(),
min_size: None,
max_size: None,
size: Size::from((width, height)),
};
// Preferred Size with Equal Space
let available_space = AbsoluteSize::from((width, height));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing.size.width, Dimension::Pixel(width));
assert_eq!(preferred_sizing.size.height, Dimension::Pixel(height));
// Preferred Size with Greater Space
let available_space = AbsoluteSize::from((width + 100, height + 100));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing.size.width, Dimension::Pixel(width));
assert_eq!(preferred_sizing.size.height, Dimension::Pixel(height));
// Preferred Size with Less Space
let available_space = AbsoluteSize::from((width - 100, height - 100));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing.size.width, Dimension::Pixel(width));
assert_eq!(preferred_sizing.size.height, Dimension::Pixel(height));
}
#[test]
fn test_fixed_desired_size_and_no_margin() {
let padding_top = 20;
let padding_bottom = 30;
let padding_left = 40;
let padding_right = 60;
let width = 500;
let height = 300;
let child_size = Sizing {
padding: Padding {
top: padding_top.into(),
right: padding_right.into(),
left: padding_left.into(),
bottom: padding_bottom.into(),
},
margin: Default::default(),
min_size: None,
max_size: None,
size: Size::from((width, height)),
};
// The Sizing should not change for any test
let expected_sizing = Sizing {
padding: Padding {
top: padding_top.into(),
right: padding_right.into(),
left: padding_left.into(),
bottom: padding_bottom.into(),
},
margin: Default::default(),
min_size: None,
max_size: None,
size: Size::from((width, height)),
};
let width_with_padding = width + padding_left + padding_right;
let height_with_padding = height + padding_top + padding_bottom;
// Preferred Size with Equal Space (including padding)
let available_space = AbsoluteSize::from((width_with_padding, height_with_padding));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_sizing);
// Preferred Size with Equal Space (excluding padding)
let available_space = AbsoluteSize::from((width, height));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_sizing);
// Preferred Size with Greater Space
let available_space = AbsoluteSize::from((width_with_padding + 100, height_with_padding + 100));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_sizing);
// Preferred Size with Less Space
let available_space = AbsoluteSize::from((width - 100, height - 100));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_sizing);
}
#[test]
fn test_fixed_desired_size_and_no_padding() {
let margin_top = 20;
let margin_bottom = 30;
let margin_left = 40;
let margin_right = 60;
let width = 500;
let height = 300;
let child_size = Sizing {
margin: Margin {
top: margin_top.into(),
right: margin_right.into(),
left: margin_left.into(),
bottom: margin_bottom.into(),
},
padding: Default::default(),
min_size: None,
max_size: None,
size: Size::from((width, height)),
};
// Sizing should not change at any point
let expected_sizing = Sizing {
margin: Margin {
top: margin_top.into(),
right: margin_right.into(),
left: margin_left.into(),
bottom: margin_bottom.into(),
},
padding: Default::default(),
min_size: None,
max_size: None,
size: Size::from((width, height)),
};
let height_with_margin = height + margin_top + margin_bottom;
let width_with_margin = width + margin_left + margin_right;
// Preferred Size with Equal Space (including margin)
let available_space = AbsoluteSize::from((width_with_margin, height_with_margin));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_sizing);
// Preferred Size with Equal Space (excluding margin)
let available_space = AbsoluteSize::from((width, height));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_sizing);
// Preferred Size with Greater Space
let available_space = AbsoluteSize::from((width_with_margin + 100, height_with_margin + 100));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_sizing);
// Preferred Size with Less Space
let available_space = AbsoluteSize::from((width - 100, height - 100));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_sizing);
}
#[test]
fn test_fixed_desired_size_with_padding_and_margin() {
let margin_top = 20;
let margin_bottom = 30;
let margin_left = 40;
let margin_right = 60;
let padding_top = margin_top;
let padding_bottom = margin_bottom;
let padding_left = margin_left;
let padding_right = margin_right;
let width = 500;
let height = 300;
let child_size = Sizing {
margin: Margin {
top: margin_top.into(),
right: margin_right.into(),
left: margin_left.into(),
bottom: margin_bottom.into(),
},
padding: Padding {
top: padding_top.into(),
right: padding_right.into(),
left: padding_left.into(),
bottom: padding_bottom.into(),
},
min_size: None,
max_size: None,
size: Size::from((width, height)),
};
// Sizing should not change at any point
let expected_size = Sizing {
margin: Margin {
top: margin_top.into(),
right: margin_right.into(),
left: margin_left.into(),
bottom: margin_bottom.into(),
},
padding: Padding {
top: padding_top.into(),
right: padding_right.into(),
left: padding_left.into(),
bottom: padding_bottom.into(),
},
min_size: None,
max_size: None,
size: Size::from((width, height)),
};
let total_height = height + margin_top + margin_bottom + padding_top + padding_bottom;
let total_width = width + margin_left + margin_right + padding_left + padding_right;
// Preferred Size with Equal Space (including margin)
let available_space = AbsoluteSize::from((total_width, total_height));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_size);
// Preferred Size with Equal Space (excluding margin)
let available_space = AbsoluteSize::from((width, height));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_size);
// Preferred Size with Greater Space
let available_space = AbsoluteSize::from((total_width + 100, total_height + 100));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_size);
// Preferred Size with Less Space
let available_space = AbsoluteSize::from((width - 100, height - 100));
let preferred_sizing = child_size.calculate_sizing(available_space);
assert_eq!(preferred_sizing, expected_size);
}
#[test]
fn test_percent_desired_size_only() {
let width = 0.25;
let height = 0.25;
let available_width = 511;
let available_height = 293;
let child_size = Sizing {
margin: Default::default(),
padding: Default::default(),
min_size: None,
max_size: None,
size: Size::from((width, height)),
};
// For the first test
let expected_size = Sizing {
margin: Default::default(),
padding: Default::default(),
min_size: None,
max_size: None,
size: Size::from((available_width / 4, available_height / 4)),
};
let available_space = AbsoluteSize::from((available_width, available_height));
let calculated_size = child_size.calculate_sizing(available_space);
assert_eq!(calculated_size, expected_size);
}