// The MIT License (MIT)
//
// Copyright (C) 2026 Scott Duensing
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#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 < barW * 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.
//
// The *Ex variants accept a caller-supplied bar thickness for widgets
// (such as ScrollPane) that need a non-default scrollbar width. The
// plain variants forward to the Ex variants using WGT_SB_W.

#include "dvxWgtP.h"


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) {
    widgetDrawScrollbarHEx(d, ops, colors, sbX, sbY, sbW, totalSize, visibleSize, scrollPos, WGT_SB_W);
}


void widgetDrawScrollbarHEx(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, int32_t barW) {
    if (sbW < barW * 3) {
        return;
    }

    int32_t thumbPos;
    int32_t thumbSize;

    widgetScrollbarThumb(sbW - barW * 2, totalSize, visibleSize, scrollPos, &thumbPos, &thumbSize);
    drawScrollbar(d, ops, colors, ScrollbarHorizontalE, sbX, sbY, sbW, barW, thumbPos, thumbSize);
}


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) {
    widgetDrawScrollbarVEx(d, ops, colors, sbX, sbY, sbH, totalSize, visibleSize, scrollPos, WGT_SB_W);
}


void widgetDrawScrollbarVEx(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, int32_t barW) {
    if (sbH < barW * 3) {
        return;
    }

    int32_t thumbPos;
    int32_t thumbSize;

    widgetScrollbarThumb(sbH - barW * 2, totalSize, visibleSize, scrollPos, &thumbPos, &thumbSize);
    drawScrollbar(d, ops, colors, ScrollbarVerticalE, sbX, sbY, sbH, barW, thumbPos, thumbSize);
}


// 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 thumbPos;
    int32_t thumbSize;

    widgetScrollbarThumb(sbLen - WGT_SB_W * 2, totalSize, visibleSize, scrollPos, &thumbPos, &thumbSize);

    if (thumbSize <= 0) {
        return ScrollHitNoneE;
    }

    int32_t trackRel = relPos - WGT_SB_W;

    if (trackRel < thumbPos) {
        return ScrollHitPageDecE;
    }

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

    return ScrollHitThumbE;
}
