mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
Make Row and Col work
This commit is contained in:
parent
90a25efbd8
commit
5b7acf8b4f
4 changed files with 153 additions and 56 deletions
|
@ -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 }
|
||||||
|
]
|
||||||
|
|
|
@ -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,27 +452,22 @@ 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
|
draw(
|
||||||
// opposite order from how they should be rendered. (If we didn't reverse here, then
|
drawable.bounds,
|
||||||
// for example we would draw children and then their parents, which wouldn't go well.)
|
drawable.content,
|
||||||
for drawable in drawables.into_iter().rev() {
|
pos,
|
||||||
draw(
|
staging_belt,
|
||||||
drawable.bounds,
|
glyph_brush,
|
||||||
drawable.content,
|
cmd_encoder,
|
||||||
pos + drawable.offset,
|
texture_view,
|
||||||
staging_belt,
|
gpu_device,
|
||||||
glyph_brush,
|
rect_resources,
|
||||||
cmd_encoder,
|
load_op,
|
||||||
texture_view,
|
texture_size,
|
||||||
gpu_device,
|
);
|
||||||
rect_resources,
|
|
||||||
load_op,
|
|
||||||
texture_size,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue