Make Row and Col work

This commit is contained in:
Richard Feldman 2022-02-23 20:36:37 -05:00
parent 90a25efbd8
commit 5b7acf8b4f
No known key found for this signature in database
GPG key ID: 7E4127D1E4241798
4 changed files with 153 additions and 56 deletions

View file

@ -12,4 +12,14 @@ render =
styles = { bgColor: rgba 100 200 250 1, borderColor: rgba 10 20 30 1, borderWidth : 10, textColor : rgba 220 220 250 1 } styles = { bgColor: rgba 100 200 250 1, borderColor: rgba 10 20 30 1, borderWidth : 10, textColor : rgba 220 220 250 1 }
Button (Text "Hello, World!") styles Col
[
Row
[
Button (Text "Corner ") styles,
Button (Text "Top Mid ") { styles & bgColor: rgba 200 200 50 1 },
Button (Text "Top Right ") { styles & bgColor: rgba 50 50 250 1 }
],
Button (Text "Mid Left ") { styles & bgColor: rgba 150 100 200 1 },
Button (Text "Bottom Left") { styles & bgColor: rgba 250 50 50 1 }
]

View file

@ -232,20 +232,17 @@ fn run_event_loop(title: &str, root: RocElem) -> Result<(), Box<dyn Error>> {
// ); // );
// TODO use with_capacity based on some heuristic // TODO use with_capacity based on some heuristic
let mut drawables = Vec::new(); let (_bounds, drawable) = to_drawable(
add_drawable(
&root, &root,
Bounds { Bounds {
width: size.width as f32, width: size.width as f32,
height: size.height as f32, height: size.height as f32,
}, },
&mut drawables,
&mut glyph_brush, &mut glyph_brush,
); );
process_drawables( process_drawable(
drawables, drawable,
&mut staging_belt, &mut staging_belt,
&mut glyph_brush, &mut glyph_brush,
&mut cmd_encoder, &mut cmd_encoder,
@ -416,7 +413,7 @@ pub fn render(title: RocStr, root: RocElem) {
run_event_loop(title.as_str(), root).expect("Error running event loop"); run_event_loop(title.as_str(), root).expect("Error running event loop");
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, Default)]
struct Bounds { struct Bounds {
width: f32, width: f32,
height: f32, height: f32,
@ -424,7 +421,6 @@ struct Bounds {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct Drawable { struct Drawable {
offset: Vector2<f32>,
bounds: Bounds, bounds: Bounds,
content: DrawableContent, content: DrawableContent,
} }
@ -433,18 +429,18 @@ struct Drawable {
enum DrawableContent { enum DrawableContent {
/// This stores an actual Section because an earlier step needs to know the bounds of /// This stores an actual Section because an earlier step needs to know the bounds of
/// the text, and making a Section is a convenient way to compute those bounds. /// the text, and making a Section is a convenient way to compute those bounds.
Text(OwnedSection), Text(OwnedSection, Vector2<f32>),
FillRect { FillRect {
color: RgbaTup, color: RgbaTup,
border_width: f32, border_width: f32,
border_color: RgbaTup, border_color: RgbaTup,
}, },
// Row(Vec<(Vector2<f32>, Drawable)>), Multi(Vec<Drawable>),
// Col(Vec<(Vector2<f32>, Drawable)>), Offset(Vec<(Vector2<f32>, Drawable)>),
} }
fn process_drawables( fn process_drawable(
drawables: Vec<Drawable>, drawable: Drawable,
staging_belt: &mut wgpu::util::StagingBelt, staging_belt: &mut wgpu::util::StagingBelt,
glyph_brush: &mut GlyphBrush<()>, glyph_brush: &mut GlyphBrush<()>,
cmd_encoder: &mut CommandEncoder, cmd_encoder: &mut CommandEncoder,
@ -456,17 +452,13 @@ fn process_drawables(
) { ) {
// TODO iterate through drawables, // TODO iterate through drawables,
// calculating a pos using offset, // calculating a pos using offset,
// calling draw and updating boiunding boxes // calling draw and updating bounding boxes
let pos: Vector2<f32> = (0.0, 0.0).into(); let mut pos: Vector2<f32> = (0.0, 0.0).into();
// Draw these in reverse order, since when traversing the tree, we added them in the
// opposite order from how they should be rendered. (If we didn't reverse here, then
// for example we would draw children and then their parents, which wouldn't go well.)
for drawable in drawables.into_iter().rev() {
draw( draw(
drawable.bounds, drawable.bounds,
drawable.content, drawable.content,
pos + drawable.offset, pos,
staging_belt, staging_belt,
glyph_brush, glyph_brush,
cmd_encoder, cmd_encoder,
@ -477,7 +469,6 @@ fn process_drawables(
texture_size, texture_size,
); );
} }
}
fn draw( fn draw(
bounds: Bounds, bounds: Bounds,
@ -495,8 +486,8 @@ fn draw(
use DrawableContent::*; use DrawableContent::*;
match content { match content {
Text(section) => { Text(section, offset) => {
glyph_brush.queue(section.with_screen_position(pos).to_borrowed()); glyph_brush.queue(section.with_screen_position(pos + offset).to_borrowed());
glyph_brush glyph_brush
.draw_queued( .draw_queued(
@ -536,37 +527,74 @@ fn draw(
load_op, load_op,
); );
} }
Offset(children) => {
for (offset, child) in children.into_iter() {
draw(
child.bounds,
child.content,
pos + offset,
staging_belt,
glyph_brush,
cmd_encoder,
texture_view,
gpu_device,
rect_resources,
load_op,
texture_size,
);
}
}
Multi(children) => {
for child in children.into_iter() {
draw(
child.bounds,
child.content,
pos,
staging_belt,
glyph_brush,
cmd_encoder,
texture_view,
gpu_device,
rect_resources,
load_op,
texture_size,
);
}
}
} }
} }
fn add_drawable( fn to_drawable(
elem: &RocElem, elem: &RocElem,
bounds: Bounds, bounds: Bounds,
drawables: &mut Vec<Drawable>,
glyph_brush: &mut GlyphBrush<()>, glyph_brush: &mut GlyphBrush<()>,
) -> Bounds { ) -> (Bounds, Drawable) {
use RocElemTag::*; use RocElemTag::*;
match elem.tag() { match elem.tag() {
Button => { Button => {
let button = unsafe { &elem.entry().button }; let button = unsafe { &elem.entry().button };
let styles = button.styles; let styles = button.styles;
let child_bounds = add_drawable(&*button.child, bounds, drawables, glyph_brush); let (child_bounds, child_drawable) = to_drawable(&*button.child, bounds, glyph_brush);
drawables.push(Drawable { let button_drawable = Drawable {
bounds: child_bounds, bounds: child_bounds,
offset: (0.0, 0.0).into(),
// TODO let buttons specify this
content: DrawableContent::FillRect { content: DrawableContent::FillRect {
color: styles.bg_color, color: styles.bg_color,
border_width: styles.border_width, border_width: styles.border_width,
border_color: styles.border_color, border_color: styles.border_color,
}, },
}); };
child_bounds let drawable = Drawable {
bounds: child_bounds,
content: DrawableContent::Multi(vec![button_drawable, child_drawable]),
};
(child_bounds, drawable)
} }
Text => { Text => {
// TODO let text color and font settings inherit from parent
let text = unsafe { &elem.entry().text }; let text = unsafe { &elem.entry().text };
let is_centered = true; // TODO don't hardcode this let is_centered = true; // TODO don't hardcode this
let layout = wgpu_glyph::Layout::default().h_align(if is_centered { let layout = wgpu_glyph::Layout::default().h_align(if is_centered {
@ -600,19 +628,70 @@ fn add_drawable(
} }
} }
drawables.push(Drawable { let drawable = Drawable {
bounds: text_bounds, bounds: text_bounds,
offset, content: DrawableContent::Text(section, offset),
content: DrawableContent::Text(section), };
});
text_bounds (text_bounds, drawable)
} }
Row => { Row => {
todo!("Row"); let row = unsafe { &elem.entry().row_or_col };
let mut final_bounds = Bounds::default();
let mut offset: Vector2<f32> = (0.0, 0.0).into();
let mut offset_entries = Vec::with_capacity(row.children.len());
for child in row.children.as_slice().iter() {
let (child_bounds, child_drawable) = to_drawable(&child, bounds, glyph_brush);
offset_entries.push((offset, child_drawable));
// Make sure the final height is enough to fit this child
final_bounds.height = final_bounds.height.max(child_bounds.height);
// Add the child's width to the final width
final_bounds.width = final_bounds.width + child_bounds.width;
// Offset the next child to make sure it appears after this one.
offset.x += child_bounds.width;
}
(
final_bounds,
Drawable {
bounds: final_bounds,
content: DrawableContent::Offset(offset_entries),
},
)
} }
Col => { Col => {
todo!("Col"); let col = unsafe { &elem.entry().row_or_col };
let mut final_bounds = Bounds::default();
let mut offset: Vector2<f32> = (0.0, 0.0).into();
let mut offset_entries = Vec::with_capacity(col.children.len());
for child in col.children.as_slice().iter() {
let (child_bounds, child_drawable) = to_drawable(&child, bounds, glyph_brush);
offset_entries.push((offset, child_drawable));
// Make sure the final width is enough to fit this child
final_bounds.width = final_bounds.width.max(child_bounds.width);
// Add the child's height to the final height
final_bounds.height = final_bounds.height + child_bounds.height;
// Offset the next child to make sure it appears after this one.
offset.y += child_bounds.height;
}
(
final_bounds,
Drawable {
bounds: final_bounds,
content: DrawableContent::Offset(offset_entries),
},
)
} }
} }
} }
@ -622,9 +701,7 @@ fn owned_section_from_str(
bounds: Bounds, bounds: Bounds,
layout: wgpu_glyph::Layout<wgpu_glyph::BuiltInLineBreaker>, layout: wgpu_glyph::Layout<wgpu_glyph::BuiltInLineBreaker>,
) -> OwnedSection { ) -> OwnedSection {
let is_centered = false;
// TODO don't hardcode any of this! // TODO don't hardcode any of this!
let area_bounds: Vector2<f32> = Vector2::new(200.0, 300.0);
let color /*: RgbaTup */ = colors::WHITE; let color /*: RgbaTup */ = colors::WHITE;
let size: f32 = 40.0; let size: f32 = 40.0;

View file

@ -1,8 +1,7 @@
use crate::graphics::colors::RgbaTup; use crate::graphics::colors::RgbaTup;
use crate::graphics::primitives::rect::Rect;
use core::ffi::c_void; use core::ffi::c_void;
use core::mem::{self, ManuallyDrop}; use core::mem::{self, ManuallyDrop};
use roc_std::RocStr; use roc_std::{RocList, RocStr};
use std::ffi::CStr; use std::ffi::CStr;
use std::os::raw::c_char; use std::os::raw::c_char;
@ -86,6 +85,12 @@ pub struct RocButton {
pub styles: ButtonStyles, pub styles: ButtonStyles,
} }
#[repr(C)]
pub struct RocRowOrCol {
pub children: RocList<RocElem>,
pub styles: ButtonStyles,
}
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct ButtonStyles { pub struct ButtonStyles {
@ -99,4 +104,5 @@ pub struct ButtonStyles {
pub union RocElemEntry { pub union RocElemEntry {
pub button: ManuallyDrop<RocButton>, pub button: ManuallyDrop<RocButton>,
pub text: ManuallyDrop<RocStr>, pub text: ManuallyDrop<RocStr>,
pub row_or_col: ManuallyDrop<RocRowOrCol>,
} }

View file

@ -211,6 +211,10 @@ impl<T> RocList<T> {
unsafe { core::slice::from_raw_parts(self.elements, self.length) } unsafe { core::slice::from_raw_parts(self.elements, self.length) }
} }
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { core::slice::from_raw_parts_mut(self.elements, self.length) }
}
/// Copy the contents of the given slice into the end of this list, /// Copy the contents of the given slice into the end of this list,
/// reallocating and resizing as necessary. /// reallocating and resizing as necessary.
pub fn append_slice(&mut self, slice: &[T]) { pub fn append_slice(&mut self, slice: &[T]) {