diff --git a/src/helpers/ui/LemonFont.h b/src/helpers/ui/LemonFont.h new file mode 100644 index 00000000..d793bea4 --- /dev/null +++ b/src/helpers/ui/LemonFont.h @@ -0,0 +1,444 @@ +// Lemon font, converted from lemon.bdf +// Range: U+0020–U+017F (352 glyphs) +// Generated by bdf2adafruit.py +#pragma once +#include + +static const uint8_t lemonBitmaps[] PROGMEM = { + 0xF4, 0xB6, 0x80, 0x56, 0xD5, 0xB5, 0x00, 0x27, 0x86, 0x1E, 0x20, 0xCD, 0x24, 0xB3, 0x45, 0x11, + 0x59, 0x34, 0xE0, 0x2A, 0x49, 0x11, 0x88, 0x92, 0x54, 0x96, 0xF6, 0x90, 0x21, 0x3E, 0x42, 0x00, + 0x58, 0xF0, 0xC0, 0x11, 0x22, 0x44, 0x88, 0x69, 0xDB, 0x96, 0x75, 0x50, 0xE1, 0x16, 0x8F, 0xE1, + 0x61, 0x1E, 0x99, 0x97, 0x11, 0xF8, 0xE1, 0x1E, 0x68, 0xE9, 0x96, 0xF1, 0x22, 0x44, 0x69, 0x69, + 0x96, 0x69, 0x97, 0x16, 0xD8, 0x51, 0x60, 0x2A, 0x22, 0xE3, 0x80, 0x88, 0xA8, 0xF4, 0xA0, 0x80, + 0x69, 0xBB, 0x87, 0x69, 0x9F, 0x99, 0xE9, 0xE9, 0x9E, 0x78, 0x88, 0x87, 0xE9, 0x99, 0x9E, 0xF8, + 0xE8, 0x8F, 0xF8, 0xE8, 0x88, 0x78, 0x8B, 0x97, 0x99, 0xF9, 0x99, 0xE9, 0x25, 0xC0, 0x71, 0x11, + 0x96, 0x9A, 0xCA, 0x99, 0x88, 0x88, 0x8F, 0x9F, 0xF9, 0x99, 0x9D, 0xDB, 0xB9, 0x69, 0x99, 0x96, + 0xE9, 0x9E, 0x88, 0x69, 0x99, 0x96, 0x30, 0xE9, 0x9E, 0x99, 0x78, 0x61, 0x1E, 0xF9, 0x08, 0x42, + 0x10, 0x99, 0x99, 0x97, 0x99, 0x96, 0x66, 0x99, 0x9F, 0xF9, 0x99, 0x69, 0x99, 0x8A, 0x88, 0x42, + 0x10, 0xF1, 0x24, 0x8F, 0xF2, 0x49, 0x27, 0x88, 0x44, 0x22, 0x11, 0xE4, 0x92, 0x4F, 0x22, 0xA2, + 0xF0, 0xA4, 0x79, 0x9B, 0x50, 0x88, 0xE9, 0x99, 0xE0, 0x78, 0x88, 0x70, 0x11, 0x79, 0x9B, 0x50, + 0x69, 0xF8, 0x70, 0x73, 0xC9, 0x20, 0x79, 0x9B, 0x51, 0x60, 0x88, 0xE9, 0x99, 0x90, 0x4D, 0x54, + 0x21, 0x92, 0x49, 0xC0, 0x88, 0x9A, 0xE9, 0x90, 0xD5, 0x54, 0x9F, 0xB9, 0x90, 0xE9, 0x99, 0x90, + 0x69, 0x99, 0x60, 0xE9, 0x99, 0xE8, 0x80, 0x79, 0x99, 0x71, 0x10, 0xBC, 0x88, 0x80, 0x78, 0x61, + 0xE0, 0x5D, 0x24, 0x40, 0x99, 0x99, 0x70, 0x99, 0x96, 0x60, 0x99, 0x9F, 0x90, 0x99, 0x69, 0x90, + 0x99, 0x99, 0x71, 0x60, 0xF2, 0x48, 0xF0, 0x29, 0x6C, 0x91, 0xFF, 0x89, 0x36, 0x94, 0x45, 0x6A, + 0x20, 0x6F, 0xF6, 0xBC, 0x17, 0xAA, 0xA7, 0x40, 0x32, 0x11, 0xC4, 0x27, 0xC0, 0x8B, 0x94, 0xA7, + 0x44, 0x8A, 0x88, 0xE2, 0x38, 0x80, 0xEE, 0x34, 0x69, 0x96, 0x2C, 0xA0, 0x7A, 0x1B, 0x69, 0xB6, + 0x17, 0x80, 0x79, 0x97, 0x5A, 0x50, 0xF8, 0x42, 0xE0, 0x7A, 0x1B, 0xED, 0xAE, 0x17, 0x80, 0xE0, + 0x55, 0x00, 0x27, 0x20, 0x70, 0xC5, 0x4E, 0xC7, 0x1C, 0x60, 0x99, 0x99, 0xE8, 0x7D, 0x6A, 0xD2, + 0x94, 0xF0, 0x47, 0x80, 0x75, 0x69, 0x96, 0xA2, 0xA8, 0x46, 0x10, 0xA3, 0x29, 0xE2, 0x46, 0x10, + 0xE0, 0x88, 0xE0, 0xC0, 0x84, 0x0A, 0xD8, 0xA3, 0xC2, 0x41, 0x4B, 0xC0, 0x42, 0x69, 0x9F, 0x99, + 0x24, 0x69, 0x9F, 0x99, 0x25, 0x06, 0x99, 0xF9, 0x90, 0x5A, 0x69, 0x9F, 0x99, 0x48, 0x0C, 0x94, + 0xBD, 0x29, 0x69, 0x69, 0x9F, 0x99, 0x7E, 0x49, 0xBC, 0x92, 0x70, 0x78, 0x88, 0x87, 0x24, 0x42, + 0xF8, 0xE8, 0x8F, 0x24, 0xF8, 0xE8, 0x8F, 0x4A, 0xF8, 0xE8, 0x8F, 0xA0, 0xF8, 0xE8, 0x8F, 0x88, + 0x74, 0x92, 0xE0, 0x28, 0x74, 0x92, 0xE0, 0x54, 0x74, 0x92, 0xE0, 0xA3, 0xA4, 0x97, 0x72, 0x7A, + 0x94, 0xB8, 0x2A, 0x80, 0xE4, 0xA5, 0x29, 0x84, 0x06, 0x99, 0x96, 0x24, 0x06, 0x99, 0x96, 0x4A, + 0x06, 0x99, 0x96, 0x5A, 0x06, 0x99, 0x96, 0x48, 0x0C, 0x94, 0xA4, 0xC0, 0xAA, 0x80, 0x35, 0x65, + 0x9A, 0x6A, 0xC0, 0x84, 0x99, 0x99, 0x97, 0x12, 0x99, 0x99, 0x97, 0x25, 0x09, 0x99, 0x99, 0x70, + 0x50, 0x99, 0x99, 0x97, 0x11, 0x22, 0xA2, 0x10, 0x84, 0x88, 0xE9, 0x9E, 0x80, 0x69, 0xA9, 0x9A, + 0x80, 0x84, 0x07, 0x99, 0xB5, 0x24, 0x07, 0x99, 0xB5, 0x4A, 0x07, 0x99, 0xB5, 0x5A, 0x07, 0x99, + 0xB5, 0x90, 0x79, 0x9B, 0x50, 0x20, 0x79, 0x9B, 0x50, 0x75, 0x6F, 0x45, 0x80, 0x78, 0x88, 0x72, + 0x40, 0x84, 0x06, 0x9F, 0x87, 0x24, 0x06, 0x9F, 0x87, 0x4A, 0x06, 0x9F, 0x87, 0xA0, 0x69, 0xF8, + 0x70, 0x93, 0x55, 0x28, 0x64, 0x92, 0x54, 0x64, 0x92, 0xA3, 0x24, 0x90, 0xA6, 0x97, 0x99, 0x96, + 0x5A, 0x0E, 0x99, 0x99, 0x41, 0x00, 0x64, 0xA5, 0x26, 0x12, 0x06, 0x99, 0x96, 0x4A, 0x06, 0x99, + 0x96, 0x5A, 0x06, 0x99, 0x96, 0x90, 0x69, 0x99, 0x60, 0x20, 0x3E, 0x02, 0x00, 0x35, 0x67, 0x9A, + 0xB0, 0x84, 0x09, 0x99, 0x97, 0x11, 0x00, 0x94, 0xA5, 0x27, 0x4A, 0x09, 0x99, 0x97, 0x50, 0x12, + 0x94, 0xA4, 0xE0, 0x24, 0x09, 0x99, 0x97, 0x16, 0x88, 0xE9, 0x99, 0xE8, 0x80, 0x50, 0x99, 0x99, + 0x71, 0x60, 0xF0, 0x69, 0x9F, 0x99, 0xF0, 0x79, 0x9B, 0x50, 0x96, 0x06, 0x99, 0xF9, 0x90, 0x96, + 0x07, 0x99, 0xB5, 0x64, 0xA5, 0xE9, 0x48, 0x20, 0x74, 0xA5, 0x65, 0x04, 0x24, 0x07, 0x88, 0x88, + 0x70, 0x24, 0x07, 0x88, 0x87, 0x25, 0x07, 0x88, 0x88, 0x70, 0x25, 0x07, 0x88, 0x87, 0x20, 0x78, + 0x88, 0x87, 0x20, 0x78, 0x88, 0x70, 0x52, 0x07, 0x88, 0x88, 0x70, 0x52, 0x07, 0x88, 0x87, 0xA4, + 0x0E, 0x99, 0x99, 0xE0, 0x04, 0x51, 0x9C, 0x92, 0x4B, 0x14, 0x72, 0x7A, 0x94, 0xB8, 0x38, 0x9D, + 0x29, 0x59, 0x40, 0x60, 0xF8, 0xE8, 0x8F, 0xF0, 0x69, 0xF8, 0x70, 0x96, 0x0F, 0x8E, 0x88, 0xF0, + 0x96, 0x06, 0x9F, 0x87, 0x40, 0xF8, 0xE8, 0x8F, 0x40, 0x69, 0xF8, 0x70, 0xF4, 0x39, 0x08, 0x78, + 0x20, 0x69, 0xF8, 0x61, 0xA4, 0x0F, 0x8E, 0x88, 0xF0, 0xA4, 0x06, 0x9F, 0x87, 0x25, 0x07, 0x88, + 0xB9, 0x70, 0x25, 0x07, 0x99, 0xB5, 0x16, 0x96, 0x07, 0x88, 0xB9, 0x70, 0x96, 0x07, 0x99, 0xB5, + 0x16, 0x20, 0x78, 0x8B, 0x97, 0x20, 0x79, 0x9B, 0x51, 0x60, 0x78, 0x8B, 0x97, 0x24, 0x24, 0x07, + 0x99, 0xB5, 0x16, 0x25, 0x09, 0x9F, 0x99, 0x90, 0x25, 0x88, 0xE9, 0x99, 0x90, 0xFD, 0x27, 0x92, + 0x49, 0x20, 0xF2, 0x1C, 0x94, 0xA5, 0x20, 0x5A, 0x07, 0x22, 0x22, 0x70, 0x5A, 0x06, 0x22, 0x22, + 0xE3, 0xA4, 0x97, 0xE3, 0x24, 0x90, 0xA8, 0x74, 0x92, 0xE0, 0xA8, 0x64, 0x92, 0xE9, 0x25, 0xE2, + 0x4D, 0x5E, 0x40, 0x43, 0xA4, 0x97, 0xD5, 0x40, 0xFD, 0x14, 0x51, 0x57, 0xA0, 0x48, 0x36, 0x94, + 0xA5, 0x26, 0x25, 0x07, 0x11, 0x19, 0x60, 0x25, 0x06, 0x22, 0x22, 0x2C, 0x9A, 0xCA, 0x99, 0x48, + 0x88, 0x9A, 0xE9, 0x94, 0x80, 0x9A, 0xE9, 0x90, 0x12, 0x88, 0x88, 0x8F, 0x12, 0xC4, 0x44, 0x44, + 0x40, 0x88, 0x88, 0x8F, 0x24, 0x64, 0x92, 0x4A, 0x80, 0x39, 0x88, 0x88, 0xF0, 0x31, 0xC4, 0x44, + 0x44, 0x42, 0x88, 0x8A, 0x8F, 0xC4, 0x44, 0x54, 0x40, 0x8A, 0xC8, 0x8F, 0xC9, 0x3C, 0x90, 0x24, + 0x09, 0xDD, 0xBB, 0x90, 0x24, 0x0E, 0x99, 0x99, 0x9D, 0xDB, 0xBD, 0x48, 0x24, 0x0E, 0x99, 0x9D, + 0x48, 0x52, 0x9D, 0xDB, 0xB9, 0x52, 0x0E, 0x99, 0x99, 0x88, 0x0E, 0x99, 0x99, 0x9D, 0xDB, 0xB9, + 0x16, 0x24, 0x0E, 0x99, 0x99, 0x16, 0xF0, 0x69, 0x99, 0x96, 0xF0, 0x69, 0x99, 0x60, 0x96, 0x06, + 0x99, 0x99, 0x60, 0x96, 0x06, 0x99, 0x96, 0x5A, 0x06, 0x99, 0x99, 0x60, 0x5A, 0x06, 0x99, 0x96, + 0x7E, 0x49, 0xA4, 0x91, 0xF0, 0x75, 0x6F, 0x47, 0x80, 0x24, 0xE9, 0x9E, 0x99, 0x24, 0x0B, 0xC8, + 0x88, 0xE9, 0x9E, 0x99, 0x48, 0xBC, 0x88, 0x84, 0x80, 0xA4, 0xE9, 0x9E, 0x99, 0xA4, 0x0B, 0xC8, + 0x88, 0x24, 0x07, 0x86, 0x11, 0xE0, 0x24, 0x07, 0x86, 0x1E, 0x25, 0x07, 0x86, 0x11, 0xE0, 0x25, + 0x07, 0x86, 0x1E, 0x78, 0x61, 0x1E, 0x22, 0x78, 0x61, 0xE2, 0x20, 0x52, 0x07, 0x86, 0x11, 0xE0, + 0x52, 0x07, 0x86, 0x1E, 0xF9, 0x08, 0x42, 0x11, 0x00, 0x5D, 0x24, 0x50, 0x51, 0x01, 0xF2, 0x10, + 0x84, 0x20, 0x31, 0x4E, 0x44, 0x42, 0xF9, 0x08, 0xE2, 0x10, 0x5D, 0x74, 0x40, 0x5A, 0x09, 0x99, + 0x99, 0x70, 0x5A, 0x09, 0x99, 0x97, 0xF0, 0x99, 0x99, 0x97, 0xF0, 0x99, 0x99, 0x70, 0x96, 0x09, + 0x99, 0x99, 0x70, 0x96, 0x09, 0x99, 0x97, 0x25, 0x29, 0x99, 0x99, 0x70, 0x25, 0x29, 0x99, 0x97, + 0x4C, 0x81, 0x29, 0x4A, 0x52, 0x70, 0x4C, 0x81, 0x29, 0x4A, 0x4E, 0x99, 0x99, 0x97, 0x42, 0x99, + 0x99, 0x74, 0x20, 0x25, 0x09, 0x99, 0x9F, 0x90, 0x25, 0x09, 0x99, 0xF9, 0x22, 0x81, 0x15, 0x10, + 0x84, 0x20, 0x25, 0x09, 0x99, 0x97, 0x16, 0x50, 0x22, 0xA2, 0x10, 0x84, 0x24, 0x0F, 0x12, 0x48, + 0xF0, 0x24, 0x0F, 0x24, 0x8F, 0x20, 0xF1, 0x24, 0x8F, 0x20, 0xF2, 0x48, 0xF0, 0x52, 0x0F, 0x12, + 0x48, 0xF0, 0x52, 0x0F, 0x24, 0x8F, 0x34, 0xC4, 0x44, 0x40, +}; + +static const GFXglyph lemonGlyphs[] PROGMEM = { + { 0, 0, 0, 5, 0, 0 }, // U+0020 + { 0, 1, 6, 5, 2, -6 }, // U+0021 + { 1, 3, 3, 5, 1, -7 }, // U+0022 + { 3, 5, 5, 5, 0, -5 }, // U+0023 + { 7, 4, 7, 5, 1, -7 }, // U+0024 + { 11, 4, 6, 5, 1, -6 }, // U+0025 + { 14, 5, 6, 5, 0, -6 }, // U+0026 + { 18, 1, 3, 5, 2, -7 }, // U+0027 + { 19, 3, 8, 5, 2, -7 }, // U+0028 + { 22, 3, 8, 5, 2, -7 }, // U+0029 + { 25, 4, 5, 5, 1, -5 }, // U+002A + { 28, 5, 5, 5, 0, -6 }, // U+002B + { 32, 2, 3, 5, 1, -2 }, // U+002C + { 33, 4, 1, 5, 1, -4 }, // U+002D + { 34, 1, 2, 5, 2, -2 }, // U+002E + { 35, 4, 8, 5, 1, -7 }, // U+002F + { 39, 4, 6, 5, 1, -6 }, // U+0030 + { 42, 2, 6, 5, 1, -6 }, // U+0031 + { 44, 4, 6, 5, 1, -6 }, // U+0032 + { 47, 4, 6, 5, 1, -6 }, // U+0033 + { 50, 4, 6, 5, 1, -6 }, // U+0034 + { 53, 4, 6, 5, 1, -6 }, // U+0035 + { 56, 4, 6, 5, 1, -6 }, // U+0036 + { 59, 4, 6, 5, 1, -6 }, // U+0037 + { 62, 4, 6, 5, 1, -6 }, // U+0038 + { 65, 4, 6, 5, 1, -6 }, // U+0039 + { 68, 1, 5, 5, 2, -5 }, // U+003A + { 69, 2, 6, 5, 1, -5 }, // U+003B + { 71, 3, 5, 5, 1, -5 }, // U+003C + { 73, 3, 3, 5, 1, -5 }, // U+003D + { 75, 3, 5, 5, 2, -5 }, // U+003E + { 77, 3, 6, 5, 1, -6 }, // U+003F + { 80, 4, 6, 5, 1, -6 }, // U+0040 + { 83, 4, 6, 5, 1, -6 }, // U+0041 + { 86, 4, 6, 5, 1, -6 }, // U+0042 + { 89, 4, 6, 5, 1, -6 }, // U+0043 + { 92, 4, 6, 5, 1, -6 }, // U+0044 + { 95, 4, 6, 5, 1, -6 }, // U+0045 + { 98, 4, 6, 5, 1, -6 }, // U+0046 + { 101, 4, 6, 5, 1, -6 }, // U+0047 + { 104, 4, 6, 5, 1, -6 }, // U+0048 + { 107, 3, 6, 5, 1, -6 }, // U+0049 + { 110, 4, 6, 5, 1, -6 }, // U+004A + { 113, 4, 6, 5, 1, -6 }, // U+004B + { 116, 4, 6, 5, 1, -6 }, // U+004C + { 119, 4, 6, 5, 1, -6 }, // U+004D + { 122, 4, 6, 5, 1, -6 }, // U+004E + { 125, 4, 6, 5, 1, -6 }, // U+004F + { 128, 4, 6, 5, 1, -6 }, // U+0050 + { 131, 4, 7, 5, 1, -6 }, // U+0051 + { 135, 4, 6, 5, 1, -6 }, // U+0052 + { 138, 4, 6, 5, 1, -6 }, // U+0053 + { 141, 5, 6, 5, 0, -6 }, // U+0054 + { 145, 4, 6, 5, 1, -6 }, // U+0055 + { 148, 4, 6, 5, 1, -6 }, // U+0056 + { 151, 4, 6, 5, 1, -6 }, // U+0057 + { 154, 4, 6, 5, 1, -6 }, // U+0058 + { 157, 5, 6, 5, 0, -6 }, // U+0059 + { 161, 4, 6, 5, 1, -6 }, // U+005A + { 164, 3, 8, 5, 1, -7 }, // U+005B + { 167, 4, 8, 5, 1, -7 }, // U+005C + { 171, 3, 8, 5, 1, -7 }, // U+005D + { 174, 5, 3, 5, 0, -7 }, // U+005E + { 176, 4, 1, 5, 1, 0 }, // U+005F + { 177, 2, 3, 5, 2, -7 }, // U+0060 + { 178, 4, 5, 5, 1, -5 }, // U+0061 + { 181, 4, 7, 5, 1, -7 }, // U+0062 + { 185, 4, 5, 5, 1, -5 }, // U+0063 + { 188, 4, 7, 5, 1, -7 }, // U+0064 + { 192, 4, 5, 5, 1, -5 }, // U+0065 + { 195, 3, 7, 5, 2, -7 }, // U+0066 + { 198, 4, 7, 5, 1, -5 }, // U+0067 + { 202, 4, 7, 5, 1, -7 }, // U+0068 + { 206, 2, 7, 5, 2, -7 }, // U+0069 + { 208, 3, 9, 5, 1, -7 }, // U+006A + { 212, 4, 7, 5, 1, -7 }, // U+006B + { 216, 2, 7, 5, 2, -7 }, // U+006C + { 218, 4, 5, 5, 1, -5 }, // U+006D + { 221, 4, 5, 5, 1, -5 }, // U+006E + { 224, 4, 5, 5, 1, -5 }, // U+006F + { 227, 4, 7, 5, 1, -5 }, // U+0070 + { 231, 4, 7, 5, 1, -5 }, // U+0071 + { 235, 4, 5, 5, 1, -5 }, // U+0072 + { 238, 4, 5, 5, 1, -5 }, // U+0073 + { 241, 3, 6, 5, 1, -6 }, // U+0074 + { 244, 4, 5, 5, 1, -5 }, // U+0075 + { 247, 4, 5, 5, 1, -5 }, // U+0076 + { 250, 4, 5, 5, 1, -5 }, // U+0077 + { 253, 4, 5, 5, 1, -5 }, // U+0078 + { 256, 4, 7, 5, 1, -5 }, // U+0079 + { 260, 4, 5, 5, 1, -5 }, // U+007A + { 263, 3, 8, 5, 1, -7 }, // U+007B + { 266, 1, 8, 5, 2, -7 }, // U+007C + { 267, 3, 8, 5, 2, -7 }, // U+007D + { 270, 5, 4, 5, 0, -5 }, // U+007E + { 273, 0, 0, 1, 0, 0 }, // U+007F + { 273, 0, 0, 1, 0, 0 }, // U+0080 + { 273, 0, 0, 1, 0, 0 }, // U+0081 + { 273, 0, 0, 1, 0, 0 }, // U+0082 + { 273, 0, 0, 1, 0, 0 }, // U+0083 + { 273, 0, 0, 1, 0, 0 }, // U+0084 + { 273, 0, 0, 1, 0, 0 }, // U+0085 + { 273, 0, 0, 1, 0, 0 }, // U+0086 + { 273, 0, 0, 1, 0, 0 }, // U+0087 + { 273, 0, 0, 1, 0, 0 }, // U+0088 + { 273, 0, 0, 1, 0, 0 }, // U+0089 + { 273, 0, 0, 1, 0, 0 }, // U+008A + { 273, 0, 0, 1, 0, 0 }, // U+008B + { 273, 0, 0, 1, 0, 0 }, // U+008C + { 273, 0, 0, 1, 0, 0 }, // U+008D + { 273, 0, 0, 1, 0, 0 }, // U+008E + { 273, 0, 0, 1, 0, 0 }, // U+008F + { 273, 0, 0, 1, 0, 0 }, // U+0090 + { 273, 0, 0, 1, 0, 0 }, // U+0091 + { 273, 0, 0, 1, 0, 0 }, // U+0092 + { 273, 0, 0, 1, 0, 0 }, // U+0093 + { 273, 0, 0, 1, 0, 0 }, // U+0094 + { 273, 4, 4, 5, 1, -4 }, // U+0095 + { 275, 0, 0, 1, 0, 0 }, // U+0096 + { 275, 0, 0, 1, 0, 0 }, // U+0097 + { 275, 0, 0, 1, 0, 0 }, // U+0098 + { 275, 0, 0, 1, 0, 0 }, // U+0099 + { 275, 0, 0, 1, 0, 0 }, // U+009A + { 275, 0, 0, 1, 0, 0 }, // U+009B + { 275, 0, 0, 1, 0, 0 }, // U+009C + { 275, 0, 0, 1, 0, 0 }, // U+009D + { 275, 0, 0, 1, 0, 0 }, // U+009E + { 275, 0, 0, 1, 0, 0 }, // U+009F + { 275, 0, 0, 1, 0, 0 }, // U+00A0 + { 275, 1, 6, 5, 2, -6 }, // U+00A1 + { 276, 4, 7, 5, 0, -6 }, // U+00A2 + { 280, 5, 7, 5, 0, -7 }, // U+00A3 + { 285, 5, 6, 5, 0, -6 }, // U+00A4 + { 289, 5, 7, 5, 0, -7 }, // U+00A5 + { 294, 1, 7, 5, 2, -6 }, // U+00A6 + { 295, 4, 8, 5, 0, -7 }, // U+00A7 + { 299, 3, 1, 5, 1, -6 }, // U+00A8 + { 300, 6, 7, 5, 0, -7 }, // U+00A9 + { 306, 4, 4, 5, 1, -6 }, // U+00AA + { 308, 4, 3, 5, 1, -5 }, // U+00AB + { 310, 5, 3, 5, 0, -4 }, // U+00AC + { 312, 3, 1, 5, 1, -3 }, // U+00AD + { 313, 6, 7, 5, 0, -7 }, // U+00AE + { 319, 4, 1, 5, 1, -7 }, // U+00AF + { 320, 3, 3, 5, 1, -6 }, // U+00B0 + { 322, 4, 5, 5, 0, -5 }, // U+00B1 + { 325, 3, 5, 5, 1, -7 }, // U+00B2 + { 327, 3, 5, 5, 1, -7 }, // U+00B3 + { 329, 2, 2, 5, 1, -8 }, // U+00B4 + { 330, 4, 6, 5, 1, -5 }, // U+00B5 + { 333, 5, 6, 5, 0, -6 }, // U+00B6 + { 337, 2, 2, 5, 2, -4 }, // U+00B7 + { 338, 3, 3, 5, 1, -4 }, // U+00B8 + { 340, 2, 4, 5, 1, -6 }, // U+00B9 + { 341, 4, 4, 5, 0, -8 }, // U+00BA + { 343, 5, 3, 5, 1, -5 }, // U+00BB + { 345, 5, 8, 5, 1, -8 }, // U+00BC + { 350, 5, 7, 5, 1, -8 }, // U+00BD + { 355, 6, 8, 5, 0, -8 }, // U+00BE + { 361, 3, 6, 5, 2, -6 }, // U+00BF + { 364, 4, 8, 5, 1, -8 }, // U+00C0 + { 368, 4, 8, 5, 1, -8 }, // U+00C1 + { 372, 4, 9, 5, 1, -9 }, // U+00C2 + { 377, 4, 8, 5, 1, -8 }, // U+00C3 + { 381, 5, 8, 5, 0, -8 }, // U+00C4 + { 386, 4, 8, 5, 1, -8 }, // U+00C5 + { 390, 6, 6, 5, 0, -6 }, // U+00C6 + { 395, 4, 8, 5, 0, -6 }, // U+00C7 + { 399, 4, 8, 5, 1, -8 }, // U+00C8 + { 403, 4, 8, 5, 1, -8 }, // U+00C9 + { 407, 4, 8, 5, 1, -8 }, // U+00CA + { 411, 4, 8, 5, 1, -8 }, // U+00CB + { 415, 3, 9, 5, 1, -9 }, // U+00CC + { 419, 3, 9, 5, 1, -9 }, // U+00CD + { 423, 3, 9, 5, 1, -9 }, // U+00CE + { 427, 3, 8, 5, 1, -8 }, // U+00CF + { 430, 5, 6, 5, 0, -6 }, // U+00D0 + { 434, 5, 8, 5, 0, -8 }, // U+00D1 + { 439, 4, 8, 5, 1, -8 }, // U+00D2 + { 443, 4, 8, 5, 1, -8 }, // U+00D3 + { 447, 4, 8, 5, 1, -8 }, // U+00D4 + { 451, 4, 8, 5, 1, -8 }, // U+00D5 + { 455, 5, 7, 5, 0, -7 }, // U+00D6 + { 460, 3, 3, 5, 1, -5 }, // U+00D7 + { 462, 6, 6, 5, 0, -6 }, // U+00D8 + { 467, 4, 8, 5, 1, -8 }, // U+00D9 + { 471, 4, 8, 5, 1, -8 }, // U+00DA + { 475, 4, 9, 5, 1, -9 }, // U+00DB + { 480, 4, 8, 5, 1, -8 }, // U+00DC + { 484, 5, 8, 5, 0, -8 }, // U+00DD + { 489, 4, 7, 5, 1, -6 }, // U+00DE + { 493, 4, 7, 5, 1, -6 }, // U+00DF + { 497, 4, 8, 5, 1, -8 }, // U+00E0 + { 501, 4, 8, 5, 1, -8 }, // U+00E1 + { 505, 4, 8, 5, 1, -8 }, // U+00E2 + { 509, 4, 8, 5, 1, -8 }, // U+00E3 + { 513, 4, 7, 5, 1, -7 }, // U+00E4 + { 517, 4, 7, 5, 1, -7 }, // U+00E5 + { 521, 5, 5, 5, 1, -5 }, // U+00E6 + { 525, 4, 7, 5, 1, -5 }, // U+00E7 + { 529, 4, 8, 5, 1, -8 }, // U+00E8 + { 533, 4, 8, 5, 1, -8 }, // U+00E9 + { 537, 4, 8, 5, 1, -8 }, // U+00EA + { 541, 4, 7, 5, 1, -7 }, // U+00EB + { 545, 2, 8, 5, 2, -8 }, // U+00EC + { 547, 3, 8, 5, 2, -8 }, // U+00ED + { 550, 3, 8, 5, 2, -8 }, // U+00EE + { 553, 3, 7, 5, 2, -7 }, // U+00EF + { 556, 4, 8, 5, 1, -8 }, // U+00F0 + { 560, 4, 8, 5, 1, -8 }, // U+00F1 + { 564, 5, 8, 5, 0, -8 }, // U+00F2 + { 569, 4, 8, 5, 1, -8 }, // U+00F3 + { 573, 4, 8, 5, 1, -8 }, // U+00F4 + { 577, 4, 8, 5, 1, -8 }, // U+00F5 + { 581, 4, 7, 5, 1, -7 }, // U+00F6 + { 585, 5, 5, 5, 0, -6 }, // U+00F7 + { 589, 6, 5, 5, 0, -5 }, // U+00F8 + { 593, 4, 8, 5, 1, -8 }, // U+00F9 + { 597, 5, 8, 5, 0, -8 }, // U+00FA + { 602, 4, 8, 5, 1, -8 }, // U+00FB + { 606, 5, 7, 5, 0, -7 }, // U+00FC + { 611, 4, 10, 5, 1, -8 }, // U+00FD + { 616, 4, 9, 5, 1, -7 }, // U+00FE + { 621, 4, 9, 5, 1, -7 }, // U+00FF + { 626, 4, 8, 5, 1, -8 }, // U+0100 + { 630, 4, 7, 5, 1, -7 }, // U+0101 + { 634, 4, 9, 5, 1, -9 }, // U+0102 + { 639, 4, 8, 5, 1, -8 }, // U+0103 + { 643, 5, 7, 5, 1, -6 }, // U+0104 + { 648, 5, 6, 5, 1, -5 }, // U+0105 + { 652, 4, 9, 5, 1, -9 }, // U+0106 + { 657, 4, 8, 5, 1, -8 }, // U+0107 + { 661, 4, 9, 5, 1, -9 }, // U+0108 + { 666, 4, 8, 5, 1, -8 }, // U+0109 + { 670, 4, 8, 5, 1, -8 }, // U+010A + { 674, 4, 7, 5, 1, -7 }, // U+010B + { 678, 4, 9, 5, 1, -9 }, // U+010C + { 683, 4, 8, 5, 1, -8 }, // U+010D + { 687, 4, 9, 5, 1, -9 }, // U+010E + { 692, 6, 8, 5, 1, -8 }, // U+010F + { 698, 5, 6, 5, 0, -6 }, // U+0110 + { 702, 5, 7, 5, 1, -7 }, // U+0111 + { 707, 4, 8, 5, 1, -8 }, // U+0112 + { 711, 4, 7, 5, 1, -7 }, // U+0113 + { 715, 4, 9, 5, 1, -9 }, // U+0114 + { 720, 4, 8, 5, 1, -8 }, // U+0115 + { 724, 4, 8, 5, 1, -8 }, // U+0116 + { 728, 4, 7, 5, 1, -7 }, // U+0117 + { 732, 5, 7, 5, 1, -6 }, // U+0118 + { 737, 4, 6, 5, 1, -5 }, // U+0119 + { 740, 4, 9, 5, 1, -9 }, // U+011A + { 745, 4, 8, 5, 1, -8 }, // U+011B + { 749, 4, 9, 5, 1, -9 }, // U+011C + { 754, 4, 10, 5, 1, -8 }, // U+011D + { 759, 4, 9, 5, 1, -9 }, // U+011E + { 764, 4, 10, 5, 1, -8 }, // U+011F + { 769, 4, 8, 5, 1, -8 }, // U+0120 + { 773, 4, 9, 5, 1, -7 }, // U+0121 + { 778, 4, 8, 5, 1, -6 }, // U+0122 + { 782, 4, 10, 5, 1, -8 }, // U+0123 + { 787, 4, 9, 5, 1, -9 }, // U+0124 + { 792, 4, 9, 5, 1, -9 }, // U+0125 + { 797, 6, 6, 5, 0, -6 }, // U+0126 + { 802, 5, 7, 5, 0, -7 }, // U+0127 + { 807, 4, 9, 5, 0, -9 }, // U+0128 + { 812, 4, 8, 5, 1, -8 }, // U+0129 + { 816, 3, 8, 5, 1, -8 }, // U+012A + { 819, 3, 7, 5, 2, -7 }, // U+012B + { 822, 3, 9, 5, 1, -9 }, // U+012C + { 826, 3, 8, 5, 2, -8 }, // U+012D + { 829, 3, 8, 5, 1, -6 }, // U+012E + { 832, 2, 9, 5, 2, -7 }, // U+012F + { 835, 3, 8, 5, 1, -8 }, // U+0130 + { 838, 2, 5, 5, 2, -5 }, // U+0131 + { 840, 6, 6, 5, 1, -6 }, // U+0132 + { 845, 5, 8, 5, 1, -7 }, // U+0133 + { 850, 4, 9, 5, 1, -9 }, // U+0134 + { 855, 4, 10, 5, 1, -8 }, // U+0135 + { 860, 4, 8, 5, 1, -6 }, // U+0136 + { 864, 4, 9, 5, 1, -7 }, // U+0137 + { 869, 4, 5, 5, 1, -5 }, // U+0138 + { 872, 4, 8, 5, 1, -8 }, // U+0139 + { 876, 4, 9, 5, 2, -9 }, // U+013A + { 881, 4, 8, 5, 1, -6 }, // U+013B + { 885, 3, 9, 5, 1, -7 }, // U+013C + { 889, 4, 7, 5, 1, -7 }, // U+013D + { 893, 4, 10, 5, 2, -9 }, // U+013E + { 898, 4, 6, 5, 1, -6 }, // U+013F + { 901, 4, 7, 5, 2, -7 }, // U+0140 + { 905, 4, 6, 5, 1, -6 }, // U+0141 + { 908, 3, 7, 5, 2, -7 }, // U+0142 + { 911, 4, 9, 5, 1, -9 }, // U+0143 + { 916, 4, 8, 5, 1, -8 }, // U+0144 + { 920, 4, 8, 5, 1, -6 }, // U+0145 + { 924, 4, 10, 5, 1, -8 }, // U+0146 + { 929, 4, 8, 5, 1, -8 }, // U+0147 + { 933, 4, 8, 5, 1, -8 }, // U+0148 + { 937, 4, 8, 5, 1, -8 }, // U+0149 + { 941, 4, 8, 5, 1, -6 }, // U+014A + { 945, 4, 10, 5, 1, -8 }, // U+014B + { 950, 4, 8, 5, 1, -8 }, // U+014C + { 954, 4, 7, 5, 1, -7 }, // U+014D + { 958, 4, 9, 5, 1, -9 }, // U+014E + { 963, 4, 8, 5, 1, -8 }, // U+014F + { 967, 4, 9, 5, 1, -9 }, // U+0150 + { 972, 4, 8, 5, 1, -8 }, // U+0151 + { 976, 6, 6, 5, 0, -6 }, // U+0152 + { 981, 5, 5, 5, 1, -5 }, // U+0153 + { 985, 4, 8, 5, 1, -8 }, // U+0154 + { 989, 4, 8, 5, 1, -8 }, // U+0155 + { 993, 4, 8, 5, 1, -6 }, // U+0156 + { 997, 4, 7, 5, 1, -5 }, // U+0157 + { 1001, 4, 8, 5, 1, -8 }, // U+0158 + { 1005, 4, 8, 5, 1, -8 }, // U+0159 + { 1009, 4, 9, 5, 1, -9 }, // U+015A + { 1014, 4, 8, 5, 1, -8 }, // U+015B + { 1018, 4, 9, 5, 1, -9 }, // U+015C + { 1023, 4, 8, 5, 1, -8 }, // U+015D + { 1027, 4, 8, 5, 1, -6 }, // U+015E + { 1031, 4, 7, 5, 1, -5 }, // U+015F + { 1035, 4, 9, 5, 1, -9 }, // U+0160 + { 1040, 4, 8, 5, 1, -8 }, // U+0161 + { 1044, 5, 7, 5, 0, -6 }, // U+0162 + { 1049, 3, 7, 5, 1, -6 }, // U+0163 + { 1052, 5, 9, 5, 0, -9 }, // U+0164 + { 1058, 4, 8, 5, 1, -8 }, // U+0165 + { 1062, 5, 6, 5, 0, -6 }, // U+0166 + { 1066, 3, 6, 5, 1, -6 }, // U+0167 + { 1069, 4, 9, 5, 1, -9 }, // U+0168 + { 1074, 4, 8, 5, 1, -8 }, // U+0169 + { 1078, 4, 8, 5, 1, -8 }, // U+016A + { 1082, 4, 7, 5, 1, -7 }, // U+016B + { 1086, 4, 9, 5, 1, -9 }, // U+016C + { 1091, 4, 8, 5, 1, -8 }, // U+016D + { 1095, 4, 9, 5, 1, -9 }, // U+016E + { 1100, 4, 8, 5, 1, -8 }, // U+016F + { 1104, 5, 9, 5, 1, -9 }, // U+0170 + { 1110, 5, 8, 5, 1, -8 }, // U+0171 + { 1115, 4, 8, 5, 1, -6 }, // U+0172 + { 1119, 4, 7, 5, 1, -5 }, // U+0173 + { 1123, 4, 9, 5, 1, -9 }, // U+0174 + { 1128, 4, 8, 5, 1, -8 }, // U+0175 + { 1132, 5, 9, 5, 0, -9 }, // U+0176 + { 1138, 4, 10, 5, 1, -8 }, // U+0177 + { 1143, 5, 8, 5, 0, -8 }, // U+0178 + { 1148, 4, 9, 5, 1, -9 }, // U+0179 + { 1153, 4, 8, 5, 1, -8 }, // U+017A + { 1157, 4, 8, 5, 1, -8 }, // U+017B + { 1161, 4, 7, 5, 1, -7 }, // U+017C + { 1165, 4, 9, 5, 1, -9 }, // U+017D + { 1170, 4, 8, 5, 1, -8 }, // U+017E + { 1174, 4, 7, 5, 1, -7 }, // U+017F +}; + +static const GFXfont Lemon PROGMEM = { + (uint8_t*)lemonBitmaps, + (GFXglyph*)lemonGlyphs, + 0x0020, 0x017F, + 10 // yAdvance +}; diff --git a/src/helpers/ui/SH1106Display.cpp b/src/helpers/ui/SH1106Display.cpp index 72c8c2a5..97e7966a 100644 --- a/src/helpers/ui/SH1106Display.cpp +++ b/src/helpers/ui/SH1106Display.cpp @@ -1,6 +1,7 @@ #include "SH1106Display.h" #include #include "Adafruit_SH110X.h" +#include "LemonFont.h" bool SH1106Display::i2c_probe(TwoWire &wire, uint8_t addr) { @@ -46,7 +47,14 @@ void SH1106Display::startFrame(Color bkg) void SH1106Display::setTextSize(int sz) { - display.setTextSize(sz); + _text_size = (uint8_t)sz; + if (sz == 1) { + display.setFont(nullptr); // use default font path; we override print() ourselves + display.setTextSize(1); + } else { + display.setFont(nullptr); + display.setTextSize(sz); + } } void SH1106Display::setColor(Color c) @@ -60,9 +68,75 @@ void SH1106Display::setCursor(int x, int y) display.setCursor(x, y); } +// Decode one UTF-8 codepoint from *p, advancing p past it. +uint32_t SH1106Display::decodeUtf8(const uint8_t*& p) { + uint8_t c = *p++; + if (c < 0x80) return c; + if ((c & 0xE0) == 0xC0) { + uint32_t cp = c & 0x1F; + if (*p) cp = (cp << 6) | (*p++ & 0x3F); + return cp; + } + if ((c & 0xF0) == 0xE0) { + uint32_t cp = c & 0x0F; + if (*p) cp = (cp << 6) | (*p++ & 0x3F); + if (*p) cp = (cp << 6) | (*p++ & 0x3F); + return cp; + } + // 4-byte and invalid — skip continuation bytes + while (*p && (*p & 0xC0) == 0x80) p++; + return '?'; +} + +// Draw one Lemon glyph at (x, y), return new cursor x. +int16_t SH1106Display::drawLemonChar(int16_t x, int16_t y, uint32_t cp) { + if (cp < Lemon.first || cp > Lemon.last) { + // outside font range — use default advance + return x + 6; + } + const GFXglyph* glyph = &lemonGlyphs[cp - Lemon.first]; + uint8_t w = pgm_read_byte(&glyph->width); + uint8_t h = pgm_read_byte(&glyph->height); + int8_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); + int8_t yo = (int8_t)pgm_read_byte(&glyph->yOffset); + uint8_t xa = pgm_read_byte(&glyph->xAdvance); + uint16_t bo = pgm_read_word(&glyph->bitmapOffset); + + uint8_t bits = 0, bit = 0; + for (uint8_t row = 0; row < h; row++) { + for (uint8_t col = 0; col < w; col++) { + if (!bit) { bits = pgm_read_byte(&lemonBitmaps[bo++]); bit = 0x80; } + if (bits & bit) + display.drawPixel(x + xo + col, y + yo + row, _color); + bit >>= 1; + } + } + return x + xa; +} + +uint8_t SH1106Display::lemonXAdvance(uint32_t cp) { + if (cp < Lemon.first || cp > Lemon.last) return 6; + const GFXglyph* glyph = &lemonGlyphs[cp - Lemon.first]; + return pgm_read_byte(&glyph->xAdvance); +} + void SH1106Display::print(const char *str) { - display.print(str); + if (_text_size != 1) { display.print(str); return; } + + int16_t cx = display.getCursorX(); + int16_t cy = display.getCursorY(); + const uint8_t* p = (const uint8_t*)str; + while (*p) { + uint32_t cp = decodeUtf8(p); + if (cp == '\n') { + cy += Lemon.yAdvance; + cx = 0; + } else { + cx = drawLemonChar(cx, cy, cp); + } + } + display.setCursor(cx, cy); } void SH1106Display::fillRect(int x, int y, int w, int h) @@ -82,10 +156,15 @@ void SH1106Display::drawXbm(int x, int y, const uint8_t *bits, int w, int h) uint16_t SH1106Display::getTextWidth(const char *str) { - int16_t x1, y1; - uint16_t w, h; - display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h); - return w; + if (_text_size != 1) { + int16_t x1, y1; uint16_t w, h; + display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h); + return w; + } + uint16_t width = 0; + const uint8_t* p = (const uint8_t*)str; + while (*p) width += lemonXAdvance(decodeUtf8(p)); + return width; } void SH1106Display::setBrightness(uint8_t level) diff --git a/src/helpers/ui/SH1106Display.h b/src/helpers/ui/SH1106Display.h index 3855f3d6..e66d8980 100644 --- a/src/helpers/ui/SH1106Display.h +++ b/src/helpers/ui/SH1106Display.h @@ -21,11 +21,15 @@ class SH1106Display : public DisplayDriver uint8_t _color; uint8_t _contrast; uint8_t _precharge; + uint8_t _text_size; bool i2c_probe(TwoWire &wire, uint8_t addr); + static uint32_t decodeUtf8(const uint8_t*& p); + int16_t drawLemonChar(int16_t x, int16_t y, uint32_t cp); + uint8_t lemonXAdvance(uint32_t cp); public: - SH1106Display() : DisplayDriver(128, 64), display(128, 64, &Wire, PIN_OLED_RESET) { _isOn = false; _contrast = 255; _precharge = 0x1F; } + SH1106Display() : DisplayDriver(128, 64), display(128, 64, &Wire, PIN_OLED_RESET) { _isOn = false; _contrast = 255; _precharge = 0x1F; _text_size = 1; } bool begin(); bool isOn() override { return _isOn; } @@ -43,4 +47,12 @@ public: uint16_t getTextWidth(const char *str) override; void setBrightness(uint8_t level) override; void endFrame() override; + + // UTF-8 is handled natively in print() — no substitution needed + void translateUTF8ToBlocks(char* dest, const char* src, size_t dest_size) override { + size_t len = strlen(src); + if (len >= dest_size) len = dest_size - 1; + memcpy(dest, src, len); + dest[len] = '\0'; + } };