An applicaiton and simulator for a bike lighting system #245
|
@ -7,31 +7,30 @@ mod types;
|
|||
pub use types::{DashboardPattern, Pattern, RGB};
|
||||
|
||||
pub trait UI {
|
||||
fn check_event(&self) -> Option<Event>;
|
||||
fn update_lights(&self, dashboard_lights: DashboardPattern, lights: Pattern);
|
||||
}
|
||||
|
||||
pub trait Animation {
|
||||
fn tick(&self, frame: Duration) -> (DashboardPattern, Pattern);
|
||||
fn tick(&self, time: std::time::Instant) -> (DashboardPattern, Pattern);
|
||||
}
|
||||
|
||||
pub struct DefaultAnimation {}
|
||||
|
||||
impl Animation for DefaultAnimation {
|
||||
fn tick(&self, _: Duration) -> (DashboardPattern, Pattern) {
|
||||
fn tick(&self, time: std::time::Instant) -> (DashboardPattern, Pattern) {
|
||||
(PRIDE_DASHBOARD, PRIDE)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Event {
|
||||
Brake,
|
||||
BrakeRelease,
|
||||
LeftBlinker,
|
||||
LeftBlinkerRelease,
|
||||
NextPattern,
|
||||
PreviousPattern,
|
||||
RightBlinker,
|
||||
RightBlinkerRelease,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -63,8 +62,12 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, frame: Duration) {
|
||||
let (dashboard, lights) = self.current_animation.tick(frame);
|
||||
pub fn tick(&mut self, time: std::time::Instant) {
|
||||
match self.ui.check_event() {
|
||||
Some(event) => println!("event received: {:?}", event),
|
||||
None => (),
|
||||
};
|
||||
let (dashboard, lights) = self.current_animation.tick(time);
|
||||
self.dashboard_lights = dashboard.clone();
|
||||
self.lights = lights.clone();
|
||||
self.ui.update_lights(dashboard, lights);
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
use adw::prelude::*;
|
||||
use glib::{Object, Sender};
|
||||
use gtk::subclass::prelude::*;
|
||||
use lights_core::{App, DashboardPattern, Pattern, RGB, UI};
|
||||
use std::{cell::RefCell, env, rc::Rc};
|
||||
use lights_core::{App, DashboardPattern, Event, Pattern, RGB, UI};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
env,
|
||||
rc::Rc,
|
||||
sync::mpsc::{Receiver, TryRecvError},
|
||||
};
|
||||
|
||||
const WIDTH: i32 = 640;
|
||||
const HEIGHT: i32 = 480;
|
||||
|
@ -202,19 +207,27 @@ impl BikeLights {
|
|||
}
|
||||
|
||||
struct GTKUI {
|
||||
tx: Rc<RefCell<Option<Sender<Update>>>>,
|
||||
tx: Sender<Update>,
|
||||
rx: Receiver<Event>,
|
||||
}
|
||||
|
||||
impl UI for GTKUI {
|
||||
fn check_event(&self) -> Option<Event> {
|
||||
match self.rx.try_recv() {
|
||||
Ok(event) => Some(event),
|
||||
Err(TryRecvError::Empty) => None,
|
||||
Err(TryRecvError::Disconnected) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn update_lights(&self, dashboard_lights: DashboardPattern, lights: Pattern) {
|
||||
if let Some(tx) = self.tx.borrow().as_ref() {
|
||||
tx.send(Update {
|
||||
self.tx
|
||||
.send(Update {
|
||||
dashboard: dashboard_lights,
|
||||
lights,
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -223,14 +236,17 @@ fn main() {
|
|||
.build();
|
||||
|
||||
adw_app.connect_activate(move |adw_app| {
|
||||
let (tx, rx) = gtk::glib::MainContext::channel::<Update>(gtk::glib::Priority::DEFAULT);
|
||||
let (update_tx, update_rx) =
|
||||
gtk::glib::MainContext::channel::<Update>(gtk::glib::Priority::DEFAULT);
|
||||
let (event_tx, event_rx) = std::sync::mpsc::channel();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
let mut bike_app = App::new(Box::new(GTKUI {
|
||||
tx: Rc::new(RefCell::new(Some(tx))),
|
||||
tx: update_tx,
|
||||
rx: event_rx,
|
||||
}));
|
||||
loop {
|
||||
bike_app.tick(std::time::Duration::from_millis(0));
|
||||
bike_app.tick(std::time::Instant::now());
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
});
|
||||
|
@ -254,6 +270,27 @@ fn main() {
|
|||
let brake_button = gtk::Button::builder().label("Brakes").build();
|
||||
let right_button = gtk::Button::builder().label("R").build();
|
||||
|
||||
left_button.connect_clicked({
|
||||
let event_tx = event_tx.clone();
|
||||
move |_| {
|
||||
let _ = event_tx.send(Event::LeftBlinker);
|
||||
}
|
||||
});
|
||||
|
||||
brake_button.connect_clicked({
|
||||
let event_tx = event_tx.clone();
|
||||
move |_| {
|
||||
let _ = event_tx.send(Event::Brake);
|
||||
}
|
||||
});
|
||||
|
||||
right_button.connect_clicked({
|
||||
let event_tx = event_tx.clone();
|
||||
move |_| {
|
||||
let _ = event_tx.send(Event::RightBlinker);
|
||||
}
|
||||
});
|
||||
|
||||
controls.append(&left_button);
|
||||
controls.append(&brake_button);
|
||||
controls.append(&right_button);
|
||||
|
@ -273,7 +310,7 @@ fn main() {
|
|||
layout.append(&dashboard_lights);
|
||||
layout.append(&bike_lights);
|
||||
|
||||
rx.attach(None, {
|
||||
update_rx.attach(None, {
|
||||
let dashboard_lights = dashboard_lights.clone();
|
||||
let bike_lights = bike_lights.clone();
|
||||
move |Update { dashboard, lights }| {
|
||||
|
|
Loading…
Reference in New Issue