firmware for my Touchscreen E-Paper Input Module for Framework Laptop 16
0

Configure Feed

Select the types of activity you want to include in your feed.

fw16-epd-gui: add slider element

+171 -27
+10 -10
fw16-epd-gui/src/element/button.rs
··· 22 22 23 23 #[derive(Debug, defmt::Format)] 24 24 pub struct Button<'a> { 25 - rect: RoundedRectangle, 26 - label: &'a str, 27 - rect_style: PrimitiveStyle<BinaryColor>, 28 - char_style: MonoTextStyle<'a, BinaryColor>, 29 - touch_feedback: bool, 30 - touch_feedback_immediate_release: bool, 25 + pub rect: RoundedRectangle, 26 + pub label: &'a str, 27 + pub rect_style: PrimitiveStyle<BinaryColor>, 28 + pub char_style: MonoTextStyle<'a, BinaryColor>, 29 + pub touch_feedback: bool, 30 + pub touch_feedback_immediate_release: bool, 31 31 32 32 began_click: bool, 33 33 inverted: bool, ··· 88 88 true, 89 89 touch_feedback_immediate_release, 90 90 ) 91 - } 92 - 93 - pub fn rect(&self) -> Rectangle { 94 - self.rect.bounding_box() 95 91 } 96 92 97 93 fn invert(&mut self) { ··· 171 167 } 172 168 173 169 ret 170 + } 171 + 172 + fn bounding_box(&self) -> Rectangle { 173 + self.rect.into_styled(self.rect_style).bounding_box() 174 174 } 175 175 }
+6 -11
fw16-epd-gui/src/element/mod.rs
··· 1 1 pub mod button; 2 + pub mod slider; 2 3 3 4 use embedded_graphics::mono_font::ascii::FONT_10X20; 4 5 use embedded_graphics::mono_font::MonoTextStyle; 5 6 use embedded_graphics::pixelcolor::BinaryColor; 6 7 use embedded_graphics::prelude::*; 7 - use embedded_graphics::primitives::{PrimitiveStyle, PrimitiveStyleBuilder}; 8 + use embedded_graphics::primitives::{PrimitiveStyle, PrimitiveStyleBuilder, Rectangle}; 8 9 use fw16_epd_program_interface::{Event, TouchEvent}; 10 + use tp370pgh01::{DIM_X, DIM_Y}; 9 11 use crate::draw_target::EpdDrawTarget; 10 12 11 13 pub const DEFAULT_PRIMITIVE_STYLE: PrimitiveStyle<BinaryColor> = PrimitiveStyleBuilder::new() ··· 21 23 fn draw_init(&self, target: &mut EpdDrawTarget); 22 24 23 25 fn tick(&mut self, target: &mut EpdDrawTarget, ev: Event) -> Self::Output; 24 - } 25 26 26 - impl<T: Drawable<Color = BinaryColor>> Gui for T { 27 - type Output = (); 28 - 29 - fn draw_init(&self, target: &mut EpdDrawTarget) { 30 - self.draw(target).unwrap(); 31 - } 32 - 33 - fn tick(&mut self, _target: &mut EpdDrawTarget, _ev: Event) { 34 - // no-op 27 + // By default, assume element fills the display 28 + fn bounding_box(&self) -> Rectangle { 29 + Rectangle::new(Point::zero(), Size::new(DIM_X as u32, DIM_Y as u32)) 35 30 } 36 31 }
+114
fw16-epd-gui/src/element/slider.rs
··· 1 + use embedded_graphics::prelude::*; 2 + use embedded_graphics::geometry::Point; 3 + use embedded_graphics::pixelcolor::BinaryColor; 4 + use embedded_graphics::primitives::{Circle, Line, PrimitiveStyle, Rectangle}; 5 + use fw16_epd_program_interface::{Event, TouchEventType}; 6 + use crate::draw_target::EpdDrawTarget; 7 + use crate::element::{Gui, DEFAULT_PRIMITIVE_STYLE}; 8 + 9 + pub struct Slider { 10 + pub start_point: Point, 11 + pub length: i32, 12 + pub min: i32, 13 + pub max: i32, 14 + pub value: i32, 15 + 16 + pub line_style: PrimitiveStyle<BinaryColor>, 17 + pub marker_style: PrimitiveStyle<BinaryColor>, 18 + pub marker_radius: i32, 19 + 20 + sliding: bool, 21 + } 22 + 23 + impl Slider { 24 + pub fn new(start_point: Point, length: i32, min: i32, max: i32, starting_value: i32, line_style: PrimitiveStyle<BinaryColor>, marker_style: PrimitiveStyle<BinaryColor>, marker_radius: i32) -> Self { 25 + Self { 26 + start_point, 27 + length, 28 + min, 29 + max, 30 + value: starting_value, 31 + 32 + line_style, 33 + marker_style, 34 + marker_radius, 35 + 36 + sliding: false, 37 + } 38 + } 39 + 40 + pub fn with_default_style(start_point: Point, length: i32, min: i32, max: i32, starting_value: i32) -> Self { 41 + Self { 42 + start_point, 43 + length, 44 + min, 45 + max, 46 + value: starting_value, 47 + 48 + line_style: DEFAULT_PRIMITIVE_STYLE, 49 + marker_style: DEFAULT_PRIMITIVE_STYLE, 50 + marker_radius: 9, 51 + 52 + sliding: false, 53 + } 54 + } 55 + } 56 + 57 + impl Gui for Slider { 58 + type Output = bool; 59 + 60 + fn draw_init(&self, target: &mut EpdDrawTarget) { 61 + target.fill_solid(&self.bounding_box(), BinaryColor::Off).unwrap(); 62 + 63 + Line::new(self.start_point, self.start_point + Point::new(self.length, 0)) 64 + .into_styled(self.line_style) 65 + .draw(target) 66 + .unwrap(); 67 + 68 + let x = self.start_point.x + (self.length * (self.value - self.min)) / (self.max - self.min); 69 + let marker_point = Point::new(x, self.start_point.y); 70 + Circle::with_center(marker_point, self.marker_radius as u32 * 2) 71 + .into_styled(self.marker_style) 72 + .draw(target) 73 + .unwrap(); 74 + } 75 + 76 + fn tick(&mut self, target: &mut EpdDrawTarget, ev: Event) -> bool { 77 + if let Event::Touch(ev) = ev { 78 + let p = ev.eg_point(); 79 + 80 + if self.bounding_box().contains(p) && ev.ev_type == TouchEventType::Down { 81 + self.sliding = true; 82 + } else if ev.ev_type == TouchEventType::Up { 83 + self.sliding = false; 84 + } 85 + 86 + if self.sliding { 87 + if p.x >= self.start_point.x && p.x <= (self.start_point.x + self.length) { 88 + let xmin = self.start_point.x; 89 + let xmax = xmin + self.length; 90 + 91 + self.value = self.min + ((self.max - self.min) * (ev.eg_point().x - xmin)) / (xmax - xmin); 92 + self.draw_init(target); 93 + } else if p.x < self.start_point.x { 94 + self.value = self.min; 95 + self.draw_init(target); 96 + } else { 97 + self.value = self.max; 98 + self.draw_init(target); 99 + } 100 + 101 + return true; 102 + } 103 + } 104 + 105 + false 106 + } 107 + 108 + fn bounding_box(&self) -> Rectangle { 109 + let real_radius = self.marker_radius + self.marker_style.stroke_width as i32; 110 + let top_left = self.start_point + Point::new(-real_radius, -real_radius); 111 + Rectangle::new(top_left, Size::new((self.length + 2 * real_radius) as u32, 2 * real_radius as u32)) 112 + } 113 + 114 + }
+41 -6
fw16-epd-main/src/gui.rs
··· 2 2 use embedded_graphics::geometry::AnchorPoint; 3 3 use embedded_graphics::pixelcolor::BinaryColor; 4 4 use embedded_graphics::prelude::*; 5 - use embedded_graphics::primitives::{Line, Rectangle}; 5 + use embedded_graphics::primitives::{Line, PrimitiveStyle, Rectangle}; 6 6 use fw16_epd_gui::draw_target::EpdDrawTarget; 7 7 use fw16_epd_gui::element::button::Button; 8 8 use fw16_epd_gui::element::{Gui, DEFAULT_PRIMITIVE_STYLE}; 9 + use fw16_epd_gui::element::slider::Slider; 9 10 use fw16_epd_program_interface::{RefreshBlockMode, SafeOption, Event, TouchEventType}; 10 11 use crate::{next_event, set_touch_enabled}; 11 12 ··· 84 85 struct ScratchpadPage { 85 86 exit_button: Button<'static>, 86 87 clear_button: Button<'static>, 88 + toggle_button: Button<'static>, 89 + slider: Slider, 90 + eraser: bool, 87 91 prev_pos: Option<Point>, 88 92 } 89 93 90 94 impl ScratchpadPage { 91 95 fn new() -> Self { 92 96 let exit_button = Button::with_default_style_auto_sized(Point::new(10, 416 - 10 - 20), "Exit", true); 97 + 93 98 let next_pos = exit_button 94 - .rect() 99 + .bounding_box() 95 100 .translate(Point::new(10, 0)) 96 101 .anchor_point(AnchorPoint::TopRight); 97 102 let clear_button = Button::with_default_style_auto_sized(next_pos, "Clear", true); 98 103 104 + let next_pos = clear_button 105 + .bounding_box() 106 + .translate(Point::new(10, 0)) 107 + .anchor_point(AnchorPoint::TopRight); 108 + let toggle_button = Button::with_default_style_auto_sized(next_pos, "Eraser", false); 109 + 110 + let slider = Slider::with_default_style(Point::new(20, 20), 100, 1, 10, 2); 111 + 99 112 Self { 100 113 exit_button, 101 114 clear_button, 115 + toggle_button, 116 + slider, 117 + eraser: false, 102 118 prev_pos: None, 103 119 } 104 120 } ··· 110 126 fn draw_init(&self, draw_target: &mut EpdDrawTarget) { 111 127 self.exit_button.draw_init(draw_target); 112 128 self.clear_button.draw_init(draw_target); 129 + self.toggle_button.draw_init(draw_target); 130 + self.slider.draw_init(draw_target); 113 131 } 114 132 115 133 fn tick(&mut self, draw_target: &mut EpdDrawTarget, ev: Event) -> Self::Output { 116 134 let mut refresh: Option<RefreshBlockMode> = None; 135 + let mut handle_drawing: bool = true; 117 136 118 137 let e = self.exit_button.tick(draw_target, ev); 119 138 if e.clicked { ··· 134 153 refresh = Some(RefreshBlockMode::BlockAcknowledge); 135 154 } 136 155 156 + let t = self.toggle_button.tick(draw_target, ev); 157 + if t.clicked { 158 + self.eraser = !self.eraser; 159 + self.toggle_button.label = if self.eraser { "Pen" } else { "Eraser" }; 160 + refresh = Some(RefreshBlockMode::NonBlocking); 161 + } 162 + if t.needs_refresh { 163 + refresh = Some(RefreshBlockMode::BlockAcknowledge); 164 + } 165 + 166 + if self.slider.tick(draw_target, ev) { 167 + refresh = Some(RefreshBlockMode::NonBlocking); 168 + debug!("stroke width = {}", self.slider.value); 169 + handle_drawing = false; 170 + } 171 + 137 172 if let Event::Touch(ev) = ev { 138 - if matches!(ev.ev_type, TouchEventType::Move | TouchEventType::Up) { 173 + if handle_drawing && matches!(ev.ev_type, TouchEventType::Move | TouchEventType::Up) { 139 174 if let Some(prev) = self.prev_pos { 175 + let style = PrimitiveStyle::with_stroke(BinaryColor::from(!self.eraser), self.slider.value as u32); 140 176 Line::new(prev, ev.eg_point()) 141 - .into_styled(DEFAULT_PRIMITIVE_STYLE) 177 + .into_styled(style) 142 178 .draw(draw_target) 143 179 .unwrap(); 144 180 145 - self.exit_button.draw_init(draw_target); 146 - self.clear_button.draw_init(draw_target); 181 + self.draw_init(draw_target); 147 182 148 183 if refresh.is_none() { 149 184 refresh = Some(RefreshBlockMode::NonBlocking);