From 923af2049d9988e3c0d12542dd969ae57d2dc9a5 Mon Sep 17 00:00:00 2001 From: Nyoxis Date: Sat, 4 Nov 2023 02:49:49 +0200 Subject: [PATCH 01/32] Initial barebone of widgets with new screen to test widgets. Work on hardware is not implemented yet. --- kampela-ui/src/lib.rs | 5 ++ kampela-ui/src/main.rs | 5 ++ kampela-ui/src/test.rs | 50 ++++++++++++++++++ kampela-ui/src/uistate.rs | 15 +++++- kampela-ui/src/widget/button.rs | 92 +++++++++++++++++++++++++++++++++ kampela-ui/src/widget/view.rs | 18 +++++++ 6 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 kampela-ui/src/test.rs create mode 100644 kampela-ui/src/widget/button.rs create mode 100644 kampela-ui/src/widget/view.rs diff --git a/kampela-ui/src/lib.rs b/kampela-ui/src/lib.rs index e4e58ce..3dc5603 100644 --- a/kampela-ui/src/lib.rs +++ b/kampela-ui/src/lib.rs @@ -2,12 +2,17 @@ pub mod uistate; pub mod platform; +pub mod widget{ + pub mod button; + pub mod view; +} pub mod display_def; pub mod pin; mod seed_entry; pub mod backup; mod restore_or_generate; +mod test; pub mod transaction; pub mod qr; diff --git a/kampela-ui/src/main.rs b/kampela-ui/src/main.rs index 7368cdd..b3483f6 100644 --- a/kampela-ui/src/main.rs +++ b/kampela-ui/src/main.rs @@ -29,6 +29,11 @@ use pin::Pincode; mod restore_or_generate; mod seed_entry; +mod test; +mod widget { + pub mod view; + pub mod button; +} mod backup; diff --git a/kampela-ui/src/test.rs b/kampela-ui/src/test.rs new file mode 100644 index 0000000..bda379d --- /dev/null +++ b/kampela-ui/src/test.rs @@ -0,0 +1,50 @@ +use embedded_graphics::{ + mono_font::{ + ascii::{FONT_10X20}, + MonoTextStyle, + }, + primitives::Rectangle, + pixelcolor::BinaryColor, + prelude::{DrawTarget, Point}, + geometry::{Size}, +}; +use embedded_text::{ + alignment::{HorizontalAlignment, VerticalAlignment}, + style::TextBoxStyleBuilder, + TextBox, +}; + +use crate::{display_def::*, uistate::UpdateRequest}; +use crate::uistate::EventResult; +use crate::widget::{view::View, button::Button}; + +pub struct Test { + button: Button +} +impl Test { + pub fn new() -> Self { + Test { + button: Button::new( + "hello", + Rectangle { + top_left: Point { x: 100, y: 100 }, + size: Size { width: 100, height: 20 } + } + ) + } + + } + pub fn draw> (&self, target: &mut D) -> Result<(), D::Error> { + self.button + .draw(target)?; + Ok(()) + } + pub fn handle_tap> (&self, point: Point, target: &mut D) -> Result { + let out = UpdateRequest::new(); + let mut res = Ok(EventResult{request: out, state: None}); + if self.button.widget.area.contains(point){ + res = self.button.handle_tap(point, target) + } + res + } +} diff --git a/kampela-ui/src/uistate.rs b/kampela-ui/src/uistate.rs index c960739..1a94e67 100644 --- a/kampela-ui/src/uistate.rs +++ b/kampela-ui/src/uistate.rs @@ -36,6 +36,7 @@ use crate::platform::{NfcTransaction, Platform}; use crate::seed_entry::SeedEntryState; use crate::restore_or_generate; +use crate::test::Test; use rand::{CryptoRng, Rng}; @@ -112,10 +113,12 @@ pub struct UIState

