Build the core of the application.

This commit is contained in:
Savanni D'Gerinel 2023-11-26 20:57:28 -05:00
parent 0448eb03de
commit a07cfd49a8
6 changed files with 807 additions and 70 deletions

1
Cargo.lock generated
View File

@ -3637,6 +3637,7 @@ dependencies = [
"glib",
"gtk4",
"libadwaita",
"lights-core",
"pango",
]

View File

@ -1,14 +1,72 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
use std::time::Duration;
mod patterns;
pub use patterns::*;
mod types;
pub use types::{DashboardPattern, Pattern, RGB};
pub trait UI {
fn update_lights(&self, dashboard_lights: DashboardPattern, lights: Pattern);
}
#[cfg(test)]
mod tests {
use super::*;
pub trait Animation {
fn tick(&self, frame: Duration) -> (DashboardPattern, Pattern);
}
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
pub struct DefaultAnimation {}
impl Animation for DefaultAnimation {
fn tick(&self, _: Duration) -> (DashboardPattern, Pattern) {
(PRIDE_DASHBOARD, PRIDE)
}
}
#[derive(Clone)]
pub enum Event {
Brake,
BrakeRelease,
LeftBlinker,
LeftBlinkerRelease,
NextPattern,
PreviousPattern,
RightBlinker,
RightBlinkerRelease,
}
#[derive(Clone)]
pub enum State {
Pattern(u8),
Brake,
LeftBlinker,
RightBlinker,
BrakeLeftBlinker,
BrakeRightBlinker,
}
pub struct App {
ui: Box<dyn UI>,
state: State,
current_animation: Box<dyn Animation>,
dashboard_lights: DashboardPattern,
lights: Pattern,
}
impl App {
pub fn new(ui: Box<dyn UI>) -> Self {
Self {
ui,
state: State::Pattern(0),
current_animation: Box::new(DefaultAnimation {}),
dashboard_lights: OFF_DASHBOARD,
lights: OFF,
}
}
pub fn tick(&mut self, frame: Duration) {
let (dashboard, lights) = self.current_animation.tick(frame);
self.dashboard_lights = dashboard.clone();
self.lights = lights.clone();
self.ui.update_lights(dashboard, lights);
}
}

View File

@ -0,0 +1,671 @@
use crate::RGB;
pub type DashboardPattern = [RGB; 3];
pub type Pattern = [RGB; 60];
pub const OFF_DASHBOARD: DashboardPattern = [
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
];
pub const OFF: Pattern = [
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
];
pub const PRIDE_DASHBOARD: DashboardPattern = [
RGB { r: 228, g: 3, b: 3 },
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 115,
g: 41,
b: 130,
},
];
pub const PRIDE: Pattern = [
RGB { r: 228, g: 3, b: 3 },
RGB { r: 228, g: 3, b: 3 },
RGB { r: 228, g: 3, b: 3 },
RGB { r: 228, g: 3, b: 3 },
RGB { r: 228, g: 3, b: 3 },
RGB { r: 228, g: 3, b: 3 },
RGB { r: 228, g: 3, b: 3 },
RGB { r: 228, g: 3, b: 3 },
RGB { r: 228, g: 3, b: 3 },
RGB { r: 228, g: 3, b: 3 },
RGB {
r: 255,
g: 140,
b: 0,
},
RGB {
r: 255,
g: 140,
b: 0,
},
RGB {
r: 255,
g: 140,
b: 0,
},
RGB {
r: 255,
g: 140,
b: 0,
},
RGB {
r: 255,
g: 140,
b: 0,
},
RGB {
r: 255,
g: 140,
b: 0,
},
RGB {
r: 255,
g: 140,
b: 0,
},
RGB {
r: 255,
g: 140,
b: 0,
},
RGB {
r: 255,
g: 140,
b: 0,
},
RGB {
r: 255,
g: 140,
b: 0,
},
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 255,
g: 237,
b: 0,
},
RGB {
r: 0,
g: 128,
b: 38,
},
RGB {
r: 0,
g: 128,
b: 38,
},
RGB {
r: 0,
g: 128,
b: 38,
},
RGB {
r: 0,
g: 128,
b: 38,
},
RGB {
r: 0,
g: 128,
b: 38,
},
RGB {
r: 0,
g: 128,
b: 38,
},
RGB {
r: 0,
g: 128,
b: 38,
},
RGB {
r: 0,
g: 128,
b: 38,
},
RGB {
r: 0,
g: 128,
b: 38,
},
RGB {
r: 0,
g: 128,
b: 38,
},
RGB {
r: 36,
g: 64,
b: 142,
},
RGB {
r: 36,
g: 64,
b: 142,
},
RGB {
r: 36,
g: 64,
b: 142,
},
RGB {
r: 36,
g: 64,
b: 142,
},
RGB {
r: 36,
g: 64,
b: 142,
},
RGB {
r: 36,
g: 64,
b: 142,
},
RGB {
r: 36,
g: 64,
b: 142,
},
RGB {
r: 36,
g: 64,
b: 142,
},
RGB {
r: 36,
g: 64,
b: 142,
},
RGB {
r: 36,
g: 64,
b: 142,
},
RGB {
r: 115,
g: 41,
b: 130,
},
RGB {
r: 115,
g: 41,
b: 130,
},
RGB {
r: 115,
g: 41,
b: 130,
},
RGB {
r: 115,
g: 41,
b: 130,
},
RGB {
r: 115,
g: 41,
b: 130,
},
RGB {
r: 115,
g: 41,
b: 130,
},
RGB {
r: 115,
g: 41,
b: 130,
},
RGB {
r: 115,
g: 41,
b: 130,
},
RGB {
r: 115,
g: 41,
b: 130,
},
RGB {
r: 115,
g: 41,
b: 130,
},
];
pub const TRANS_PRIDE_DASHBOARD: DashboardPattern = [
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 245,
g: 169,
b: 184,
},
];
pub const TRANS_PRIDE: Pattern = [
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 255,
g: 255,
b: 255,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 245,
g: 169,
b: 184,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
RGB {
r: 91,
g: 206,
b: 250,
},
];

