effing works
Signed-off-by: Frank Villaro-Dixon <frank@villaro-dixon.eu>
This commit is contained in:
parent
fa132e2230
commit
91172deddd
4 changed files with 170 additions and 50 deletions
29
src/apps.rs
29
src/apps.rs
|
@ -2,9 +2,9 @@ pub struct BeoApps {
|
||||||
pub apps: Vec<Box<dyn App>>,
|
pub apps: Vec<Box<dyn App>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MainMenu {
|
pub struct MainMenu {
|
||||||
pub last_id: usize,
|
// Can either be the default, or the current
|
||||||
pub default_id: usize,
|
pub selected_id: usize,
|
||||||
pub names: Vec<String>,
|
pub names: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ impl AppBase {
|
||||||
|
|
||||||
pub trait App {
|
pub trait App {
|
||||||
fn base(&self) -> &AppBase;
|
fn base(&self) -> &AppBase;
|
||||||
|
fn base_mut(&mut self) -> &mut AppBase;
|
||||||
// fn main_menu(&self) -> &MainMenu;
|
// fn main_menu(&self) -> &MainMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,12 +35,15 @@ impl Spotify {
|
||||||
base: AppBase {
|
base: AppBase {
|
||||||
name: "Spotify".to_string(),
|
name: "Spotify".to_string(),
|
||||||
main_menu: MainMenu {
|
main_menu: MainMenu {
|
||||||
last_id: 0,
|
selected_id: 0,
|
||||||
default_id: 0,
|
|
||||||
names: vec![
|
names: vec![
|
||||||
"Playlists".to_string(),
|
"Playlists".to_string(),
|
||||||
"Artists".to_string(),
|
"Artists".to_string(),
|
||||||
"Albums".to_string(),
|
"Albums".to_string(),
|
||||||
|
"Songs".to_string(),
|
||||||
|
"Genres".to_string(),
|
||||||
|
"New Releases".to_string(),
|
||||||
|
"Charts".to_string(),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -51,6 +55,9 @@ impl App for Spotify {
|
||||||
fn base(&self) -> &AppBase {
|
fn base(&self) -> &AppBase {
|
||||||
&self.base
|
&self.base
|
||||||
}
|
}
|
||||||
|
fn base_mut(&mut self) -> &mut AppBase {
|
||||||
|
&mut self.base
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similar implementations for other apps like Radio and Settings
|
// Similar implementations for other apps like Radio and Settings
|
||||||
|
@ -64,8 +71,7 @@ impl Radio {
|
||||||
base: AppBase {
|
base: AppBase {
|
||||||
name: "Radio".to_string(),
|
name: "Radio".to_string(),
|
||||||
main_menu: MainMenu {
|
main_menu: MainMenu {
|
||||||
last_id: 0,
|
selected_id: 0,
|
||||||
default_id: 0,
|
|
||||||
names: vec![
|
names: vec![
|
||||||
"Favorites".to_string(),
|
"Favorites".to_string(),
|
||||||
"Local".to_string(),
|
"Local".to_string(),
|
||||||
|
@ -81,6 +87,9 @@ impl App for Radio {
|
||||||
fn base(&self) -> &AppBase {
|
fn base(&self) -> &AppBase {
|
||||||
&self.base
|
&self.base
|
||||||
}
|
}
|
||||||
|
fn base_mut(&mut self) -> &mut AppBase {
|
||||||
|
&mut self.base
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Settings {
|
struct Settings {
|
||||||
|
@ -93,8 +102,7 @@ impl Settings {
|
||||||
base: AppBase {
|
base: AppBase {
|
||||||
name: "Settings".to_string(),
|
name: "Settings".to_string(),
|
||||||
main_menu: MainMenu {
|
main_menu: MainMenu {
|
||||||
last_id: 0,
|
selected_id: 0,
|
||||||
default_id: 0,
|
|
||||||
names: vec![
|
names: vec![
|
||||||
"Display".to_string(),
|
"Display".to_string(),
|
||||||
"Sound".to_string(),
|
"Sound".to_string(),
|
||||||
|
@ -110,6 +118,9 @@ impl App for Settings {
|
||||||
fn base(&self) -> &AppBase {
|
fn base(&self) -> &AppBase {
|
||||||
&self.base
|
&self.base
|
||||||
}
|
}
|
||||||
|
fn base_mut(&mut self) -> &mut AppBase {
|
||||||
|
&mut self.base
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_beo_apps() -> BeoApps {
|
pub fn get_beo_apps() -> BeoApps {
|
||||||
|
|
20
src/hid.rs
20
src/hid.rs
|
@ -133,23 +133,25 @@ impl Beo5Device {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
evdev::InputEventKind::Switch(switch) => {
|
evdev::InputEventKind::Key(switch) => {
|
||||||
/*
|
|
||||||
match switch {
|
match switch {
|
||||||
evdev::SwitchType::LE=> {
|
evdev::Key::BTN_DPAD_RIGHT => {
|
||||||
if ev.value() == 1 {
|
if ev.value() == 1 {
|
||||||
return Beo5Event::RightButtonPressed;
|
return Some(Beo5Event::RightButtonPressed);
|
||||||
} else {
|
} else {
|
||||||
return Beo5Event::RightButtonReleased;
|
return Some(Beo5Event::RightButtonReleased);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
evdev::Switch::SW_LEFT => {
|
evdev::Key::BTN_DPAD_LEFT => {
|
||||||
if ev.value() == 1 {
|
if ev.value() == 1 {
|
||||||
return Beo5Event::LeftButtonPressed;
|
if ev.value() == 1 {
|
||||||
|
return Some(Beo5Event::LeftButtonPressed);
|
||||||
} else {
|
} else {
|
||||||
return Beo5Event::LeftButtonReleased;
|
return Some(Beo5Event::LeftButtonReleased);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
evdev::Switch::SW_GO => {
|
evdev::Switch::SW_GO => {
|
||||||
if ev.value() == 1 {
|
if ev.value() == 1 {
|
||||||
return Beo5Event::GoButtonPressed;
|
return Beo5Event::GoButtonPressed;
|
||||||
|
@ -164,12 +166,12 @@ impl Beo5Device {
|
||||||
return Beo5Event::PowerButtonReleased;
|
return Beo5Event::PowerButtonReleased;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// Shouldn't be any other switches
|
// Shouldn't be any other switches
|
||||||
_ => {
|
_ => {
|
||||||
panic!("Unknown switch event: {ev:?}")
|
panic!("Unknown switch event: {ev:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
_ => {} //SYN et al
|
_ => {} //SYN et al
|
||||||
}
|
}
|
||||||
|
|
39
src/main.rs
39
src/main.rs
|
@ -13,9 +13,13 @@ use winit::{
|
||||||
mod helpers;
|
mod helpers;
|
||||||
use helpers::PerfGraph;
|
use helpers::PerfGraph;
|
||||||
|
|
||||||
|
// XXX rename to smth else
|
||||||
struct Fonts {
|
struct Fonts {
|
||||||
sans: FontId,
|
sans: FontId,
|
||||||
bold: FontId,
|
bold: FontId,
|
||||||
|
app_title: Paint,
|
||||||
|
app_menu: Paint,
|
||||||
|
app_menu_selected: Paint,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -41,13 +45,36 @@ fn run(
|
||||||
surface: glutin::surface::Surface<glutin::surface::WindowSurface>,
|
surface: glutin::surface::Surface<glutin::surface::WindowSurface>,
|
||||||
window: Window,
|
window: Window,
|
||||||
) {
|
) {
|
||||||
let fonts = Fonts {
|
let font_bold = canvas
|
||||||
sans: canvas
|
|
||||||
.add_font_mem(&resource!("assets/Roboto-Regular.ttf"))
|
|
||||||
.expect("Cannot add font"),
|
|
||||||
bold: canvas
|
|
||||||
.add_font_mem(&resource!("assets/Roboto-Bold.ttf"))
|
.add_font_mem(&resource!("assets/Roboto-Bold.ttf"))
|
||||||
.expect("Cannot add font"),
|
.expect("Cannot add font");
|
||||||
|
let font_sans = canvas
|
||||||
|
.add_font_mem(&resource!("assets/Roboto-Regular.ttf"))
|
||||||
|
.expect("Cannot add font");
|
||||||
|
|
||||||
|
let mut app_title = Paint::color(Color::hex("FFFFFF"));
|
||||||
|
app_title.set_font(&[font_bold]);
|
||||||
|
app_title.set_text_baseline(Baseline::Top);
|
||||||
|
app_title.set_text_align(Align::Center);
|
||||||
|
app_title.set_font_size(20.);
|
||||||
|
|
||||||
|
let mut app_menu = Paint::color(Color::hex("F0F0FF"));
|
||||||
|
app_menu.set_font(&[font_sans]);
|
||||||
|
app_menu.set_text_baseline(Baseline::Top);
|
||||||
|
app_menu.set_text_align(Align::Center);
|
||||||
|
app_menu.set_font_size(14.);
|
||||||
|
let mut app_menu_selected = Paint::color(Color::hex("F0F0FF"));
|
||||||
|
app_menu_selected.set_font(&[font_bold]);
|
||||||
|
app_menu_selected.set_text_baseline(Baseline::Top);
|
||||||
|
app_menu_selected.set_text_align(Align::Center);
|
||||||
|
app_menu_selected.set_font_size(14.);
|
||||||
|
|
||||||
|
let fonts = Fonts {
|
||||||
|
sans: font_sans,
|
||||||
|
bold: font_bold,
|
||||||
|
app_title,
|
||||||
|
app_menu,
|
||||||
|
app_menu_selected,
|
||||||
};
|
};
|
||||||
|
|
||||||
let apps = get_beo_apps();
|
let apps = get_beo_apps();
|
||||||
|
|
130
src/ui.rs
130
src/ui.rs
|
@ -6,9 +6,14 @@ use crate::apps::{App, BeoApps};
|
||||||
use crate::roundy_math;
|
use crate::roundy_math;
|
||||||
|
|
||||||
pub struct BeoUi {
|
pub struct BeoUi {
|
||||||
pub beo_apps: BeoApps,
|
beo_apps: BeoApps,
|
||||||
pub current_app_id: Option<usize>,
|
current_app_id: Option<usize>,
|
||||||
pub laser_pct: f32,
|
|
||||||
|
// Basically the id of the current menu. However it is float, because
|
||||||
|
// it's UI and it will move smoothly on the screen.
|
||||||
|
// XXX for items in menu
|
||||||
|
//displayed_menu_item_id: Option<f32>,
|
||||||
|
laser_pct: f32, // XXX this could be removed as only used when laser moved, could be given to fn directly
|
||||||
}
|
}
|
||||||
|
|
||||||
const CANVAS_HEIGHT: f32 = 768.;
|
const CANVAS_HEIGHT: f32 = 768.;
|
||||||
|
@ -36,6 +41,18 @@ impl BeoUi {
|
||||||
self.laser_pct = pct;
|
self.laser_pct = pct;
|
||||||
self.choose_app_from_laser_pct();
|
self.choose_app_from_laser_pct();
|
||||||
}
|
}
|
||||||
|
Beo5Event::LeftButtonPressed => {
|
||||||
|
println!("Left button pressed");
|
||||||
|
if let Some(selected_app) = self.current_app_mut() {
|
||||||
|
selected_app.base_mut().main_menu.selected_id += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Beo5Event::RightButtonPressed => {
|
||||||
|
println!("Right button pressed");
|
||||||
|
if let Some(selected_app) = self.current_app_mut() {
|
||||||
|
selected_app.base_mut().main_menu.selected_id -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// TODO: pass event to current app
|
// TODO: pass event to current app
|
||||||
}
|
}
|
||||||
|
@ -44,18 +61,9 @@ impl BeoUi {
|
||||||
|
|
||||||
pub fn draw<T: Renderer>(&self, canvas: &mut Canvas<T>, fonts: &Fonts) {
|
pub fn draw<T: Renderer>(&self, canvas: &mut Canvas<T>, fonts: &Fonts) {
|
||||||
self.draw_main_menu(canvas, fonts);
|
self.draw_main_menu(canvas, fonts);
|
||||||
|
|
||||||
if let Some(selected_app) = self.current_app() {
|
if let Some(selected_app) = self.current_app() {
|
||||||
let mut paint_title = Paint::color(Color::hex("FFFFFF"));
|
self.draw_app(canvas, fonts, selected_app);
|
||||||
paint_title.set_font(&[fonts.bold]);
|
|
||||||
paint_title.set_text_baseline(Baseline::Top);
|
|
||||||
paint_title.set_text_align(Align::Center);
|
|
||||||
paint_title.set_font_size(20.);
|
|
||||||
let _ = canvas.fill_text(
|
|
||||||
CANVAS_WIDTH / 2.,
|
|
||||||
10.,
|
|
||||||
selected_app.base().name(),
|
|
||||||
&paint_title,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +83,6 @@ impl BeoUi {
|
||||||
if delta < LASER_EPS_MATCH {
|
if delta < LASER_EPS_MATCH {
|
||||||
self.current_app_id = Some(i);
|
self.current_app_id = Some(i);
|
||||||
return;
|
return;
|
||||||
//Some(&self.beo_apps.apps[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.current_app_id = None;
|
self.current_app_id = None;
|
||||||
|
@ -84,6 +91,9 @@ impl BeoUi {
|
||||||
fn current_app(&self) -> Option<&Box<dyn App>> {
|
fn current_app(&self) -> Option<&Box<dyn App>> {
|
||||||
self.current_app_id.map(|id| &self.beo_apps.apps[id])
|
self.current_app_id.map(|id| &self.beo_apps.apps[id])
|
||||||
}
|
}
|
||||||
|
fn current_app_mut(&mut self) -> Option<&mut Box<dyn App>> {
|
||||||
|
self.current_app_id.map(|id| &mut self.beo_apps.apps[id])
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_main_menu<T: Renderer>(&self, canvas: &mut Canvas<T>, fonts: &Fonts) {
|
fn draw_main_menu<T: Renderer>(&self, canvas: &mut Canvas<T>, fonts: &Fonts) {
|
||||||
let canvas_width = canvas.width();
|
let canvas_width = canvas.width();
|
||||||
|
@ -103,10 +113,11 @@ impl BeoUi {
|
||||||
y: canvas_height as f32,
|
y: canvas_height as f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
let apps = &self.beo_apps.apps;
|
|
||||||
// draw the main apps in the circle
|
// draw the main apps in the circle
|
||||||
|
let apps = &self.beo_apps.apps;
|
||||||
let pts = main_menu_circle.get_equidistant_points(apps.len(), canvas_size);
|
let pts = main_menu_circle.get_equidistant_points(apps.len(), canvas_size);
|
||||||
|
|
||||||
|
// XXX To be taken from global struct
|
||||||
let mut paint_normal = Paint::color(Color::hex("B7410E"));
|
let mut paint_normal = Paint::color(Color::hex("B7410E"));
|
||||||
paint_normal.set_font(&[fonts.sans]);
|
paint_normal.set_font(&[fonts.sans]);
|
||||||
paint_normal.set_text_baseline(Baseline::Top);
|
paint_normal.set_text_baseline(Baseline::Top);
|
||||||
|
@ -115,15 +126,16 @@ impl BeoUi {
|
||||||
paint_selected.set_font(&[fonts.bold]);
|
paint_selected.set_font(&[fonts.bold]);
|
||||||
paint_selected.set_text_baseline(Baseline::Top);
|
paint_selected.set_text_baseline(Baseline::Top);
|
||||||
|
|
||||||
let mut i = 0;
|
for appid in 0..apps.len() {
|
||||||
for app in apps {
|
let paint;
|
||||||
//if self.current_app == Some(app) {
|
if self.current_app_id == Some(appid) {
|
||||||
// let _ =
|
paint = &paint_selected;
|
||||||
// canvas.fill_text(pts[i].x, pts[i].y, apps[i].base().name(), &paint_selected);
|
} else {
|
||||||
//} else {
|
paint = &paint_normal;
|
||||||
let _ = canvas.fill_text(pts[i].x, pts[i].y, app.base().name(), &paint_normal);
|
}
|
||||||
// }
|
|
||||||
i += 1;
|
let app = &apps[appid];
|
||||||
|
let _ = canvas.fill_text(pts[appid].x, pts[appid].y, app.base().name(), paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw the laser
|
// draw the laser
|
||||||
|
@ -135,4 +147,72 @@ impl BeoUi {
|
||||||
path.ellipse(ex + 15., ey, 30., 10.);
|
path.ellipse(ex + 15., ey, 30., 10.);
|
||||||
canvas.fill_path(&path, &ellipse_color);
|
canvas.fill_path(&path, &ellipse_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_app<T: Renderer>(&self, canvas: &mut Canvas<T>, fonts: &Fonts, app: &Box<dyn App>) {
|
||||||
|
/*
|
||||||
|
let biggest_menu_name = app
|
||||||
|
.base()
|
||||||
|
.main_menu
|
||||||
|
.names
|
||||||
|
.iter()
|
||||||
|
.max_by_key(|x| x.len())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let menu_separated_px = biggest_menu_name.len() as f32 * 8.;
|
||||||
|
*/
|
||||||
|
|
||||||
|
let num_menu_elements_before = 1;
|
||||||
|
let num_menu_elements_after = 2;
|
||||||
|
// That means max 1 + >1< + 2 = 4 elements in total
|
||||||
|
// Minimum aronud 3: 0 + >1< + 2
|
||||||
|
|
||||||
|
let current_menu_id = app.base().main_menu.selected_id;
|
||||||
|
let menu_elements = &app.base().main_menu.names;
|
||||||
|
|
||||||
|
// Calculate indices for slices
|
||||||
|
let start_before =
|
||||||
|
(current_menu_id as isize - num_menu_elements_before as isize).max(0) as usize;
|
||||||
|
let end_before = current_menu_id;
|
||||||
|
let start_after = current_menu_id + 1;
|
||||||
|
let end_after =
|
||||||
|
((current_menu_id + 1 + num_menu_elements_after).min(menu_elements.len())) as usize;
|
||||||
|
|
||||||
|
// Safely getting slices using clamping
|
||||||
|
let menu_elems_before = &menu_elements[start_before..end_before];
|
||||||
|
let menu_elem_selected = &menu_elements[current_menu_id];
|
||||||
|
let menu_elems_after = &menu_elements[start_after..end_after];
|
||||||
|
|
||||||
|
//println!("menu_elems_before: {:?}", menu_elems_before);
|
||||||
|
//println!("current_menu: {:?}", menu_elem_selected);
|
||||||
|
//println!("menu_elems_after: {:?}", menu_elems_after);
|
||||||
|
|
||||||
|
let mut toti = 0.;
|
||||||
|
for i in 0..menu_elems_before.len() {
|
||||||
|
let _ = canvas.fill_text(
|
||||||
|
toti * 100. + 50.,
|
||||||
|
CANVAS_HEIGHT - 80.,
|
||||||
|
&menu_elems_before[i],
|
||||||
|
&fonts.app_menu,
|
||||||
|
);
|
||||||
|
toti += 1.;
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = canvas.fill_text(
|
||||||
|
toti * 100. + 50.,
|
||||||
|
CANVAS_HEIGHT - 80.,
|
||||||
|
&menu_elem_selected,
|
||||||
|
&fonts.app_menu_selected,
|
||||||
|
);
|
||||||
|
toti += 1.;
|
||||||
|
|
||||||
|
for i in 0..menu_elems_after.len() {
|
||||||
|
let _ = canvas.fill_text(
|
||||||
|
toti * 100. + 50.,
|
||||||
|
CANVAS_HEIGHT - 80.,
|
||||||
|
&menu_elems_after[i],
|
||||||
|
&fonts.app_menu,
|
||||||
|
);
|
||||||
|
toti += 1.;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue