// 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.

// mkwgticon.c -- Generate 24x24 BMP widget icons for the DVX BASIC toolbox
//
// Usage: mkwgticon <output.bmp> <type>
// Types: button, label, textbox, checkbox, radio, dropdown, combobox,
//        listbox, listview, treeview, image, imgbtn, canvas, slider,
//        spinner, progress, timer, frame, hbox, vbox, splitter,
//        scrollpane, tabctrl, toolbar, statusbar, separator, spacer,
//        terminal

#include "bmpDraw.h"

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define ICON_W           24
#define ICON_H           24
#define MINI_CHAR_W      3
#define MINI_CHAR_H      5
#define MINI_CHAR_STRIDE 4
#define MINI_CHAR_BITS   15
#define LOWER_TO_UPPER   32

static BmpCanvasT canvas;

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

static void bevel(int x0, int y0, int w, int h, int bw);
static void drawButton(void);
static void drawCanvas(void);
static void drawCheckbox(void);
static void drawCombobox(void);
static void drawDatactrl(void);
static void drawDbgrid(void);
static void drawDropdown(void);
static void drawFrame(void);
static void drawHbox(void);
static void drawImage(void);
static void drawImgbtn(void);
static void drawLabel(void);
static void drawListbox(void);
static void drawListview(void);
static void drawProgress(void);
static void drawRadio(void);
static void drawScrollpane(void);
static void drawSeparator(void);
static void drawSlider(void);
static void drawSpacer(void);
static void drawSpinner(void);
static void drawSplitter(void);
static void drawStatusbar(void);
static void drawTabctrl(void);
static void drawTerminal(void);
static void drawTextbox(void);
static void drawTimer(void);
static void drawToolbar(void);
static void drawTreeview(void);
static void drawVbox(void);
static void drawWrapbox(void);
static void miniChar(int x, int y, char ch, uint8_t r, uint8_t g, uint8_t b);
static void miniText(int x, int y, const char *text, uint8_t r, uint8_t g, uint8_t b);


static void bevel(int x0, int y0, int w, int h, int bw) {
    // Raised bevel: white top-left, dark bottom-right
    for (int i = 0; i < bw; i++) {
        bmpHLine(&canvas, x0 + i, y0 + i, w - i * 2, 255, 255, 255);
        bmpVLine(&canvas, x0 + i, y0 + i, h - i * 2, 255, 255, 255);
        bmpHLine(&canvas, x0 + i, y0 + h - 1 - i, w - i * 2, 128, 128, 128);
        bmpVLine(&canvas, x0 + w - 1 - i, y0 + i, h - i * 2, 128, 128, 128);
    }
}


static void drawButton(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 3, 5, 18, 14, 192, 192, 192);
    bevel(3, 5, 18, 14, 2);
    miniText(7, 9, "OK", 0, 0, 0);
}


static void drawCanvas(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 3, 3, 18, 18, 255, 255, 255);
    bmpRect(&canvas, 3, 3, 18, 18, 128, 128, 128);
    // Diagonal line
    for (int i = 0; i < 14; i++) {
        bmpPixel(&canvas, 4 + i, 4 + i, 255, 0, 0);
    }
    // Circle
    for (int i = 0; i < 8; i++) {
        bmpPixel(&canvas, 14 + i/2, 6, 0, 0, 255);
        bmpPixel(&canvas, 14 + i/2, 12, 0, 0, 255);
    }
}


static void drawCheckbox(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 4, 7, 10, 10, 255, 255, 255);
    bmpRect(&canvas, 4, 7, 10, 10, 128, 128, 128);
    // Checkmark
    bmpPixel(&canvas, 6, 12, 0, 0, 0); bmpPixel(&canvas, 7, 13, 0, 0, 0); bmpPixel(&canvas, 8, 14, 0, 0, 0);
    bmpPixel(&canvas, 9, 13, 0, 0, 0); bmpPixel(&canvas, 10, 12, 0, 0, 0); bmpPixel(&canvas, 11, 11, 0, 0, 0);
    bmpPixel(&canvas, 12, 10, 0, 0, 0);
    miniText(16, 9, "AB", 0, 0, 0);
}


