Skip to content

Commit a39525f

Browse files
committed
Use scalable vector Qube layer title
1 parent 4578b32 commit a39525f

2 files changed

Lines changed: 544 additions & 10 deletions

File tree

keyboards/k04_qube/src/qube_display.rs

Lines changed: 272 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ use embassy_nrf::peripherals::{P0_02, P0_03, P0_28, P1_10, P1_11, P1_13, SPI3};
2020
use embassy_nrf::spim::{self, Spim};
2121
use embassy_nrf::{interrupt, Peri};
2222
use embassy_time::{Delay, Duration, Instant, Timer};
23-
use embedded_graphics::mono_font::ascii::{FONT_6X10, FONT_9X15, FONT_9X18_BOLD};
23+
use embedded_graphics::mono_font::ascii::{FONT_6X10, FONT_9X15};
2424
use embedded_graphics::mono_font::MonoTextStyle;
2525
use embedded_graphics::pixelcolor::Rgb565;
2626
use embedded_graphics::prelude::*;
2727
use embedded_graphics::primitives::{
28-
PrimitiveStyle, PrimitiveStyleBuilder, Rectangle, RoundedRectangle,
28+
Line, PrimitiveStyle, PrimitiveStyleBuilder, Rectangle, RoundedRectangle,
2929
};
3030
use embedded_graphics::text::{Alignment, Baseline, Text, TextStyleBuilder};
3131
use embedded_hal_bus::spi::{ExclusiveDevice, NoDelay};
@@ -65,6 +65,10 @@ const SAFE_W: u32 = SCREEN_W as u32 - (SAFE_X as u32 * 2);
6565
const PANEL_RADIUS: u32 = 12;
6666
const CHIP_RADIUS: u32 = 8;
6767
const BAR_RADIUS: u32 = 5;
68+
const LAYER_TITLE_W: i32 = 12;
69+
const LAYER_TITLE_H: i32 = 24;
70+
const LAYER_TITLE_GAP: i32 = 1;
71+
const LAYER_TITLE_STROKE: u32 = 2;
6872

