Skip to content

Commit

Permalink
Fix table fit and add manual system init for test
Browse files Browse the repository at this point in the history
  • Loading branch information
namse committed Oct 22, 2024
1 parent 91ed6e9 commit f37cfda
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 116 deletions.
150 changes: 44 additions & 106 deletions namui/namui-prebuilt/src/table/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;

use namui::*;
use std::collections::HashMap;

Expand Down Expand Up @@ -215,10 +218,12 @@ impl Component for InternalSlice<'_> {
};
units.push(unit);

let need_clip = fit_bounding_box_map.get(&index).is_some();

intermediates.push(Intermediate {
key,
render,
need_clip: true,
need_clip,
table_cell_type: TableCellType::Fit { align },
});
}
Expand Down Expand Up @@ -256,8 +261,10 @@ impl Component for InternalSlice<'_> {
let pixel_sizes = pixel_size_or_ratio_list.iter().map(|(pixel_size, ratio)| {
if let Some(pixel_size) = pixel_size {
*pixel_size
} else if let Some(ratio) = ratio {
(direction_pixel_size - non_ratio_pixel_size_sum) * *ratio / ratio_sum
} else {
(direction_pixel_size - non_ratio_pixel_size_sum) * ratio.unwrap() / ratio_sum
0.px()
}
});

Expand Down Expand Up @@ -294,8 +301,8 @@ impl Component for InternalSlice<'_> {
},
};

let rendering_tree = ctx.ghost_compose(key, |ctx| {
let mut ctx = ctx.translate((xywh.x(), xywh.y()));
ctx.compose_with_key(key, |mut ctx| {
ctx = ctx.translate((xywh.x(), xywh.y()));

if let TableCellType::Fit { align } = table_cell_type {
let bounding_box = fit_bounding_box_map.get(&index);
Expand All @@ -319,31 +326,42 @@ impl Component for InternalSlice<'_> {
ctx = ctx.translate((x, y));
}
}
ctx.compose(|ctx| {
let rendering_tree = ctx.ghost_compose(0, |mut ctx| {
if need_clip {
ctx = ctx.clip(
Path::new().add_rect(Rect::Xywh {
x: px(0.0),
y: px(0.0),
width: xywh.width(),
height: xywh.height(),
}),
ClipOp::Intersect,
);
}
render(direction, xywh.wh(), ctx);
});

if need_clip {
ctx = ctx.clip(
Path::new().add_rect(Rect::Xywh {
x: px(0.0),
y: px(0.0),
width: xywh.width(),
height: xywh.height(),
}),
ClipOp::Intersect,
);
}
render(direction, xywh.wh(), ctx);
});

if let TableCellType::Fit { .. } = table_cell_type {
let bounding_box = namui::bounding_box(&rendering_tree);
set_bounding_box_map.mutate({
move |bounding_box_map| {
bounding_box_map.insert(index, bounding_box);
if let TableCellType::Fit { .. } = table_cell_type {
let is_first_draw = fit_bounding_box_map.get(&index).is_none();
let bounding_box = namui::bounding_box(&rendering_tree);
println!("xywh: {:?}", xywh);
println!("rendering_tree: {:#?}", rendering_tree);
println!("bounding_box: {:?}", bounding_box);
set_bounding_box_map.mutate({
move |bounding_box_map| {
bounding_box_map.insert(index, bounding_box);
}
});

if !is_first_draw {
ctx.add(rendering_tree);
}
} else {
ctx.add(rendering_tree);
}
});
}

ctx.add(rendering_tree);
});

advanced_pixel_size += pixel_size;
}
Expand Down Expand Up @@ -446,83 +464,3 @@ pub fn fit<'a>(
}),
}
}

// #[cfg(test)]
// mod tests {
// use super::*;
// use std::sync::atomic::AtomicBool;

// #[test]
// fn closure_should_give_right_wh() {
// let button_render_called = AtomicBool::new(false);
// let label_render_called = AtomicBool::new(false);
// let body_render_called = AtomicBool::new(false);
// let body_inner_render_called = AtomicBool::new(false);

// let button = calculative(
// |parent_wh| parent_wh.height,
// |wh, ctx| {
// button_render_called.store(true, std::sync::atomic::Ordering::Relaxed);
// assert_eq!(px(20.0), wh.width);
// assert_eq!(px(20.0), wh.height);
// },
// );

// let label = ratio(1, |wh, ctx| {
// label_render_called.store(true, std::sync::atomic::Ordering::Relaxed);
// assert_eq!(px(280.0), wh.width);
// assert_eq!(px(20.0), wh.height);
// });

// let header = fixed(px(20.0), horizontal([("button", button), ("label", label)]));

// let body = ratio(1.0, |wh, ctx| {
// body_render_called.store(true, std::sync::atomic::Ordering::Relaxed);
// assert_eq!(px(300.0), wh.width);
// assert_eq!(px(480.0), wh.height);
// vertical([
// (
// "0",
// ratio(
// 1,
// padding(5.px(), |wh, ctx| {
// body_inner_render_called
// .store(true, std::sync::atomic::Ordering::Relaxed);
// assert_eq!(px(290.0), wh.width);
// assert_eq!(px(470.0), wh.height);
// }),
// ),
// ),
// // Note: RenderingTree is not testable yet, So you cannot test fit well now.
// ("empty", fit(FitAlign::LeftTop, RenderingTree::Empty)),
// ])(wh, ctx)
// });

// let ctx = todo!();

// vertical([header, body])(
// Wh {
// width: px(300.0),
// height: px(500.0),
// },
// ctx,
// );