static void drawCombobox(void) {
    bmpClear(&canvas, 192, 192, 192);
    drawDropdown();
    // Add text to distinguish from dropdown
    miniText(4, 9, "AB", 0, 0, 0);
}


static void drawDatactrl(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Navigation bar
    bmpFillRect(&canvas, 2, 8, 20, 8, 200, 200, 200);
    bmpRect(&canvas, 2, 8, 20, 8, 128, 128, 128);
    // |< button
    bmpVLine(&canvas, 5, 10, 4, 0, 0, 0);
    bmpPixel(&canvas, 6, 11, 0, 0, 0); bmpPixel(&canvas, 7, 12, 0, 0, 0);
    bmpPixel(&canvas, 6, 13, 0, 0, 0); bmpPixel(&canvas, 7, 12, 0, 0, 0);
    // > button
    bmpPixel(&canvas, 16, 11, 0, 0, 0); bmpPixel(&canvas, 17, 12, 0, 0, 0);
    bmpPixel(&canvas, 16, 13, 0, 0, 0);
    // >| button
    bmpVLine(&canvas, 19, 10, 4, 0, 0, 0);
    bmpPixel(&canvas, 18, 11, 0, 0, 0); bmpPixel(&canvas, 18, 13, 0, 0, 0);
    // Database cylinder icon above
    bmpFillRect(&canvas, 7, 2, 10, 4, 255, 255, 200);
    bmpRect(&canvas, 7, 2, 10, 4, 128, 128, 0);
    bmpHLine(&canvas, 7, 3, 10, 128, 128, 0);
}


static void drawDbgrid(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Grid outline
    bmpRect(&canvas, 1, 1, 22, 22, 128, 128, 128);
    // Header row (darker)
    bmpFillRect(&canvas, 2, 2, 20, 5, 160, 160, 200);
    bmpHLine(&canvas, 2, 7, 20, 128, 128, 128);
    // Column dividers
    bmpVLine(&canvas, 8, 2, 20, 128, 128, 128);
    bmpVLine(&canvas, 15, 2, 20, 128, 128, 128);
    // Data rows
    bmpFillRect(&canvas, 2, 8, 20, 14, 255, 255, 255);
    bmpHLine(&canvas, 2, 14, 20, 200, 200, 200);
    // Selected row highlight
    bmpFillRect(&canvas, 2, 15, 20, 7, 0, 0, 128);
}


static void drawDropdown(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 2, 7, 20, 11, 255, 255, 255);
    bmpRect(&canvas, 2, 7, 20, 11, 128, 128, 128);
    // Down arrow button
    bmpFillRect(&canvas, 16, 8, 5, 9, 192, 192, 192);
    bevel(16, 8, 5, 9, 1);
    bmpPixel(&canvas, 17, 11, 0, 0, 0); bmpPixel(&canvas, 18, 12, 0, 0, 0); bmpPixel(&canvas, 19, 11, 0, 0, 0);
}


static void drawFrame(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpRect(&canvas, 3, 6, 18, 15, 128, 128, 128);
    bmpFillRect(&canvas, 5, 4, 14, 5, 192, 192, 192);
    miniText(6, 4, "GRP", 0, 0, 0);
}


static void drawHbox(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpRect(&canvas, 2, 4, 20, 16, 0, 0, 128);
    bmpVLine(&canvas, 8, 4, 16, 0, 0, 128);
    bmpVLine(&canvas, 15, 4, 16, 0, 0, 128);
    // Arrow
    bmpHLine(&canvas, 4, 12, 16, 0, 0, 128);
    bmpPixel(&canvas, 18, 11, 0, 0, 128); bmpPixel(&canvas, 18, 13, 0, 0, 128);
}


static void drawImage(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 3, 3, 18, 18, 255, 255, 255);
    bmpRect(&canvas, 3, 3, 18, 18, 128, 128, 128);
    // Mountain landscape
    bmpPixel(&canvas, 8, 8, 255, 255, 0); // sun
    bmpPixel(&canvas, 9, 8, 255, 255, 0);
    bmpPixel(&canvas, 8, 7, 255, 255, 0);
    bmpPixel(&canvas, 9, 7, 255, 255, 0);
    // Mountain
    for (int i = 0; i < 7; i++) {
        bmpHLine(&canvas, 10 - i, 17 - i, 1 + i * 2, 0, 128, 0);
    }
}


