LoganDark

librecalibrate button example

Jan 11th, 2022
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 6.33 KB | None | 0 0
  1. use std::collections::HashSet;
  2. use std::sync::mpsc;
  3.  
  4. use ab_glyph_rasterizer::Rasterizer;
  5. use allsorts::gsub::{FeatureInfo, Features};
  6. use allsorts::tag;
  7.  
  8. use librecalibrate::draw::{Point, Region};
  9. use librecalibrate::draw::font::{Font, LayoutOptions};
  10. use librecalibrate::draw::shape::Impression;
  11. use librecalibrate::draw::shape::raw::rounded_rect;
  12. use libremarkable::device::CURRENT_DEVICE;
  13. use libremarkable::framebuffer::{FramebufferBase, FramebufferDraw, FramebufferIO, FramebufferRefresh};
  14. use libremarkable::framebuffer::common::{display_temp, dither_mode, DRAWING_QUANT_BIT, mxcfb_rect, waveform_mode};
  15. use libremarkable::framebuffer::common::color::GRAY;
  16. use libremarkable::framebuffer::core::Framebuffer;
  17. use libremarkable::framebuffer::refresh::PartialRefreshMode;
  18. use libremarkable::input::{InputDevice, InputEvent};
  19. use libremarkable::input::ev::EvDevContext;
  20. use libremarkable::input::multitouch::MultitouchEvent;
  21. use libremarkable::input::wacom::{WacomEvent, WacomPen};
  22.  
  23. fn main() {
  24.     // Use /dev/fbo so that the rm2fb client can be swapped out
  25.     let mut fb = Framebuffer::from_path("/dev/fb0" /* CURRENT_DEVICE.get_framebuffer_path() */);
  26.  
  27.     fb.clear();
  28.     fb.full_refresh(
  29.         waveform_mode::WAVEFORM_MODE_DU,
  30.         display_temp::TEMP_USE_REMARKABLE_DRAW,
  31.         dither_mode::EPDC_FLAG_EXP1,
  32.         DRAWING_QUANT_BIT,
  33.         true
  34.     );
  35.  
  36.     let mut font = Font::from_bytes(include_bytes!("Inter-Regular.otf"))
  37.         .expect("couldn't load font");
  38.  
  39.     let options = LayoutOptions {
  40.         features: Features::Custom(vec![
  41.             FeatureInfo {
  42.                 feature_tag: tag!(b"cv11"),
  43.                 alternate: None
  44.             }
  45.         ]),
  46.         ..Default::default()
  47.     };
  48.  
  49.     const TEXT_SIZE: f32 = 32.0; // Pixels per em value
  50.  
  51.     const BUTTON_X_PADDING: f32 = 32.0;
  52.     const BUTTON_Y_PADDING: f32 = 24.0;
  53.     const BUTTON_BORDER_RADIUS: f32 = 6.0;
  54.     const BUTTON_OUTLINE_WIDTH: f32 = 3.0;
  55.  
  56.     let span = font.shape("Tap this button to exit! UwU~", &options)
  57.         .expect("failed to layout button text");
  58.  
  59.     let text_bounds = span.bounding_box(&mut font, TEXT_SIZE);
  60.  
  61.     let button_size = (
  62.         text_bounds.extents.0 + (BUTTON_X_PADDING * 2.0),
  63.         text_bounds.metrics.cap_height + (BUTTON_Y_PADDING * 2.0)
  64.     );
  65.  
  66.     let button_pos = (
  67.         (1404.0 - button_size.0) / 2.0,
  68.         (1872.0 - button_size.1) / 2.0
  69.     );
  70.  
  71.     let text_pos = (
  72.         button_pos.0 + BUTTON_X_PADDING,
  73.         button_pos.1 + BUTTON_Y_PADDING + (text_bounds.metrics.cap_height - TEXT_SIZE)
  74.     );
  75.  
  76.     let ras_min_x = button_pos.0 as usize;
  77.     let ras_min_y = button_pos.1 as usize;
  78.     let ras_max_x = (button_pos.0 + button_size.0).ceil() as usize;
  79.     let ras_max_y = (button_pos.1 + button_size.1).ceil() as usize;
  80.  
  81.     eprintln!("({}, {}) -> ({}, {})", ras_min_x, ras_min_y, ras_max_x, ras_max_y);
  82.  
  83.     let mut ras = Rasterizer::new(ras_max_x - ras_min_x, ras_max_y - ras_min_y);
  84.     let button_region = Region::new(button_pos.0.fract(), button_pos.1.fract(), button_size.0, button_size.1);
  85.  
  86.     let mut draw_btn = |fb: &mut Framebuffer, pressed: bool| {
  87.         ras.clear();
  88.  
  89.         if pressed {
  90.             rounded_rect(&mut ras, button_region, BUTTON_BORDER_RADIUS, Impression::Negative);
  91.         } else {
  92.             rounded_rect(&mut ras, button_region, BUTTON_BORDER_RADIUS, Impression::Positive);
  93.             rounded_rect(&mut ras, button_region.inset(BUTTON_OUTLINE_WIDTH), (BUTTON_BORDER_RADIUS - BUTTON_OUTLINE_WIDTH).max(0.0), Impression::Negative);
  94.         }
  95.  
  96.         span.rasterize_to(&mut ras, &mut font, (text_pos.0 - ras_min_x as f32, text_pos.1 - ras_min_y as f32), TEXT_SIZE);
  97.  
  98.         ras.for_each_pixel_2d(|x, y, a| {
  99.             let color = GRAY((a * 256.0).max(0.0).min(255.999) as u8);
  100.             //let color = if a >= 0.5 { color::BLACK } else { color::WHITE };
  101.  
  102.             fb.write_pixel((x as i32 + ras_min_x as i32, y as i32 + ras_min_y as i32).into(), color);
  103.         });
  104.  
  105.         fb.partial_refresh(
  106.             &mxcfb_rect {
  107.                 left: ras_min_x as _,
  108.                 top: ras_min_y as _,
  109.                 width: (ras_max_x - ras_min_x) as _,
  110.                 height: (ras_max_y - ras_min_y) as _
  111.             },
  112.             PartialRefreshMode::Async,
  113.             waveform_mode::WAVEFORM_MODE_GC16_FAST,
  114.             display_temp::TEMP_USE_REMARKABLE_DRAW,
  115.             dither_mode::EPDC_FLAG_EXP1,
  116.             DRAWING_QUANT_BIT,
  117.             false
  118.         )
  119.     };
  120.  
  121.     draw_btn(&mut fb, false);
  122.  
  123.     let (tx, rx) = mpsc::channel::<InputEvent>();
  124.  
  125.     let mut touch_ctx = EvDevContext::new(InputDevice::Multitouch, tx.clone());
  126.     let mut wacom_ctx = EvDevContext::new(InputDevice::Wacom, tx.clone());
  127.  
  128.     touch_ctx.start();
  129.     wacom_ctx.start();
  130.  
  131.     let mut fingers_on_btn = HashSet::with_capacity(16);
  132.     let mut wacom_on_btn = false;
  133.     let mut wacom_pen_position = (0.0, 0.0);
  134.     let mut button_clicked = false;
  135.  
  136.     let button_region_wacom = button_region.offsetted((ras_min_x as f32, ras_min_y as f32));
  137.     let button_region_touch = button_region_wacom.inset(-24.0);
  138.  
  139.     loop {
  140.         let event = rx.recv()
  141.             .expect("couldn't receive from input channel");
  142.  
  143.         let button_pressed_before = !fingers_on_btn.is_empty() || wacom_on_btn;
  144.  
  145.         match event {
  146.             InputEvent::MultitouchEvent { event } => match event {
  147.                 MultitouchEvent::Press { finger } => {
  148.                     let pos: Point = (finger.pos.x as f32, finger.pos.y as f32);
  149.  
  150.                     if button_region_touch.contains(pos) {
  151.                         fingers_on_btn.insert(finger.tracking_id);
  152.                     }
  153.                 }
  154.  
  155.                 MultitouchEvent::Release { finger } => {
  156.                     let pos: Point = (finger.pos.x as f32, finger.pos.y as f32);
  157.  
  158.                     if fingers_on_btn.remove(&finger.tracking_id) && button_region_touch.contains(pos) {
  159.                         button_clicked = true;
  160.                     }
  161.                 }
  162.  
  163.                 _ => {}
  164.             }
  165.  
  166.             InputEvent::WacomEvent { event } => match event {
  167.                 WacomEvent::Hover { position, .. } |
  168.                 WacomEvent::Draw { position, .. } => {
  169.                     wacom_pen_position = (position.x, position.y);
  170.                 }
  171.  
  172.                 WacomEvent::InstrumentChange { pen, state } => {
  173.                     if pen == WacomPen::Touch {
  174.                         if state {
  175.                             wacom_on_btn = button_region_wacom.contains(wacom_pen_position);
  176.                         } else if std::mem::replace(&mut wacom_on_btn, false) && button_region_wacom.contains(wacom_pen_position) {
  177.                             button_clicked = true;
  178.                         }
  179.                     }
  180.                 }
  181.  
  182.                 _ => {}
  183.             }
  184.  
  185.             _ => {}
  186.         }
  187.  
  188.         let button_pressed_after = !fingers_on_btn.is_empty() || wacom_on_btn;
  189.  
  190.         if button_clicked {
  191.             fb.clear();
  192.             fb.full_refresh(
  193.                 waveform_mode::WAVEFORM_MODE_DU,
  194.                 display_temp::TEMP_USE_REMARKABLE_DRAW,
  195.                 dither_mode::EPDC_FLAG_EXP1,
  196.                 DRAWING_QUANT_BIT,
  197.                 false
  198.             );
  199.  
  200.             break
  201.         } else if button_pressed_after != button_pressed_before {
  202.             draw_btn(&mut fb, button_pressed_after);
  203.         }
  204.     }
  205. }
  206.  
Advertisement
Add Comment
Please, Sign In to add comment