' 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

CONST CHART_WIDTH = 640
CONST CHART_HEIGHT = 480
CONST MARGIN_LEFT = 80
CONST MARGIN_BOTTOM = 60
CONST MARGIN_TOP = 40
CONST 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 v0 AS LONG, BYVAL v1 AS LONG, BYVAL v2 AS LONG, BYVAL v3 AS LONG, BYVAL v4 AS LONG, BYVAL v5 AS LONG, BYVAL v6 AS LONG, BYVAL v7 AS LONG, BYVAL n AS LONG)
    LOCAL i AS LONG
    LOCAL minV AS LONG
    LOCAL maxV AS LONG
    LOCAL x AS LONG
    LOCAL barLen AS LONG
    LOCAL vals(7) AS LONG
    vals(0) = v0: vals(1) = v1: vals(2) = v2: vals(3) = v3
    vals(4) = v4: vals(5) = v5: vals(6) = v6: vals(7) = v7
    minV = 0
    maxV = vals(0)
    FOR i = 0 TO n - 1
        IF vals(i) > maxV THEN maxV = vals(i)
    NEXT i
    PRINT "Bar chart data (n="; n; " range="; minV; "-"; maxV; ")"
    FOR i = 0 TO n - 1
        x = MapX(i, n)
        barLen = (vals(i) * 40) / maxV
        PRINT "  ["; i; "] value="; vals(i); " pos="; x; " height="; barLen
    NEXT i
END SUB

SUB PrintLineChart(BYVAL v0 AS LONG, BYVAL v1 AS LONG, BYVAL v2 AS LONG, BYVAL v3 AS LONG, BYVAL v4 AS LONG, BYVAL v5 AS LONG, BYVAL v6 AS LONG, BYVAL v7 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
    LOCAL vals(7) AS LONG
    vals(0) = v0: vals(1) = v1: vals(2) = v2: vals(3) = v3
    vals(4) = v4: vals(5) = v5: vals(6) = v6: vals(7) = v7
    minV = vals(0)
    maxV = vals(0)
    FOR i = 0 TO n - 1
        IF vals(i) < minV THEN minV = vals(i)
        IF vals(i) > maxV THEN maxV = vals(i)
    NEXT i
    PRINT "Line chart data (n="; n; " range="; minV; "-"; maxV; ")"
    x1 = MapX(0, n)
    y1 = MapY(vals(0), minV, maxV)
    FOR i = 1 TO n - 1
        x2 = MapX(i, n)
        y2 = MapY(vals(i), minV, maxV)
        PRINT "  segment "; i - 1; "-"; i; ": ("
        PRINT x1; ","; y1; ") -> ("; x2; ","; y2; ")"
        x1 = x2
        y1 = y2
    NEXT i
END SUB

SUB PrintPiePreview(BYVAL v0 AS LONG, BYVAL v1 AS LONG, BYVAL v2 AS LONG, BYVAL v3 AS LONG, BYVAL n AS LONG)
    LOCAL i AS LONG
    LOCAL total AS LONG
    LOCAL vals(3) AS LONG
    vals(0) = v0: vals(1) = v1: vals(2) = v2: vals(3) = v3
    total = 0
    FOR i = 0 TO n - 1
        total = total + vals(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 = (vals(i) * 360.0) / total
        PRINT "  slice "; i; ": "; vals(i); " ("
        PRINT sliceAngle; " deg, "
        PRINT (vals(i) * 100) / total; "%)"
        angle = angle + sliceAngle
    NEXT i
END SUB

FUNCTION CreateDataSet(BYVAL n AS LONG) AS LONG
    LOCAL v0 AS LONG: v0 = 7
    LOCAL v1 AS LONG: v1 = 13
    LOCAL v2 AS LONG: v2 = 23
    LOCAL v3 AS LONG: v3 = 37
    LOCAL v4 AS LONG: v4 = 55
    LOCAL v5 AS LONG: v5 = 77
    LOCAL v6 AS LONG: v6 = 7
    LOCAL v7 AS LONG: v7 = 55
    PrintBarChart(v0, v1, v2, v3, v4, v5, v6, v7, n)
    PRINT ""
    PrintLineChart(v0, v1, v2, v3, v4, v5, v6, v7, n)
    FUNCTION = 0
END FUNCTION

SUB TemperatureChart()
    PRINT "Temperature readings (12 months):"
    LOCAL t0 AS LONG: t0 = 2
    LOCAL t1 AS LONG: t1 = 5
    LOCAL t2 AS LONG: t2 = 10
    LOCAL t3 AS LONG: t3 = 16
    LOCAL t4 AS LONG: t4 = 22
    LOCAL t5 AS LONG: t5 = 28
    LOCAL t6 AS LONG: t6 = 31
    LOCAL t7 AS LONG: t7 = 30
    PrintLineChart(t0, t1, t2, t3, t4, t5, t6, t7, 8)
END SUB

SUB PieSlices()
    PrintPiePreview(40, 25, 20, 15, 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