static void drawImgbtn(void) {
    bmpClear(&canvas, 192, 192, 192);
    bevel(2, 3, 20, 18, 2);
    // Small image inside
    bmpFillRect(&canvas, 7, 7, 10, 10, 200, 200, 255);
    bmpRect(&canvas, 7, 7, 10, 10, 0, 0, 128);
}


static void drawLabel(void) {
    bmpClear(&canvas, 192, 192, 192);
    miniText(3, 9, "LABEL", 0, 0, 128);
}


static void drawListbox(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 3, 3, 18, 18, 255, 255, 255);
    bmpRect(&canvas, 3, 3, 18, 18, 128, 128, 128);
    // List items
    bmpHLine(&canvas, 5, 6, 10, 0, 0, 0);
    bmpFillRect(&canvas, 5, 9, 14, 3, 0, 0, 128); // selected
    bmpHLine(&canvas, 5, 10, 10, 255, 255, 255);
    bmpHLine(&canvas, 5, 14, 10, 0, 0, 0);
    bmpHLine(&canvas, 5, 17, 10, 0, 0, 0);
}


static void drawListview(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 2, 2, 20, 20, 255, 255, 255);
    bmpRect(&canvas, 2, 2, 20, 20, 128, 128, 128);
    // Column headers
    bmpFillRect(&canvas, 3, 3, 18, 4, 192, 192, 192);
    bmpHLine(&canvas, 3, 6, 18, 128, 128, 128);
    bmpVLine(&canvas, 10, 3, 18, 128, 128, 128);
    // Grid lines
    bmpHLine(&canvas, 3, 10, 18, 192, 192, 192);
    bmpHLine(&canvas, 3, 14, 18, 192, 192, 192);
}


static void drawProgress(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 2, 8, 20, 8, 255, 255, 255);
    bmpRect(&canvas, 2, 8, 20, 8, 128, 128, 128);
    // Fill
    bmpFillRect(&canvas, 3, 9, 12, 6, 0, 0, 128);
}


static void drawRadio(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Circle outline
    for (int i = 5; i <= 9; i++) { bmpPixel(&canvas, i, 6, 128, 128, 128); bmpPixel(&canvas, i, 16, 128, 128, 128); }
    for (int i = 7; i <= 15; i++) { bmpPixel(&canvas, 4, i, 128, 128, 128); bmpPixel(&canvas, 10, i, 128, 128, 128); }
    // Filled dot
    bmpFillRect(&canvas, 6, 9, 3, 3, 0, 0, 0);
    miniText(14, 9, "AB", 0, 0, 0);
}


static void drawScrollpane(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 2, 2, 18, 18, 255, 255, 255);
    bmpRect(&canvas, 2, 2, 20, 20, 128, 128, 128);
    // Scrollbar
    bmpFillRect(&canvas, 19, 2, 3, 20, 192, 192, 192);
    bmpFillRect(&canvas, 19, 5, 3, 6, 160, 160, 160);
    bevel(19, 5, 3, 6, 1);
}


static void drawSeparator(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Horizontal separator line
    bmpHLine(&canvas, 3, 11, 18, 128, 128, 128);
    bmpHLine(&canvas, 3, 12, 18, 255, 255, 255);
    // Vertical separator line
    bmpVLine(&canvas, 12, 3, 18, 128, 128, 128);
    bmpVLine(&canvas, 13, 3, 18, 255, 255, 255);
}


static void drawSlider(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Track
    bmpHLine(&canvas, 3, 12, 18, 128, 128, 128);
    bmpHLine(&canvas, 3, 13, 18, 255, 255, 255);
    // Thumb
    bmpFillRect(&canvas, 10, 8, 4, 8, 192, 192, 192);
    bevel(10, 8, 4, 8, 1);
}


