Compare commits

...

4 commits

Author SHA1 Message Date
fa132e2230 rework app logic
Signed-off-by: Frank Villaro-Dixon <frank@villaro-dixon.eu>
2024-05-09 00:17:11 +02:00
ff510a8692 refactor shit
Signed-off-by: Frank Villaro-Dixon <frank@villaro-dixon.eu>
2024-05-09 00:00:45 +02:00
8341b9d54c clippy
Signed-off-by: Frank Villaro-Dixon <frank@villaro-dixon.eu>
2024-05-08 23:21:27 +02:00
65088be75c split into file
Signed-off-by: Frank Villaro-Dixon <frank@villaro-dixon.eu>
2024-05-08 23:20:57 +02:00
6 changed files with 170 additions and 94 deletions

122
src/apps.rs Normal file
View file

@ -0,0 +1,122 @@
pub struct BeoApps {
pub apps: Vec<Box<dyn App>>,
}
struct MainMenu {
pub last_id: usize,
pub default_id: usize,
pub names: Vec<String>,
}
pub struct AppBase {
name: String,
pub main_menu: MainMenu,
}
impl AppBase {
pub fn name(&self) -> &str {
&self.name
}
}
pub trait App {
fn base(&self) -> &AppBase;
// fn main_menu(&self) -> &MainMenu;
}
struct Spotify {
base: AppBase,
}
impl Spotify {
fn new() -> Self {
Spotify {
base: AppBase {
name: "Spotify".to_string(),
main_menu: MainMenu {
last_id: 0,
default_id: 0,
names: vec![
"Playlists".to_string(),
"Artists".to_string(),
"Albums".to_string(),
],
},
},
}
}
}
impl App for Spotify {
fn base(&self) -> &AppBase {
&self.base
}
}
// Similar implementations for other apps like Radio and Settings
struct Radio {
base: AppBase,
}
impl Radio {
fn new() -> Self {
Radio {
base: AppBase {
name: "Radio".to_string(),
main_menu: MainMenu {
last_id: 0,
default_id: 0,
names: vec![
"Favorites".to_string(),
"Local".to_string(),
"Global".to_string(),
],
},
},
}
}
}
impl App for Radio {
fn base(&self) -> &AppBase {
&self.base
}
}
struct Settings {
base: AppBase,
}
impl Settings {
fn new() -> Self {
Settings {
base: AppBase {
name: "Settings".to_string(),
main_menu: MainMenu {
last_id: 0,
default_id: 0,
names: vec![
"Display".to_string(),
"Sound".to_string(),
"Network".to_string(),
],
},
},
}
}
}
impl App for Settings {
fn base(&self) -> &AppBase {
&self.base
}
}
pub fn get_beo_apps() -> BeoApps {
let apps: Vec<Box<dyn App>> = vec![
Box::new(Spotify::new()),
Box::new(Radio::new()),
Box::new(Settings::new()),
];
BeoApps { apps }
}

View file

