#define DVX_WIDGET_IMPL
// widgetScrollbar.c  -- Shared scrollbar painting and hit-testing
//
// These are not widgets themselves -- they are stateless rendering and
// hit-testing utilities shared by ScrollPane, TreeView, TextArea,
// ListBox, and ListView. Each owning widget stores its own scroll
// position; these functions are purely geometric.
//
// The scrollbar model uses three parts: two arrow buttons (one at each
// end) and a proportional thumb in the track between them. Thumb size
// is proportional to (visibleSize / totalSize), clamped to SB_MIN_THUMB
// to remain grabbable even when content is very large. Thumb position
// maps linearly from scrollPos to track position.
//
// Arrow triangles are drawn with simple loop-based scanlines (4 rows),
// producing 7-pixel-wide arrow glyphs. This avoids any font or bitmap
// dependency for the scrollbar chrome.
//
// The minimum scrollbar length guard (sbW < WGT_SB_W * 3) ensures
// there is at least room for both arrow buttons plus a minimal track.
// If the container is too small, the scrollbar is simply not drawn
// rather than rendering a corrupted mess.

#include "dvxWidgetPlugin.h"


// ============================================================
// widgetDrawScrollbarH
// ============================================================

void widgetDrawScrollbarH(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t sbX, int32_t sbY, int32_t sbW, int32_t totalSize, int32_t visibleSize, int32_t scrollPos) {
    if (sbW < WGT_SB_W * 3) {
        return;
    }

    // Trough background
    BevelStyleT troughBevel = BEVEL_TROUGH(colors);
    drawBevel(d, ops, sbX, sbY, sbW, WGT_SB_W, &troughBevel);

    // Left arrow button
    BevelStyleT btnBevel = BEVEL_SB_BUTTON(colors);
    drawBevel(d, ops, sbX, sbY, WGT_SB_W, WGT_SB_W, &btnBevel);

    // Left arrow triangle
    {
        int32_t  cx = sbX + WGT_SB_W / 2;
        int32_t  cy = sbY + WGT_SB_W / 2;
        uint32_t fg = colors->scrollbarFg;

        for (int32_t i = 0; i < 4; i++) {
            drawVLine(d, ops, cx - 2 + i, cy - i, 1 + i * 2, fg);
        }
    }

    // Right arrow button
    int32_t rightX = sbX + sbW - WGT_SB_W;
    drawBevel(d, ops, rightX, sbY, WGT_SB_W, WGT_SB_W, &btnBevel);

    // Right arrow triangle
    {
        int32_t  cx = rightX + WGT_SB_W / 2;
        int32_t  cy = sbY + WGT_SB_W / 2;
        uint32_t fg = colors->scrollbarFg;

        for (int32_t i = 0; i < 4; i++) {
            drawVLine(d, ops, cx + 2 - i, cy - i, 1 + i * 2, fg);
        }
    }

    // Thumb
    int32_t trackLen = sbW - WGT_SB_W * 2;

    if (trackLen > 0 && totalSize > 0) {
        int32_t thumbPos;
        int32_t thumbSize;
        widgetScrollbarThumb(trackLen, totalSize, visibleSize, scrollPos, &thumbPos, &thumbSize);

        drawBevel(d, ops, sbX + WGT_SB_W + thumbPos, sbY, thumbSize, WGT_SB_W, &btnBevel);
    }
}


// ============================================================
// widgetDrawScrollbarV
// ============================================================

void widgetDrawScrollbarV(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t sbX, int32_t sbY, int32_t sbH, int32_t totalSize, int32_t visibleSize, int32_t scrollPos) {
    if (sbH < WGT_SB_W * 3) {
        return;
    }

    // Trough background
    BevelStyleT troughBevel = BEVEL_TROUGH(colors);
    drawBevel(d, ops, sbX, sbY, WGT_SB_W, sbH, &troughBevel);

    // Up arrow button
    BevelStyleT btnBevel = BEVEL_SB_BUTTON(colors);
    drawBevel(d, ops, sbX, sbY, WGT_SB_W, WGT_SB_W, &btnBevel);

    // Up arrow triangle
    {
        int32_t  cx = sbX + WGT_SB_W / 2;
        int32_t  cy = sbY + WGT_SB_W / 2;
        uint32_t fg = colors->scrollbarFg;

        for (int32_t i = 0; i < 4; i++) {
            drawHLine(d, ops, cx - i, cy - 2 + i, 1 + i * 2, fg);
        }
    }

    // Down arrow button
    int32_t downY = sbY + sbH - WGT_SB_W;
    drawBevel(d, ops, sbX, downY, WGT_SB_W, WGT_SB_W, &btnBevel);

    // Down arrow triangle
    {
        int32_t  cx = sbX + WGT_SB_W / 2;
        int32_t  cy = downY + WGT_SB_W / 2;
        uint32_t fg = colors->scrollbarFg;

        for (int32_t i = 0; i < 4; i++) {
            drawHLine(d, ops, cx - i, cy + 2 - i, 1 + i * 2, fg);
        }
    }

    // Thumb
    int32_t trackLen = sbH - WGT_SB_W * 2;

    if (trackLen > 0 && totalSize > 0) {
        int32_t thumbPos;
        int32_t thumbSize;
        widgetScrollbarThumb(trackLen, totalSize, visibleSize, scrollPos, &thumbPos, &thumbSize);

        drawBevel(d, ops, sbX, sbY + WGT_SB_W + thumbPos, WGT_SB_W, thumbSize, &btnBevel);
    }
}


// ============================================================
// widgetScrollbarHitTest
// ============================================================

// Axis-agnostic hit test. The caller converts (vx,vy) into a 1D
// position along the scrollbar axis (relPos) and the scrollbar
// length (sbLen). Returns which zone was hit: arrow buttons,
// page-up/page-down trough regions, or the thumb itself.
// This factoring lets all scrollbar-owning widgets share the same
// logic without duplicating per-axis code.
ScrollHitE widgetScrollbarHitTest(int32_t sbLen, int32_t relPos, int32_t totalSize, int32_t visibleSize, int32_t scrollPos) {
    if (relPos < WGT_SB_W) {
        return ScrollHitArrowDecE;
    }

    if (relPos >= sbLen - WGT_SB_W) {
        return ScrollHitArrowIncE;
    }

    int32_t trackLen = sbLen - WGT_SB_W * 2;

    if (trackLen > 0) {
        int32_t thumbPos;
        int32_t thumbSize;
        widgetScrollbarThumb(trackLen, totalSize, visibleSize, scrollPos, &thumbPos, &thumbSize);

        int32_t trackRel = relPos - WGT_SB_W;

        if (trackRel < thumbPos) {
            return ScrollHitPageDecE;
        }

        if (trackRel >= thumbPos + thumbSize) {
            return ScrollHitPageIncE;
        }

        return ScrollHitThumbE;
    }

    return ScrollHitNoneE;
}