where P: Platform, { screen: Screen, + test: Test, pub platform: P, } pub enum Screen { + Test, PinEntry, OnboardingRestoreOrGenerate, OnboardingRestore(SeedEntryState), @@ -134,12 +137,14 @@ impl UIState

{ platform.read_entropy(); if platform.entropy_display().0.is_empty() { UIState { - screen: Screen::OnboardingRestoreOrGenerate, + screen: Screen::Test, + test: Test::new(), platform: platform, } } else { UIState { screen: Screen::QRAddress, + test: Test::new(), platform: platform, } } @@ -174,6 +179,11 @@ impl UIState

{ let mut out = UpdateRequest::new(); let mut new_screen = None; match self.screen { + Screen::Test => { + let res = self.test.handle_tap(point, fast_display)?; + out = res.request; + new_screen = res.state; + }, Screen::PinEntry => { let res = self.platform.handle_pin_event(point, h)?; out = res.request;/* @@ -289,6 +299,9 @@ impl UIState

{ let clear = PrimitiveStyle::with_fill(BinaryColor::Off); display.bounding_box().into_styled(clear).draw(display)?; match self.screen { + Screen::Test => { + self.test.draw(display)?; + } Screen::PinEntry => { self.platform.draw_pincode()?; } diff --git a/kampela-ui/src/widget/button.rs b/kampela-ui/src/widget/button.rs new file mode 100644 index 0000000..ecb5077 --- /dev/null +++ b/kampela-ui/src/widget/button.rs @@ -0,0 +1,92 @@ +#[cfg(not(feature="std"))] +use alloc::{format, string::String, string::ToString, vec::Vec}; +use core::fmt::Display; +#[cfg(feature="std")] +use std::{format, string::String, string::ToString, vec::Vec}; + +use embedded_graphics::{ + pixelcolor::BinaryColor, + prelude::{DrawTarget, Point, Primitive}, + geometry::Dimensions, + Drawable, + mono_font::{ + ascii::{FONT_6X10}, + MonoTextStyle, + }, + primitives::{ + Circle, PrimitiveStyle, Rectangle, + }, +}; + +use embedded_text::{ + alignment::{HorizontalAlignment, VerticalAlignment}, + style::TextBoxStyleBuilder, + TextBox, +}; + +use crate::{ + widget::view::{View, Widget}, + platform::Platform, +}; + +use crate::uistate::{EventResult, UpdateRequest, Screen}; + +pub struct Button { + label: String, + pub widget: Widget, +} + +impl Button { + pub fn new(label: &str, area: Rectangle) -> Self { + Button { + label: label.to_string(), + widget: Widget { area }, + } + } +} + +impl > View for Button { + fn draw(&self, target: &mut D) -> Result<(),D::Error> { + let character_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On); + let thin_stroke = PrimitiveStyle::with_stroke(BinaryColor::On, 2); + + self.widget.area.into_styled(thin_stroke).draw(target)?; + + let textbox_style = TextBoxStyleBuilder::new() + .alignment(HorizontalAlignment::Center) + .vertical_alignment(VerticalAlignment::Middle) + .build(); + + TextBox::with_textbox_style( + &self.label, + self.widget.area.bounding_box(), + character_style, + textbox_style, + ) + .draw(target)?; + Ok(()) + } + fn handle_tap(&self, point: Point, target: &mut D) -> Result { + let mut request = UpdateRequest::new(); + let character_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::Off); + let filled = PrimitiveStyle::with_fill(BinaryColor::On); + + self.widget.area.into_styled(filled).draw(target)?; + + let textbox_style = TextBoxStyleBuilder::new() + .alignment(HorizontalAlignment::Center) + .vertical_alignment(VerticalAlignment::Middle) + .build(); + + TextBox::with_textbox_style( + &self.label, + self.widget.area, + character_style, + textbox_style, + ) + .draw(target)?; + request.set_both(); + let state = None; + Ok(EventResult {request, state}) + } +} \ No newline at end of file diff --git a/kampela-ui/src/widget/view.rs b/kampela-ui/src/widget/view.rs new file mode 100644 index 0000000..fd32221 --- /dev/null +++ b/kampela-ui/src/widget/view.rs @@ -0,0 +1,18 @@ +use embedded_graphics::{ + pixelcolor::BinaryColor, + prelude::{DrawTarget, Point}, + primitives::Rectangle, +}; + +use crate::uistate::EventResult; + +pub struct Widget { + pub area: Rectangle, +} + +pub trait View where + D: DrawTarget, +{ + fn draw(&self, target: &mut D) -> Result<(),D::Error>; + fn handle_tap(&self, point: Point, target: &mut D) -> Result; +} From 4a5e40bd5dd796ab9eea7dbeac96407176628945 Mon Sep 17 00:00:00 2001 From: Nyoxis Date: Wed, 8 Nov 2023 17:08:24 +0200 Subject: [PATCH 02/32] Added nested widgets code structure. Each widget should be independent and its coordinates encapsulated, though global render target used. --- kampela-ui/src/test.rs | 37 +++++++++------- kampela-ui/src/uistate.rs | 7 ++- kampela-ui/src/widget/button.rs | 31 +++++++------ kampela-ui/src/widget/view.rs | 77 ++++++++++++++++++++++++++++++--- 4 files changed, 117 insertions(+), 35 deletions(-) diff --git a/kampela-ui/src/test.rs b/kampela-ui/src/test.rs index bda379d..a50a9c6 100644 --- a/kampela-ui/src/test.rs +++ b/kampela-ui/src/test.rs @@ -8,43 +8,48 @@ use embedded_graphics::{ prelude::{DrawTarget, Point}, geometry::{Size}, }; -use embedded_text::{ - alignment::{HorizontalAlignment, VerticalAlignment}, - style::TextBoxStyleBuilder, - TextBox, -}; use crate::{display_def::*, uistate::UpdateRequest}; use crate::uistate::EventResult; -use crate::widget::{view::View, button::Button}; +use crate::widget::{view::{View, DrawWindow}, button::Button}; pub struct Test { - button: Button + area: Rectangle, + button: Button, } + impl Test { pub fn new() -> Self { Test { + area: Rectangle { + top_left: Point { x: 132, y: 88 }, + size: Size { width: 132, height: 88 }, + }, button: Button::new( "hello", Rectangle { - top_left: Point { x: 100, y: 100 }, - size: Size { width: 100, height: 20 } + top_left: Point { x: 0, y: 0 }, + size: Size { width: 66, height: 44 }, } ) } } - pub fn draw> (&self, target: &mut D) -> Result<(), D::Error> { +} +impl > View for Test { + fn area(&self) -> Rectangle { + self.area + } + fn draw_view(&self, target: &mut DrawWindow) -> Result<(), D::Error> { self.button .draw(target)?; Ok(()) } - pub fn handle_tap> (&self, point: Point, target: &mut D) -> Result { - let out = UpdateRequest::new(); - let mut res = Ok(EventResult{request: out, state: None}); - if self.button.widget.area.contains(point){ - res = self.button.handle_tap(point, target) - } + fn handle_tap_view(&mut self, point: Point, target: &mut DrawWindow) -> Result { + let mut res = Ok(EventResult{request: UpdateRequest::new(), state: None}); + if let Some(a) = self.button.handle_tap(point, target) { + res = a; + }; res } } diff --git a/kampela-ui/src/uistate.rs b/kampela-ui/src/uistate.rs index 1a94e67..d060873 100644 --- a/kampela-ui/src/uistate.rs +++ b/kampela-ui/src/uistate.rs @@ -37,6 +37,7 @@ use crate::seed_entry::SeedEntryState; use crate::restore_or_generate; use crate::test::Test; +use crate::widget::view::View; use rand::{CryptoRng, Rng}; @@ -180,7 +181,11 @@ impl UIState

{ let mut new_screen = None; match self.screen { Screen::Test => { - let res = self.test.handle_tap(point, fast_display)?; + let mut res = Ok(EventResult{request: UpdateRequest::new(), state: None}); + if let Some(a) = self.test.handle_tap(point, fast_display) { + res = a; + }; + let res = res?; out = res.request; new_screen = res.state; }, diff --git a/kampela-ui/src/widget/button.rs b/kampela-ui/src/widget/button.rs index ecb5077..fbf360c 100644 --- a/kampela-ui/src/widget/button.rs +++ b/kampela-ui/src/widget/button.rs @@ -24,12 +24,9 @@ use embedded_text::{ TextBox, }; -use crate::{ - widget::view::{View, Widget}, - platform::Platform, -}; +use crate::widget::view::{View, Widget, DrawWindow}; -use crate::uistate::{EventResult, UpdateRequest, Screen}; +use crate::uistate::{EventResult, UpdateRequest}; pub struct Button { label: String, @@ -40,17 +37,22 @@ impl Button { pub fn new(label: &str, area: Rectangle) -> Self { Button { label: label.to_string(), - widget: Widget { area }, + widget: Widget::new(area), } } } impl > View for Button { - fn draw(&self, target: &mut D) -> Result<(),D::Error> { + fn area(&self) -> Rectangle { + self.widget.area() + } + + fn draw_view(&self, target: &mut DrawWindow) -> Result<(),D::Error> { let character_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On); let thin_stroke = PrimitiveStyle::with_stroke(BinaryColor::On, 2); - self.widget.area.into_styled(thin_stroke).draw(target)?; + let area =