Set up a GTK simulator for the bike lights engine
This commit is contained in:
parent
8b53114d0d
commit
0448eb03de
|
@ -165,6 +165,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "az"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
|
@ -960,6 +966,18 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6"
|
||||
|
||||
[[package]]
|
||||
name = "fixed"
|
||||
version = "1.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02c69ce7e7c0f17aa18fdd9d0de39727adb9c6281f2ad12f57cbe54ae6e76e7d"
|
||||
dependencies = [
|
||||
"az",
|
||||
"bytemuck",
|
||||
"half",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.27"
|
||||
|
@ -2155,6 +2173,10 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lights-core"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.8"
|
||||
|
@ -3605,6 +3627,19 @@ version = "0.3.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "simulator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cairo-rs",
|
||||
"fixed",
|
||||
"gio",
|
||||
"glib",
|
||||
"gtk4",
|
||||
"libadwaita",
|
||||
"pango",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.2.3"
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
resolver = "2"
|
||||
members = [
|
||||
"authdb",
|
||||
"bike-lights/core",
|
||||
"bike-lights/simulator",
|
||||
"changeset",
|
||||
"config",
|
||||
"config-derive",
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "lights-core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,14 @@
|
|||
pub fn add(left: usize, right: usize) -> usize {
|
||||
left + right
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "simulator"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
adw = { version = "0.5", package = "libadwaita", features = [ "v1_2" ] }
|
||||
cairo-rs = { version = "0.18" }
|
||||
fixed = { version = "1" }
|
||||
gio = { version = "0.18" }
|
||||
glib = { version = "0.18" }
|
||||
gtk = { version = "0.7", package = "gtk4", features = [ "v4_8" ] }
|
||||
pango = { version = "*" }
|
|
@ -0,0 +1,295 @@
|
|||
use adw::prelude::*;
|
||||
use glib::Object;
|
||||
use gtk::subclass::prelude::*;
|
||||
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 DashboardLightsPrivate {
|
||||
lights: Rc<RefCell<[RGB; 3]>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for DashboardLightsPrivate {
|
||||
const NAME: &'static str = "DashboardLights";
|
||||
type Type = DashboardLights;
|
||||
type ParentType = gtk::DrawingArea;
|
||||
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
lights: Rc::new(RefCell::new([
|
||||
RGB { r: 0, g: 0, b: 0 },
|
||||
RGB { r: 0, g: 0, b: 0 },
|
||||
RGB { r: 0, g: 0, b: 0 },
|
||||
])),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for DashboardLightsPrivate {}
|
||||
impl WidgetImpl for DashboardLightsPrivate {}
|
||||
impl DrawingAreaImpl for DashboardLightsPrivate {}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct DashboardLights(ObjectSubclass<DashboardLightsPrivate>) @extends gtk::DrawingArea, gtk::Widget;
|
||||
}
|
||||
|
||||
impl DashboardLights {
|
||||
pub fn new() -> Self {
|
||||
let s: Self = Object::builder().build();
|
||||
|
||||
s.set_width_request(WIDTH);
|
||||
s.set_height_request(100);
|
||||
|
||||
s.set_draw_func({
|
||||
let s = s.clone();
|
||||
move |_, context, width, _| {
|
||||
let start = width as f64 / 2. - 150.;
|
||||
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,
|
||||
);
|
||||
context.rectangle(start + 100. * i as f64, 10., 80., 80.);
|
||||
let _ = context.fill();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
pub fn set_lights(&self, lights: [RGB; 3]) {
|
||||
*self.imp().lights.borrow_mut() = lights;
|
||||
self.queue_draw();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BikeLightsPrivate {
|
||||
lights: Rc<RefCell<[RGB; 60]>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for BikeLightsPrivate {
|
||||
const NAME: &'static str = "BikeLights";
|
||||
type Type = BikeLights;
|
||||
type ParentType = gtk::DrawingArea;
|
||||
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
lights: Rc::new(RefCell::new([
|
||||
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 },
|
||||
])),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for BikeLightsPrivate {}
|
||||
impl WidgetImpl for BikeLightsPrivate {}
|
||||
impl DrawingAreaImpl for BikeLightsPrivate {}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct BikeLights(ObjectSubclass<BikeLightsPrivate>) @extends gtk::DrawingArea, gtk::Widget;
|
||||
}
|
||||
|
||||
impl BikeLights {
|
||||
pub fn new() -> Self {
|
||||
let s: Self = Object::builder().build();
|
||||
|
||||
s.set_width_request(WIDTH);
|
||||
s.set_height_request(200);
|
||||
|
||||
s.set_draw_func({
|
||||
let s = s.clone();
|
||||
move |_, context, _, _| {
|
||||
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,
|
||||
);
|
||||
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,
|
||||
);
|
||||
context.rectangle(5. + 20. * i as f64, 30., 15., 15.);
|
||||
let _ = context.fill();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
pub fn set_lights(&self, lights: [RGB; 60]) {
|
||||
*self.imp().lights.borrow_mut() = lights;
|
||||
self.queue_draw();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let app = adw::Application::builder()
|
||||
.application_id("com.luminescent-dreams.bike-light-simulator")
|
||||
.build();
|
||||
|
||||
app.connect_activate(move |app| {
|
||||
let window = adw::ApplicationWindow::builder()
|
||||
.application(app)
|
||||
.default_width(WIDTH)
|
||||
.default_height(HEIGHT)
|
||||
.build();
|
||||
let layout = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.build();
|
||||
let controls = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Horizontal)
|
||||
.build();
|
||||
|
||||
let dashboard_lights = DashboardLights::new();
|
||||
let bike_lights = BikeLights::new();
|
||||
|
||||
let left_button = gtk::Button::builder().label("L").build();
|
||||
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);
|
||||
layout.append(&controls);
|
||||
|
||||
let pattern_controls = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Horizontal)
|
||||
.build();
|
||||
|
||||
let previous_pattern = gtk::Button::builder().label("Previous").build();
|
||||
let next_pattern = gtk::Button::builder().label("Next").build();
|
||||
|
||||
pattern_controls.append(&previous_pattern);
|
||||
pattern_controls.append(&next_pattern);
|
||||
layout.append(&pattern_controls);
|
||||
|
||||
layout.append(&dashboard_lights);
|
||||
layout.append(&bike_lights);
|
||||
|
||||
window.set_content(Some(&layout));
|
||||
window.present();
|
||||
});
|
||||
|
||||
let args: Vec<String> = env::args().collect();
|
||||
ApplicationExtManual::run_with_args(&app, &args);
|
||||
}
|
Loading…
Reference in New Issue