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

Configure Feed

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

at a3ff1f4e4e2aaec4a4c1ec5def91c21d36dc12f7 183 lines 6.5 kB view raw
1use embedded_graphics::prelude::*; 2use embedded_graphics::mono_font::MonoTextStyle; 3use embedded_graphics::pixelcolor::BinaryColor; 4use embedded_graphics::primitives::{CornerRadii, PrimitiveStyle, Rectangle, RoundedRectangle}; 5use embedded_graphics::text::{Alignment, Baseline, Text, TextStyle, TextStyleBuilder}; 6use embedded_graphics::text::renderer::TextRenderer; 7use fugit::ExtU32; 8use eepy_sys::input_common::{Event, TouchEventType}; 9use eepy_sys::misc::{now, Instant}; 10use crate::draw_target::EpdDrawTarget; 11use crate::element::{Gui, DEFAULT_PRIMITIVE_STYLE, DEFAULT_TEXT_STYLE}; 12 13const CENTRE_STYLE: TextStyle = TextStyleBuilder::new() 14 .alignment(Alignment::Center) 15 .baseline(Baseline::Middle) 16 .build(); 17 18#[cfg_attr(feature = "defmt", derive(defmt::Format))] 19#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] 20pub struct ButtonOutput { 21 pub clicked: bool, 22 pub long_clicked: bool, 23 pub needs_refresh: bool, 24} 25 26#[cfg_attr(feature = "defmt", derive(defmt::Format))] 27#[derive(Debug)] 28pub struct Button<'a> { 29 pub rect: RoundedRectangle, 30 pub label: &'a str, 31 pub rect_style: PrimitiveStyle<BinaryColor>, 32 pub char_style: MonoTextStyle<'a, BinaryColor>, 33 pub touch_feedback: bool, 34 pub touch_feedback_immediate_release: bool, 35 36 click_begin_time: Option<Instant>, 37 inverted: bool, 38 should_uninvert: bool, 39} 40 41impl<'a> Button<'a> { 42 pub fn new(rect: RoundedRectangle, label: &'a str, rect_style: PrimitiveStyle<BinaryColor>, char_style: MonoTextStyle<'a, BinaryColor>, touch_feedback: bool, touch_feedback_immediate_release: bool) -> Self { 43 Self { 44 rect, 45 label, 46 rect_style, 47 char_style, 48 touch_feedback, 49 touch_feedback_immediate_release, 50 click_begin_time: None, 51 inverted: false, 52 should_uninvert: false, 53 } 54 } 55 56 pub fn auto_sized(top_left: Point, corner_radii: CornerRadii, label: &'a str, rect_style: PrimitiveStyle<BinaryColor>, char_style: MonoTextStyle<'a, BinaryColor>, touch_feedback: bool, touch_feedback_immediate_release: bool) -> Self { 57 let size = Size::new((char_style.font.character_size.width + char_style.font.character_spacing) * (label.len() as u32 + 1), char_style.line_height()); 58 Self { 59 rect: RoundedRectangle::new(Rectangle::new(top_left, size), corner_radii), 60 label, 61 rect_style, 62 char_style, 63 touch_feedback, 64 touch_feedback_immediate_release, 65 click_begin_time: None, 66 inverted: false, 67 should_uninvert: false, 68 } 69 } 70 71 pub fn with_default_style(rect: Rectangle, label: &'a str, touch_feedback_immediate_release: bool) -> Self { 72 Self { 73 rect: RoundedRectangle::new(rect, CornerRadii::new(Size::new(3, 3))), 74 label, 75 rect_style: DEFAULT_PRIMITIVE_STYLE, 76 char_style: DEFAULT_TEXT_STYLE, 77 touch_feedback: true, 78 touch_feedback_immediate_release, 79 click_begin_time: None, 80 inverted: false, 81 should_uninvert: false, 82 } 83 } 84 85 pub fn with_default_style_auto_sized(top_left: Point, label: &'a str, touch_feedback_immediate_release: bool) -> Self { 86 Self::auto_sized( 87 top_left, 88 CornerRadii::new(Size::new(3, 3)), 89 label, 90 DEFAULT_PRIMITIVE_STYLE, 91 DEFAULT_TEXT_STYLE, 92 true, 93 touch_feedback_immediate_release, 94 ) 95 } 96 97 fn invert(&mut self) { 98 self.rect_style.fill_color = self.rect_style.fill_color.map(|c| c.invert()); 99 self.char_style.text_color = self.char_style.text_color.map(|c| c.invert()); 100 self.inverted = !self.inverted; 101 } 102} 103 104impl<'a> Gui for Button<'a> { 105 type Output = ButtonOutput; 106 107 fn draw_init(&self, target: &mut EpdDrawTarget) { 108 self.rect 109 .into_styled(self.rect_style) 110 .draw(target) 111 .unwrap(); 112 113 Text::with_text_style( 114 self.label, 115 self.rect.bounding_box().center(), 116 self.char_style, 117 CENTRE_STYLE 118 ) 119 .draw(target) 120 .unwrap(); 121 } 122 123 fn tick(&mut self, target: &mut EpdDrawTarget, ev: Event) -> Self::Output { 124 let mut ret = ButtonOutput::default(); 125 126 if let Event::Touch(ev) = ev { 127 if self.rect.contains(ev.eg_point()) { 128 match (self.click_begin_time, ev.ev_type) { 129 (None, TouchEventType::Down) => { 130 self.click_begin_time = Some(now()); 131 if self.touch_feedback { 132 self.invert(); 133 self.draw_init(target); 134 ret.needs_refresh = true; 135 } 136 }, 137 (Some(t), TouchEventType::Up) => { 138 self.click_begin_time = None; 139 if self.inverted { 140 if self.touch_feedback_immediate_release { 141 self.invert(); 142 self.draw_init(target); 143 ret.needs_refresh = true; 144 } else { 145 self.should_uninvert = true; 146 } 147 } 148 149 ret.clicked = true; 150 if now().checked_duration_since(t).unwrap() > 500.millis::<1, 1_000_000>() { 151 ret.long_clicked = true; 152 } 153 }, 154 _ => {}, 155 } 156 } else { 157 self.click_begin_time = None; 158 if self.inverted { 159 if self.touch_feedback_immediate_release { 160 self.invert(); 161 self.draw_init(target); 162 ret.needs_refresh = true; 163 } else { 164 self.should_uninvert = true; 165 } 166 } 167 } 168 } 169 170 if ev == Event::RefreshFinished && self.should_uninvert { 171 self.should_uninvert = false; 172 self.invert(); 173 self.draw_init(target); 174 ret.needs_refresh = true; 175 } 176 177 ret 178 } 179 180 fn bounding_box(&self) -> Rectangle { 181 self.rect.into_styled(self.rect_style).bounding_box() 182 } 183}