' Bar chart and line chart drawing with GDI primitives via DECLARE
#COMPILE EXE
#DIM ALL

DECLARE FUNCTION GetDC LIB "USER32.DLL" (BYVAL hWnd AS LONG) AS LONG
DECLARE FUNCTION ReleaseDC LIB "USER32.DLL" (BYVAL hWnd AS LONG, BYVAL hDC AS LONG) AS LONG
DECLARE FUNCTION MoveToEx LIB "GDI32.DLL" (BYVAL hDC AS LONG, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL lpPoint AS LONG) AS LONG
DECLARE FUNCTION LineTo LIB "GDI32.DLL" (BYVAL hDC AS LONG, BYVAL x AS LONG, BYVAL y AS LONG) AS LONG
DECLARE FUNCTION Rectangle LIB "GDI32.DLL" (BYVAL hDC AS LONG, BYVAL left AS LONG, BYVAL top AS LONG, BYVAL right AS LONG, BYVAL bottom AS LONG) AS LONG
DECLARE FUNCTION SelectObject LIB "GDI32.DLL" (BYVAL hDC AS LONG, BYVAL hObject AS LONG) AS LONG
DECLARE FUNCTION CreateSolidBrush LIB "GDI32.DLL" (BYVAL crColor AS LONG) AS LONG
DECLARE FUNCTION DeleteObject LIB "GDI32.DLL" (BYVAL hObject AS LONG) AS LONG

%CHART_WIDTH  = 640
%CHART_HEIGHT = 480
%MARGIN_LEFT  = 80
%MARGIN_BOTTOM = 60
%MARGIN_TOP   = 40
%MARGIN_RIGHT = 40

FUNCTION MapX(BYVAL i AS LONG, BYVAL n AS LONG) AS LONG
    LOCAL width AS LONG
    width = %CHART_WIDTH - %MARGIN_LEFT - %MARGIN_RIGHT
    FUNCTION = %MARGIN_LEFT + (i * width) / n
END FUNCTION

FUNCTION MapY(BYVAL val AS LONG, BYVAL minV AS LONG, BYVAL maxV AS LONG) AS LONG
    LOCAL height AS LONG
    height = %CHART_HEIGHT - %MARGIN_TOP - %MARGIN_BOTTOM
    IF maxV = minV THEN
        FUNCTION = %MARGIN_TOP + height / 2
    ELSE
        FUNCTION = %MARGIN_TOP + height - ((val - minV) * height) / (maxV - minV)
    END IF
END FUNCTION

SUB DrawBar(BYVAL hDC AS LONG, BYVAL x AS LONG, BYVAL yTop AS LONG, BYVAL yBot AS LONG, BYVAL width AS LONG, BYVAL color AS LONG)
    LOCAL hBrush AS LONG
    hBrush = CreateSolidBrush(color)
    DeleteObject(hBrush)
    Rectangle(hDC, x - width / 2, yTop, x + width / 2, yBot)
END SUB

SUB DrawLine(BYVAL hDC AS LONG, BYVAL x1 AS LONG, BYVAL y1 AS LONG, BYVAL x2 AS LONG, BYVAL y2 AS LONG)
    MoveToEx(hDC, x1, y1, 0)
    LineTo(hDC, x2, y2)
END SUB

SUB PrintBarChart(BYVAL data() AS LONG, BYVAL n AS LONG)
    LOCAL i  AS LONG
    LOCAL minV  AS LONG
    LOCAL maxV  AS LONG
    LOCAL x  AS LONG
    LOCAL yTop  AS LONG
    LOCAL yBot  AS LONG
    minV = 0
    maxV = data(0)
    FOR i = 0 TO n - 1
        IF data(i) > maxV THEN maxV = data(i)
    NEXT i
    PRINT "Bar chart data (n="; n; " range="; minV; "-"; maxV; ")"
    FOR i = 0 TO n - 1
        x = MapX(i, n)
        yTop = MapY(data(i), minV, maxV)
        yBot = MapY(0, minV, maxV)
        LOCAL barLen AS LONG
        barLen = (data(i) * 40) / maxV
        PRINT "  ["; i; "] value="; data(i); " pos="; x; " height="; barLen
    NEXT i
END SUB

SUB PrintLineChart(BYVAL data() AS LONG, BYVAL n AS LONG)
    LOCAL i  AS LONG
    LOCAL minV  AS LONG
    LOCAL maxV  AS LONG
    LOCAL x1  AS LONG
    LOCAL y1  AS LONG
    LOCAL x2  AS LONG
    LOCAL y2  AS LONG
    minV = data(0)
    maxV = data(0)
    FOR i = 0 TO n - 1
        IF data(i) < minV THEN minV = data(i)
        IF data(i) > maxV THEN maxV = data(i)
    NEXT i
    PRINT "Line chart data (n="; n; " range="; minV; "-"; maxV; ")"
    x1 = MapX(0, n)
    y1 = MapY(data(0), minV, maxV)
    FOR i = 1 TO n - 1
        x2 = MapX(i, n)
        y2 = MapY(data(i), minV, maxV)
        PRINT "  segment "; i - 1; "-"; i; ": ("
        PRINT x1; ","; y1; ") -> ("; x2; ","; y2; ")"
        x1 = x2
        y1 = y2
    NEXT i
END SUB

SUB PrintPiePreview(BYVAL slices() AS LONG, BYVAL n AS LONG)
    LOCAL i  AS LONG
    LOCAL total  AS LONG
    total = 0
    FOR i = 0 TO n - 1
        total = total + slices(i)
    NEXT i
    PRINT "Pie chart (n="; n; " total="; total; "):"
    LOCAL angle AS DOUBLE
    angle = 0.0
    FOR i = 0 TO n - 1
        LOCAL sliceAngle AS DOUBLE
        sliceAngle = (slices(i) * 360.0) / total
        PRINT "  slice "; i; ": "; slices(i); " ("
        PRINT sliceAngle; " deg, "
        PRINT (slices(i) * 100) / total; "%)"
        angle = angle + sliceAngle
    NEXT i
END SUB

FUNCTION CreateDataSet(BYVAL n AS LONG) AS LONG
    DIM d(0:n - 1) AS LONG
    LOCAL i AS LONG
    FOR i = 0 TO n - 1
        d(i) = (i * i + i * 3 + 7) MOD 100
    NEXT i
    PrintBarChart(d(), n)
    PRINT ""
    PrintLineChart(d(), n)
    FUNCTION = 0
END FUNCTION

SUB TemperatureChart()
    PRINT "Temperature readings (12 months):"
    DIM temps(0:11) AS LONG
    temps(0) = 2
    temps(1) = 5
    temps(2) = 10
    temps(3) = 16
    temps(4) = 22
    temps(5) = 28
    temps(6) = 31
    temps(7) = 30
    temps(8) = 25
    temps(9) = 18
    temps(10) = 10
    temps(11) = 4
    PrintLineChart(temps(), 12)
END SUB

SUB PieSlices()
    DIM s(0:3) AS LONG
    s(0) = 40
    s(1) = 25
    s(2) = 20
    s(3) = 15
    PrintPiePreview(s(), 4)
END SUB

FUNCTION PBMAIN() AS LONG
    PRINT "=== Graphics Chart Demo ==="
    PRINT "GDI: Rectangle, MoveToEx, LineTo via DECLARE"
    PRINT ""
    CreateDataSet(8)
    PRINT ""
    TemperatureChart()
    PRINT ""
    PieSlices()
    PRINT ""
    PRINT "=== End Chart Demo ==="
    FUNCTION = 0
END FUNCTION