static void drawSpacer(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Dotted rectangle outline
    for (int i = 0; i < 20; i += 2) {
        bmpPixel(&canvas, 2 + i, 4, 128, 128, 128);
        bmpPixel(&canvas, 2 + i, 19, 128, 128, 128);
    }
    for (int i = 0; i < 16; i += 2) {
        bmpPixel(&canvas, 2, 4 + i, 128, 128, 128);
        bmpPixel(&canvas, 21, 4 + i, 128, 128, 128);
    }
    // Double-headed arrow
    bmpHLine(&canvas, 5, 12, 14, 128, 128, 128);
    bmpPixel(&canvas, 6, 11, 128, 128, 128); bmpPixel(&canvas, 6, 13, 128, 128, 128);
    bmpPixel(&canvas, 18, 11, 128, 128, 128); bmpPixel(&canvas, 18, 13, 128, 128, 128);
}


static void drawSpinner(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 3, 6, 14, 12, 255, 255, 255);
    bmpRect(&canvas, 3, 6, 14, 12, 128, 128, 128);
    miniText(5, 9, "42", 0, 0, 0);
    // Up/down buttons
    bmpFillRect(&canvas, 17, 6, 5, 6, 192, 192, 192);
    bevel(17, 6, 5, 6, 1);
    bmpFillRect(&canvas, 17, 12, 5, 6, 192, 192, 192);
    bevel(17, 12, 5, 6, 1);
    // Arrows
    bmpPixel(&canvas, 19, 8, 0, 0, 0); bmpPixel(&canvas, 18, 9, 0, 0, 0); bmpPixel(&canvas, 20, 9, 0, 0, 0);
    bmpPixel(&canvas, 18, 14, 0, 0, 0); bmpPixel(&canvas, 20, 14, 0, 0, 0); bmpPixel(&canvas, 19, 15, 0, 0, 0);
}


static void drawSplitter(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 2, 2, 9, 20, 200, 200, 200);
    bmpRect(&canvas, 2, 2, 9, 20, 128, 128, 128);
    bmpFillRect(&canvas, 13, 2, 9, 20, 200, 200, 200);
    bmpRect(&canvas, 13, 2, 9, 20, 128, 128, 128);
    // Grip dots
    for (int i = 0; i < 3; i++) {
        bmpPixel(&canvas, 11, 9 + i * 3, 128, 128, 128);
        bmpPixel(&canvas, 12, 9 + i * 3, 255, 255, 255);
    }
}


static void drawStatusbar(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 1, 14, 22, 8, 192, 192, 192);
    // Sunken panels
    bmpHLine(&canvas, 2, 15, 12, 128, 128, 128);
    bmpHLine(&canvas, 2, 20, 12, 255, 255, 255);
    bmpVLine(&canvas, 2, 15, 6, 128, 128, 128);
    bmpVLine(&canvas, 13, 15, 6, 255, 255, 255);
    bmpHLine(&canvas, 15, 15, 7, 128, 128, 128);
    bmpHLine(&canvas, 15, 20, 7, 255, 255, 255);
    bmpVLine(&canvas, 15, 15, 6, 128, 128, 128);
    bmpVLine(&canvas, 21, 15, 6, 255, 255, 255);
}


static void drawTabctrl(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Tab buttons
    bmpFillRect(&canvas, 3, 4, 8, 5, 192, 192, 192);
    bmpHLine(&canvas, 3, 4, 8, 255, 255, 255);
    bmpVLine(&canvas, 3, 4, 5, 255, 255, 255);
    bmpVLine(&canvas, 10, 4, 5, 128, 128, 128);
    bmpFillRect(&canvas, 11, 5, 8, 4, 180, 180, 180);
    bmpHLine(&canvas, 11, 5, 8, 255, 255, 255);
    bmpVLine(&canvas, 18, 5, 4, 128, 128, 128);
    // Body
    bmpFillRect(&canvas, 2, 9, 20, 13, 192, 192, 192);
    bmpRect(&canvas, 2, 9, 20, 13, 128, 128, 128);
}


static void drawTerminal(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 2, 2, 20, 20, 0, 0, 0);
    bmpRect(&canvas, 2, 2, 20, 20, 128, 128, 128);
    // Green text on black
    miniText(4, 5, "C", 0, 255, 0);
    bmpHLine(&canvas, 4, 11, 4, 0, 255, 0);
    miniText(4, 14, "A", 0, 255, 0);
    // Cursor
    bmpFillRect(&canvas, 8, 14, 2, 5, 0, 255, 0);
}


