mirror of
https://github.com/Astatin3/IntroToWebAuthoring.git
synced 2026-06-08 16:18:01 -06:00
Finish constraint layout
This commit is contained in:
+11
-15
@@ -1,27 +1,14 @@
|
|||||||
mod cursors;
|
mod cursors;
|
||||||
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub use cursors::{Cursor, set_cursor};
|
pub use cursors::{Cursor, set_cursor};
|
||||||
|
|
||||||
use wasm_bindgen::prelude::wasm_bindgen;
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
log,
|
|
||||||
render::Renderer,
|
render::Renderer,
|
||||||
views::{View, default_view},
|
views::{View, default_view},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Activity {
|
|
||||||
fn new() -> Self
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
fn update(&mut self, dt: f32);
|
|
||||||
fn draw(&self, renderer: &mut Renderer, state: &AppState);
|
|
||||||
fn l_click(&mut self, renderer: &mut Renderer, state: &AppState);
|
|
||||||
fn mouse_move(&mut self, renderer: &mut Renderer, state: &AppState);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct App {
|
pub struct App {
|
||||||
// pub(crate) activities: Vec<Box<dyn Activity>>,
|
// pub(crate) activities: Vec<Box<dyn Activity>>,
|
||||||
@@ -47,12 +34,18 @@ impl AppState {
|
|||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(renderer: Renderer) -> Self {
|
pub fn new(renderer: Renderer) -> Self {
|
||||||
App {
|
let (width, height) = (renderer.actual_width, renderer.actual_height);
|
||||||
|
|
||||||
|
let mut this = App {
|
||||||
root_view: Some(default_view()),
|
root_view: Some(default_view()),
|
||||||
renderer,
|
renderer,
|
||||||
// current_activity: Some(0),
|
// current_activity: Some(0),
|
||||||
state: AppState::new(),
|
state: AppState::new(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
this.resize(width, height);
|
||||||
|
|
||||||
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&mut self) {
|
pub fn draw(&mut self) {
|
||||||
@@ -72,6 +65,9 @@ impl App {
|
|||||||
impl App {
|
impl App {
|
||||||
pub fn resize(&mut self, width: usize, height: usize) {
|
pub fn resize(&mut self, width: usize, height: usize) {
|
||||||
self.renderer.resize(width, height);
|
self.renderer.resize(width, height);
|
||||||
|
if let Some(view) = &mut self.root_view {
|
||||||
|
view.resize(0., 0., width as f32, height as f32);
|
||||||
|
}
|
||||||
self.draw();
|
self.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// mod activities;
|
|
||||||
mod app;
|
mod app;
|
||||||
mod fonts;
|
mod fonts;
|
||||||
mod render;
|
mod render;
|
||||||
|
|||||||
+9
-328
@@ -1,9 +1,4 @@
|
|||||||
// use crate::console_log;
|
// use crate::render::rand;
|
||||||
use crate::render::rand;
|
|
||||||
|
|
||||||
// macro_rules! log {
|
|
||||||
// ($($t:tt)*) => (console_log(&format_args!($($t)*).to_string()))
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub struct ImgBuffer {
|
pub struct ImgBuffer {
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
@@ -20,14 +15,14 @@ impl ImgBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn randomize(&mut self, rand: &mut rand::Rnd) {
|
// pub fn randomize(&mut self, rand: &mut rand::Rnd) {
|
||||||
for pixel in self.data.chunks_mut(4) {
|
// for pixel in self.data.chunks_mut(4) {
|
||||||
pixel[0] = rand.next_i32() as u8;
|
// pixel[0] = rand.next_i32() as u8;
|
||||||
pixel[1] = pixel[0];
|
// pixel[1] = pixel[0];
|
||||||
pixel[2] = pixel[0];
|
// pixel[2] = pixel[0];
|
||||||
pixel[3] = 255;
|
// pixel[3] = 255;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn overlay_bitmap(&mut self, other: &Bitmap, xoffset: usize, yoffset: usize) {
|
pub fn overlay_bitmap(&mut self, other: &Bitmap, xoffset: usize, yoffset: usize) {
|
||||||
let length = self.data.len();
|
let length = self.data.len();
|
||||||
@@ -77,320 +72,6 @@ impl ImgBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // use icy_sixel::{
|
|
||||||
// // DiffusionMethod, MethodForLargest, MethodForRep, PixelFormat, Quality, sixel_string,
|
|
||||||
// // };
|
|
||||||
|
|
||||||
// pub struct Bitmap {
|
|
||||||
// pub data: Vec<u8>,
|
|
||||||
// pub width: usize,
|
|
||||||
// pub height: usize,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl Bitmap {
|
|
||||||
// pub fn new(width: usize, height: usize) -> Self {
|
|
||||||
// Self {
|
|
||||||
// data: vec![0; width * height],
|
|
||||||
// width,
|
|
||||||
// height,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn from_data(data: Vec<u8>, width: usize, height: usize) -> Self {
|
|
||||||
// assert!(data.len() == width * height);
|
|
||||||
// Self {
|
|
||||||
// data,
|
|
||||||
// width,
|
|
||||||
// height,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn overlay(&mut self, other: &Bitmap, xoffset: usize, yoffset: usize) {
|
|
||||||
// for y in 0..other.height {
|
|
||||||
// for x in 0..other.width {
|
|
||||||
// self.data[(y + yoffset as usize) * self.width + (x + xoffset as usize)] =
|
|
||||||
// other.data[y * other.width + x];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // /// Prints a 1 byte per pixel greyscale bitmap to Sixel format in console
|
|
||||||
// // pub fn print(&self) {
|
|
||||||
// // let mut bitmap_rgb888 = vec![0; self.width * self.height * 3];
|
|
||||||
|
|
||||||
// // for y in 0..self.height {
|
|
||||||
// // for x in 0..self.width {
|
|
||||||
// // let index = y * self.width + x;
|
|
||||||
|
|
||||||
// // let pixel = self.data[index];
|
|
||||||
|
|
||||||
// // bitmap_rgb888[index * 3] = pixel;
|
|
||||||
// // bitmap_rgb888[index * 3 + 1] = pixel;
|
|
||||||
// // bitmap_rgb888[index * 3 + 2] = pixel;
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // let sixel_data = sixel_string(
|
|
||||||
// // &bitmap_rgb888,
|
|
||||||
// // self.width as i32,
|
|
||||||
// // self.height as i32,
|
|
||||||
// // PixelFormat::RGB888,
|
|
||||||
// // DiffusionMethod::None,
|
|
||||||
// // MethodForLargest::Auto,
|
|
||||||
// // MethodForRep::Auto,
|
|
||||||
// // Quality::AUTO,
|
|
||||||
// // )
|
|
||||||
// // .unwrap();
|
|
||||||
|
|
||||||
// // println!("{}", sixel_data);
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl Bitmap {
|
|
||||||
// /// Sets a pixel value with bounds checking
|
|
||||||
// fn set_pixel(&mut self, x: usize, y: usize, value: u8) {
|
|
||||||
// if x < self.width && y < self.height {
|
|
||||||
// self.data[y * self.width + x] = value;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Gets a pixel value with bounds checking
|
|
||||||
// fn get_pixel(&self, x: usize, y: usize) -> u8 {
|
|
||||||
// if x < self.width && y < self.height {
|
|
||||||
// self.data[y * self.width + x]
|
|
||||||
// } else {
|
|
||||||
// 0
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Draws an antialiased line with arbitrary thickness
|
|
||||||
// pub fn draw_line(
|
|
||||||
// &mut self,
|
|
||||||
// x0: usize,
|
|
||||||
// y0: usize,
|
|
||||||
// x1: usize,
|
|
||||||
// y1: usize,
|
|
||||||
// thickness: f32,
|
|
||||||
// color: u8,
|
|
||||||
// ) {
|
|
||||||
// let x0 = x0 as f32;
|
|
||||||
// let y0 = y0 as f32;
|
|
||||||
// let x1 = x1 as f32;
|
|
||||||
// let y1 = y1 as f32;
|
|
||||||
|
|
||||||
// let dx = x1 - x0;
|
|
||||||
// let dy = y1 - y0;
|
|
||||||
// let length = (dx * dx + dy * dy).sqrt();
|
|
||||||
|
|
||||||
// if length < 0.001 {
|
|
||||||
// // Handle degenerate case of zero-length line
|
|
||||||
// // self.draw_thick_point(x0 as usize, y0 as usize, thickness, color);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Unit vector perpendicular to the line
|
|
||||||
// // let perp_x = -dy / length;
|
|
||||||
// // let perp_y = dx / length;
|
|
||||||
|
|
||||||
// // Half thickness for calculations
|
|
||||||
// let half_thickness = thickness * 0.5;
|
|
||||||
|
|
||||||
// // Calculate bounding box with some padding for antialiasing
|
|
||||||
// let padding = (thickness * 0.5 + 1.0).ceil() as i32;
|
|
||||||
// let min_x = ((x0.min(x1) - padding as f32).floor() as i32).max(0) as usize;
|
|
||||||
// let max_x =
|
|
||||||
// ((x0.max(x1) + padding as f32).ceil() as i32).min(self.width as i32 - 1) as usize;
|
|
||||||
// let min_y = ((y0.min(y1) - padding as f32).floor() as i32).max(0) as usize;
|
|
||||||
// let max_y =
|
|
||||||
// ((y0.max(y1) + padding as f32).ceil() as i32).min(self.height as i32 - 1) as usize;
|
|
||||||
|
|
||||||
// // For each pixel in the bounding box, calculate distance to line
|
|
||||||
// for y in min_y..=max_y {
|
|
||||||
// for x in min_x..=max_x {
|
|
||||||
// let px = x as f32;
|
|
||||||
// let py = y as f32;
|
|
||||||
|
|
||||||
// // Calculate distance from point to line segment
|
|
||||||
// let distance = self.point_to_line_segment_distance(px, py, x0, y0, x1, y1);
|
|
||||||
|
|
||||||
// // Calculate alpha based on distance and thickness
|
|
||||||
// let alpha = self.calculate_alpha(distance, half_thickness);
|
|
||||||
|
|
||||||
// if alpha > 0.0 {
|
|
||||||
// self.blend_pixel(x, y, color, alpha);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Blends a pixel with the existing value using alpha blending
|
|
||||||
// fn blend_pixel(&mut self, x: usize, y: usize, color: u8, alpha: f32) {
|
|
||||||
// if x < self.width && y < self.height {
|
|
||||||
// let existing = self.get_pixel(x, y) as f32;
|
|
||||||
// let new_value = (existing * (1.0 - alpha) + color as f32 * alpha).round() as u8;
|
|
||||||
// self.set_pixel(x, y, new_value);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Calculates the shortest distance from a point to a line segment
|
|
||||||
// fn point_to_line_segment_distance(
|
|
||||||
// &self,
|
|
||||||
// px: f32,
|
|
||||||
// py: f32,
|
|
||||||
// x0: f32,
|
|
||||||
// y0: f32,
|
|
||||||
// x1: f32,
|
|
||||||
// y1: f32,
|
|
||||||
// ) -> f32 {
|
|
||||||
// let dx = x1 - x0;
|
|
||||||
// let dy = y1 - y0;
|
|
||||||
// let length_sq = dx * dx + dy * dy;
|
|
||||||
|
|
||||||
// if length_sq < 0.001 {
|
|
||||||
// // Line segment is actually a point
|
|
||||||
// let dpx = px - x0;
|
|
||||||
// let dpy = py - y0;
|
|
||||||
// return (dpx * dpx + dpy * dpy).sqrt();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Calculate parameter t for the closest point on the line segment
|
|
||||||
// let t = ((px - x0) * dx + (py - y0) * dy) / length_sq;
|
|
||||||
// let t = t.max(0.0).min(1.0); // Clamp to [0, 1] to stay on segment
|
|
||||||
|
|
||||||
// // Find the closest point on the line segment
|
|
||||||
// let closest_x = x0 + t * dx;
|
|
||||||
// let closest_y = y0 + t * dy;
|
|
||||||
|
|
||||||
// // Return distance to closest point
|
|
||||||
// let dpx = px - closest_x;
|
|
||||||
// let dpy = py - closest_y;
|
|
||||||
// (dpx * dpx + dpy * dpy).sqrt()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Calculates alpha value based on distance from line edge
|
|
||||||
// fn calculate_alpha(&self, distance: f32, half_thickness: f32) -> f32 {
|
|
||||||
// if distance <= half_thickness - 0.5 {
|
|
||||||
// // Inside the line core - full opacity
|
|
||||||
// 1.0
|
|
||||||
// } else if distance <= half_thickness + 0.5 {
|
|
||||||
// // In the antialiasing zone - linear falloff
|
|
||||||
// half_thickness + 0.5 - distance
|
|
||||||
// } else {
|
|
||||||
// // Outside the line - transparent
|
|
||||||
// 0.0
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // // Draw a thick line by creating a capsule shape
|
|
||||||
// // fn draw_line(&mut self, x1: usize, y1: usize, x2: usize, y2: usize, width: usize, color: u8) {
|
|
||||||
// // let half_width = width as f32 / 2.0;
|
|
||||||
|
|
||||||
// // // Calculate line vector and length
|
|
||||||
// // let dx = (x2 - x1) as f32;
|
|
||||||
// // let dy = (y2 - y1) as f32;
|
|
||||||
// // let length = (dx * dx + dy * dy).sqrt();
|
|
||||||
|
|
||||||
// // // if length < 0.001 {
|
|
||||||
// // // // Degenerate case: just draw a circle
|
|
||||||
// // // self.draw_circle(x1, y1, half_width as i32, color);
|
|
||||||
// // // return;
|
|
||||||
// // // }
|
|
||||||
|
|
||||||
// // // Normalize the line direction
|
|
||||||
// // let nx = dx / length;
|
|
||||||
// // let ny = dy / length;
|
|
||||||
|
|
||||||
// // // Calculate perpendicular vector for line thickness
|
|
||||||
// // let px = -ny * half_width;
|
|
||||||
// // let py = nx * half_width;
|
|
||||||
|
|
||||||
// // // Get the four corners of the rectangle
|
|
||||||
// // let corner1_x = (x1 as f32 + px) as usize;
|
|
||||||
// // let corner1_y = (y1 as f32 + py) as usize;
|
|
||||||
// // let corner2_x = (x1 as f32 - px) as usize;
|
|
||||||
// // let corner2_y = (y1 as f32 - py) as usize;
|
|
||||||
// // let corner3_x = (x2 as f32 - px) as usize;
|
|
||||||
// // let corner3_y = (y2 as f32 - py) as usize;
|
|
||||||
// // let corner4_x = (x2 as f32 + px) as usize;
|
|
||||||
// // let corner4_y = (y2 as f32 + py) as usize;
|
|
||||||
|
|
||||||
// // // Draw the main rectangle body
|
|
||||||
// // self.fill_quadrilateral(
|
|
||||||
// // corner1_x, corner1_y, corner2_x, corner2_y, corner3_x, corner3_y, corner4_x, corner4_y,
|
|
||||||
// // color,
|
|
||||||
// // );
|
|
||||||
|
|
||||||
// // // // Draw rounded ends
|
|
||||||
// // // let radius = (half_width) as i32;
|
|
||||||
// // // self.draw_circle(x1, y1, radius, color);
|
|
||||||
// // // self.draw_circle(x2, y2, radius, color);
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // fn fill_quadrilateral(
|
|
||||||
// // &mut self,
|
|
||||||
// // x1: usize,
|
|
||||||
// // y1: usize,
|
|
||||||
// // x2: usize,
|
|
||||||
// // y2: usize,
|
|
||||||
// // x3: usize,
|
|
||||||
// // y3: usize,
|
|
||||||
// // x4: usize,
|
|
||||||
// // y4: usize,
|
|
||||||
// // color: u8,
|
|
||||||
// // ) {
|
|
||||||
// // // Find bounding box
|
|
||||||
// // let binding_x = [x1, x2, x3, x4];
|
|
||||||
// // let binding_y = [y1, y2, y3, y4];
|
|
||||||
// // let min_x = binding_x.iter().min().unwrap();
|
|
||||||
// // let max_x = binding_x.iter().max().unwrap();
|
|
||||||
// // let min_y = binding_y.iter().min().unwrap();
|
|
||||||
// // let max_y = binding_y.iter().max().unwrap();
|
|
||||||
|
|
||||||
// // // For each point in bounding box, test if it's inside the quadrilateral
|
|
||||||
// // for y in *min_y..=*max_y {
|
|
||||||
// // for x in *min_x..=*max_x {
|
|
||||||
// // if self.point_in_quad(x, y, x1, y1, x2, y2, x3, y3, x4, y4) {
|
|
||||||
// // self.set_pixel(x, y, color);
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // // Test if a point is inside a quadrilateral using cross products
|
|
||||||
// // fn point_in_quad(
|
|
||||||
// // &self,
|
|
||||||
// // px: usize,
|
|
||||||
// // py: usize,
|
|
||||||
// // x1: usize,
|
|
||||||
// // y1: usize,
|
|
||||||
// // x2: usize,
|
|
||||||
// // y2: usize,
|
|
||||||
// // x3: usize,
|
|
||||||
// // y3: usize,
|
|
||||||
// // x4: usize,
|
|
||||||
// // y4: usize,
|
|
||||||
// // ) -> bool {
|
|
||||||
// // // Test against each edge of the quadrilateral
|
|
||||||
// // let sign1 = self.cross_product(px - x1, py - y1, x2 - x1, y2 - y1);
|
|
||||||
// // let sign2 = self.cross_product(px - x2, py - y2, x3 - x2, y3 - y2);
|
|
||||||
// // let sign3 = self.cross_product(px - x3, py - y3, x4 - x3, y4 - y3);
|
|
||||||
// // let sign4 = self.cross_product(px - x4, py - y4, x1 - x4, y1 - y4);
|
|
||||||
|
|
||||||
// // // Point is inside if all cross products have the same sign
|
|
||||||
// // (sign1 >= 0 && sign2 >= 0 && sign3 >= 0 && sign4 >= 0)
|
|
||||||
// // || (sign1 <= 0 && sign2 <= 0 && sign3 <= 0 && sign4 <= 0)
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // // Calculate 2D cross product
|
|
||||||
// // fn cross_product(&self, ax: usize, ay: usize, bx: usize, by: usize) -> usize {
|
|
||||||
// // ax * by - ay * bx
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // fn set_pixel(&mut self, x: usize, y: usize, color: u8) {
|
|
||||||
// // self.data[y*self.width + x] = color;
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub struct Bitmap {
|
pub struct Bitmap {
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
|
|||||||
@@ -25,29 +25,10 @@ impl ColorRectView {
|
|||||||
constraints: (None, None, None, None),
|
constraints: (None, None, None, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
pub fn set_bounds(&mut self, width: Option<Bounds>, height: Option<Bounds>) {
|
||||||
|
|
||||||
impl View for ColorRectView {
|
|
||||||
fn draw(&mut self, renderer: &mut Renderer, x: f32, y: f32, w: f32, h: f32) {
|
|
||||||
renderer.rect_xywh(x as i32, y as i32, w as i32, h as i32, self.color);
|
|
||||||
// log!("Draw");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LayoutView for ColorRectView {
|
|
||||||
fn set_bounds(&mut self, width: Option<Bounds>, height: Option<Bounds>) {
|
|
||||||
self.bounds = (width, height);
|
self.bounds = (width, height);
|
||||||
}
|
}
|
||||||
fn bounds(&self, _ph: f32, _pw: f32) -> (Bounds, Bounds) {
|
pub fn set_constraints(
|
||||||
(
|
|
||||||
*self.bounds.0.as_ref().unwrap_or(&Bounds::Pixels(100.)),
|
|
||||||
self.bounds.1.unwrap_or(Bounds::Pixels(100.)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConstraintView for ColorRectView {
|
|
||||||
fn set_constraints(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
top: Option<Constraint>,
|
top: Option<Constraint>,
|
||||||
left: Option<Constraint>,
|
left: Option<Constraint>,
|
||||||
@@ -56,7 +37,27 @@ impl ConstraintView for ColorRectView {
|
|||||||
) {
|
) {
|
||||||
self.constraints = (top, left, right, bottom)
|
self.constraints = (top, left, right, bottom)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for ColorRectView {
|
||||||
|
fn draw(&mut self, renderer: &mut Renderer, x: f32, y: f32, w: f32, h: f32) {
|
||||||
|
renderer.rect_xywh(x as i32, y as i32, w as i32, h as i32, self.color);
|
||||||
|
// log!("Draw");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&mut self, x: f32, y: f32, w: f32, h: f32) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayoutView for ColorRectView {
|
||||||
|
fn bounds(&self, _ph: f32, _pw: f32) -> (Bounds, Bounds) {
|
||||||
|
(
|
||||||
|
*self.bounds.0.as_ref().unwrap_or(&Bounds::Pixels(100.)),
|
||||||
|
*self.bounds.1.as_ref().unwrap_or(&Bounds::Pixels(100.)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConstraintView for ColorRectView {
|
||||||
fn get_constraints(
|
fn get_constraints(
|
||||||
&self,
|
&self,
|
||||||
) -> (
|
) -> (
|
||||||
|
|||||||
+42
-133
@@ -1,7 +1,6 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
log,
|
|
||||||
render::Renderer,
|
render::Renderer,
|
||||||
views::{LayoutView, View},
|
views::{LayoutView, View},
|
||||||
};
|
};
|
||||||
@@ -19,13 +18,6 @@ pub enum Constraint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait ConstraintView: LayoutView {
|
pub trait ConstraintView: LayoutView {
|
||||||
fn set_constraints(
|
|
||||||
&mut self,
|
|
||||||
top: Option<Constraint>,
|
|
||||||
left: Option<Constraint>,
|
|
||||||
right: Option<Constraint>,
|
|
||||||
bottom: Option<Constraint>,
|
|
||||||
);
|
|
||||||
fn get_constraints(
|
fn get_constraints(
|
||||||
&self,
|
&self,
|
||||||
) -> (
|
) -> (
|
||||||
@@ -38,7 +30,7 @@ pub trait ConstraintView: LayoutView {
|
|||||||
|
|
||||||
pub struct ConstraintLayout {
|
pub struct ConstraintLayout {
|
||||||
pub children: Vec<Box<dyn ConstraintView>>,
|
pub children: Vec<Box<dyn ConstraintView>>,
|
||||||
child_positions: Option<Vec<Rect>>,
|
child_positions: Option<HashMap<usize, Rect>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Rect {
|
struct Rect {
|
||||||
@@ -63,35 +55,13 @@ impl ConstraintLayout {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let this = ConstraintLayout {
|
ConstraintLayout {
|
||||||
children,
|
children,
|
||||||
child_positions: None,
|
child_positions: None,
|
||||||
};
|
|
||||||
|
|
||||||
this.test();
|
|
||||||
|
|
||||||
this
|
|
||||||
}
|
|
||||||
pub fn test(&self) {
|
|
||||||
let dependencies = self
|
|
||||||
.children
|
|
||||||
.iter()
|
|
||||||
.map(|c| {
|
|
||||||
let constraints = c.get_constraints();
|
|
||||||
[constraints.0, constraints.1, constraints.2, constraints.3]
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let dac = topological_sort(&dependencies);
|
|
||||||
|
|
||||||
for i in 0..dac.len() {
|
|
||||||
log!("{:?}", dac[i])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl View for ConstraintLayout {
|
pub fn recalculate_positions(&mut self, x: f32, y: f32, self_w: f32, self_h: f32) {
|
||||||
fn draw(&mut self, renderer: &mut Renderer, x: f32, y: f32, self_w: f32, self_h: f32) {
|
|
||||||
let self_top = y;
|
let self_top = y;
|
||||||
let self_left = x;
|
let self_left = x;
|
||||||
let self_right = x + self_w;
|
let self_right = x + self_w;
|
||||||
@@ -126,46 +96,40 @@ impl View for ConstraintLayout {
|
|||||||
crate::views::Bounds::Pixels(x) => x,
|
crate::views::Bounds::Pixels(x) => x,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (y, height) = match (c_top, c_bottom) {
|
let y_align = |constraint: &Option<Constraint>| match constraint {
|
||||||
(None, None) => unreachable!("Vertically unconstrained"),
|
Some(Constraint::TopParent(margin)) => Some(self_top + margin),
|
||||||
(Some(Constraint::TopParent(top_margin)), None) => {
|
Some(Constraint::BottomParent(margin)) => Some(self_bottom - margin),
|
||||||
(self_top + top_margin, c_height)
|
Some(Constraint::Top(margin, id)) => {
|
||||||
|
let other = calculated_positions.get(&id).unwrap();
|
||||||
|
Some(other.y - margin)
|
||||||
}
|
}
|
||||||
(Some(Constraint::BottomParent(top_margin)), None) => {
|
|
||||||
(self_top + top_margin + c_height, c_height)
|
Some(Constraint::Bottom(margin, id)) => {
|
||||||
|
let other = calculated_positions.get(&id).unwrap();
|
||||||
|
Some(other.y + other.height + margin)
|
||||||
}
|
}
|
||||||
(None, Some(Constraint::TopParent(top_margin))) => {
|
None => None,
|
||||||
(self_top - top_margin, c_height)
|
_ => unreachable!(),
|
||||||
}
|
|
||||||
(None, Some(Constraint::BottomParent(bottom_margin))) => {
|
|
||||||
(self_h - (bottom_margin + c_height), c_height)
|
|
||||||
}
|
|
||||||
(Some(Constraint::TopParent(_)), Some(Constraint::TopParent(_))) => unreachable!(),
|
|
||||||
(Some(Constraint::BottomParent(_)), Some(Constraint::BottomParent(_))) => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
(Some(Constraint::BottomParent(_)), Some(Constraint::TopParent(_))) => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
(Some(Constraint::TopParent(_)), Some(Constraint::BottomParent(top_margin))) => {
|
|
||||||
(self_top + top_margin + c_height, c_height)
|
|
||||||
}
|
|
||||||
_ => todo!(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(height >= 0.);
|
let y = match (y_align(c_top), y_align(c_bottom)) {
|
||||||
|
(Some(top), Some(bottom)) => (bottom + top - c_height) / 2.,
|
||||||
|
(Some(top), None) => top,
|
||||||
|
(None, Some(bottom)) => bottom - c_height,
|
||||||
|
(None, None) => unreachable!("Vertically unconstrained"),
|
||||||
|
};
|
||||||
|
|
||||||
let x_align = |constraint: &Option<Constraint>| match constraint {
|
let x_align = |constraint: &Option<Constraint>| match constraint {
|
||||||
Some(Constraint::LeftParent(margin)) => Some(self_left + margin),
|
Some(Constraint::LeftParent(margin)) => Some(self_left + margin),
|
||||||
Some(Constraint::RightParent(margin)) => Some(self_right - margin),
|
Some(Constraint::RightParent(margin)) => Some(self_right - margin),
|
||||||
Some(Constraint::Left(margin, id)) => {
|
Some(Constraint::Left(margin, id)) => {
|
||||||
let other = calculated_positions.get(&id).unwrap();
|
let other = calculated_positions.get(&id).unwrap();
|
||||||
Some(other.x - margin - c_width)
|
Some(other.x - margin)
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Constraint::Right(margin, id)) => {
|
Some(Constraint::Right(margin, id)) => {
|
||||||
let other = calculated_positions.get(&id).unwrap();
|
let other = calculated_positions.get(&id).unwrap();
|
||||||
Some(other.x + other.width + margin)
|
Some(other.x + other.width - margin)
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@@ -178,82 +142,33 @@ impl View for ConstraintLayout {
|
|||||||
(None, None) => unreachable!("Horizontally unconstrained"),
|
(None, None) => unreachable!("Horizontally unconstrained"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// let (x, width) = match (c_left, c_right) {
|
|
||||||
// (None, None) => unreachable!("Vertically unconstrained"),
|
|
||||||
// (Some(Constraint::LeftParent(left_margin)), None) => {
|
|
||||||
// (self_top + left_margin, width)
|
|
||||||
// }
|
|
||||||
// (Some(Constraint::RightParent(right_margin)), None) => {
|
|
||||||
// (self_top - right_margin + width, width)
|
|
||||||
// }
|
|
||||||
// (None, Some(Constraint::LeftParent(left_margin))) => {
|
|
||||||
// (self_top - left_margin, width)
|
|
||||||
// }
|
|
||||||
// (None, Some(Constraint::RightParent(right_margin))) => {
|
|
||||||
// (self_w - (right_margin + width), width)
|
|
||||||
// // (self_top + top_margin + height, height)
|
|
||||||
// }
|
|
||||||
// (Some(Constraint::Left(left_margin, n)), None) => {
|
|
||||||
// let other = calculated_positions.get(n).unwrap();
|
|
||||||
// (other.x - (width + left_margin), width)
|
|
||||||
// }
|
|
||||||
// (Some(Constraint::Right(right_margin, idx)), None) => {
|
|
||||||
// (self_top - right_margin + width, width)
|
|
||||||
// }
|
|
||||||
// (None, Some(Constraint::Left(left_margin, idx))) => (self_top - left_margin, width),
|
|
||||||
// (None, Some(Constraint::Right(right_margin, idx))) => {
|
|
||||||
// (self_w - (right_margin + width), width)
|
|
||||||
// // (self_top + top_margin + height, height)
|
|
||||||
// }
|
|
||||||
// (Some(Constraint::LeftParent(_)), Some(Constraint::LeftParent(_))) => {
|
|
||||||
// unreachable!()
|
|
||||||
// }
|
|
||||||
// (Some(Constraint::RightParent(_)), Some(Constraint::RightParent(_))) => {
|
|
||||||
// unreachable!()
|
|
||||||
// }
|
|
||||||
// (Some(Constraint::RightParent(_)), Some(Constraint::LeftParent(_))) => {
|
|
||||||
// unreachable!()
|
|
||||||
// }
|
|
||||||
// (Some(Constraint::TopParent(_)), Some(Constraint::BottomParent(top_margin))) => {
|
|
||||||
// (self_top + top_margin + width, width)
|
|
||||||
// }
|
|
||||||
// _ => todo!(),
|
|
||||||
// };
|
|
||||||
|
|
||||||
assert!(c_width >= 0.);
|
|
||||||
|
|
||||||
calculated_positions.insert(
|
calculated_positions.insert(
|
||||||
idx,
|
idx,
|
||||||
Rect {
|
Rect {
|
||||||
x: x,
|
x: x,
|
||||||
y: y,
|
y: y,
|
||||||
width: c_width,
|
width: c_width,
|
||||||
height: height,
|
height: c_height,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
child.draw(renderer, x, y, c_width, height);
|
|
||||||
|
|
||||||
// match c_top {
|
|
||||||
// None => {}
|
|
||||||
// Some(Constraint::TopParent(top_margin)) => {
|
|
||||||
|
|
||||||
// // let child_top = self_top + top_margin;
|
|
||||||
// // let child_left = self_left;
|
|
||||||
// // let child_right = self_right;
|
|
||||||
// // let child_bottom = child_top + child.get_height();
|
|
||||||
|
|
||||||
// // child.draw(renderer, child_left, child_top, child_right - child_left, child_bottom - child_top);
|
|
||||||
// }
|
|
||||||
// _ => unreachable!(),
|
|
||||||
// }
|
|
||||||
|
|
||||||
// match
|
|
||||||
|
|
||||||
// let child_top = child_top.unwrap_or(self_top);
|
|
||||||
// let child_left = child_left.unwrap_or(self_left);
|
|
||||||
// let child_right = child_right.unwrap_or(self_right);
|
|
||||||
// let child_bottom = child_bottom.unwrap_or(self_bottom);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.child_positions = Some(calculated_positions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for ConstraintLayout {
|
||||||
|
fn draw(&mut self, renderer: &mut Renderer, _x: f32, _y: f32, _self_w: f32, _self_h: f32) {
|
||||||
|
if let Some(child_positions) = &mut self.child_positions {
|
||||||
|
for i in 0..self.children.len() {
|
||||||
|
let rect = child_positions.get(&i).unwrap();
|
||||||
|
self.children[i].draw(renderer, rect.x, rect.y, rect.width, rect.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&mut self, x: f32, y: f32, w: f32, h: f32) {
|
||||||
|
self.recalculate_positions(x, y, w, h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,9 +238,3 @@ fn get_dependency(constraint: &Constraint) -> Option<usize> {
|
|||||||
_ => None, // Parent constraints have no dependencies
|
_ => None, // Parent constraints have no dependencies
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl LayoutView for ConstraintLayout {
|
|
||||||
// fn set_bounds(&mut self, width: Option<Bounds>, height: Option<Bounds>) {
|
|
||||||
// // Implement bounds setting logic here
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
+29
-3
@@ -14,6 +14,7 @@ use vertical_layout::VerticalLayout;
|
|||||||
|
|
||||||
pub trait View {
|
pub trait View {
|
||||||
fn draw(&mut self, renderer: &mut Renderer, x: f32, y: f32, w: f32, h: f32);
|
fn draw(&mut self, renderer: &mut Renderer, x: f32, y: f32, w: f32, h: f32);
|
||||||
|
fn resize(&mut self, x: f32, y: f32, w: f32, h: f32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
@@ -23,7 +24,7 @@ pub enum Bounds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait LayoutView: View {
|
pub trait LayoutView: View {
|
||||||
fn set_bounds(&mut self, width: Option<Bounds>, height: Option<Bounds>);
|
// fn set_bounds(&mut self, width: Option<Bounds>, height: Option<Bounds>);
|
||||||
fn bounds(&self, pw: f32, ph: f32) -> (Bounds, Bounds);
|
fn bounds(&self, pw: f32, ph: f32) -> (Bounds, Bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,9 +40,11 @@ pub fn default_view() -> Box<dyn View> {
|
|||||||
a.set_constraints(
|
a.set_constraints(
|
||||||
Some(Constraint::TopParent(temp_margin)),
|
Some(Constraint::TopParent(temp_margin)),
|
||||||
None,
|
None,
|
||||||
Some(Constraint::Left(temp_margin, 2)),
|
Some(Constraint::Left(temp_margin, 1)),
|
||||||
Some(Constraint::BottomParent(temp_margin)),
|
None,
|
||||||
|
// Some(Constraint::BottomParent(temp_margin)),
|
||||||
);
|
);
|
||||||
|
a.set_bounds(Some(Bounds::Pixels(200.)), Some(Bounds::Pixels(100.)));
|
||||||
|
|
||||||
let mut b = ColorRectView::new(0, 127, 0);
|
let mut b = ColorRectView::new(0, 127, 0);
|
||||||
|
|
||||||
@@ -70,11 +73,34 @@ pub fn default_view() -> Box<dyn View> {
|
|||||||
Some(Constraint::BottomParent(temp_margin)),
|
Some(Constraint::BottomParent(temp_margin)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut center = ColorRectView::new(127, 127, 0);
|
||||||
|
|
||||||
|
center.set_constraints(
|
||||||
|
Some(Constraint::TopParent(temp_margin)),
|
||||||
|
Some(Constraint::LeftParent(temp_margin)),
|
||||||
|
Some(Constraint::RightParent(temp_margin)),
|
||||||
|
Some(Constraint::BottomParent(temp_margin)),
|
||||||
|
);
|
||||||
|
|
||||||
|
center.set_bounds(Some(Bounds::Pixels(350.)), Some(Bounds::Pixels(100.)));
|
||||||
|
|
||||||
|
let mut center_top = ColorRectView::new(127, 0, 127);
|
||||||
|
|
||||||
|
center_top.set_constraints(
|
||||||
|
None,
|
||||||
|
// Some(Constraint::Left(0., 4)),
|
||||||
|
None,
|
||||||
|
Some(Constraint::Right(0., 4)),
|
||||||
|
Some(Constraint::Top(20., 4)),
|
||||||
|
);
|
||||||
|
|
||||||
Box::new(ConstraintLayout::new(vec![
|
Box::new(ConstraintLayout::new(vec![
|
||||||
Box::new(a),
|
Box::new(a),
|
||||||
Box::new(b),
|
Box::new(b),
|
||||||
Box::new(c),
|
Box::new(c),
|
||||||
Box::new(d),
|
Box::new(d),
|
||||||
|
Box::new(center),
|
||||||
|
Box::new(center_top),
|
||||||
]))
|
]))
|
||||||
|
|
||||||
// Box::new(VerticalLayout::new(vec![
|
// Box::new(VerticalLayout::new(vec![
|
||||||
|
|||||||
+7
-14
@@ -39,21 +39,13 @@ impl TextView {
|
|||||||
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
pub fn set_bounds(&mut self, width: Option<Bounds>, height: Option<Bounds>) {
|
||||||
|
self.bounds = (width, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for TextView {
|
impl View for TextView {
|
||||||
fn draw(&mut self, renderer: &mut Renderer, x: f32, y: f32, w: f32, h: f32) {
|
fn draw(&mut self, renderer: &mut Renderer, x: f32, y: f32, w: f32, h: f32) {
|
||||||
// renderer.rasterize_font(
|
|
||||||
// x as i32,
|
|
||||||
// y as i32,
|
|
||||||
// &self.text,
|
|
||||||
// 20.,
|
|
||||||
// FontHandle::AtiksonHyperlegibleRegular,
|
|
||||||
// );
|
|
||||||
// renderer.
|
|
||||||
|
|
||||||
// renderer.rect_xywh(x as i32, y as i32, w as i32, h as i32, self.color);
|
|
||||||
|
|
||||||
let (x, y) = renderer.undistort(x as f32, y as f32);
|
let (x, y) = renderer.undistort(x as f32, y as f32);
|
||||||
|
|
||||||
let (mut width, mut height): (usize, usize) = (0, 0);
|
let (mut width, mut height): (usize, usize) = (0, 0);
|
||||||
@@ -82,12 +74,13 @@ impl View for TextView {
|
|||||||
|
|
||||||
// new_bitmap
|
// new_bitmap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resize(&mut self, x: f32, y: f32, w: f32, h: f32) {
|
||||||
|
// todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutView for TextView {
|
impl LayoutView for TextView {
|
||||||
fn set_bounds(&mut self, width: Option<Bounds>, height: Option<Bounds>) {
|
|
||||||
self.bounds = (width, height);
|
|
||||||
}
|
|
||||||
fn bounds(&self, _ph: f32, _pw: f32) -> (Bounds, Bounds) {
|
fn bounds(&self, _ph: f32, _pw: f32) -> (Bounds, Bounds) {
|
||||||
// let (x, y) = renderer.undistort(x as f32, y as f32);
|
// let (x, y) = renderer.undistort(x as f32, y as f32);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ impl VerticalLayout {
|
|||||||
bounds: (None, None),
|
bounds: (None, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn set_bounds(&mut self, width: Option<Bounds>, height: Option<Bounds>) {
|
||||||
|
self.bounds = (width, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for VerticalLayout {
|
impl View for VerticalLayout {
|
||||||
@@ -38,13 +41,10 @@ impl View for VerticalLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn resize(&mut self, x: f32, y: f32, w: f32, h: f32) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutView for VerticalLayout {
|
impl LayoutView for VerticalLayout {
|
||||||
fn set_bounds(&mut self, width: Option<Bounds>, height: Option<Bounds>) {
|
|
||||||
self.bounds = (width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bounds(&self, pw: f32, ph: f32) -> (Bounds, Bounds) {
|
fn bounds(&self, pw: f32, ph: f32) -> (Bounds, Bounds) {
|
||||||
let (mut maxx, mut totaly): (f32, f32) = (0., 0.);
|
let (mut maxx, mut totaly): (f32, f32) = (0., 0.);
|
||||||
for view in &self.views {
|
for view in &self.views {
|
||||||
|
|||||||
Reference in New Issue
Block a user