mod animation;
mod edit;
mod floating;
mod input;
mod invalidation;
mod keyboard;
mod keyed;
mod layout;
mod lock;
mod menu;
mod popup;
mod region;
mod screencopy;
mod scroll;
mod services;
mod style;
mod text;
mod text_input;
mod timer;
mod transform;
mod window;
use std::cell::Cell;
use std::io;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use crabshell_reactive::Runtime;
use crate::{Cx, NodeView, Output, PanelWindow, Rect, Size, TextSystem, Window};
struct Harness {
runtime: Runtime,
cx: Cx,
text: TextSystem,
}
impl Harness {
fn new() -> Harness {
let runtime = Runtime::current();
Harness {
runtime,
cx: Cx::new(runtime.new_owner()),
text: TextSystem::new(),
}
}
fn panel(&self) -> PanelWindow {
PanelWindow::new(&Output::new("DP-1"))
}
fn window(&mut self, panel: PanelWindow, width: f32, height: f32) -> Window {
let window = Window::new(&self.cx, panel);
window.set_size(Size::new(width, height));
self.frame(&window);
window
}
fn frame(&mut self, window: &Window) {
self.runtime.flush();
if window.needs_layout() {
window.layout(&mut self.text);
}
}
}
fn node_at<'a>(root: NodeView<'a>, path: &[usize]) -> NodeView<'a> {
path.iter().fold(root, |node, &index| {
node
.children()
.nth(index)
.unwrap_or_else(|| panic!("{} has no child {index}", node.path()))
})
}
fn rect_at(window: &Window, path: &[usize]) -> Rect {
node_at(window.view().root(), path).rect()
}
fn paths(window: &Window) -> Vec<String> {
fn walk(node: NodeView<'_>, out: &mut Vec<String>) {
out.push(node.path().to_owned());
for child in node.children() {
walk(child, out);
}
}
let mut out = Vec::new();
walk(window.view().root(), &mut out);
out
}
#[derive(Clone, Default)]
struct Counter(Rc<Cell<u32>>);
impl Counter {
fn hit(&self) {
self.0.set(self.0.get() + 1);
}
fn get(&self) -> u32 {
self.0.get()
}
}
fn capture_logs(f: impl FnOnce()) -> String {
#[derive(Clone, Default)]
struct Buffer(Arc<Mutex<Vec<u8>>>);
impl io::Write for Buffer {
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
self
.0
.lock()
.expect("log buffer lock")
.extend_from_slice(bytes);
Ok(bytes.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
let buffer = Buffer::default();
let writer = buffer.clone();
let subscriber = tracing_subscriber::fmt()
.with_writer(move || writer.clone())
.finish();
tracing::subscriber::with_default(subscriber, f);
let bytes = buffer.0.lock().expect("log buffer lock").clone();
String::from_utf8(bytes).expect("log output is UTF-8")
}