6973
const COL_BG: Rgb565 = Rgb565::new(1, 3, 5);
7074
const COL_FG: Rgb565 = Rgb565::new(30, 61, 30);
@@ -668,7 +672,6 @@ impl DisplayRenderer<Rgb565> for QubeStatusRenderer {
668672
let small = MonoTextStyle::new(&FONT_6X10, COL_MUTED);
669673
let small_dim = MonoTextStyle::new(&FONT_6X10, COL_DIM);
670674
let body = MonoTextStyle::new(&FONT_9X15, COL_FG);
671-
let layer_title = MonoTextStyle::new(&FONT_9X18_BOLD, COL_FG);
672675
let body_muted = MonoTextStyle::new(&FONT_9X15, COL_MUTED);
673676
let body_accent = MonoTextStyle::new(&FONT_9X15, COL_ACCENT);
674677
let body_amber = MonoTextStyle::new(&FONT_9X15, COL_AMBER);
@@ -734,8 +737,7 @@ impl DisplayRenderer<Rgb565> for QubeStatusRenderer {
734737
let _ = write!(&mut s, "LAYER {}", ctx.layer);
735738
let _ =
736739
Text::with_text_style(&s, Point::new(SCREEN_W as i32 / 2, 69), small, tc).draw(display);
737-
let _ = Text::with_text_style(name, Point::new(SCREEN_W as i32 / 2, 92), layer_title, tc)
738-
.draw(display);
740+
draw_vector_text_centered(display, name, SCREEN_W as i32 / 2, 101, COL_FG);
739741

740742
// Modifier chips.
741743
draw_panel(display, SAFE_X, 138, SAFE_W, 27, COL_PANEL, COL_BORDER);
@@ -846,6 +848,271 @@ fn draw_chip<D: DrawTarget<Color = Rgb565>>(
846848
Text::with_text_style(label, Point::new(x + w as i32 / 2, y + 3), text, tc).draw(display);
847849
}
848850

851+
fn draw_vector_text_centered<D: DrawTarget<Color = Rgb565>>(
852+
display: &mut D,
853+
text: &str,
854+
center_x: i32,
855+
center_y: i32,
856+
color: Rgb565,
857+
) {
858+
let chars = text.chars().count() as i32;
859+
if chars == 0 {
860+
return;
861+
}
862+
let total_w = chars * LAYER_TITLE_W + (chars - 1) * LAYER_TITLE_GAP;
863+
let mut x = center_x - total_w / 2;
864+
let y = center_y - LAYER_TITLE_H / 2;
865+
for ch in text.chars() {
866+
draw_vector_glyph(display, ch, x, y, color);
867+
x += LAYER_TITLE_W + LAYER_TITLE_GAP;
868+
}
869+
}
870+
871+
fn draw_vector_glyph<D: DrawTarget<Color = Rgb565>>(
872+
display: &mut D,
873+
ch: char,
874+
x: i32,
875+
y: i32,
876+
color: Rgb565,
877+
) {
878+
match ch {
879+
'A' => {
880+
seg(display, x, y, 1, 14, 3, 0, color);
881+
seg(display, x, y, 9, 14, 7, 0, color);
882+
seg(display, x, y, 3, 0, 7, 0, color);
883+
seg(display, x, y, 2, 7, 8, 7, color);
884+
}
885+
'B' => {
886+
seg(display, x, y, 1, 0, 1, 14, color);
887+
seg(display, x, y, 1, 0, 7, 0, color);
888+
seg(display, x, y, 7, 0, 10, 3, color);
889+
seg(display, x, y, 10, 3, 10, 5, color);
890+
seg(display, x, y, 10, 5, 8, 7, color);
891+
seg(display, x, y, 1, 7, 8, 7, color);
892+
seg(display, x, y, 8, 7, 10, 9, color);
893+
seg(display, x, y, 10, 9, 10, 12, color);
894+
seg(display, x, y, 10, 12, 7, 14, color);
895+
seg(display, x, y, 1, 14, 7, 14, color);
896+
}
897+
'D' => {
898+
seg(display, x, y, 1, 0, 1, 14, color);
899+
seg(display, x, y, 1, 0, 7, 0, color);
900+
seg(display, x, y, 7, 0, 10, 3, color);
901+
seg(display, x, y, 10, 3, 10, 11, color);
902+
seg(display, x, y, 10, 11, 7, 14, color);
903+
seg(display, x, y, 1, 14, 7, 14, color);
904+
}
905+
'E' => {
906+
seg(display, x, y, 1, 0, 1, 14, color);
907+
seg(display, x, y, 1, 0, 10, 0, color);
908+
seg(display, x, y, 1, 7, 8, 7, color);
909+
seg(display, x, y, 1, 14, 10, 14, color);
910+
}
911+
'F' => {
912+
seg(display, x, y, 1, 0, 1, 14, color);
913+
seg(display, x, y, 1, 0, 10, 0, color);
914+
seg(display, x, y, 1, 7, 8, 7, color);
915+
}
916+
'G' => {
917+
seg(display, x, y, 10, 1, 3, 1, color);
918+
seg(display, x, y, 3, 1, 1, 4, color);
919+
seg(display, x, y, 1, 4, 1, 11, color);
920+
seg(display, x, y, 1, 11, 3, 14, color);
921+
seg(display, x, y, 3, 14, 10, 14, color);
922+
seg(display, x, y, 10, 14, 10, 8, color);
923+
seg(display, x, y, 10, 8, 6, 8, color);
924+
}
925+
'J' => {
926+
seg(display, x, y, 2, 0, 10, 0, color);
927+
seg(display, x, y, 8, 0, 8, 11, color);
928+
seg(display, x, y, 8, 11, 6, 14, color);
929+
seg(display, x, y, 6, 14, 2, 14, color);
930+
seg(display, x, y, 2, 14, 1, 11, color);
931+
}
932+
'L' => {
933+
seg(display, x, y, 1, 0, 1, 14, color);
934+
seg(display, x, y, 1, 14, 10, 14, color);
935+
}
936+
'M' => {
937+
seg(display, x, y, 1, 14, 1, 0, color);
938+
seg(display, x, y, 1, 0, 5, 7, color);
939+
seg(display, x, y, 5, 7, 9, 0, color);
940+
seg(display, x, y, 9, 0, 9, 14, color);
941+
}
942+
'N' => {
943+
seg(display, x, y, 1, 14, 1, 0, color);
944+
seg(display, x, y, 1, 0, 10, 14, color);
945+
seg(display, x, y, 10, 14, 10, 0, color);
946+
}
947+
'P' => {
948+
seg(display, x, y, 1, 14, 1, 0, color);
949+
seg(display, x, y, 1, 0, 8, 0, color);
950+
seg(display, x, y, 8, 0, 10, 3, color);
951+
seg(display, x, y, 10, 3, 10, 6, color);
952+
seg(display, x, y, 10, 6, 8, 8, color);
953+
seg(display, x, y, 1, 8, 8, 8, color);
954+
}
955+
'R' => {
956+
seg(display, x, y, 1, 14, 1, 0, color);
957+
seg(display, x, y, 1, 0, 8, 0, color);
958+
seg(display, x, y, 8, 0, 10, 3, color);
959+
seg(display, x, y, 10, 3, 10, 6, color);
960+
seg(display, x, y, 10, 6, 8, 8, color);
961+
seg(display, x, y, 1, 8, 8, 8, color);
962+
seg(display, x, y, 6, 8, 10, 14, color);
963+
}
964+
'S' => {
965+
seg(display, x, y, 10, 1, 3, 1, color);
966+
seg(display, x, y, 3, 1, 1, 4, color);
967+
seg(display, x, y, 1, 4, 3, 7, color);
968+
seg(display, x, y, 3, 7, 8, 7, color);
969+
seg(display, x, y, 8, 7, 10, 10, color);
970+
seg(display, x, y, 10, 10, 8, 13, color);
971+
seg(display, x, y, 8, 13, 1, 13, color);
972+
}
973+
'T' => {
974+
seg(display, x, y, 1, 0, 10, 0, color);
975+
seg(display, x, y, 5, 0, 5, 14, color);
976+
}
977+
'U' => {
978+
seg(display, x, y, 1, 0, 1, 11, color);
979+
seg(display, x, y, 1, 11, 4, 14, color);
980+
seg(display, x, y, 4, 14, 8, 14, color);
981+
seg(display, x, y, 8, 14, 10, 11, color);
982+
seg(display, x, y, 10, 11, 10, 0, color);
983+
}
984+
'V' => {
985+
seg(display, x, y, 1, 0, 5, 14, color);
986+
seg(display, x, y, 5, 14, 10, 0, color);
987+
}
988+
'Y' => {
989+
seg(display, x, y, 1, 0, 5, 7, color);
990+
seg(display, x, y, 10, 0, 5, 7, color);
991+
seg(display, x, y, 5, 7, 5, 14, color);
992+
}
993+
'0' => {
994+
seg(display, x, y, 3, 0, 8, 0, color);
995+
seg(display, x, y, 8, 0, 10, 3, color);
996+
seg(display, x, y, 10, 3, 10, 11, color);
997+
seg(display, x, y, 10, 11, 8, 14, color);
998+
seg(display, x, y, 8, 14, 3, 14, color);
999+
seg(display, x, y, 3, 14, 1, 11, color);
1000+
seg(display, x, y, 1, 11, 1, 3, color);
1001+
seg(display, x, y, 1, 3, 3, 0, color);
1002+
}
1003+
'1' => {
1004+
seg(display, x, y, 5, 0, 5, 14, color);
1005+
seg(display, x, y, 3, 3, 5, 0, color);
1006+
seg(display, x, y, 2, 14, 8, 14, color);
1007+
}
1008+
'2' => {
1009+
seg(display, x, y, 2, 1, 8, 1, color);
1010+
seg(display, x, y, 8, 1, 10, 4, color);
1011+
seg(display, x, y, 10, 4, 1, 14, color);
1012+
seg(display, x, y, 1, 14, 10, 14, color);
1013+
}
1014+
'3' => {
1015+
seg(display, x, y, 2, 1, 8, 1, color);
1016+
seg(display, x, y, 8, 1, 10, 4, color);
1017+
seg(display, x, y, 6, 7, 10, 7, color);
1018+
seg(display, x, y, 10, 7, 10, 11, color);
1019+
seg(display, x, y, 10, 11, 8, 14, color);
1020+
seg(display, x, y, 8, 14, 2, 14, color);
1021+
}
1022+
'4' => {
1023+
seg(display, x, y, 9, 0, 9, 14, color);
1024+
seg(display, x, y, 1, 0, 1, 7, color);
1025+
seg(display, x, y, 1, 7, 10, 7, color);
1026+
}
1027+
'5' => {
1028+
seg(display, x, y, 10, 1, 2, 1, color);
1029+
seg(display, x, y, 2, 1, 2, 7, color);
1030+
seg(display, x, y, 2, 7, 8, 7, color);
1031+
seg(display, x, y, 8, 7, 10, 10, color);
1032+
seg(display, x, y, 10, 10, 8, 14, color);
1033+
seg(display, x, y, 8, 14, 1, 14, color);
1034+
}
1035+
'6' => {
1036+
seg(display, x, y, 9, 1, 3, 1, color);
1037+
seg(display, x, y, 3, 1, 1, 5, color);
1038+
seg(display, x, y, 1, 5, 1, 11, color);
1039+
seg(display, x, y, 1, 11, 3, 14, color);
1040+
seg(display, x, y, 3, 14, 8, 14, color);
1041+
seg(display, x, y, 8, 14, 10, 11, color);
1042+
seg(display, x, y, 10, 11, 8, 8, color);
1043+
seg(display, x, y, 8, 8, 1, 8, color);
1044+
}
1045+
'7' => {
1046+
seg(display, x, y, 1, 1, 10, 1, color);
1047+
seg(display, x, y, 10, 1, 4, 14, color);
1048+
}
1049+
'8' => {
1050+
seg(display, x, y, 3, 0, 8, 0, color);
1051+
seg(display, x, y, 8, 0, 10, 3, color);
1052+
seg(display, x, y, 10, 3, 8, 7, color);
1053+
seg(display, x, y, 8, 7, 10, 11, color);
1054+
seg(display, x, y, 10, 11, 8, 14, color);
1055+
seg(display, x, y, 8, 14, 3, 14, color);
1056+
seg(display, x, y, 3, 14, 1, 11, color);
1057+
seg(display, x, y, 1, 11, 3, 7, color);
1058+
seg(display, x, y, 3, 7, 1, 3, color);
1059+
seg(display, x, y, 1, 3, 3, 0, color);
1060+
seg(display, x, y, 3, 7, 8, 7, color);
1061+
}
1062+
'9' => {
1063+
seg(display, x, y, 8, 14, 10, 10, color);
1064+
seg(display, x, y, 10, 10, 10, 3, color);
1065+
seg(display, x, y, 10, 3, 8, 0, color);
1066+
seg(display, x, y, 8, 0, 3, 0, color);
1067+
seg(display, x, y, 3, 0, 1, 3, color);
1068+
seg(display, x, y, 1, 3, 3, 7, color);
1069+
seg(display, x, y, 3, 7, 10, 7, color);
1070+
}
1071+
'?' => {
1072+
seg(display, x, y, 2, 2, 5, 0, color);
1073+
seg(display, x, y, 5, 0, 9, 2, color);
1074+
seg(display, x, y, 9, 2, 9, 5, color);
1075+
seg(display, x, y, 9, 5, 5, 8, color);
1076+
dot(display, x, y, 5, 13, color);
1077+
}
1078+
_ => {}
1079+
}
1080+
}
1081+
1082+
fn seg<D: DrawTarget<Color = Rgb565>>(
1083+
display: &mut D,
1084+
x: i32,
1085+
y: i32,
1086+
x0: i32,
1087+
y0: i32,
1088+
x1: i32,
1089+
y1: i32,
1090+
color: Rgb565,
1091+
) {
1092+
let p0 = Point::new(x + x0 * LAYER_TITLE_W / 10, y + y0 * LAYER_TITLE_H / 14);
1093+
let p1 = Point::new(x + x1 * LAYER_TITLE_W / 10, y + y1 * LAYER_TITLE_H / 14);
1094+
let _ = Line::new(p0, p1)
1095+
.into_styled(PrimitiveStyle::with_stroke(color, LAYER_TITLE_STROKE))
1096+
.draw(display);
1097+
}
1098+
1099+
fn dot<D: DrawTarget<Color = Rgb565>>(
1100+
display: &mut D,
1101+
x: i32,
1102+
y: i32,
1103+
cx: i32,
1104+
cy: i32,
1105+
color: Rgb565,
1106+
) {
1107+
let p = Point::new(
1108+
x + cx * LAYER_TITLE_W / 10 - 1,
1109+
y + cy * LAYER_TITLE_H / 14 - 1,
1110+
);
1111+
let _ = Rectangle::new(Point::new(p.x, p.y), Size::new(3, 3))
1112+
.into_styled(PrimitiveStyle::with_fill(color))
1113+
.draw(display);
1114+
}
1115+
8491116
#[derive(Clone, Copy)]
8501117
enum BatReading {
8511118
Unknown,

0 commit comments

Comments
 (0)