// assert_eq!(
// true,
// button_render_called.load(std::sync::atomic::Ordering::Relaxed)
// );
// assert_eq!(
// true,
// label_render_called.load(std::sync::atomic::Ordering::Relaxed)
// );
// assert_eq!(
// true,
// body_render_called.load(std::sync::atomic::Ordering::Relaxed)
// );
// assert_eq!(
// true,
// body_inner_render_called.load(std::sync::atomic::Ordering::Relaxed)
// );
// }
// }
188 changes: 188 additions & 0 deletions namui/namui-prebuilt/src/table/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
use super::*;
use crate::simple_rect;
use std::sync::{atomic::AtomicBool, Arc, Mutex};

struct MockSkCalculate;
impl SkCalculate for MockSkCalculate {
fn group_glyph(&self, _font: &Font, _paint: &Paint) -> Arc<dyn GroupGlyph> {
unimplemented!()
}

fn font_metrics(&self, _font: &Font) -> Option<FontMetrics> {
unimplemented!()
}

fn load_typeface(&self, _typeface_name: String, _bytes: Vec<u8>) -> JoinHandle<Result<()>> {
unimplemented!()
}

fn path_contains_xy(&self, _path: &Path, _paint: Option<&Paint>, _xy: Xy<Px>) -> bool {
unimplemented!()
}

fn path_bounding_box(&self, _path: &Path, _paint: Option<&Paint>) -> Option<Rect<Px>> {
unimplemented!()
}

fn load_image_from_raw(&self, _image_info: ImageInfo, _bitmap: &[u8]) -> JoinHandle<Image> {
unimplemented!()
}

fn load_image_from_encoded(&self, _bytes: &[u8]) -> JoinHandle<Image> {
todo!()
}
}

#[tokio::test]
async fn closure_should_give_right_wh() {
namui::system::init_for_test().await.unwrap();
let button_render_called = Arc::new(AtomicBool::new(false));
let label_render_called = Arc::new(AtomicBool::new(false));
let body_render_called = Arc::new(AtomicBool::new(false));
let body_inner_render_called = Arc::new(AtomicBool::new(false));

let mut world = World::init(Instant::now, &MockSkCalculate);

struct Test {
button_render_called: Arc<AtomicBool>,
label_render_called: Arc<AtomicBool>,
body_render_called: Arc<AtomicBool>,
body_inner_render_called: Arc<AtomicBool>,
}

impl Component for Test {
fn render(self, ctx: &RenderCtx) {
let Self {
button_render_called,
label_render_called,
body_render_called,
body_inner_render_called,
} = self;

let button = calculative(
|parent_wh| parent_wh.height,
|wh, _ctx| {
button_render_called.store(true, std::sync::atomic::Ordering::Relaxed);
assert_eq!(px(20.0), wh.width);
assert_eq!(px(20.0), wh.height);
},
);

let label = ratio(1, |wh, _ctx| {
label_render_called.store(true, std::sync::atomic::Ordering::Relaxed);
assert_eq!(px(280.0), wh.width);
assert_eq!(px(20.0), wh.height);
});

let header = fixed(px(20.0), horizontal([("button", button), ("label", label)]));

let body = ratio(1.0, |wh, ctx| {
body_render_called.store(true, std::sync::atomic::Ordering::Relaxed);
assert_eq!(px(300.0), wh.width);
assert_eq!(px(480.0), wh.height);
vertical([
(
"0",
ratio(
1,
padding(5.px(), |wh, _ctx| {
body_inner_render_called
.store(true, std::sync::atomic::Ordering::Relaxed);
assert_eq!(px(290.0), wh.width);
assert_eq!(px(470.0), wh.height);
}),
),
),
// Note: RenderingTree is not testable yet, So you cannot test fit well now.
(
"empty",
fit(FitAlign::LeftTop, |ctx| {
ctx.add(RenderingTree::Empty);
}),
),
])(wh, ctx)
});

ctx.compose(|ctx| {
vertical([header, body])(
Wh {
width: px(300.0),
height: px(500.0),
},
ctx,
);
});
}
}

world.run(Test {
button_render_called: button_render_called.clone(),
label_render_called: label_render_called.clone(),
body_render_called: body_render_called.clone(),
body_inner_render_called: body_inner_render_called.clone(),
});

assert!(button_render_called.load(std::sync::atomic::Ordering::Relaxed));
assert!(label_render_called.load(std::sync::atomic::Ordering::Relaxed));
assert!(body_render_called.load(std::sync::atomic::Ordering::Relaxed));
assert!(body_inner_render_called.load(std::sync::atomic::Ordering::Relaxed));
}

#[tokio::test]
async fn fit_should_work() {
namui::system::init_for_test().await.unwrap();
let a_width = Arc::new(Mutex::new(0.px()));

let mut world = World::init(Instant::now, &MockSkCalculate);

struct Test {
a_width: Arc<Mutex<Px>>,
}

impl Component for Test {
fn render(self, ctx: &RenderCtx) {
let Self { a_width } = self;

let a = ratio(1, |wh, _ctx| {
*a_width.lock().unwrap() = wh.width;
});

let b = fit(FitAlign::LeftTop, |ctx| {
ctx.add(simple_rect(
Wh::new(100.px(), 32.px()),
Color::TRANSPARENT,
0.0.px(),
Color::BLACK,
));
});

ctx.compose(|ctx| {
horizontal([a, b])(
Wh {
width: px(1000.0),
height: px(32.0),
},
ctx,
);
});
}
}

world.run(Test {
a_width: a_width.clone(),
});

assert_eq!(px(1000.0), *a_width.lock().unwrap());

world.run(Test {
a_width: a_width.clone(),
});

assert_eq!(px(900.0), *a_width.lock().unwrap());

world.run(Test {
a_width: a_width.clone(),
});

assert_eq!(px(900.0), *a_width.lock().unwrap());
}
Loading

0 comments on commit f37cfda

Please sign in to comment.