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.

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