@ -21,11 +21,7 @@ use winit::{event_loop::EventLoop, window::WindowBuilder};
mod perf_graph;
pub use perf_graph::PerfGraph;
pub fn start(
width: u32,
height: u32,
title: &'static str,
) {
pub fn start(width: u32, height: u32, title: &'static str) {
// This provides better error messages in debug mode.
// It's disabled in release mode so it doesn't bloat up the file size.
#[cfg(all(debug_assertions, target_arch = "wasm32"))]
@ -114,12 +110,5 @@ pub fn start(
(canvas, window, gl_context, surface)
};
run(
canvas,
event_loop,
context,
surface,
window,
);
run(canvas, event_loop, context, surface, window);
}

View file

@ -1,16 +1,12 @@
use core::panic;
use nix::{
fcntl::{FcntlArg, OFlag},
sys::epoll,
};
use std::{
collections::VecDeque,
io,
os::fd::{AsRawFd, FromRawFd, OwnedFd},
};
use evdev;
const LASER_POINTER_MAX: i32 = 121;
#[derive(Debug)]
pub enum Beo5Event {
@ -93,7 +89,7 @@ impl Beo5Device {
}
}
Err(x) => {
if (x.kind() == std::io::ErrorKind::WouldBlock) {
if x.kind() == std::io::ErrorKind::WouldBlock {
// Wait forever for bytes available on raw_fd
let mut events = [epoll::EpollEvent::empty(); 2];
epoll::epoll_wait(8, &mut events, -1);
@ -107,7 +103,7 @@ impl Beo5Device {
if ev.is_some() {
return Beo5Device::parse_event(ev.unwrap());
}
return None;
None
}
fn parse_event(ev: evdev::InputEvent) -> Option<Beo5Event> {
@ -177,6 +173,6 @@ impl Beo5Device {
}
_ => {} //SYN et al
}
return None;
None
}
}

View file

@ -1,6 +1,6 @@
use apps::get_beo_apps;
use femtovg::{
renderer::OpenGl, Align, Baseline, Canvas, Color, FontId, ImageFlags, ImageId, Paint, Path,
Renderer,
renderer::OpenGl, Align, Baseline, Canvas, Color, FontId, ImageId, Paint, Path, Renderer,
};
use instant::Instant;
use resource::resource;
@ -24,6 +24,7 @@ fn main() {
use glutin::prelude::*;
mod apps;
mod hid;
mod roundy_math;
mod ui;
@ -49,10 +50,8 @@ fn run(
.expect("Cannot add font"),
};
let mut beo = ui::Beo::new();
for app in &beo.apps {
println!(">> {}", app.name());
}
let apps = get_beo_apps();
let mut beo = ui::BeoUi::new(apps);
let start = Instant::now();
let mut prevt = start;
@ -74,7 +73,7 @@ fn run(
let mut t = 0;
el.run(move |event, _, control_flow| {
t = t + 1;
t += 1;
*control_flow = ControlFlow::Poll;
let hw_event = beo_device.get_event_nonblocking();

View file

@ -55,7 +55,7 @@ impl VirtualCircle {
pub fn get_x_on_circle(&self, y: f32) -> f32 {
// Given an x coordinate, return the y coordinate so that it lies on the circle
let x = self.center.x - (self.radius.powf(2.) - (y - self.center.y).powf(2.)).sqrt();
x as f32
self.center.x - (self.radius.powf(2.) - (y - self.center.y).powf(2.)).sqrt()
}
}

100
src/ui.rs
View file

@ -2,10 +2,12 @@ use femtovg::{Align, Baseline, Canvas, Color, Paint, Path, Renderer};
use crate::{hid::Beo5Event, Fonts};
use crate::apps::{App, BeoApps};
use crate::roundy_math;
pub struct Beo {
pub apps: Vec<Box<dyn App>>,
pub struct BeoUi {
pub beo_apps: BeoApps,
pub current_app_id: Option<usize>,
pub laser_pct: f32,
}
@ -19,10 +21,11 @@ fn laser_pct_to_y_pos(pct: f32) -> f32 {
(pct * 1.5 - 0.25) * CANVAS_HEIGHT
}
impl Beo {
pub fn new() -> Beo {
Beo {
apps: get_apps(),
impl BeoUi {
pub fn new(apps: BeoApps) -> BeoUi {
BeoUi {
beo_apps: apps,
current_app_id: None,
laser_pct: 0.0,
}
}
@ -31,7 +34,7 @@ impl Beo {
match event {
Beo5Event::LaserPosition(pct) => {
self.laser_pct = pct;
println!("Laser moved to {}%", pct * 100.);
self.choose_app_from_laser_pct();
}
_ => {
// TODO: pass event to current app
@ -41,9 +44,7 @@ impl Beo {
pub fn draw<T: Renderer>(&self, canvas: &mut Canvas<T>, fonts: &Fonts) {
self.draw_main_menu(canvas, fonts);
if let Some(selected_app_id) = self.lasered_application_id() {
let selected_app = self.apps.get(selected_app_id).unwrap();
if let Some(selected_app) = self.current_app() {
let mut paint_title = Paint::color(Color::hex("FFFFFF"));
paint_title.set_font(&[fonts.bold]);
paint_title.set_text_baseline(Baseline::Top);
@ -52,16 +53,17 @@ impl Beo {
let _ = canvas.fill_text(
CANVAS_WIDTH / 2.,
10.,
format!("{}", selected_app.name()),
selected_app.base().name(),
&paint_title,
);
}
}
fn lasered_application_id(&self) -> Option<usize> {
let app_count = self.apps.len();
fn choose_app_from_laser_pct(&mut self) {
let app_count = self.beo_apps.apps.len();
if app_count == 0 {
return None;
self.current_app_id = None;
return;
}
let dx = 100.0 / (app_count as f32 * 2.);
@ -71,10 +73,16 @@ impl Beo {
let evt_app_pos = dx * (i * 2 + 1) as f32 * CANVAS_HEIGHT / 100.0;
let delta = (laser_y - evt_app_pos).abs();
if delta < LASER_EPS_MATCH {
return Some(i);
self.current_app_id = Some(i);
return;
//Some(&self.beo_apps.apps[i]);
}
}
return None;
self.current_app_id = None;
}
fn current_app(&self) -> Option<&Box<dyn App>> {
self.current_app_id.map(|id| &self.beo_apps.apps[id])
}
fn draw_main_menu<T: Renderer>(&self, canvas: &mut Canvas<T>, fonts: &Fonts) {
@ -95,7 +103,7 @@ impl Beo {
y: canvas_height as f32,
};
let apps = &self.apps;
let apps = &self.beo_apps.apps;
// draw the main apps in the circle
let pts = main_menu_circle.get_equidistant_points(apps.len(), canvas_size);
@ -106,22 +114,16 @@ impl Beo {
let mut paint_selected = Paint::color(Color::hex("D7612E"));
paint_selected.set_font(&[fonts.bold]);
paint_selected.set_text_baseline(Baseline::Top);
for i in 0..apps.len() {
if self.lasered_application_id() == Some(i) {
let _ = canvas.fill_text(
pts[i].x as f32,
pts[i].y as f32,
format!("{}", apps[i].name()),
&paint_selected,
);
} else {
let _ = canvas.fill_text(
pts[i].x as f32,
pts[i].y as f32,
format!("{}", apps[i].name()),
&paint_normal,
);
}
let mut i = 0;
for app in apps {
//if self.current_app == Some(app) {
// let _ =
// canvas.fill_text(pts[i].x, pts[i].y, apps[i].base().name(), &paint_selected);
//} else {
let _ = canvas.fill_text(pts[i].x, pts[i].y, app.base().name(), &paint_normal);
// }
i += 1;
}
// draw the laser
@ -134,35 +136,3 @@ impl Beo {
canvas.fill_path(&path, &ellipse_color);
}
}
pub trait App {
fn name(&self) -> &str;
}
struct Spotify;
impl App for Spotify {
fn name(&self) -> &str {
"Spotify"
}
}
struct Radio;
impl App for Radio {
fn name(&self) -> &str {
"Radio"
}
}
struct Settings;
impl App for Settings {
fn name(&self) -> &str {
"Settings"
}
}
fn get_apps() -> Vec<Box<dyn App>> {
vec![
Box::new(Spotify {}),
Box::new(Radio {}),
Box::new(Settings {}),
]
}