View File

@ -0,0 +1,9 @@
#[derive(Clone)]
pub struct RGB {
pub r: u8,
pub g: u8,
pub b: u8,
}
pub type DashboardPattern = [RGB; 3];
pub type Pattern = [RGB; 60];

View File

@ -12,4 +12,5 @@ fixed = { version = "1" }
gio = { version = "0.18" }
glib = { version = "0.18" }
gtk = { version = "0.7", package = "gtk4", features = [ "v4_8" ] }
lights-core = { path = "../core" }
pango = { version = "*" }

View File

@ -1,19 +1,19 @@
use adw::prelude::*;
use glib::Object;
use glib::{Object, Sender};
use gtk::subclass::prelude::*;
use lights_core::{App, DashboardPattern, Pattern, RGB, UI};
use std::{cell::RefCell, env, rc::Rc};
const WIDTH: i32 = 640;
const HEIGHT: i32 = 480;
pub struct RGB {
pub r: u8,
pub g: u8,
pub b: u8,
pub struct Update {
dashboard: DashboardPattern,
lights: Pattern,
}
pub struct DashboardLightsPrivate {
lights: Rc<RefCell<[RGB; 3]>>,
lights: Rc<RefCell<DashboardPattern>>,
}
#[glib::object_subclass]
@ -55,9 +55,9 @@ impl DashboardLights {
let lights = s.imp().lights.borrow();
for i in 0..3 {
context.set_source_rgb(
lights[i].r as f64,
lights[i].g as f64,
lights[i].b as f64,
lights[i].r as f64 / 256.,
lights[i].g as f64 / 256.,
lights[i].b as f64 / 256.,
);
context.rectangle(start + 100. * i as f64, 10., 80., 80.);
let _ = context.fill();
@ -75,7 +75,7 @@ impl DashboardLights {
}
pub struct BikeLightsPrivate {
lights: Rc<RefCell<[RGB; 60]>>,
lights: Rc<RefCell<Pattern>>,
}
#[glib::object_subclass]
@ -173,18 +173,18 @@ impl BikeLights {
let lights = s.imp().lights.borrow();
for i in 0..30 {
context.set_source_rgb(
lights[i].r as f64,
lights[i].g as f64,
lights[i].b as f64,
lights[i].r as f64 / 256.,
lights[i].g as f64 / 256.,
lights[i].b as f64 / 256.,
);
context.rectangle(5. + 20. * i as f64, 5., 15., 15.);
let _ = context.fill();
}
for i in 0..30 {
context.set_source_rgb(
lights[i + 30].r as f64,
lights[i + 30].g as f64,
lights[i + 30].b as f64,
lights[i + 30].r as f64 / 256.,
lights[i + 30].g as f64 / 256.,
lights[i + 30].b as f64 / 256.,
);
context.rectangle(5. + 20. * i as f64, 30., 15., 15.);
let _ = context.fill();
@ -201,14 +201,42 @@ impl BikeLights {
}
}
struct GTKUI {
tx: Rc<RefCell<Option<Sender<Update>>>>,
}
impl UI for GTKUI {
fn update_lights(&self, dashboard_lights: DashboardPattern, lights: Pattern) {
if let Some(tx) = self.tx.borrow().as_ref() {
tx.send(Update {
dashboard: dashboard_lights,
lights,
})
.unwrap();
}
}
}
fn main() {
let app = adw::Application::builder()
let adw_app = adw::Application::builder()
.application_id("com.luminescent-dreams.bike-light-simulator")
.build();
app.connect_activate(move |app| {
adw_app.connect_activate(move |adw_app| {
let (tx, rx) = gtk::glib::MainContext::channel::<Update>(gtk::glib::Priority::DEFAULT);
std::thread::spawn(move || {
let mut bike_app = App::new(Box::new(GTKUI {
tx: Rc::new(RefCell::new(Some(tx))),
}));
loop {
bike_app.tick(std::time::Duration::from_millis(0));
std::thread::sleep(std::time::Duration::from_millis(100));
}
});
let window = adw::ApplicationWindow::builder()
.application(app)
.application(adw_app)
.default_width(WIDTH)
.default_height(HEIGHT)
.build();
@ -226,47 +254,6 @@ 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 dashboard_lights = dashboard_lights.clone();
move |_| {
dashboard_lights.set_lights([
RGB {
r: 128,
g: 128,
b: 0,
},
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
]);
}
});
brake_button.connect_clicked({
let dashboard_lights = dashboard_lights.clone();
move |_| {
dashboard_lights.set_lights([
RGB { r: 128, g: 0, b: 0 },
RGB { r: 128, g: 0, b: 0 },
RGB { r: 128, g: 0, b: 0 },
]);
}
});
right_button.connect_clicked({
let dashboard_lights = dashboard_lights.clone();
move |_| {
dashboard_lights.set_lights([
RGB { r: 0, g: 0, b: 0 },
RGB { r: 0, g: 0, b: 0 },
RGB {
r: 128,
g: 128,
b: 0,
},
]);
}
});
controls.append(&left_button);
controls.append(&brake_button);
controls.append(&right_button);
@ -286,10 +273,20 @@ fn main() {
layout.append(&dashboard_lights);
layout.append(&bike_lights);
rx.attach(None, {
let dashboard_lights = dashboard_lights.clone();
let bike_lights = bike_lights.clone();
move |Update { dashboard, lights }| {
dashboard_lights.set_lights(dashboard);
bike_lights.set_lights(lights);
glib::ControlFlow::Continue
}
});
window.set_content(Some(&layout));
window.present();
});
let args: Vec<String> = env::args().collect();
ApplicationExtManual::run_with_args(&app, &args);
ApplicationExtManual::run_with_args(&adw_app, &args);
}