diff --git a/lib/charts/BarChart.cpp b/lib/charts/BarChart.cpp index cdc04d8..c3e8116 100644 --- a/lib/charts/BarChart.cpp +++ b/lib/charts/BarChart.cpp @@ -1,7 +1,22 @@ #include "charts.h" -void BarChart::reset() +void BarChart::reset(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + pos_x = x; + pos_y = y; + + if (w != width) + { + delete[] ys; + delete[] changed; + + width = w; + ys = new float[width]; + changed = new bool[width]; + } + + height = h; + memset(ys, 0, width * sizeof(float)); memset(changed, false, width * sizeof(bool)); redraw_all = true; diff --git a/lib/charts/StackedChart.cpp b/lib/charts/StackedChart.cpp new file mode 100644 index 0000000..be602bd --- /dev/null +++ b/lib/charts/StackedChart.cpp @@ -0,0 +1,87 @@ +#include "charts.h" + +uint16_t trim_w(uint16_t pos, uint16_t width, uint16_t w) +{ + return min(width, (uint16_t)(max(w, pos) - pos)); +} + +size_t StackedChart::addChart(Chart *c) +{ + Chart **cc = new Chart *[charts_sz + 1]; + memcpy(cc, charts, charts_sz * sizeof(Chart *)); + cc[charts_sz] = c; + free(charts); + + c->reset(pos_x + c->pos_x, pos_y + c->pos_y, trim_w(c->pos_x, c->width, width), c->height); + charts = cc; + return charts_sz++; +} + +uint16_t StackedChart::setHeight(size_t c, uint16_t h) +{ + if (h < height) + { + charts[c]->reset(charts[c]->pos_x, charts[c]->pos_y, charts[c]->width, h); + + uint16_t used_space = 0; + for (int i = 0; i < charts_sz; i++) + { + used_space += charts[i]->height; + } + + return used_space; + } + // this chart gets special treatment - pack all other charts, + // and make this one as big as possible + uint16_t used_space = 0; + for (int i = 0; i < c; i++) + { + charts[i]->reset(charts[i]->pos_x, pos_y + used_space, charts[i]->width, + charts[i]->height); + used_space += charts[i]->height; + } + + uint16_t more_used_space = used_space; + for (int i = c + 1; i < charts_sz; i++) + { + more_used_space += charts[i]->height; + } + + if (more_used_space < height) + { + charts[c]->reset(charts[c]->pos_x, pos_y + used_space, charts[c]->width, + height - more_used_space); + used_space += charts[c]->height; + } + + for (int i = c + 1; i < charts_sz; i++) + { + charts[i]->reset(charts[i]->pos_x, pos_y + used_space, charts[i]->width, + charts[i]->height); + used_space += charts[i]->height; + } + + return used_space; +} + +void StackedChart::reset(uint16_t x, uint16_t y, uint16_t w, uint16_t h) +{ + for (int i = 0; i < charts_sz; i++) + { + uint16_t rel_x = charts[i]->pos_x - pos_x; + uint16_t rel_y = charts[i]->pos_y - pos_y; + charts[i]->reset(x + rel_x, y + rel_y, trim_w(rel_x, charts[i]->width, w), + charts[i]->height); + } + + pos_x = x; + pos_y = y; + width = w; + height = h; +} + +void StackedChart::draw() +{ + for (int i = 0; i < charts_sz; i++) + charts[i]->draw(); +} diff --git a/lib/charts/charts.h b/lib/charts/charts.h index 83675a8..54fc2fa 100644 --- a/lib/charts/charts.h +++ b/lib/charts/charts.h @@ -17,7 +17,21 @@ struct Chart /* * This method resets the state and sets the reference time. */ - virtual void reset() = 0; + virtual void reset(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {}; + + /* + * Redraw everything that needs redrawing. + */ + virtual void draw() {}; +}; + +/* + * ProgressChart supports updates with progressive redraw of just the affected area. + */ +struct ProgressChart : Chart +{ + ProgressChart(OLEDDisplay &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h) + : Chart(d, x, y, w, h) {}; /* * Update one data point, and return what column needs redrawing. @@ -28,14 +42,9 @@ struct Chart * If you fancy animated progress, then pass the output of updatePoint to here. */ virtual void drawOne(int x) = 0; - - /* - * Redraw everything that needs redrawing. - */ - virtual void draw() = 0; }; -struct BarChart : Chart +struct BarChart : ProgressChart { float min_x, max_x, min_y, max_y; float level_y; @@ -46,8 +55,8 @@ struct BarChart : Chart BarChart(OLEDDisplay &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), min_x(min_x), max_x(max_x), min_y(min_y), max_y(max_y), - level_y(level_y), redraw_all(true) + : ProgressChart(d, x, y, w, h), min_x(min_x), max_x(max_x), min_y(min_y), + max_y(max_y), level_y(level_y), redraw_all(true) { ys = new float[w]; changed = new bool[w]; @@ -56,7 +65,7 @@ struct BarChart : Chart memset(changed, 0, w * sizeof(bool)); }; - void reset() override; + void reset(uint16_t x, uint16_t y, uint16_t w, uint16_t h) override; int updatePoint(float x, float y) override; void drawOne(int x) override; void draw() override; @@ -85,4 +94,31 @@ struct DecoratedBarChart : BarChart void draw() override; }; +struct StackedChart : Chart +{ + Chart **charts; + size_t charts_sz; + + StackedChart(OLEDDisplay &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h) + : Chart(d, x, y, w, h), charts(NULL), charts_sz(0) {}; + + /* + * addChart adds c to the StackedChart, treats pos_x and pos_y of the chart + * as relative to this chart's origin, and trims width to fit. Adjust the + * height and pack charts using setHeight. + */ + size_t addChart(Chart *c); + + /* + * Adjust the height of the chart and return the resulting required height. + * If h is >= height, the chart gets a special treatment: packs all other + * charts, and uses up the rest of space. + */ + uint16_t setHeight(size_t c, uint16_t h); + + void reset(uint16_t x, uint16_t y, uint16_t w, uint16_t h) override; + + void draw() override; +}; + #endif diff --git a/src/main.cpp b/src/main.cpp index 939ffaa..2e8fbb6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -367,6 +367,7 @@ void osdProcess() #endif BarChart *bar; +StackedChart stacked(display, 0, 0, 0, 0); void init_radio() { @@ -657,11 +658,18 @@ void setup(void) xTaskCreate(logToSerialTask, "LOG_DATA_JSON", 2048, NULL, 1, NULL); #endif - bar = new DecoratedBarChart( - display, 0, 0, display.width(), display.height() / 2 + AXIS_HEIGHT, FREQ_BEGIN, - FREQ_END, LO_RSSI_THRESHOLD, HI_RSSI_THRESHOLD, -(float)show_db_after); + bar = new DecoratedBarChart(display, 0, 0, display.width(), 0, FREQ_BEGIN, FREQ_END, + LO_RSSI_THRESHOLD, HI_RSSI_THRESHOLD, + -(float)show_db_after); - bar->reset(); + stacked.reset(0, 0, display.width(), display.height() - 6); + + size_t b = stacked.addChart(bar); + size_t c = + stacked.addChart(new Chart(display, 0, 0, display.width(), 0)); + + stacked.setHeight(c, stacked.height - WATERFALL_START); + stacked.setHeight(b, stacked.height); } // Formula to translate 33 bin to approximate RSSI value @@ -1245,7 +1253,7 @@ void loop(void) } #endif - bar->draw(); + stacked.draw(); // Render display data here display.display(); #ifdef OSD_ENABLED