// 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
// widgetSeparator.c  -- Separator widget (horizontal and vertical)
//
// A purely decorative widget that draws a 2px etched line (shadow +
// highlight pair) to visually divide groups of widgets. The etched
// line technique (dark line followed by light line offset by 1px)
// creates a subtle 3D groove that matches the Motif/Win3.1 aesthetic.
//
// Separate constructors (wgtHSeparator/wgtVSeparator) rather than a
// runtime orientation parameter because separators are always fixed
// orientation at construction time.
//
// The min size in the cross-axis is SEPARATOR_THICKNESS (2px), while
// the main axis min is 0 -- the separator stretches to fill the
// available width/height in its parent layout. This makes separators
// work correctly in both HBox and VBox containers without explicit
// sizing.
//
// No mouse/key handlers -- purely decorative, non-focusable.

#include "dvxWgtP.h"

#define SEPARATOR_THICKNESS  2

static int32_t sTypeId = -1;

typedef struct {
    bool vertical;
} SeparatorDataT;


// ============================================================
// Prototypes
// ============================================================

WidgetT     *wgtHSeparator(WidgetT *parent);
void         wgtRegister(void);
WidgetT     *wgtVSeparator(WidgetT *parent);
void         widgetSeparatorCalcMinSize(WidgetT *w, const BitmapFontT *font);
void         widgetSeparatorPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);


WidgetT *wgtHSeparator(WidgetT *parent) {
    WidgetT *w = widgetAlloc(parent, sTypeId);

    if (!w) {
        return NULL;
    }

    SeparatorDataT *d = calloc(1, sizeof(SeparatorDataT));

    if (!d) {
        widgetAllocRollback(w);
        return NULL;
    }

    // Auto-orient to the parent: horizontal container -> vertical
    // divider, vertical container -> horizontal divider.  This
    // lets a single "Line" basName work correctly in both
    // toolbars and menus without requiring callers to pick
    // between HSeparator and VSeparator by widget type.
    if (parent && widgetIsHorizContainer(parent->type)) {
        d->vertical = true;
    }

    w->data = d;
    return w;
}


// ============================================================
// DXE registration
// ============================================================


static const WidgetClassT sClassSeparator = {
    .version = WGT_CLASS_VERSION,
    .flags   = 0,
    .handlers = {
        [WGT_METHOD_PAINT]         = (void *)widgetSeparatorPaint,
        [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetSeparatorCalcMinSize,
    }
};

static const struct {
    WidgetT *(*hSeparator)(WidgetT *parent);
    WidgetT *(*vSeparator)(WidgetT *parent);
} sApi = {
    .hSeparator = wgtHSeparator,
    .vSeparator = wgtVSeparator
};

static const WgtIfaceT sIface = {
    .basName      = "Line",
    .props        = NULL,
    .propCount    = 0,
    .methods      = NULL,
    .methodCount  = 0,
    .events       = NULL,
    .eventCount   = 0,
    .createSig    = WGT_CREATE_PARENT
};

void wgtRegister(void) {
    sTypeId = wgtRegisterClass(&sClassSeparator);
    wgtRegisterApi("separator", &sApi);
    wgtRegisterIface("separator", &sIface);
}


WidgetT *wgtVSeparator(WidgetT *parent) {
    WidgetT *w = widgetAlloc(parent, sTypeId);

    if (!w) {
        return NULL;
    }

    SeparatorDataT *d = calloc(1, sizeof(SeparatorDataT));

    if (!d) {
        widgetAllocRollback(w);
        return NULL;
    }

    w->data      = d;
    d->vertical  = true;
    return w;
}


void widgetSeparatorCalcMinSize(WidgetT *w, const BitmapFontT *font) {
    (void)font;
    SeparatorDataT *d = (SeparatorDataT *)w->data;

    if (d->vertical) {
        w->calcMinW = SEPARATOR_THICKNESS;
        w->calcMinH = 0;
    } else {
        w->calcMinW = 0;
        w->calcMinH = SEPARATOR_THICKNESS;
    }
}


void widgetSeparatorPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) {
    (void)font;
    SeparatorDataT *sd = (SeparatorDataT *)w->data;

    if (sd->vertical) {
        int32_t cx = w->x + w->w / 2;
        drawVLine(d, ops, cx, w->y, w->h, colors->windowShadow);
        drawVLine(d, ops, cx + 1, w->y, w->h, colors->windowHighlight);
    } else {
        int32_t cy = w->y + w->h / 2;
        drawHLine(d, ops, w->x, cy, w->w, colors->windowShadow);
        drawHLine(d, ops, w->x, cy + 1, w->w, colors->windowHighlight);
    }
}
