/* * EEZ Modular Firmware * Copyright (C) 2015-present, Envox d.o.o. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include namespace eez { namespace gui { #define BAR_GRAPH_ORIENTATION_LEFT_RIGHT 1 #define BAR_GRAPH_ORIENTATION_RIGHT_LEFT 2 #define BAR_GRAPH_ORIENTATION_TOP_BOTTOM 3 #define BAR_GRAPH_ORIENTATION_BOTTOM_TOP 4 #define BAR_GRAPH_ORIENTATION_MASK 0x0F #define BAR_GRAPH_DO_NOT_DISPLAY_VALUE (1 << 4) int calcValuePosInBarGraphWidget(Value &value, float min, float max, int d) { return (int)roundf((value.getFloat() - min) * d / (max - min)); } int calcValuePosInBarGraphWidgetWithClamp(Value &value, float min, float max, int d) { int p = calcValuePosInBarGraphWidget(value, min, max, d); if (p < 0) { p = 0; } else if (p >= d) { p = d - 1; } return p; } void drawLineInBarGraphWidget(const BarGraphWidget *barGraphWidget, int p, uint16_t lineStyleID, int x, int y, int w, int h) { const Style *style = getStyle(lineStyleID); display::setColor(style->color); if ((barGraphWidget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_LEFT_RIGHT) { display::drawVLine(x + p, y, h - 1); } else if ((barGraphWidget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_RIGHT_LEFT) { display::drawVLine(x - p, y, h - 1); } else if ((barGraphWidget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_TOP_BOTTOM) { display::drawHLine(x, y + p, w - 1); } else { display::drawHLine(x, y - p, w - 1); } } bool BarGraphWidgetState::updateState() { WIDGET_STATE_START(BarGraphWidget); const Style* style = getStyle(g_hooks.overrideStyle(widgetCursor, widget->style)); WIDGET_STATE(flags.active, g_isActiveWidget); WIDGET_STATE(flags.blinking, g_isBlinkTime && isBlinking(widgetCursor, widget->data)); WIDGET_STATE(data, get(widgetCursor, widget->data)); WIDGET_STATE(color, getColor(widgetCursor, widget->data, style)); WIDGET_STATE(backgroundColor, getBackgroundColor(widgetCursor, widget->data, style)); WIDGET_STATE(activeColor, getActiveColor(widgetCursor, widget->data, style)); WIDGET_STATE(activeBackgroundColor, getActiveBackgroundColor(widgetCursor, widget->data, style)); WIDGET_STATE(line1Data, get(widgetCursor, widget->line1Data)); WIDGET_STATE(line2Data, get(widgetCursor, widget->line2Data)); bool refreshTextData = true; auto currentTime = millis(); if (hasPreviousState && textData != data) { uint32_t refreshRate = getTextRefreshRate(widgetCursor, widget->data); if (refreshRate != 0 && currentTime - textDataRefreshLastTime < refreshRate) { refreshTextData = false; } } if (refreshTextData) { WIDGET_STATE(textData, data); textDataRefreshLastTime = currentTime; } WIDGET_STATE_END() } void BarGraphWidgetState::render() { const WidgetCursor &widgetCursor = g_widgetCursor; auto widget = (const BarGraphWidget *)widgetCursor.widget; const Style* style = getStyle(g_hooks.overrideStyle(widgetCursor, widget->style)); int x = widgetCursor.x; int y = widgetCursor.y; const int w = widgetCursor.w; const int h = widgetCursor.h; float min = getMin(widgetCursor, widget->data).getFloat(); float max; Value displayValueRange = getDisplayValueRange(widgetCursor, widget->data); if (displayValueRange.getType() == VALUE_TYPE_FLOAT) { max = displayValueRange.getFloat(); } else { max = getMax(widgetCursor, widget->data).getFloat(); } bool horizontal = (widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_LEFT_RIGHT || (widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_RIGHT_LEFT; int d = horizontal ? w : h; // calc bar position (monitored value) int pValue = calcValuePosInBarGraphWidgetWithClamp(data, min, max, d); // calc line 1 position (set value) int pLine1 = calcValuePosInBarGraphWidget(line1Data, min, max, d); bool drawLine1 = pLine1 >= 0 && pLine1 < d; // calc line 2 position (limit value) int pLine2 = calcValuePosInBarGraphWidget(line2Data, min, max, d); bool drawLine2 = pLine2 >= 0 && pLine2 < d; if (drawLine1 && drawLine2) { // make sure line positions don't overlap if (pLine1 == pLine2) { pLine1 = pLine2 - 1; } // make sure all lines are visible if (pLine1 < 0) { pLine2 -= pLine1; pLine1 = 0; } } Style textStyle; memcpy(&textStyle, widget->textStyle ? getStyle(widget->textStyle) : style, sizeof(Style)); if (style->color != color) { textStyle.color = flags.active || flags.blinking ? activeColor : color; } uint16_t fg = flags.active || flags.blinking ? activeColor : color; uint16_t bg = flags.active || flags.blinking ? activeBackgroundColor : backgroundColor; if (horizontal) { // calc text position char valueText[64]; int pText = 0; int wText = 0; if (!(widget->orientation & BAR_GRAPH_DO_NOT_DISPLAY_VALUE)) { if (widget->textStyle) { font::Font font = styleGetFont(&textStyle); textData.toText(valueText, sizeof(valueText)); wText = display::measureStr(valueText, -1, font, w); int padding = textStyle.paddingLeft; wText += padding; if (pValue + wText <= d) { textStyle.backgroundColor = bg; pText = pValue; } else { textStyle.backgroundColor = fg; textStyle.color = textStyle.activeColor; wText += padding; pText = MAX(pValue - wText, 0); } } } else { pText = pValue; } if ((widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_LEFT_RIGHT) { // draw bar if (pText > 0) { display::setColor(fg); display::fillRect(x, y, x + pText - 1, y + h - 1); } if (!(widget->orientation & BAR_GRAPH_DO_NOT_DISPLAY_VALUE)) { drawText(valueText, -1, x + pText, y, wText, h, &textStyle); } // draw background, but do not draw over line 1 and line 2 display::setColor(bg); int pBackground = pText + wText; if (drawLine1) { if (pBackground <= pLine1) { if (pBackground < pLine1) { display::fillRect(x + pBackground, y, x + pLine1 - 1, y + h - 1); } pBackground = pLine1 + 1; } } if (drawLine2) { if (pBackground <= pLine2) { if (pBackground < pLine2) { display::fillRect(x + pBackground, y, x + pLine2 - 1, y + h - 1); } pBackground = pLine2 + 1; } } if (pBackground < d) { display::fillRect(x + pBackground, y, x + d - 1, y + h - 1); } } else { x += w - 1; // draw bar if (pText > 0) { display::setColor(fg); display::fillRect(x - (pText - 1), y, x, y + h - 1); } if (!(widget->orientation & BAR_GRAPH_DO_NOT_DISPLAY_VALUE)) { drawText(valueText, -1, x - (pText + wText - 1), y, wText, h, &textStyle); } // draw background, but do not draw over line 1 and line 2 display::setColor(bg); int pBackground = pText + wText; if (drawLine1) { if (pBackground <= pLine1) { if (pBackground < pLine1) { display::fillRect(x - (pLine1 - 1), y, x - pBackground, y + h - 1); } pBackground = pLine1 + 1; } } if (drawLine2) { if (pBackground <= pLine2) { if (pBackground < pLine2) { display::fillRect(x - (pLine2 - 1), y, x - pBackground, y + h - 1); } pBackground = pLine2 + 1; } } if (pBackground < d) { display::fillRect(x - (d - 1), y, x - pBackground, y + h - 1); } } if (drawLine1) { drawLineInBarGraphWidget(widget, pLine1, widget->line1Style, x, y, w, h); } if (drawLine2) { drawLineInBarGraphWidget(widget, pLine2, widget->line2Style, x, y, w, h); } } else { // calc text position char valueText[64]; int pText = 0; int hText = 0; if (widget->textStyle) { font::Font font = styleGetFont(&textStyle); textData.toText(valueText, sizeof(valueText)); hText = font.getHeight(); int padding = textStyle.paddingTop; hText += padding; if (pValue + hText <= d) { textStyle.backgroundColor = bg; pText = pValue; } else { textStyle.backgroundColor = fg; textStyle.color = textStyle.activeColor; hText += padding; pText = MAX(pValue - hText, 0); } } if ((widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_TOP_BOTTOM) { // draw bar if (pText > 0) { display::setColor(fg); display::fillRect(x, y, x + w - 1, y + pText - 1); } drawText(valueText, -1, x, y + pText, w, hText, &textStyle); // draw background, but do not draw over line 1 and line 2 display::setColor(bg); int pBackground = pText + hText; if (drawLine1) { if (pBackground <= pLine1) { if (pBackground < pLine1) { display::fillRect(x, y + pBackground, x + w - 1, y + pLine1 - 1); } pBackground = pLine1 + 1; } } if (drawLine2) { if (pBackground <= pLine2) { if (pBackground < pLine2) { display::fillRect(x, y + pBackground, x + w - 1, y + pLine2 - 1); } pBackground = pLine2 + 1; } } if (pBackground < d) { display::fillRect(x, y + pBackground, x + w - 1, y + d - 1); } } else { y += h - 1; // draw bar if (pText > 0) { display::setColor(fg); display::fillRect(x, y - (pText - 1), x + w - 1, y); } drawText(valueText, -1, x, y - (pText + hText - 1), w, hText, &textStyle); // draw background, but do not draw over line 1 and line 2 display::setColor(bg); int pBackground = pText + hText; if (drawLine1) { if (pBackground <= pLine1) { if (pBackground < pLine1) { display::fillRect(x, y - (pLine1 - 1), x + w - 1, y - pBackground); } pBackground = pLine1 + 1; } } if (drawLine2) { if (pBackground <= pLine2) { if (pBackground < pLine2) { display::fillRect(x, y - (pLine2 - 1), x + w - 1, y - (pBackground)); } pBackground = pLine2 + 1; } } if (pBackground < d) { display::fillRect(x, y - (d - 1), x + w - 1, y - pBackground); } } if (drawLine1) { drawLineInBarGraphWidget(widget, pLine1, widget->line1Style, x, y, w, h); } if (drawLine2) { drawLineInBarGraphWidget(widget, pLine2, widget->line2Style, x, y, w, h); } } } } // namespace gui } // namespace eez