diff --git a/src/eez/gui/widgets/gauge.cpp b/src/eez/gui/widgets/gauge.cpp index 85ee7d657..20f048075 100644 --- a/src/eez/gui/widgets/gauge.cpp +++ b/src/eez/gui/widgets/gauge.cpp @@ -32,6 +32,41 @@ namespace eez { namespace gui { +//////////////////////////////////////////////////////////////////////////////// + +void arcBar(Agg2D &graphics, int xCenter, int yCenter, int radOuter, int radInner, float angle) { + graphics.moveTo(xCenter - radOuter, yCenter); + + graphics.arcTo( + radOuter, // rx + radOuter, // ry + Agg2D::deg2Rad(0), // angle + 0, // largeArcFlag + 1, // sweepFlag + xCenter + radOuter * cos(Agg2D::deg2Rad(angle)), // dx + yCenter - radOuter * sin(Agg2D::deg2Rad(angle)) // dy + ); + + graphics.lineTo( + xCenter + radInner * cos(Agg2D::deg2Rad(angle)), + yCenter - radInner * sin(Agg2D::deg2Rad(angle)) + ); + + graphics.arcTo( + radInner, // rx + radInner, // ry + Agg2D::deg2Rad(-180), // angle + 0, // largeArcFlag + 0, // sweepFlag + xCenter - radInner, // dx + yCenter // dy + ); + + graphics.lineTo(xCenter - radOuter, yCenter); +} + +//////////////////////////////////////////////////////////////////////////////// + struct GaugeWidget : public Widget { int16_t min; int16_t max; @@ -45,7 +80,12 @@ struct GaugeWidget : public Widget { EnumFunctionType GAUGE_enum = nullptr; DrawFunctionType GAUGE_draw = [](const WidgetCursor &widgetCursor) { - auto widget = (const GaugeWidget*)widgetCursor.widget; + using namespace mcu::display; + + static const int BORDER_WIDTH = 32; + static const int BAR_WIDTH = 16; + + auto widget = (const GaugeWidget*)widgetCursor.widget; widgetCursor.currentState->size = sizeof(WidgetState); @@ -54,273 +94,58 @@ DrawFunctionType GAUGE_draw = [](const WidgetCursor &widgetCursor) { bool refresh = !widgetCursor.previousState || widgetCursor.previousState->data != widgetCursor.currentState->data; if (refresh) { - const Style* style = getStyle(widget->style); - - mcu::display::setColor(style->background_color); - mcu::display::fillRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + widget->w - 1, widgetCursor.y + widget->h - 1, 0); - - static const int BORDER_WIDTH = 32; - static const int BAR_WIDTH = 16; float min = get(widgetCursor, widget->min).toFloat(); float max = get(widgetCursor, widget->max).toFloat(); + float value = widgetCursor.currentState->data.getFloat(); + const Style* style = getStyle(widget->style); const Style* barStyle = getStyle(widget->barStyle); - //mcu::display::setColor(barStyle->color); - //fillArcBar( - // widgetCursor.x + widget->w / 2, - // widgetCursor.y + widget->h - 4, - // (widget->w - 8) / 2 - BORDER_WIDTH / 2, - // remap(widgetCursor.currentState->data.getFloat(), min, 180.0f, max, 0.0f), - // 180.0f, - // BAR_WIDTH - //); - - //mcu::display::setColor(style->color); - //drawArcBar( - // widgetCursor.x + widget->w / 2, - // widgetCursor.y + widget->h - 4, - // (widget->w - 8) / 2 - BORDER_WIDTH / 2, - // 0.0f, - // 180.0f, - // BORDER_WIDTH - //); - - uint8_t *pixels = (uint8_t *)alloc(widget->w * widget->h * 4); - - agg::rendering_buffer rbuf; - rbuf.attach(pixels, widget->w, widget->h, widget->w * 4); - - Agg2D m_graphics; - - m_graphics.attach(rbuf.buf(), rbuf.width(), rbuf.height(), rbuf.stride()); - - static int d = 0; - static int dir = 1; - d += dir * 2; - if (d > 100) { - d = 100; - dir = -1; - } - if (d < 0) { - d = 0; - dir = 1; - } - - m_graphics.viewport( - 0, 0, 600, 600, - 0 + d, 0 + d, widget->w - d, widget->h - d, - //Agg2D::Anisotropic - Agg2D::XMidYMid - ); - - using namespace mcu::display; - auto colorBackground = getColor16FromIndex(style->background_color); auto colorBorder = getColor16FromIndex(style->color); + auto colorBar = getColor16FromIndex(barStyle->color); auto xCenter = widget->w / 2; - auto yCenter = widget->h / 2; - auto rad = 50; - - //// clear background - //m_graphics.clearAll(COLOR_TO_R(colorBackground), COLOR_TO_G(colorBackground), COLOR_TO_B(colorBackground)); - - //// draw border - //m_graphics.resetPath(); - //m_graphics.noFill(); - //m_graphics.lineColor(COLOR_TO_R(colorBorder), COLOR_TO_G(colorBorder), COLOR_TO_B(colorBorder)); - //m_graphics.lineWidth(8); - //m_graphics.moveTo(20, 100); - //m_graphics.arcRel( - // 50, // rx - // 50, // ry - // Agg2D::deg2Rad(35), // angle - // 0, // largeArcFlag - // 1, // sweepFlag - // 100, // dx - // 0 // dy - //); - //m_graphics.drawPath(); - - { - m_graphics.clearAll(255, 255, 255); - - - // Rounded Rect - m_graphics.lineColor(0, 0, 0); - m_graphics.noFill(); - m_graphics.roundedRect(0.5, 0.5, 600 - 0.5, 600 - 0.5, 20.0); - - - m_graphics.fillColor(0, 0, 0); - m_graphics.noLine(); - - m_graphics.lineColor(50, 0, 0); - m_graphics.fillColor(180, 200, 100); - m_graphics.lineWidth(1.0); - - // Text Alignment - m_graphics.line(250.5 - 150, 150.5, 250.5 + 150, 150.5); - m_graphics.line(250.5, 150.5 - 20, 250.5, 150.5 + 20); - m_graphics.line(250.5 - 150, 200.5, 250.5 + 150, 200.5); - m_graphics.line(250.5, 200.5 - 20, 250.5, 200.5 + 20); - m_graphics.line(250.5 - 150, 250.5, 250.5 + 150, 250.5); - m_graphics.line(250.5, 250.5 - 20, 250.5, 250.5 + 20); - m_graphics.line(250.5 - 150, 300.5, 250.5 + 150, 300.5); - m_graphics.line(250.5, 300.5 - 20, 250.5, 300.5 + 20); - m_graphics.line(250.5 - 150, 350.5, 250.5 + 150, 350.5); - m_graphics.line(250.5, 350.5 - 20, 250.5, 350.5 + 20); - m_graphics.line(250.5 - 150, 400.5, 250.5 + 150, 400.5); - m_graphics.line(250.5, 400.5 - 20, 250.5, 400.5 + 20); - m_graphics.line(250.5 - 150, 450.5, 250.5 + 150, 450.5); - m_graphics.line(250.5, 450.5 - 20, 250.5, 450.5 + 20); - m_graphics.line(250.5 - 150, 500.5, 250.5 + 150, 500.5); - m_graphics.line(250.5, 500.5 - 20, 250.5, 500.5 + 20); - m_graphics.line(250.5 - 150, 550.5, 250.5 + 150, 550.5); - m_graphics.line(250.5, 550.5 - 20, 250.5, 550.5 + 20); - - - m_graphics.fillColor(100, 50, 50); - m_graphics.noLine(); - - // Gradients (Aqua Buttons) - //======================================= - double xb1 = 400; - double yb1 = 80; - double xb2 = xb1 + 150; - double yb2 = yb1 + 36; - - m_graphics.fillColor(Agg2D::Color(0, 50, 180, 180)); - m_graphics.lineColor(Agg2D::Color(0, 0, 80, 255)); - m_graphics.lineWidth(1.0); - m_graphics.roundedRect(xb1, yb1, xb2, yb2, 12, 18); - - m_graphics.lineColor(Agg2D::Color(0, 0, 0, 0)); - m_graphics.fillLinearGradient(xb1, yb1, xb1, yb1 + 30, - Agg2D::Color(100, 200, 255, 255), - Agg2D::Color(255, 255, 255, 0)); - m_graphics.roundedRect(xb1 + 3, yb1 + 2.5, xb2 - 3, yb1 + 30, 9, 18, 1, 1); - - m_graphics.fillColor(Agg2D::Color(0, 0, 50, 200)); - m_graphics.noLine(); - - m_graphics.fillLinearGradient(xb1, yb2 - 20, xb1, yb2 - 3, - Agg2D::Color(0, 0, 255, 0), - Agg2D::Color(100, 255, 255, 255)); - m_graphics.roundedRect(xb1 + 3, yb2 - 20, xb2 - 3, yb2 - 2, 1, 1, 9, 18); - - - // Aqua Button Pressed - xb1 = 400; - yb1 = 30; - xb2 = xb1 + 150; - yb2 = yb1 + 36; - - m_graphics.fillColor(Agg2D::Color(0, 50, 180, 180)); - m_graphics.lineColor(Agg2D::Color(0, 0, 0, 255)); - m_graphics.lineWidth(2.0); - m_graphics.roundedRect(xb1, yb1, xb2, yb2, 12, 18); - - m_graphics.lineColor(Agg2D::Color(0, 0, 0, 0)); - m_graphics.fillLinearGradient(xb1, yb1 + 2, xb1, yb1 + 25, - Agg2D::Color(60, 160, 255, 255), - Agg2D::Color(100, 255, 255, 0)); - m_graphics.roundedRect(xb1 + 3, yb1 + 2.5, xb2 - 3, yb1 + 30, 9, 18, 1, 1); - - m_graphics.fillColor(Agg2D::Color(0, 0, 50, 255)); - m_graphics.noLine(); - - m_graphics.fillLinearGradient(xb1, yb2 - 25, xb1, yb2 - 5, - Agg2D::Color(0, 180, 255, 0), - Agg2D::Color(0, 200, 255, 255)); - m_graphics.roundedRect(xb1 + 3, yb2 - 25, xb2 - 3, yb2 - 2, 1, 1, 9, 18); - - - - - // Basic Shapes -- Ellipse - //=========================================== - m_graphics.lineWidth(3.5); - m_graphics.lineColor(20, 80, 80); - m_graphics.fillColor(200, 255, 80, 200); - m_graphics.ellipse(450, 200, 50, 90); - - - // Paths - //=========================================== - m_graphics.resetPath(); - m_graphics.fillColor(255, 0, 0, 100); - m_graphics.lineColor(0, 0, 255, 100); - m_graphics.lineWidth(2); - m_graphics.moveTo(300 / 2, 200 / 2); - m_graphics.horLineRel(-150 / 2); - m_graphics.arcRel(150 / 2, 150 / 2, 0, 1, 0, 150 / 2, -150 / 2); - m_graphics.closePolygon(); - m_graphics.drawPath(); - - m_graphics.resetPath(); - m_graphics.fillColor(255, 255, 0, 100); - m_graphics.lineColor(0, 0, 255, 100); - m_graphics.lineWidth(2); - m_graphics.moveTo(275 / 2, 175 / 2); - m_graphics.verLineRel(-150 / 2); - m_graphics.arcRel(150 / 2, 150 / 2, 0, 0, 0, -150 / 2, 150 / 2); - m_graphics.closePolygon(); - m_graphics.drawPath(); - - - m_graphics.resetPath(); - m_graphics.noFill(); - m_graphics.lineColor(127, 0, 0); - m_graphics.lineWidth(5); - m_graphics.moveTo(600 / 2, 350 / 2); - m_graphics.lineRel(50 / 2, -25 / 2); - m_graphics.arcRel(25 / 2, 25 / 2, Agg2D::deg2Rad(-30), 0, 1, 50 / 2, -25 / 2); - m_graphics.lineRel(50 / 2, -25 / 2); - m_graphics.arcRel(25 / 2, 50 / 2, Agg2D::deg2Rad(-30), 0, 1, 50 / 2, -25 / 2); - m_graphics.lineRel(50 / 2, -25 / 2); - m_graphics.arcRel(25 / 2, 75 / 2, Agg2D::deg2Rad(-30), 0, 1, 50 / 2, -25 / 2); - m_graphics.lineRel(50, -25); - m_graphics.arcRel(25 / 2, 100 / 2, Agg2D::deg2Rad(-30), 0, 1, 50 / 2, -25 / 2); - m_graphics.lineRel(50 / 2, -25 / 2); - m_graphics.drawPath(); - - - // Master Alpha. From now on everything will be translucent - //=========================================== - m_graphics.masterAlpha(0.85); - - - // Transform image to the destination path. - // The scale is determined by a rectangle - //----------------- - m_graphics.resetPath(); - m_graphics.moveTo(450, 200); - m_graphics.cubicCurveTo(595, 220, 575, 350, 595, 350); - m_graphics.lineTo(470, 340); - - // Add/Sub/Contrast Blending Modes - m_graphics.noLine(); - m_graphics.fillColor(70, 70, 0); - m_graphics.blendMode(Agg2D::BlendAdd); - m_graphics.ellipse(500, 280, 20, 40); - - m_graphics.fillColor(255, 255, 255); - m_graphics.blendMode(Agg2D::BlendOverlay); - m_graphics.ellipse(500 + 40, 280, 20, 40); - - - - // Radial gradient. - m_graphics.blendMode(Agg2D::BlendAlpha); - m_graphics.fillRadialGradient(400, 500, 40, - Agg2D::Color(255, 255, 0, 0), - Agg2D::Color(0, 0, 127), - Agg2D::Color(0, 255, 0, 0)); - m_graphics.ellipse(400, 500, 40, 40); - } + auto yCenter = widget->h - 24; + // init AGG + agg::rendering_buffer rbuf; + uint8_t *pixels = (uint8_t *)alloc(widget->w * widget->h * 4); + rbuf.attach(pixels, widget->w, widget->h, widget->w * 4); + Agg2D graphics; + graphics.attach(rbuf.buf(), rbuf.width(), rbuf.height(), rbuf.stride()); + + // clear background + graphics.clearAll(COLOR_TO_R(colorBackground), COLOR_TO_G(colorBackground), COLOR_TO_B(colorBackground)); + + // frame + graphics.lineWidth(1.5); + graphics.lineColor(COLOR_TO_R(colorBorder), COLOR_TO_G(colorBorder), COLOR_TO_B(colorBorder)); + graphics.noFill(); + graphics.roundedRect(1, 1, widget->w-2, widget->h-2, 4); + + // draw border + auto radBorderOuter = (widget->w - 12) / 2; + auto radBorderInner = radBorderOuter - BORDER_WIDTH; + graphics.resetPath(); + graphics.noFill(); + graphics.lineColor(COLOR_TO_R(colorBorder), COLOR_TO_G(colorBorder), COLOR_TO_B(colorBorder)); + graphics.lineWidth(1.5); + arcBar(graphics, xCenter, yCenter, radBorderOuter, radBorderInner, 0); + graphics.drawPath(); + + // draw bar + auto radBarOuter = (widget->w - 12) / 2 - (BORDER_WIDTH - BAR_WIDTH) / 2; + auto radBarInner = radBarOuter - BAR_WIDTH; + auto angle = remap(value, min, 180.0f, max, 0.0f); + graphics.resetPath(); + graphics.noLine(); + graphics.fillColor(COLOR_TO_R(colorBar), COLOR_TO_G(colorBar), COLOR_TO_B(colorBar)); + graphics.lineWidth(1.5); + arcBar(graphics, xCenter, yCenter, radBarOuter, radBarInner, angle); + graphics.drawPath(); + + // output generated image and free resources Image image; image.width = widget->w; image.height = widget->h; @@ -328,7 +153,6 @@ DrawFunctionType GAUGE_draw = [](const WidgetCursor &widgetCursor) { image.bpp = 32; image.lineOffset = 0; mcu::display::drawBitmap(&image, widgetCursor.x, widgetCursor.y); - free(pixels); } };