The beginnings of a simple library...
This commit is contained in:
@@ -9,12 +9,8 @@ edition = "2021"
|
||||
name = "nytegearui"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "demo"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
winit = "0.29"
|
||||
glutin = "0.31.0"
|
||||
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" }
|
||||
82
examples/rectangle_widget.rs
Normal file
82
examples/rectangle_widget.rs
Normal 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");
|
||||
*/
|
||||
}
|
||||
6
examples/simple_window.rs
Normal file
6
examples/simple_window.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
use nytegearui::window::Window;
|
||||
|
||||
fn main() {
|
||||
let mut window = Window::new();
|
||||
window.run();
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
use crate::window::Renderer;
|
||||
use gl::types::GLfloat;
|
||||
use raw_gl_context::{GlConfig, GlContext};
|
||||
use winit::window::Window as WinitWindow;
|
||||
use winit::raw_window_handle::HasRawWindowHandle;
|
||||
|
||||
use crate::widget::color::Color;
|
||||
use crate::window::Renderer;
|
||||
|
||||
pub struct OpenGLRenderer {
|
||||
context: GlContext,
|
||||
@@ -11,14 +13,21 @@ impl 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 {
|
||||
context.make_current();
|
||||
}
|
||||
gl::load_with(|symbol| context.get_proc_address(symbol) as *const _);
|
||||
|
||||
context
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some(OpenGLRenderer {
|
||||
context,
|
||||
context: gl_context,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -33,7 +42,31 @@ impl Renderer for OpenGLRenderer
|
||||
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!()
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
pub mod window;
|
||||
pub mod backends;
|
||||
pub mod widget;
|
||||
|
||||
mod backends;
|
||||
50
src/main.rs
50
src/main.rs
@@ -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
46
src/widget/color.rs
Normal 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
7
src/widget/mod.rs
Normal 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
16
src/widget/style.rs
Normal 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),
|
||||
}
|
||||
|
||||
32
src/widget/util/dimension.rs
Normal file
32
src/widget/util/dimension.rs
Normal 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
7
src/widget/util/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
mod sizing;
|
||||
mod dimension;
|
||||
mod position;
|
||||
|
||||
pub use dimension::*;
|
||||
pub use sizing::*;
|
||||
pub use position::*;
|
||||
5
src/widget/util/position.rs
Normal file
5
src/widget/util/position.rs
Normal 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
197
src/widget/util/sizing.rs
Normal 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
11
src/widget/widget.rs
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use winit::{
|
||||
event::{Event, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
window::{Window as WinitWindow, WindowBuilder},
|
||||
};
|
||||
use winit::event::{Event, WindowEvent};
|
||||
use winit::platform::pump_events::EventLoopExtPumpEvents;
|
||||
|
||||
use crate::backends::OpenGLRenderer;
|
||||
use crate::widget::color::Color;
|
||||
|
||||
pub trait Renderer
|
||||
{
|
||||
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 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
|
||||
@@ -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>>
|
||||
{
|
||||
//TODO: Expand this to allow for Metal and DirectX Renderers
|
||||
|
||||
257
tests/test_sizing.rs
Normal file
257
tests/test_sizing.rs
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user