use apps::get_beo_apps; use femtovg::{ renderer::OpenGl, Align, Baseline, Canvas, Color, FontId, ImageId, Paint, Path, Renderer, }; use instant::Instant; use resource::resource; use winit::{ event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::Window, }; mod helpers; use helpers::PerfGraph; // XXX rename to smth else struct Fonts { sans: FontId, bold: FontId, app_title: Paint, app_menu: Paint, app_menu_selected: Paint, } fn main() { helpers::start(1024, 768, "Text demo"); } use glutin::prelude::*; mod apps; mod hid; mod roundy_math; mod ui; enum UiEvent<'e> { WinitEvent(winit::event::Event<'e, ()>), HardwareEvent(evdev::InputEvent), } fn run( mut canvas: Canvas, el: EventLoop<()>, context: glutin::context::PossiblyCurrentContext, surface: glutin::surface::Surface, window: Window, ) { let font_bold = canvas .add_font_mem(&resource!("assets/Roboto-Bold.ttf")) .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 mut beo = ui::BeoUi::new(apps); let start = Instant::now(); let mut prevt = start; let mut perf = PerfGraph::new(); let mut font_size = 18.0; #[cfg(feature = "debug_inspector")] let mut font_texture_to_show: Option = None; let mut beo_device = hid::Beo5Device::new_autodiscover().expect("Couldn't find Beo5 device"); /* loop { let ev = beo_device.get_event_nonblocking(); } */ let mut t = 0; el.run(move |event, _, control_flow| { t += 1; *control_flow = ControlFlow::Poll; let hw_event = beo_device.get_event_nonblocking(); match hw_event { Some(ev) => { println!("HW Event: {:?}", ev); beo.accept_event(ev); } None => {} } match event { Event::LoopDestroyed => *control_flow = ControlFlow::Exit, Event::WindowEvent { ref event, .. } => match event { WindowEvent::Resized(physical_size) => { surface.resize( &context, physical_size.width.try_into().unwrap(), physical_size.height.try_into().unwrap(), ); } WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::KeyboardInput { input: KeyboardInput { virtual_keycode: Some(keycode), state: ElementState::Pressed, .. }, .. } => { if keycode == &VirtualKeyCode::Escape { *control_flow = ControlFlow::Exit; } println!("INput {:?}", keycode); //if *keycode == VirtualKeyCode::W { // y -= 0.1; //} if *keycode == VirtualKeyCode::NumpadAdd || *keycode == VirtualKeyCode::B { println!("Add"); font_size += 1.0; } if *keycode == VirtualKeyCode::NumpadSubtract { println!("DEL"); font_size -= 1.0; } } #[cfg(feature = "debug_inspector")] WindowEvent::MouseInput { device_id: _, state: ElementState::Pressed, .. } => { let len = canvas.debug_inspector_get_font_textures().len(); let next = match font_texture_to_show { None => 0, Some(i) => i + 1, }; font_texture_to_show = if next < len { Some(next) } else { None }; } WindowEvent::MouseWheel { device_id: _, delta: winit::event::MouseScrollDelta::LineDelta(_, y), .. } => { println!("Scroll {:?}", y); font_size += *y / 2.0; font_size = font_size.max(2.0); } _ => { println!("{:?}", event); } }, Event::RedrawRequested(_) => { let dpi_factor = window.scale_factor(); let size = window.inner_size(); canvas.set_size(size.width, size.height, dpi_factor as f32); canvas.clear_rect(0, 0, size.width, size.height, Color::rgbf(0., 0., 0.)); let elapsed = start.elapsed().as_secs_f32(); let now = Instant::now(); let dt = (now - prevt).as_secs_f32(); prevt = now; perf.update(dt); //draw_main_menu(&mut canvas, &fonts, &beo); beo.draw(&mut canvas, &fonts); let mut paint = Paint::color(Color::hex("B7410E")); paint.set_font(&[fonts.bold]); paint.set_text_baseline(Baseline::Top); paint.set_text_align(Align::Right); let _ = canvas.fill_text(size.width as f32 - 10.0, 10.0, format!("{t}"), &paint); /* draw_baselines(&mut canvas, &fonts, 5.0, 50.0, font_size); draw_alignments(&mut canvas, &fonts, 120.0, 200.0, font_size); //draw_paragraph(&mut canvas, &fonts, x, y, font_size, LOREM_TEXT); draw_inc_size(&mut canvas, &fonts, 300.0, 10.0); draw_complex(&mut canvas, 300.0, 340.0, font_size); draw_stroked(&mut canvas, &fonts, size.width as f32 - 200.0, 100.0); draw_gradient_fill(&mut canvas, &fonts, size.width as f32 - 200.0, 180.0); draw_image_fill(&mut canvas, &fonts, size.width as f32 - 200.0, 260.0, image_id, elapsed); let mut paint = Paint::color(Color::hex("B7410E")); paint.set_font(&[fonts.bold]); paint.set_text_baseline(Baseline::Top); paint.set_text_align(Align::Right); let _ = canvas.fill_text( size.width as f32 - 10.0, 10.0, format!("Scroll to increase / decrease font size. Current: {font_size}"), &paint, ); #[cfg(feature = "debug_inspector")] let _ = canvas.fill_text( size.width as f32 - 10.0, 24.0, format!("Click to show font atlas texture. Current: {:?}", font_texture_to_show), paint, ); */ // XXX Why the save/reset/restore ? canvas.save(); canvas.reset(); perf.render(&mut canvas, 1024. - 220., 768. - 60.); canvas.restore(); #[cfg(feature = "debug_inspector")] if let Some(index) = font_texture_to_show { canvas.save(); canvas.reset(); let textures = canvas.debug_inspector_get_font_textures(); if let Some(&id) = textures.get(index) { canvas.debug_inspector_draw_image(id); } canvas.restore(); } canvas.flush(); surface.swap_buffers(&context).unwrap(); } Event::MainEventsCleared => window.request_redraw(), _ => (), } }); } fn draw_baselines( canvas: &mut Canvas, fonts: &Fonts, x: f32, y: f32, font_size: f32, ) { let baselines = [ Baseline::Top, Baseline::Middle, Baseline::Alphabetic, Baseline::Bottom, ]; let mut paint = Paint::color(Color::black()); paint.set_font(&[fonts.sans]); paint.set_font_size(font_size); let base_text = "AbcpKjgF".to_string(); for (i, baseline) in baselines.iter().enumerate() { let y = y + i as f32 * 40.0; let mut path = Path::new(); path.move_to(x, y + 0.5); path.line_to(x + 250., y + 0.5); canvas.stroke_path(&path, &Paint::color(Color::rgba(255, 32, 32, 128))); paint.set_text_baseline(*baseline); if let Ok(res) = canvas.fill_text(x, y, format!("{base_text} Baseline::{baseline:?}"), &paint) { //let res = canvas.fill_text(10.0, y, format!("d النص العربي جميل جدا {:?}", baseline), &paint); let mut path = Path::new(); path.rect(res.x, res.y, res.width(), res.height()); canvas.stroke_path(&path, &Paint::color(Color::rgba(100, 100, 100, 64))); } } } fn draw_alignments( canvas: &mut Canvas, fonts: &Fonts, x: f32, y: f32, font_size: f32, ) { let alignments = [Align::Left, Align::Center, Align::Right]; let mut path = Path::new(); path.move_to(x + 0.5, y - 20.); path.line_to(x + 0.5, y + 80.); canvas.stroke_path(&path, &Paint::color(Color::rgba(255, 32, 32, 128))); let mut paint = Paint::color(Color::black()); paint.set_font(&[fonts.sans]); paint.set_font_size(font_size); for (i, alignment) in alignments.iter().enumerate() { paint.set_text_align(*alignment); if let Ok(res) = canvas.fill_text( x, y + i as f32 * 30.0, format!("Align::{alignment:?}"), &paint, ) { let mut path = Path::new(); path.rect(res.x, res.y, res.width(), res.height()); canvas.stroke_path(&path, &Paint::color(Color::rgba(100, 100, 100, 64))); } } } fn draw_paragraph( canvas: &mut Canvas, fonts: &Fonts, x: f32, y: f32, font_size: f32, text: &str, ) { let mut paint = Paint::color(Color::black()); paint.set_font(&[fonts.bold]); //paint.set_text_align(Align::Right); paint.set_font_size(font_size); let font_metrics = canvas.measure_font(&paint).expect("Error measuring font"); let width = canvas.width() as f32; let mut y = y; let lines = canvas .break_text_vec(width, text, &paint) .expect("Error while breaking text"); for line_range in lines { if let Ok(_res) = canvas.fill_text(x, y, &text[line_range], &paint) { y += font_metrics.height(); } } // let mut start = 0; // while start < text.len() { // let substr = &text[start..]; // if let Ok(index) = canvas.break_text(width, substr, &paint) { // if let Ok(res) = canvas.fill_text(x, y, &substr[0..index], &paint) { // y += res.height; // } // start += &substr[0..index].len(); // } else { // break; // } // } } fn draw_inc_size(canvas: &mut Canvas, fonts: &Fonts, x: f32, y: f32) { let mut cursor_y = y; for i in 4..23 { let mut paint = Paint::color(Color::black()); paint.set_font(&[fonts.sans]); paint.set_font_size(i as f32); let font_metrics = canvas.measure_font(&paint).expect("Error measuring font"); if let Ok(_res) = canvas.fill_text( x, cursor_y, "The quick brown fox jumps over the lazy dog", &paint, ) { cursor_y += font_metrics.height(); } } } fn draw_stroked(canvas: &mut Canvas, fonts: &Fonts, x: f32, y: f32) { let mut paint = Paint::color(Color::rgba(0, 0, 0, 128)); paint.set_font(&[fonts.bold]); paint.set_line_width(12.0); paint.set_font_size(72.0); let _ = canvas.stroke_text(x + 5.0, y + 5.0, "RUST", &paint); paint.set_color(Color::black()); paint.set_line_width(10.0); let _ = canvas.stroke_text(x, y, "RUST", &paint); paint.set_line_width(6.0); paint.set_color(Color::hex("#B7410E")); let _ = canvas.stroke_text(x, y, "RUST", &paint); paint.set_color(Color::white()); let _ = canvas.fill_text(x, y, "RUST", &paint); } fn draw_gradient_fill(canvas: &mut Canvas, fonts: &Fonts, x: f32, y: f32) { let mut paint = Paint::color(Color::rgba(0, 0, 0, 255)); paint.set_font(&[fonts.bold]); paint.set_line_width(6.0); paint.set_font_size(72.0); let _ = canvas.stroke_text(x, y, "RUST", &paint); let mut paint = Paint::linear_gradient( x, y - 60.0, x, y, Color::rgba(225, 133, 82, 255), Color::rgba(93, 55, 70, 255), ); paint.set_font(&[fonts.bold]); paint.set_font_size(72.0); let _ = canvas.fill_text(x, y, "RUST", &paint); } fn draw_image_fill( canvas: &mut Canvas, fonts: &Fonts, x: f32, y: f32, image_id: ImageId, t: f32, ) { let mut paint = Paint::color(Color::hex("#7300AB")); paint.set_line_width(3.0); let mut path = Path::new(); path.move_to(x, y - 2.0); path.line_to(x + 180.0, y - 2.0); canvas.stroke_path(&path, &paint); let text = "RUST"; let mut paint = Paint::color(Color::rgba(0, 0, 0, 128)); paint.set_font(&[fonts.bold]); paint.set_line_width(4.0); paint.set_font_size(72.0); let _ = canvas.stroke_text(x, y, text, &paint); let mut paint = Paint::image(image_id, x, y - t * 10.0, 120.0, 120.0, 0.0, 0.50); //let mut paint = Paint::image(image_id, x + 50.0, y - t*10.0, 120.0, 120.0, t.sin() / 10.0, 0.70); paint.set_font(&[fonts.bold]); paint.set_font_size(72.0); let _ = canvas.fill_text(x, y, text, &paint); } fn draw_complex(canvas: &mut Canvas, x: f32, y: f32, font_size: f32) { let mut paint = Paint::color(Color::rgb(34, 34, 34)); paint.set_font_size(font_size); let _ = canvas.fill_text( x, y, "Latin اللغة العربية Кирилица тест iiiiiiiiiiiiiiiiiiiiiiiiiiiii\nasdasd", &paint, ); //let _ = canvas.fill_text(x, y, "اللغة العربية", &paint); //canvas.fill_text(x, y, "Traditionally, text is composed to create a readable, coherent, and visually satisfying", &paint); }