diff --git a/lib/charts/BarChart.cpp b/lib/charts/BarChart.cpp index b73f731..485c0a0 100644 --- a/lib/charts/BarChart.cpp +++ b/lib/charts/BarChart.cpp @@ -200,5 +200,21 @@ void DecoratedBarChart::draw() int tick_pos = bar.x2pos(bar.min_x + step * MINOR_TICKS); display.drawVerticalLine(pos_x + tick_pos, y, MINOR_TICK_LENGTH); } + + if (draw_labels) + { // TODO: adjust chart size; for now we'll just assume that we are not ruining + // display + display.setColor(BLACK); + display.fillRect(pos_x, y + MAJOR_TICK_LENGTH, width, + display.getStringWidth("00000")); + display.setColor(WHITE); + for (float step = 1; bar.min_x + step * MAJOR_TICKS < bar.max_x; step += 1) + { + int tick_pos = bar.x2pos(bar.min_x + step * MAJOR_TICKS); + drawVerticalString(display, ArialMT_Plain_10_Vert, pos_x + tick_pos - 5, + y + MAJOR_TICK_LENGTH, + String((int)(bar.min_x + step * MAJOR_TICKS))); + } + } } } diff --git a/lib/charts/Font.cpp b/lib/charts/Font.cpp new file mode 100644 index 0000000..518c6d5 --- /dev/null +++ b/lib/charts/Font.cpp @@ -0,0 +1,147 @@ +#include "charts.h" + +extern const uint8_t ArialMT_Plain_10[]; // borrowed from OLEDDisplayFonts.h + +uint8_t *ArialMT_Plain_10_Vert = NULL; + +uint64_t _horz_line(const uint8_t *font, size_t chr_off, size_t height, size_t bytes, + size_t ln) +{ + size_t raster_height = (height + 7) / 8; + uint8_t b = 1 << (ln & 7); + + uint64_t ret = 0; + uint64_t mask = 1; + for (size_t y = ln / 8; y < bytes; y += raster_height, mask <<= 1) + { + if (font[chr_off + y] & b) + { + ret |= mask; + } + } + + return ret; +} + +uint64_t _flip(uint64_t v, size_t width) +{ + for (uint64_t b = 1, e = 1 << (width - 1); b < e; b <<= 1, e >>= 1) + { + if (!!(v & b) != !!(v & e)) + { + v = v ^ (b | e); + } + } + + return v; +} + +uint8_t *_rot(const uint8_t *font) +{ + size_t sz = 10000; + size_t p = 0; + uint8_t *vert = (uint8_t *)malloc(sz); + + size_t height = font[1]; + vert[0] = (uint8_t)height; // height -> width + vert[1] = font[0]; // width -> height + vert[2] = font[2]; // first char + size_t chars = font[3]; // char count + vert[3] = (uint8_t)chars; + + size_t map_off = chars * 4 + 4; + + for (int i = 0; i < chars; i++) + { + uint32_t v = ((uint32_t *)font)[i + 1]; + size_t chr_off = ((v & 0xff) << 8) | ((v >> 8) & 0xff); + if (chr_off != 0xffff) + { + size_t bs = (v >> 16) & 0xff; + size_t width = (v >> 24) & 0xff; + size_t raster_height = + (width + 7) / 8; // how many bytes needed to store one vertical line + + size_t bytes = height * raster_height; + v = (v & 0xff000000L) | (bytes << 16) | ((p >> 8) & 0xff) | ((p & 0xff) << 8); + + chr_off += map_off; + + if (map_off + p + bytes > sz) + { + uint8_t *vv = vert; + sz += 1000; + vert = (uint8_t *)malloc(sz); + memcpy(vert, vv, sz - 1000); + free(vv); + } + + for (size_t j = 0; j < height; j++) + { + uint64_t ln = _flip(_horz_line(font, chr_off, height, bs, j), width); + for (size_t k = 0; k < raster_height; k++, p++, ln >>= 8) + { + vert[map_off + p] = (uint8_t)ln; + } + } + } + + ((uint32_t *)vert)[i + 1] = v; + } + + if (map_off + p < sz) + { + uint8_t *vv = vert; + sz = map_off + p; + vert = (uint8_t *)malloc(sz); + memcpy(vert, vv, sz); + free(vv); + } + return vert; +} + +void init_fonts() +{ + if (ArialMT_Plain_10_Vert != NULL) + { + free(ArialMT_Plain_10_Vert); + ArialMT_Plain_10_Vert = NULL; + } + + ArialMT_Plain_10_Vert = _rot(ArialMT_Plain_10); +} + +void drawVerticalString(Display_t &display, const uint8_t *v_font, int x, int y, String s) +{ + if (v_font == NULL) + return; + + size_t w = v_font[0]; + char init_ch = v_font[2]; + size_t chars = v_font[3]; + + const uint8_t *v_chars = v_font + (chars + 1) * 4; + + for (int i = s.length(); i-- > 0;) + { + char c = s.charAt(i); + if (c < init_ch) + continue; + c -= init_ch; + if (c >= chars) + continue; + + size_t map_off = (c + 1) * 4; + size_t chr_off = (((uint16_t)v_font[map_off]) << 8) | (v_font[map_off + 1]); + size_t bs = v_font[map_off + 2]; + size_t h = v_font[map_off + 3]; + if (chr_off == 0xffff) + { + y += h; + continue; + } + + display.drawFastImage(x, y, w, h, v_chars + chr_off); + y += h; + } +} diff --git a/lib/charts/charts.h b/lib/charts/charts.h index 516e5e8..12497e8 100644 --- a/lib/charts/charts.h +++ b/lib/charts/charts.h @@ -101,12 +101,14 @@ struct BarChart : ProgressChart, Listener struct DecoratedBarChart : Chart { BarChart bar; + bool draw_labels; DecoratedBarChart(Display_t &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h, float min_x, float max_x, float min_y, float max_y, float level_y) : Chart(d, x, y, w, h), bar(d, x, y + LABEL_HEIGHT, w, h - LABEL_HEIGHT - AXIS_HEIGHT, min_x, max_x, - min_y, max_y, level_y) {}; + min_y, max_y, level_y), + draw_labels(false) {}; void reset(uint16_t x, uint16_t y, uint16_t w, uint16_t h) override; void draw() override; @@ -176,4 +178,10 @@ struct UptimeClock : Chart virtual void draw() override; }; +extern uint8_t *ArialMT_Plain_10_Vert; + +void init_fonts(); +void drawVerticalString(Display_t &display, const uint8_t *v_font, int x, int y, + String s); + #endif diff --git a/src/main.cpp b/src/main.cpp index 034d3fa..fc42d25 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1177,6 +1177,7 @@ void setup(void) configurePages(); display.clear(); + init_fonts(); Serial.println(); #ifdef METHOD_RSSI @@ -2229,6 +2230,7 @@ void display_scan_result(ScanTaskResult &dump) float step = (bar->bar.max_x - bar->bar.min_x) / bar->bar.width; bar->bar.clear(); + bar->draw_labels = true; for (int i = 0; i < config.scan_ranges_sz; i++) {