static void drawTextbox(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 2, 6, 20, 12, 255, 255, 255);
    bmpRect(&canvas, 2, 6, 20, 12, 128, 128, 128);
    miniText(4, 9, "TEXT", 0, 0, 0);
}


static void drawTimer(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Clock face
    for (int a = 0; a < 12; a++) {
        int cx = 12, cy = 12;
        // Approximate circle points
        static const int dx[] = {0, 4, 7, 8, 7, 4, 0, -4, -7, -8, -7, -4};
        static const int dy[] = {-8, -7, -4, 0, 4, 7, 8, 7, 4, 0, -4, -7};
        bmpPixel(&canvas, cx + dx[a], cy + dy[a], 0, 0, 0);
    }
    // Hands
    bmpVLine(&canvas, 12, 5, 7, 0, 0, 0);
    bmpHLine(&canvas, 12, 12, 5, 0, 0, 0);
}


static void drawToolbar(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 1, 7, 22, 10, 192, 192, 192);
    bevel(1, 7, 22, 10, 1);
    // Buttons
    bmpFillRect(&canvas, 3, 8, 5, 8, 192, 192, 192);
    bevel(3, 8, 5, 8, 1);
    bmpFillRect(&canvas, 9, 8, 5, 8, 192, 192, 192);
    bevel(9, 8, 5, 8, 1);
    bmpFillRect(&canvas, 15, 8, 5, 8, 192, 192, 192);
    bevel(15, 8, 5, 8, 1);
}


static void drawTreeview(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 2, 2, 20, 20, 255, 255, 255);
    bmpRect(&canvas, 2, 2, 20, 20, 128, 128, 128);
    // Tree lines
    bmpVLine(&canvas, 6, 5, 14, 128, 128, 128);
    bmpHLine(&canvas, 6, 7, 5, 128, 128, 128);
    bmpHLine(&canvas, 6, 12, 5, 128, 128, 128);
    bmpVLine(&canvas, 10, 12, 5, 128, 128, 128);
    bmpHLine(&canvas, 10, 16, 5, 128, 128, 128);
    // Expand box
    bmpFillRect(&canvas, 4, 4, 5, 5, 255, 255, 255);
    bmpRect(&canvas, 4, 4, 5, 5, 0, 0, 0);
    bmpHLine(&canvas, 5, 6, 3, 0, 0, 0); // minus
    bmpPixel(&canvas, 6, 5, 0, 0, 0); // plus vertical
    bmpPixel(&canvas, 6, 7, 0, 0, 0);
}


static void drawVbox(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpRect(&canvas, 2, 2, 20, 20, 0, 128, 0);
    bmpHLine(&canvas, 2, 8, 20, 0, 128, 0);
    bmpHLine(&canvas, 2, 15, 20, 0, 128, 0);
    // Arrow
    bmpVLine(&canvas, 12, 4, 16, 0, 128, 0);
    bmpPixel(&canvas, 11, 18, 0, 128, 0); bmpPixel(&canvas, 13, 18, 0, 128, 0);
}


static void drawWrapbox(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpRect(&canvas, 2, 2, 20, 20, 0, 0, 180);
    // Row 1: three small boxes
    bmpFillRect(&canvas, 4, 4, 5, 4, 200, 200, 255);
    bmpRect(&canvas, 4, 4, 5, 4, 0, 0, 180);
    bmpFillRect(&canvas, 10, 4, 5, 4, 200, 200, 255);
    bmpRect(&canvas, 10, 4, 5, 4, 0, 0, 180);
    bmpFillRect(&canvas, 16, 4, 5, 4, 200, 200, 255);
    bmpRect(&canvas, 16, 4, 5, 4, 0, 0, 180);
    // Row 2: two boxes (wrapped)
    bmpFillRect(&canvas, 4, 10, 5, 4, 200, 200, 255);
    bmpRect(&canvas, 4, 10, 5, 4, 0, 0, 180);
    bmpFillRect(&canvas, 10, 10, 5, 4, 200, 200, 255);
    bmpRect(&canvas, 10, 10, 5, 4, 0, 0, 180);
    // Row 3: one box
    bmpFillRect(&canvas, 4, 16, 5, 4, 200, 200, 255);
    bmpRect(&canvas, 4, 16, 5, 4, 0, 0, 180);
}


