diff --git a/src/main.rs b/src/main.rs index 6dfbac8..81c257f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -206,7 +206,7 @@ fn run( // XXX Why the save/reset/restore ? canvas.save(); canvas.reset(); - perf.render(&mut canvas, 500.0, 5.0); + perf.render(&mut canvas, 1024. - 220., 768. - 60.); canvas.restore(); #[cfg(feature = "debug_inspector")] diff --git a/src/main.rs.gilrs b/src/main.rs.gilrs deleted file mode 100644 index 0418c7d..0000000 --- a/src/main.rs.gilrs +++ /dev/null @@ -1,29 +0,0 @@ -use gilrs::{Gilrs, Button, Event}; - - -fn main() { - -let mut gilrs = Gilrs::new().unwrap(); - -// Iterate over all connected gamepads -for (_id, gamepad) in gilrs.gamepads() { - println!("{} is {:?}", gamepad.name(), gamepad.power_info()); -} - -let mut active_gamepad = None; - -loop { - // Examine new events - while let Some(Event { id, event, time }) = gilrs.next_event() { - println!("{:?} New event from {}: {:?}", time, id, event); - active_gamepad = Some(id); - } - - // You can also use cached gamepad state - if let Some(gamepad) = active_gamepad.map(|id| gilrs.gamepad(id)) { - if gamepad.is_pressed(Button::Start) { - println!("Button South is pressed (XBox - A, PS - X)"); - } - } -} -} \ No newline at end of file diff --git a/src/main.rs.winit b/src/main.rs.winit deleted file mode 100644 index c2f1e05..0000000 --- a/src/main.rs.winit +++ /dev/null @@ -1,118 +0,0 @@ -use std::num::NonZeroU32; - -use femtovg::renderer::OpenGl; -use femtovg::{Canvas, Color, Renderer}; -use glutin::surface::Surface; -use glutin::{context::PossiblyCurrentContext, display::Display}; -use glutin_winit::DisplayBuilder; -use raw_window_handle::HasRawWindowHandle; -use winit::dpi::PhysicalPosition; -use winit::event::{Event, WindowEvent}; -use winit::event_loop::{ControlFlow, EventLoop}; -use winit::window::WindowBuilder; -use winit::{dpi::PhysicalSize, window::Window}; - -use glutin::{ - config::ConfigTemplateBuilder, - context::ContextAttributesBuilder, - display::GetGlDisplay, - prelude::*, - surface::{SurfaceAttributesBuilder, WindowSurface}, -}; - -fn main() { - let event_loop = EventLoop::new(); - let (context, gl_display, window, surface) = create_window(&event_loop); - - let renderer = unsafe { OpenGl::new_from_function_cstr(|s| gl_display.get_proc_address(s) as *const _) } - .expect("Cannot create renderer"); - - let mut canvas = Canvas::new(renderer).expect("Cannot create canvas"); - canvas.set_size(1000, 600, window.scale_factor() as f32); - - let mut mouse_position = PhysicalPosition::new(0., 0.); - - event_loop.run(move |event, _target, control_flow| match event { - Event::WindowEvent { event, .. } => match event { - WindowEvent::CursorMoved { position, .. } => { - mouse_position = position; - window.request_redraw(); - } - WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, - _ => { - println!("{:?}", event) - } - }, - Event::RedrawRequested(_) => { - render(&context, &surface, &window, &mut canvas, mouse_position); - } - _ => { - } - }) -} - -fn create_window(event_loop: &EventLoop<()>) -> (PossiblyCurrentContext, Display, Window, Surface) { - let window_builder = WindowBuilder::new() - .with_inner_size(PhysicalSize::new(1000., 600.)) - .with_title("Femtovg"); - - let template = ConfigTemplateBuilder::new().with_alpha_size(8); - - let display_builder = DisplayBuilder::new().with_window_builder(Some(window_builder)); - - let (window, gl_config) = display_builder - .build(event_loop, template, |mut configs| configs.next().unwrap()) - .unwrap(); - - let window = window.unwrap(); - - let gl_display = gl_config.display(); - - let context_attributes = ContextAttributesBuilder::new().build(Some(window.raw_window_handle())); - - let mut not_current_gl_context = - Some(unsafe { gl_display.create_context(&gl_config, &context_attributes).unwrap() }); - - let attrs = SurfaceAttributesBuilder::::new().build( - window.raw_window_handle(), - NonZeroU32::new(1000).unwrap(), - NonZeroU32::new(600).unwrap(), - ); - - let surface = unsafe { gl_config.display().create_window_surface(&gl_config, &attrs).unwrap() }; - - ( - not_current_gl_context.take().unwrap().make_current(&surface).unwrap(), - gl_display, - window, - surface, - ) -} - -fn render( - context: &PossiblyCurrentContext, - surface: &Surface, - window: &Window, - canvas: &mut Canvas, - square_position: PhysicalPosition, -) { - // Make sure the canvas has the right size: - let size = window.inner_size(); - canvas.set_size(size.width, size.height, window.scale_factor() as f32); - - canvas.clear_rect(0, 0, size.width, size.height, Color::black()); - - // Make smol red rectangle - canvas.clear_rect( - square_position.x as u32, - square_position.y as u32, - 30, - 30, - Color::rgbf(1., 0., 0.), - ); - - // Tell renderer to execute all drawing commands - canvas.flush(); - // Display what we've just rendered - surface.swap_buffers(context).expect("Could not swap buffers"); -} diff --git a/src/ui.rs b/src/ui.rs index ae790bb..d723f54 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,4 +1,4 @@ -use femtovg::{Baseline, Canvas, Color, Paint, Path, Renderer}; +use femtovg::{Align, Baseline, Canvas, Color, Paint, Path, Renderer}; use crate::{hid::Beo5Event, Fonts}; @@ -9,6 +9,16 @@ pub struct Beo { pub laser_pct: f32, } +const CANVAS_HEIGHT: f32 = 768.; +const CANVAS_WIDTH: f32 = 1024.; +const LASER_EPS_MATCH: f32 = 15.0; +const MAIN_MENU_CIRCLE_RADIUS: f32 = CANVAS_WIDTH - 30.; + +fn laser_pct_to_y_pos(pct: f32) -> f32 { + // This is only y pos in the main menu circle, which we suppose is a const + (pct * 1.5 - 0.25) * CANVAS_HEIGHT +} + impl Beo { pub fn new() -> Beo { Beo { @@ -31,16 +41,40 @@ impl Beo { pub fn draw(&self, canvas: &mut Canvas, 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(); + + let mut paint_title = Paint::color(Color::hex("FFFFFF")); + 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., + format!("{}", selected_app.name()), + &paint_title, + ); + } } - fn lasered_application(&self) -> Option<&Box> { + fn lasered_application_id(&self) -> Option { let app_count = self.apps.len(); if app_count == 0 { return None; } - let app_idx = (self.laser_pct * app_count as f32) as usize; - self.apps.get(app_idx) + let dx = 100.0 / (app_count as f32 * 2.); + let laser_y = laser_pct_to_y_pos(self.laser_pct); + + for i in 0..app_count { + 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); + } + } + return None; } fn draw_main_menu(&self, canvas: &mut Canvas, fonts: &Fonts) { @@ -53,7 +87,7 @@ impl Beo { x: canvas_width as f32, y: canvas_height as f32 / 2.0, }, - radius: canvas_width as f32 - 30.0, + radius: MAIN_MENU_CIRCLE_RADIUS, }; let canvas_size = roundy_math::Point { @@ -64,34 +98,39 @@ impl Beo { let apps = &self.apps; // draw the main apps in the circle let pts = main_menu_circle.get_equidistant_points(apps.len(), canvas_size); + + let mut paint_normal = Paint::color(Color::hex("B7410E")); + paint_normal.set_font(&[fonts.sans]); + paint_normal.set_text_baseline(Baseline::Top); + + 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() { - let mut paint = Paint::color(Color::hex("B7410E")); - paint.set_font(&[fonts.bold]); - paint.set_text_baseline(Baseline::Top); - let _ = canvas.fill_text( - pts[i].x as f32, - pts[i].y as f32, - format!("XX {}", apps[i].name()), - &paint, - ); + 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, + ); + } } // draw the laser - let bg = Paint::linear_gradient( - 10., - canvas_height as f32 * self.laser_pct, - 20., - canvas_height as f32 * self.laser_pct + 20., - Color::rgba(255, 0, 0, 32), - Color::rgba(0, 0, 0, 16), - ); - - let ellipse_color = Paint::color(Color::hex("5C89D1")); + let ellipse_color = Paint::color(Color::hex("5C89D188")); let mut path = Path::new(); - let ey = canvas_height as f32 * self.laser_pct; + let ey = laser_pct_to_y_pos(self.laser_pct); let ex = main_menu_circle.get_x_on_circle(ey); - path.ellipse(ex, ey, 10., 20.); + path.ellipse(ex + 15., ey, 30., 10.); canvas.fill_path(&path, &ellipse_color); } } @@ -113,6 +152,17 @@ impl App for Radio { } } -fn get_apps() -> Vec> { - vec![Box::new(Spotify {}), Box::new(Radio {})] +struct Settings; +impl App for Settings { + fn name(&self) -> &str { + "Settings" + } +} + +fn get_apps() -> Vec> { + vec![ + Box::new(Spotify {}), + Box::new(Radio {}), + Box::new(Settings {}), + ] }