use eframe::egui;
use json::JsonValue;
use std::io::{self, BufRead};
use std::sync::mpsc::{sync_channel, Receiver};
use std::thread;
fn main() -> Result<(), eframe::Error> {
eframe::run_native(
"Grazer",
eframe::NativeOptions {
initial_window_size: Some(egui::vec2(480.0, 360.0)),
..Default::default()
},
Box::new(|_cc| Box::<MyApp>::default()),
)
}
struct MyApp {
address: String,
recv: Option<Receiver<JsonValue>>,
last: JsonValue,
}
impl Default for MyApp {
fn default() -> Self {
Self {
address: "about:grazer".to_owned(),
last: json::parse("[[\"h1\",[],[\"Where would you like to graze today?\"]], [\"p\",[],[\"\"]], [\"p\",[],[\"🌱👩🌿🌾🌿🌷🌸🌱💮🍊🌾🌸🌱🍅🐌🍆🌲🌹🍃🌾🐌🍇🌱🍓🌲💚🌼\"]]]").unwrap(),
recv: None,
}
}
}
impl MyApp {
fn maybe_start(&mut self, ctx: &egui::Context) {
if self.recv.is_none() {
let ctx_clone = ctx.clone();
let (sync_sender, receiver) = sync_channel(2);
self.recv = Some(receiver);
thread::spawn(move || {
for l in io::stdin().lock().lines().map(|l| l.unwrap()) {
//eprintln!("Rust got {}", l);
sync_sender
.send(json::parse(&l).expect("Invalid JSON"))
.expect("Failed to send");
ctx_clone.request_repaint();
}
std::process::exit(0);
});
}
}
fn walk_dom(&mut self, dom: &json::JsonValue, ui: &mut egui::Ui) {
use json::JsonValue::*;
match dom {
Short(s) => {
ui.label(s.as_str().replace("\n", " "));
}
String(s) => {
ui.label(s.as_str().replace("\n", " "));
}
Array(vec) => {
if vec.len() == 3 && vec[0].is_string() {
match vec[0].as_str().unwrap() {
"head" | "script" | "style" | "comment" => {}
"h1" => {
ui.heading(vec[2][0].as_str().expect("text in h1"));
}
"a" => {
if ui.link(vec[2][0].as_str().expect("text in a")).clicked() {
vec[1]["href"].as_str().and_then(|href| {
println!("navigate {}", href);
self.address = href.to_owned();
Some(())
});
}
}
"p" => {
//ui.style_mut().spacing.interact_size.y = 0.0;
ui.horizontal_wrapped(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
for val in vec[2].members() {
self.walk_dom(val, ui)
}
});
}
s => {
for val in vec[2].members() {
self.walk_dom(val, ui)
}
}
}
} else {
for val in vec {
self.walk_dom(val, ui)
}
}
}
_ => panic!("Unexpected {:?}", dom),
};
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
self.maybe_start(ctx);
loop {
match self.recv.as_mut().unwrap().try_recv() {
Ok(line) => self.last = line,
Err(_) => break,
};
}
egui::TopBottomPanel::top("my_panel")
//.frame(egui::containers::Frame::none()
// .inner_margin(egui::style::Margin::same(10.0)))
.show(ctx, |ui| {
ui.horizontal(|ui| {
let address_label = ui.label("🌍");
let response = ui
.text_edit_singleline(&mut self.address)
.labelled_by(address_label.id);
if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
println!("navigate {}", self.address);
}
if ui.button("Graze").clicked() {
println!("navigate {}", self.address);
}
});
});
egui::CentralPanel::default().show(ctx, |ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
self.walk_dom(&self.last.clone(), ui);
});
});
}
}