// 3x5 mini font for labeling icons
static void miniChar(int x, int y, char ch, uint8_t r, uint8_t g, uint8_t b) {
    // Simplified: just draw recognizable glyphs for A-Z, 0-9
    static const uint16_t font[128] = {
        ['A'] = 0x7D6F, ['B'] = 0xFD7F, ['C'] = 0x7C9F, ['D'] = 0xF56F,
        ['E'] = 0xFC9F, ['F'] = 0xFC90, ['G'] = 0x7CBF, ['H'] = 0xB7ED,
        ['I'] = 0xE92E, ['K'] = 0xB6AD, ['L'] = 0x924F, ['M'] = 0xBFED,
        ['N'] = 0xBDED, ['O'] = 0x756E, ['P'] = 0xFD20, ['R'] = 0xFD6D,
        ['S'] = 0x7C1F, ['T'] = 0xE924, ['U'] = 0xB6DE, ['V'] = 0xB6A4,
        ['W'] = 0xB7FA, ['X'] = 0xB52D, ['Y'] = 0xB524, ['Z'] = 0xE54F,
    };

    uint16_t bits = (ch >= 'A' && ch <= 'Z') ? font[(int)ch] : 0;

    for (int row = 0; row < MINI_CHAR_H; row++) {
        for (int col = 0; col < MINI_CHAR_W; col++) {
            if (bits & (1 << (MINI_CHAR_BITS - 1 - row * MINI_CHAR_W - col))) {
                bmpPixel(&canvas, x + col, y + row, r, g, b);
            }
        }
    }
}


static void miniText(int x, int y, const char *text, uint8_t r, uint8_t g, uint8_t b) {
    while (*text) {
        char ch = *text;

        if (ch >= 'a' && ch <= 'z') {
            ch -= LOWER_TO_UPPER;
        }

        miniChar(x, y, ch, r, g, b);
        x += MINI_CHAR_STRIDE;
        text++;
    }
}


int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "Usage: mkwgticon <output.bmp> <type>\n");
        return 1;
    }

    const char *path = argv[1];
    const char *type = argv[2];

    typedef struct { const char *name; void (*fn)(void); } IconT;
    IconT icons[] = {
        {"button",     drawButton},
        {"label",      drawLabel},
        {"textbox",    drawTextbox},
        {"checkbox",   drawCheckbox},
        {"radio",      drawRadio},
        {"dropdown",   drawDropdown},
        {"combobox",   drawCombobox},
        {"listbox",    drawListbox},
        {"listview",   drawListview},
        {"treeview",   drawTreeview},
        {"image",      drawImage},
        {"imgbtn",     drawImgbtn},
        {"canvas",     drawCanvas},
        {"slider",     drawSlider},
        {"spinner",    drawSpinner},
        {"progress",   drawProgress},
        {"timer",      drawTimer},
        {"frame",      drawFrame},
        {"hbox",       drawHbox},
        {"vbox",       drawVbox},
        {"splitter",   drawSplitter},
        {"scrollpane", drawScrollpane},
        {"tabctrl",    drawTabctrl},
        {"toolbar",    drawToolbar},
        {"statusbar",  drawStatusbar},
        {"separator",  drawSeparator},
        {"spacer",     drawSpacer},
        {"terminal",   drawTerminal},
        {"wrapbox",    drawWrapbox},
        {"datactrl",   drawDatactrl},
        {"dbgrid",     drawDbgrid},
        {NULL, NULL}
    };

    if (!bmpInit(&canvas, ICON_W, ICON_H)) {
        fprintf(stderr, "Out of memory\n");
        return 1;
    }

    for (int i = 0; icons[i].name; i++) {
        if (strcmp(type, icons[i].name) == 0) {
            icons[i].fn();
            bmpWrite(&canvas, path);
            bmpFree(&canvas);
            return 0;
        }
    }

    bmpFree(&canvas);
    fprintf(stderr, "Unknown type: %s\nAvailable:", type);

    for (int i = 0; icons[i].name; i++) {
        fprintf(stderr, " %s", icons[i].name);
    }

    fprintf(stderr, "\n");
    return 1;
}
