package raygui

import (
	"fmt"
	"math"
	"strconv"

	rl "github.com/gen2brain/raylib-go/raylib"
)

// MODIFIED: All occurrences of rl.GetMousePosition have been replaced with
// GetMousePositionWorld from ext.go.

// Style property
type GuiStyleProp struct {
	ControlId     uint
	PropertyId    uint
	PropertyValue int
}

// Gui control state
type ControlState int

const (
	StateNormal ControlState = iota
	StateFocused
	StatePressed
	StateDisabled
)

// Gui control text alignment
type TextAlignment int

const (
	TextAlignLeft TextAlignment = iota
	TextAlignCenter
	TextAlignRight
)

// Gui controls
type Control int

const (
	Default Control = iota
	LabelControl
	ButtonControl
	ToggleControl
	SliderControl
	ProgressBarControl
	CheckBoxControl
	ComboBoxControl
	DropdownBoxControl
	TextBoxControl
	ValueBoxControl
	SpinnerControl
	ListViewControl
	ColorPickerControl
	ScrollBarControl
	StatusBarControl
)

// Gui base properties for every control
type ControlProperty int

const (
	BorderColorNormalProp ControlProperty = iota
	BaseColorNormalProp
	TextColorNormalProp
	BorderColorFocusedProp
	BaseColorFocusedProp
	TextColorFocusedProp
	BorderColorPressedProp
	BaseColorPressedProp
	TextColorPressedProp
	BorderColorDisabledProp
	BaseColorDisabledProp
	TextColorDisabledProp
	BorderWidthProp
	TextPaddingProp
	TextAlignmentProp
	ReservedProp
)

// Gui extended properties depend on control
// NOTE: We reserve a fixed size of additional properties per control

// Default properties\
const (
	TextSizeProp ControlProperty = iota + 16
	TextSpacingProp
	LineColorProp
	BackgroundColorProp
)

// Label
//typedef enum { } GuiLabelProperty;

// Button
//typedef enum { } GuiButtonProperty;

// Toggle / ToggleGroup
const (
	GroupPadding ControlProperty = iota + 16
)

// Slider / SliderBar
const (
	SliderWidth ControlProperty = iota + 16
	SliderPadding
)

// ProgressBar
const (
	ProgressPadding ControlProperty = iota + 16
)

// CheckBox
const (
	CheckPadding ControlProperty = iota + 16
)

// ComboBox
const (
	ComboButtonWidth ControlProperty = iota + 16
	ComboButtonPadding
)

// DropdownBox
const (
	ArrowPadding ControlProperty = iota + 16
	DropdownItemsPadding
)

// TextBox / TextBoxMulti / ValueBox / Spinner
const (
	TextInnerPadding ControlProperty = iota + 16
	TextLinesPadding
	ColorSelectedFG
	ColorSelectedBG
)

// Spinner
const (
	SpinButtonWidth ControlProperty = iota + 16
	SpinButtonPadding
)

// ScrollBar
const (
	ArrowsSize ControlProperty = iota + 16
	ArrowsVisible
	ScrollSliderPadding
	ScrollSliderSize
	ScrollPadding
	ScrollSpeed
)

// ScrollBar side
type ScrollBarSide int

const (
	ScrollBarLeftSide ScrollBarSide = iota
	ScrollBarRightSide
)

// ListView
const (
	ListItemsHeight ControlProperty = iota + 16
	ListItemsPadding
	ScrollBarWidth
	ScrollBarSideProp // Renamed from ScrollBarSide due to naming conflict
)

// ColorPicker
const (
	ColorSelectorSize      ControlProperty = iota + 16
	HueBarWidth                            // Right hue bar width
	HueBarPadding                          // Right hue bar separation from panel
	HueBarSelectorHeight                   // Right hue bar selector height
	HueBarSelectorOverflow                 // Right hue bar selector overflow
)

const MaxControls = 16     // Maximum number of standard controls
const MaxPropsDefault = 16 // Maximum number of standard properties
const MaxPropsExtended = 8 // Maximum number of extended properties

//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------

// Gui control property style color element
const (
	Border ControlProperty = iota
	Base
	Text
	Other
)

//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
var guiState = StateNormal

var guiFont rl.Font      // Gui current font (WARNING: highly coupled to raylib)
var guiLocked = false    // Gui lock state (no inputs processed)
var guiAlpha float32 = 1 // Gui element transpacency on drawing

// Global gui style array (allocated on data segment by default)
// NOTE: In raygui we manage a single int array with all the possible style properties.
// When a new style is loaded, it loads over the global style... but default gui style
// could always be recovered with GuiLoadStyleDefault()
var guiStyle [MaxControls * (MaxPropsDefault + MaxPropsExtended)]uint
var guiStyleLoaded = false // Style loaded flag for lazy style initialization

const RIconSize = 16          // Size of icons (squared)
const RIconMaxIcons = 256     // Maximum number of icons
const RIconMaxNameLength = 32 // Maximum length of icon name id

// Icons data is defined by bit array (every bit represents one pixel)
// Those arrays are stored as unsigned int data arrays, so every array
// element defines 32 pixels (bits) of information
// Number of elemens depend on RICON_SIZE (by default 16x16 pixels)
const RIconDataElements = RIconSize * RIconSize / 32

//----------------------------------------------------------------------------------
// Icons data (allocated on memory data section by default)
// NOTE: A new icon set could be loaded over this array using GuiLoadIcons(),
// just note that loaded icons set must be same RICON_SIZE
//----------------------------------------------------------------------------------
var guiIcons = [RIconMaxIcons * RIconDataElements]uint32{
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_NONE
	0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // RICON_FOLDER_FILE_OPEN
	0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // RICON_FILE_SAVE_CLASSIC
	0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // RICON_FOLDER_OPEN
	0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // RICON_FOLDER_SAVE
	0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // RICON_FILE_OPEN
	0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // RICON_FILE_SAVE
	0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // RICON_FILE_EXPORT
	0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // RICON_FILE_NEW
	0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // RICON_FILE_DELETE
	0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // RICON_FILETYPE_TEXT
	0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // RICON_FILETYPE_AUDIO
	0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // RICON_FILETYPE_IMAGE
	0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // RICON_FILETYPE_PLAY
	0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // RICON_FILETYPE_VIDEO
	0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // RICON_FILETYPE_INFO
	0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // RICON_FILE_COPY
	0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // RICON_FILE_CUT
	0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // RICON_FILE_PASTE
	0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_CURSOR_HAND
	0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // RICON_CURSOR_POINTER
	0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // RICON_CURSOR_CLASSIC
	0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // RICON_PENCIL
	0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // RICON_PENCIL_BIG
	0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // RICON_BRUSH_CLASSIC
	0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // RICON_BRUSH_PAINTER
	0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // RICON_WATER_DROP
	0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // RICON_COLOR_PICKER
	0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // RICON_RUBBER
	0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // RICON_COLOR_BUCKET
	0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // RICON_TEXT_T
	0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // RICON_TEXT_A
	0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // RICON_SCALE
	0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // RICON_RESIZE
	0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // RICON_FILTER_POINT
	0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // RICON_FILTER_BILINEAR
	0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // RICON_CROP
	0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // RICON_CROP_ALPHA
	0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // RICON_SQUARE_TOGGLE
	0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // RICON_SIMMETRY
	0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // RICON_SIMMETRY_HORIZONTAL
	0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // RICON_SIMMETRY_VERTICAL
	0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // RICON_LENS
	0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // RICON_LENS_BIG
	0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // RICON_EYE_ON
	0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // RICON_EYE_OFF
	0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // RICON_FILTER_TOP
	0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // RICON_FILTER
	0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_POINT
	0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_SMALL
	0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_BIG
	0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // RICON_TARGET_MOVE
	0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // RICON_CURSOR_MOVE
	0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // RICON_CURSOR_SCALE
	0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // RICON_CURSOR_SCALE_RIGHT
	0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // RICON_CURSOR_SCALE_LEFT
	0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // RICON_UNDO
	0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // RICON_REDO
	0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // RICON_REREDO
	0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // RICON_MUTATE
	0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // RICON_ROTATE
	0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // RICON_REPEAT
	0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // RICON_SHUFFLE
	0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // RICON_EMPTYBOX
	0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // RICON_TARGET
	0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_SMALL_FILL
	0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_BIG_FILL
	0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // RICON_TARGET_MOVE_FILL
	0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // RICON_CURSOR_MOVE_FILL
	0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // RICON_CURSOR_SCALE_FILL
	0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // RICON_CURSOR_SCALE_RIGHT
	0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // RICON_CURSOR_SCALE_LEFT
	0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // RICON_UNDO_FILL
	0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // RICON_REDO_FILL
	0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // RICON_REREDO_FILL
	0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // RICON_MUTATE_FILL
	0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // RICON_ROTATE_FILL
	0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // RICON_REPEAT_FILL
	0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // RICON_SHUFFLE_FILL
	0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // RICON_EMPTYBOX_SMALL
	0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX
	0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_TOP
	0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_TOP_RIGHT
	0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_RIGHT
	0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // RICON_BOX_BOTTOM_RIGHT
	0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // RICON_BOX_BOTTOM
	0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // RICON_BOX_BOTTOM_LEFT
	0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_LEFT
	0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_TOP_LEFT
	0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_CIRCLE_MASK
	0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // RICON_BOX_CENTER
	0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // RICON_POT
	0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // RICON_ALPHA_MULTIPLY
	0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // RICON_ALPHA_CLEAR
	0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // RICON_DITHERING
	0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // RICON_MIPMAPS
	0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // RICON_BOX_GRID
	0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // RICON_GRID
	0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // RICON_BOX_CORNERS_SMALL
	0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // RICON_BOX_CORNERS_BIG
	0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // RICON_FOUR_BOXES
	0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // RICON_GRID_FILL
	0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // RICON_BOX_MULTISIZE
	0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // RICON_ZOOM_SMALL
	0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // RICON_ZOOM_MEDIUM
	0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // RICON_ZOOM_BIG
	0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // RICON_ZOOM_ALL
	0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // RICON_ZOOM_CENTER
	0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // RICON_BOX_DOTS_SMALL
	0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // RICON_BOX_DOTS_BIG
	0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // RICON_BOX_CONCENTRIC
	0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // RICON_BOX_GRID_BIG
	0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // RICON_OK_TICK
	0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // RICON_CROSS
	0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // RICON_ARROW_LEFT
	0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // RICON_ARROW_RIGHT
	0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // RICON_ARROW_BOTTOM
	0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // RICON_ARROW_TOP
	0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // RICON_ARROW_LEFT_FILL
	0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // RICON_ARROW_RIGHT_FILL
	0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // RICON_ARROW_BOTTOM_FILL
	0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // RICON_ARROW_TOP_FILL
	0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // RICON_AUDIO
	0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // RICON_FX
	0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // RICON_WAVE
	0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // RICON_WAVE_SINUS
	0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // RICON_WAVE_SQUARE
	0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // RICON_WAVE_TRIANGULAR
	0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // RICON_CROSS_SMALL
	0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // RICON_PLAYER_PREVIOUS
	0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // RICON_PLAYER_PLAY_BACK
	0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // RICON_PLAYER_PLAY
	0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // RICON_PLAYER_PAUSE
	0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // RICON_PLAYER_STOP
	0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // RICON_PLAYER_NEXT
	0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // RICON_PLAYER_RECORD
	0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // RICON_MAGNET
	0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // RICON_LOCK_CLOSE
	0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // RICON_LOCK_OPEN
	0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // RICON_CLOCK
	0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // RICON_TOOLS
	0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // RICON_GEAR
	0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // RICON_GEAR_BIG
	0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // RICON_BIN
	0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // RICON_HAND_POINTER
	0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // RICON_LASER
	0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // RICON_COIN
	0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // RICON_EXPLOSION
	0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // RICON_1UP
	0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // RICON_PLAYER
	0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // RICON_PLAYER_JUMP
	0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // RICON_KEY
	0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // RICON_DEMON
	0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // RICON_TEXT_POPUP
	0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // RICON_GEAR_EX
	0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // RICON_CRACK
	0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // RICON_CRACK_POINTS
	0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // RICON_STAR
	0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // RICON_DOOR
	0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // RICON_EXIT
	0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // RICON_MODE_2D
	0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // RICON_MODE_3D
	0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // RICON_CUBE
	0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // RICON_CUBE_FACE_TOP
	0x7fe00000, 0x50386030, 0x47fe483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // RICON_CUBE_FACE_LEFT
	0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // RICON_CUBE_FACE_FRONT
	0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3ff27fe2, 0x0ffe1ffa, 0x000007fe, // RICON_CUBE_FACE_BOTTOM
	0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // RICON_CUBE_FACE_RIGHT
	0x7fe00000, 0x7fe87ff0, 0x7ffe7fe4, 0x7fe27fe2, 0x7fe27fe2, 0x24127fe2, 0x0c06140a, 0x000007fe, // RICON_CUBE_FACE_BACK
	0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // RICON_CAMERA
	0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // RICON_SPECIAL
	0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // RICON_LINK_NET
	0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // RICON_LINK_BOXES
	0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // RICON_LINK_MULTI
	0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // RICON_LINK
	0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // RICON_LINK_BROKE
	0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // RICON_TEXT_NOTES
	0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // RICON_NOTEBOOK
	0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // RICON_SUITCASE
	0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // RICON_SUITCASE_ZIP
	0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // RICON_MAILBOX
	0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // RICON_MONITOR
	0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // RICON_PRINTER
	0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // RICON_PHOTO_CAMERA
	0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // RICON_PHOTO_CAMERA_FLASH
	0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // RICON_HOUSE
	0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // RICON_HEART
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // RICON_CORNER
	0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // RICON_VERTICAL_BARS
	0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // RICON_VERTICAL_BARS_FILL
	0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // RICON_LIFE_BARS
	0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // RICON_INFO
	0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // RICON_CROSSLINE
	0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // RICON_HELP
	0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // RICON_FILETYPE_ALPHA
	0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // RICON_FILETYPE_HOME
	0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // RICON_LAYERS_VISIBLE
	0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // RICON_LAYERS
	0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // RICON_WINDOW
	0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // RICON_HIDPI
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_200
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_201
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_202
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_203
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_204
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_205
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_206
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_207
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_208
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_209
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_210
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_211
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_212
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_213
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_214
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_215
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_216
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_217
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_218
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_219
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_220
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_221
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_222
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_223
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_224
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_225
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_226
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_227
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_228
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_229
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_230
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_231
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_232
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_233
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_234
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_235
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_236
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_237
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_238
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_239
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_240
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_241
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_242
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_243
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_244
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_245
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_246
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_247
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_248
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_249
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_250
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_251
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_252
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_253
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_254
	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_255
}

//----------------------------------------------------------------------------------
// Gui Setup Functions Definition
//----------------------------------------------------------------------------------

// Enable gui global state
func Enable() {
	guiState = StateNormal
}

// Disable gui global state
func Disable() {
	guiState = StateDisabled
}

// Lock gui global state
func Lock() {
	guiLocked = true
}

// Unlock gui global state
func Unlock() {
	guiLocked = false
}

// Convert color data from RGB to HSV
// NOTE: Color data should be passed normalized
func ConvertRGBtoHSV(rgb rl.Vector3) rl.Vector3 {
	var hsv rl.Vector3
	var min float32 = 0
	var max float32 = 0
	var delta float32 = 0

	min = rgb.X
	if rgb.Y < min {
		min = rgb.Y
	}
	if rgb.Z < min {
		min = rgb.Z
	}

	max = rgb.X
	if rgb.Y > max {
		max = rgb.Y
	}
	if rgb.Z > max {
		max = rgb.Z
	}

	hsv.Z = max // Value
	delta = max - min

	if delta < 0.00001 {
		hsv.Y = 0
		hsv.X = 0 // Undefined, maybe NAN?
		return hsv
	}

	if max > 0 {
		// NOTE: If max is 0, this divide would cause a crash
		hsv.Y = (delta / max) // Saturation
	} else {
		// NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
		hsv.Y = 0
		hsv.X = 0 // Undefined, maybe NAN?
		return hsv
	}

	// NOTE: Comparing float values could not work properly
	if rgb.X >= max {
		hsv.X = (rgb.Y - rgb.Z) / delta // Between yellow & magenta
	} else {
		if rgb.Y >= max {
			hsv.X = 2 + (rgb.Z-rgb.X)/delta // Between cyan & yellow
		} else {
			hsv.X = 4 + (rgb.X-rgb.Y)/delta // Between magenta & cyan
		}
	}

	hsv.X *= 60 // Convert to degrees

	if hsv.X < 0 {
		hsv.X += 360
	}

	return hsv
}

// Convert color data from HSV to RGB
// NOTE: Color data should be passed normalized
func ConvertHSVtoRGB(hsv rl.Vector3) rl.Vector3 {
	var rgb rl.Vector3
	var hh float32 = 0
	var p float32 = 0
	var q float32 = 0
	var t float32 = 0
	var ff float32 = 0
	var i int64 = 0

	// NOTE: Comparing float values could not work properly
	if hsv.Y <= 0 {
		rgb.X = hsv.Z
		rgb.Y = hsv.Z
		rgb.Z = hsv.Z
		return rgb
	}

	hh = hsv.X
	if hh >= 360 {
		hh = 0
	}
	hh /= 60

	i = int64(hh)
	ff = hh - float32(i)
	p = hsv.Z * (1 - hsv.Y)
	q = hsv.Z * (1 - (hsv.Y * ff))
	t = hsv.Z * (1 - (hsv.Y * (1 - ff)))

	switch i {
	case 0:
		rgb.X = hsv.Z
		rgb.Y = t
		rgb.Z = p
	case 1:
		rgb.X = q
		rgb.Y = hsv.Z
		rgb.Z = p
	case 2:
		rgb.X = p
		rgb.Y = hsv.Z
		rgb.Z = t
	case 3:
		rgb.X = p
		rgb.Y = q
		rgb.Z = hsv.Z
	case 4:
		rgb.X = t
		rgb.Y = p
		rgb.Z = hsv.Z
	// case 5:
	default:
		rgb.X = hsv.Z
		rgb.Y = p
		rgb.Z = q
	}

	return rgb
}

// Set gui controls alpha global state
func Fade(alpha float32) {
	if alpha < 0 {
		alpha = 0
	} else if alpha > 1 {
		alpha = 1
	}

	alpha = alpha
}

// Set gui state (global state)
func SetState(state ControlState) {
	guiState = state
}

// Get gui state (global state)
func GetState() ControlState {
	return guiState
}

// Set custom gui font
// NOTE: Font loading/unloading is external to raygui
func SetFont(font rl.Font) {
	if font.Texture.ID > 0 {
		// NOTE: If we try to setup a font but default style has not been
		// lazily loaded before, it will be overwritten, so we need to force
		// default style loading first
		if !guiStyleLoaded {
			LoadStyleDefault()
		}

		guiFont = font
		SetStyle(Default, TextSizeProp, uint(font.BaseSize))
	}
}

// Get custom gui font
func GetFont() rl.Font {
	return guiFont
}

// Set control style property value
func SetStyle(control Control, property ControlProperty, value uint) {
	if !guiStyleLoaded {
		LoadStyleDefault()
	}
	guiStyle[int(control)*(MaxPropsDefault+MaxPropsExtended)+int(property)] = value

	// Default properties are propagated to all controls
	if (control == 0) && (property < MaxPropsDefault) {
		for i := 1; i < MaxControls; i++ {
			guiStyle[i*(MaxPropsDefault+MaxPropsExtended)+int(property)] = value
		}
	}
}

// Get control style property value
func GetStyle(control Control, property ControlProperty) uint {
	if !guiStyleLoaded {
		LoadStyleDefault()
	}
	return guiStyle[int(control)*(MaxPropsDefault+MaxPropsExtended)+int(property)]
}

//----------------------------------------------------------------------------------
// Gui Controls Functions Definition
//----------------------------------------------------------------------------------

// NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox()
const WindowStatusBarHeight = 22

// Window Box control
func WindowBox(bounds rl.Rectangle, title string) bool {
	//GuiControlState state = guiState;
	clicked := false

	statusBarHeight := WindowStatusBarHeight + 2*GetStyle(StatusBarControl, BorderWidthProp)
	statusBarHeight += statusBarHeight % 2

	statusBar := rl.Rectangle{bounds.X, bounds.Y, bounds.Width, float32(statusBarHeight)}
	if bounds.Height < float32(statusBarHeight)*2 {
		bounds.Height = float32(statusBarHeight) * 2
	}

	windowPanel := rl.Rectangle{bounds.X, bounds.Y + float32(statusBarHeight) - 1, bounds.Width, bounds.Height - float32(statusBarHeight)}
	closeButtonRec := rl.Rectangle{
		statusBar.X + statusBar.Width - float32(GetStyle(StatusBarControl, BorderWidthProp)) - 20,
		statusBar.Y + float32(statusBarHeight)/2 - 18/2,
		18, 18,
	}

	// Update control
	//--------------------------------------------------------------------
	// NOTE: Logic is directly managed by button
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	StatusBar(statusBar, title) // Draw window header as status bar
	Panel(windowPanel)          // Draw window base

	// Draw window close button
	tempBorderWidth := GetStyle(ButtonControl, BorderWidthProp)
	tempTextAlignment := GetStyle(ButtonControl, TextAlignmentProp)
	SetStyle(ButtonControl, BorderWidthProp, 1)
	SetStyle(ButtonControl, TextAlignmentProp, uint(TextAlignCenter))
	clicked = Button(closeButtonRec, "x")
	/*
		// TODO(icons)
		#if defined(RAYGUI_SUPPORT_RICONS)
			clicked = GuiButton(closeButtonRec, GuiIconText(RICON_CROSS_SMALL, NULL));
		#else
			clicked = GuiButton(closeButtonRec, "x");
		#endif
	*/
	SetStyle(ButtonControl, BorderWidthProp, tempBorderWidth)
	SetStyle(ButtonControl, TextAlignmentProp, tempTextAlignment)

	return clicked
}

const GroupBoxLineThick = 1
const GroupBoxTextPadding = 10

// Group Box control with text name
func GroupBox(bounds rl.Rectangle, text string) {
	state := guiState

	borderColorProp := LineColorProp
	if state == StateDisabled {
		borderColorProp = BorderColorDisabledProp
	}
	borderColor := rl.GetColor(int32(GetStyle(Default, borderColorProp)))

	// Draw control
	//--------------------------------------------------------------------
	DrawRectangle(rl.Rectangle{bounds.X, bounds.Y, GroupBoxLineThick, bounds.Height}, 0, rl.Blank, rl.Fade(borderColor, guiAlpha))
	DrawRectangle(rl.Rectangle{bounds.X, bounds.Y + bounds.Height - 1, bounds.Width, GroupBoxLineThick}, 0, rl.Blank, rl.Fade(borderColor, guiAlpha))
	DrawRectangle(rl.Rectangle{bounds.X + bounds.Width - 1, bounds.Y, GroupBoxLineThick, bounds.Height}, 0, rl.Blank, rl.Fade(borderColor, guiAlpha))

	Line(rl.Rectangle{bounds.X, bounds.Y, bounds.Width, 1}, text)
	//--------------------------------------------------------------------
}

const LineTextPadding = 10

// Line control
func Line(bounds rl.Rectangle, text string) {
	state := guiState

	colorProp := LineColorProp
	if state == StateDisabled {
		colorProp = BorderColorDisabledProp
	}
	colorStyle := rl.GetColor(int32(GetStyle(Default, colorProp)))

	color := rl.Fade(colorStyle, guiAlpha)

	// Draw control
	//--------------------------------------------------------------------
	textBounds := rl.Rectangle{
		Width:  float32(GetTextWidth(text)), // TODO: Consider text icon
		Height: float32(GetStyle(Default, TextSizeProp)),
		X:      bounds.X + LineTextPadding,
		Y:      bounds.Y - float32(GetStyle(Default, TextSizeProp))/2,
	}

	// Draw line with embedded text label: "--- text --------------"
	DrawRectangle(rl.Rectangle{bounds.X, bounds.Y, LineTextPadding - 2, 1}, 0, rl.Blank, color)
	Label(textBounds, text)
	DrawRectangle(rl.Rectangle{bounds.X + LineTextPadding + textBounds.Width + 4, bounds.Y, bounds.Width - textBounds.Width - LineTextPadding - 4, 1}, 0, rl.Blank, color)
	//--------------------------------------------------------------------
}

const PanelBorderWidth = 2

// Panel control
func Panel(bounds rl.Rectangle) {
	state := guiState

	borderColorProp := LineColorProp
	if state == StateDisabled {
		borderColorProp = BorderColorDisabledProp
	}
	borderColor := rl.Fade(rl.GetColor(int32(GetStyle(Default, borderColorProp))), guiAlpha)

	colorProp := BackgroundColorProp
	if state == StateDisabled {
		colorProp = BaseColorDisabledProp
	}
	color := rl.Fade(rl.GetColor(int32(GetStyle(Default, colorProp))), guiAlpha)

	// Draw control
	//--------------------------------------------------------------------
	DrawRectangle(bounds, PanelBorderWidth, borderColor, color)
	//--------------------------------------------------------------------
}

// Scroll Panel control
func ScrollPanel(bounds, content rl.Rectangle, scroll *rl.Vector2) rl.Rectangle {
	state := guiState

	bw := float32(GetStyle(Default, BorderWidthProp))
	side := ScrollBarSide(GetStyle(ListViewControl, ScrollBarSideProp))

	scrollPos := rl.Vector2{0, 0}
	if scroll != nil {
		scrollPos = *scroll
	}

	hasHorizontalScrollBar := content.Width > bounds.Width-2*bw
	hasVerticalScrollBar := content.Height > bounds.Height-2*bw

	// Recheck to account for the other scrollbar being visible
	if !hasHorizontalScrollBar {
		hasHorizontalScrollBar = hasVerticalScrollBar && (content.Width > bounds.Width-2*bw-float32(GetStyle(ListViewControl, ScrollBarWidth)))
	}
	if !hasVerticalScrollBar {
		hasVerticalScrollBar = hasHorizontalScrollBar && (content.Height > bounds.Height-2*bw-float32(GetStyle(ListViewControl, ScrollBarWidth)))
	}

	var horizontalScrollBarWidth int = 0
	if hasHorizontalScrollBar {
		horizontalScrollBarWidth = int(GetStyle(ListViewControl, ScrollBarWidth))
	}
	var verticalScrollBarWidth int = 0
	if hasVerticalScrollBar {
		verticalScrollBarWidth = int(GetStyle(ListViewControl, ScrollBarWidth))
	}

	hx := bounds.X
	if side == ScrollBarLeftSide {
		hx = bounds.X + float32(verticalScrollBarWidth)
	}
	horizontalScrollBar := rl.Rectangle{
		X:      hx + bw,
		Y:      bounds.Y + bounds.Height - float32(horizontalScrollBarWidth) - bw,
		Width:  bounds.Width - float32(verticalScrollBarWidth) - 2*bw,
		Height: float32(horizontalScrollBarWidth),
	}

	vx := bounds.X + bounds.Width - float32(verticalScrollBarWidth) - bw
	if side == ScrollBarLeftSide {
		vx = bounds.X + bw
	}
	verticalScrollBar := rl.Rectangle{
		X:      vx,
		Y:      bounds.Y + bw,
		Width:  float32(verticalScrollBarWidth),
		Height: bounds.Height - float32(horizontalScrollBarWidth) - 2*bw,
	}

	// Calculate view area (area without the scrollbars)
	view := rl.Rectangle{bounds.X + bw, bounds.Y + bw, bounds.Width - 2*bw - float32(verticalScrollBarWidth), bounds.Height - 2*bw - float32(horizontalScrollBarWidth)}
	if side == ScrollBarLeftSide {
		view = rl.Rectangle{bounds.X + float32(verticalScrollBarWidth) + bw, bounds.Y + bw, bounds.Width - 2*bw - float32(verticalScrollBarWidth), bounds.Height - 2*bw - float32(horizontalScrollBarWidth)}
	}

	// Clip view area to the actual content size
	if view.Width > content.Width {
		view.Width = content.Width
	}
	if view.Height > content.Height {
		view.Height = content.Height
	}

	// TODO: Review!
	var horizontalMin float32
	var horizontalMax float32
	if hasHorizontalScrollBar {
		var minOffset float32
		var maxOffset float32
		if side == ScrollBarLeftSide {
			minOffset = float32(-verticalScrollBarWidth)
			maxOffset = float32(verticalScrollBarWidth)
		}
		horizontalMin = minOffset - bw
		horizontalMax = content.Width - bounds.Width + float32(verticalScrollBarWidth) + bw - maxOffset
	} else {
		var minOffset float32
		if side == ScrollBarLeftSide {
			minOffset = float32(-verticalScrollBarWidth)
		}
		horizontalMin = minOffset - bw
		horizontalMax = -bw
	}

	var verticalMin float32 = -bw
	var verticalMax float32
	if hasVerticalScrollBar {
		verticalMin = -bw
		verticalMax = content.Height - bounds.Height + float32(horizontalScrollBarWidth) + bw
	} else {
		verticalMin = -bw
		verticalMax = -bw
	}

	// Update control
	//--------------------------------------------------------------------
	if state != StateDisabled && !guiLocked {
		mousePoint := GetMousePositionWorld()

		// Check button state
		if rl.CheckCollisionPointRec(mousePoint, bounds) {
			if rl.IsMouseButtonDown(rl.MouseLeftButton) {
				state = StatePressed
			} else {
				state = StateFocused
			}

			if hasHorizontalScrollBar {
				if rl.IsKeyDown(rl.KeyRight) {
					scrollPos.X -= float32(GetStyle(ScrollBarControl, ScrollSpeed))
				}
				if rl.IsKeyDown(rl.KeyLeft) {
					scrollPos.X += float32(GetStyle(ScrollBarControl, ScrollSpeed))
				}
			}

			if hasVerticalScrollBar {
				if rl.IsKeyDown(rl.KeyDown) {
					scrollPos.Y -= float32(GetStyle(ScrollBarControl, ScrollSpeed))
				}
				if rl.IsKeyDown(rl.KeyUp) {
					scrollPos.Y += float32(GetStyle(ScrollBarControl, ScrollSpeed))
				}
			}

			wheelMove := rl.GetMouseWheelMove()

			// Horizontal scroll (Shift + Mouse wheel)
			if hasHorizontalScrollBar && (rl.IsKeyDown(rl.KeyLeftShift) || rl.IsKeyDown(rl.KeyRightShift)) {
				scrollPos.X += float32(wheelMove) * 20
			} else {
				// Vertical scroll
				scrollPos.Y += float32(wheelMove) * 20
			}
		}
	}

	// Normalize scroll values
	if scrollPos.X > -horizontalMin {
		scrollPos.X = -horizontalMin
	}
	if scrollPos.X < -horizontalMax {
		scrollPos.X = -horizontalMax
	}
	if scrollPos.Y > -verticalMin {
		scrollPos.Y = -verticalMin
	}
	if scrollPos.Y < -verticalMax {
		scrollPos.Y = -verticalMax
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	DrawRectangle(bounds, 0, rl.Blank, rl.GetColor(int32(GetStyle(Default, BackgroundColorProp)))) // Draw background

	// Save size of the scrollbar slider
	slider := GetStyle(ScrollBarControl, ScrollSliderSize)

	// Draw horizontal scrollbar if visible
	if hasHorizontalScrollBar {
		// Change scrollbar slider size to show the diff in size between the content width and the widget width
		SetStyle(ScrollBarControl, ScrollSliderSize, uint(((bounds.Width-2*bw-float32(verticalScrollBarWidth))/floor32(content.Width))*(floor32(bounds.Width)-2*bw-float32(verticalScrollBarWidth))))
		scrollPos.X = float32(-ScrollBar(horizontalScrollBar, int(-scrollPos.X), int(horizontalMin), int(horizontalMax)))
	}

	// Draw vertical scrollbar if visible
	if hasVerticalScrollBar {
		// Change scrollbar slider size to show the diff in size between the content height and the widget height
		SetStyle(ScrollBarControl, ScrollSliderSize, uint(((bounds.Height-2*bw-float32(horizontalScrollBarWidth))/floor32(content.Height))*(floor32(bounds.Height)-2*bw-float32(horizontalScrollBarWidth))))
		scrollPos.Y = float32(-ScrollBar(verticalScrollBar, int(-scrollPos.Y), int(verticalMin), int(verticalMax)))
	}

	// Draw detail corner rectangle if both scroll bars are visible
	if hasHorizontalScrollBar && hasVerticalScrollBar {
		var x float32
		if side == ScrollBarLeftSide {
			x = bounds.X + bw + 2
		} else {
			x = horizontalScrollBar.X + horizontalScrollBar.Width + 2
		}
		corner := rl.Rectangle{x, verticalScrollBar.Y + verticalScrollBar.Height + 2, float32(horizontalScrollBarWidth) - 4, float32(verticalScrollBarWidth) - 4}
		DrawRectangle(corner, 0, rl.Blank, rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, Text+(ControlProperty(state)*3)))), guiAlpha))
	}

	// Draw scrollbar lines depending on current state
	DrawRectangle(bounds, int(GetStyle(Default, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, Border+(ControlProperty(state)*3)))), guiAlpha), rl.Blank)

	// Set scrollbar slider size back to the way it was before
	SetStyle(ScrollBarControl, ScrollSliderSize, slider)
	//--------------------------------------------------------------------

	if scroll != nil {
		*scroll = scrollPos
	}

	return view
}

// Label control
func Label(bounds rl.Rectangle, text string) {
	state := guiState

	// Update control
	//--------------------------------------------------------------------
	// ...
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	colorProp := TextColorNormalProp
	if state == StateDisabled {
		colorProp = TextColorDisabledProp
	}
	DrawText(text, GetTextBounds(LabelControl, bounds), TextAlignment(GetStyle(LabelControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(LabelControl, colorProp))), guiAlpha))
	//--------------------------------------------------------------------
}

// Button control, returns true when clicked
func Button(bounds rl.Rectangle, text string) bool {
	state := guiState
	pressed := false

	// Update control
	//--------------------------------------------------------------------
	if state != StateDisabled && !guiLocked {
		mousePoint := GetMousePositionWorld()

		// Check button state
		if rl.CheckCollisionPointRec(mousePoint, bounds) {
			if rl.IsMouseButtonDown(rl.MouseLeftButton) {
				state = StatePressed
			} else {
				state = StateFocused
			}

			if rl.IsMouseButtonReleased(rl.MouseLeftButton) {
				pressed = true
			}
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	DrawRectangle(bounds, int(GetStyle(ButtonControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ButtonControl, Border+(ControlProperty(state)*3)))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(ButtonControl, Base+(ControlProperty(state)*3)))), guiAlpha))
	DrawText(text, GetTextBounds(ButtonControl, bounds), TextAlignment(GetStyle(ButtonControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(ButtonControl, Text+(ControlProperty(state)*3)))), guiAlpha))
	//------------------------------------------------------------------

	return pressed
}

// Label button control
func LabelButton(bounds rl.Rectangle, text string) bool {
	state := guiState
	pressed := false

	// NOTE: We force bounds.width to be all text
	textWidth := rl.MeasureTextEx(guiFont, text, float32(GetStyle(Default, TextSizeProp)), float32(GetStyle(Default, TextSpacingProp))).X
	if bounds.Width < textWidth {
		bounds.Width = textWidth
	}

	// Update control
	//--------------------------------------------------------------------
	if state != StateDisabled && !guiLocked {
		mousePoint := GetMousePositionWorld()

		// Check button state
		if rl.CheckCollisionPointRec(mousePoint, bounds) {
			if rl.IsMouseButtonDown(rl.MouseLeftButton) {
				state = StatePressed
			} else {
				state = StateFocused
			}

			if rl.IsMouseButtonReleased(rl.MouseLeftButton) {
				pressed = true
			}
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	DrawText(text, GetTextBounds(LabelControl, bounds), TextAlignment(GetStyle(LabelControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(LabelControl, Text+(ControlProperty(state)*3)))), guiAlpha))
	//--------------------------------------------------------------------

	return pressed
}

// Image button control, returns true when clicked
func ImageButton(bounds rl.Rectangle, text string, texture rl.Texture2D) bool {
	return ImageButtonEx(bounds, text, texture, rl.Rectangle{0, 0, float32(texture.Width), float32(texture.Height)})
}

// Image button control, returns true when clicked
func ImageButtonEx(bounds rl.Rectangle, text string, texture rl.Texture2D, texSource rl.Rectangle) bool {
	state := guiState
	clicked := false

	// Update control
	//--------------------------------------------------------------------
	if state != StateDisabled && !guiLocked {
		mousePoint := GetMousePositionWorld()

		// Check button state
		if rl.CheckCollisionPointRec(mousePoint, bounds) {
			if rl.IsMouseButtonDown(rl.MouseLeftButton) {
				state = StatePressed
			} else if rl.IsMouseButtonReleased(rl.MouseLeftButton) {
				clicked = true
			} else {
				state = StateFocused
			}
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	DrawRectangle(bounds, int(GetStyle(ButtonControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ButtonControl, Border+(ControlProperty(state)*3)))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(ButtonControl, Base+(ControlProperty(state)*3)))), guiAlpha))

	DrawText(text, GetTextBounds(ButtonControl, bounds), TextAlignment(GetStyle(ButtonControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(ButtonControl, Text+(ControlProperty(state)*3)))), guiAlpha))
	if texture.ID > 0 {
		rl.DrawTextureRec(texture, texSource, rl.Vector2{bounds.X + bounds.Width/2 - texSource.Width/2, bounds.Y + bounds.Height/2 - texSource.Height/2}, rl.Fade(rl.GetColor(int32(GetStyle(ButtonControl, Text+(ControlProperty(state)*3)))), guiAlpha))
	}
	//------------------------------------------------------------------

	return clicked
}

// Toggle Button control, returns true when active
func Toggle(bounds rl.Rectangle, text string, active bool) bool {
	state := guiState

	// Update control
	//--------------------------------------------------------------------
	if state != StateDisabled && !guiLocked {
		mousePoint := GetMousePositionWorld()

		// Check toggle button state
		if rl.CheckCollisionPointRec(mousePoint, bounds) {
			if rl.IsMouseButtonDown(rl.MouseLeftButton) {
				state = StatePressed
			} else if rl.IsMouseButtonReleased(rl.MouseLeftButton) {
				state = StateNormal
				active = !active
			} else {
				state = StateFocused
			}
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	if state == StateNormal {
		var borderColorProp, baseColorProp, textColorProp ControlProperty
		if active {
			borderColorProp = BorderColorPressedProp
			baseColorProp = BaseColorPressedProp
			textColorProp = TextColorPressedProp
		} else {
			borderColorProp = Border + ControlProperty(state)*3
			baseColorProp = Base + ControlProperty(state)*3
			textColorProp = Text + ControlProperty(state)*3
		}
		DrawRectangle(bounds, int(GetStyle(ToggleControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ToggleControl, borderColorProp))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(ToggleControl, baseColorProp))), guiAlpha))
		DrawText(text, GetTextBounds(ToggleControl, bounds), TextAlignment(GetStyle(ToggleControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(ToggleControl, textColorProp))), guiAlpha))
	} else {
		DrawRectangle(bounds, int(GetStyle(ToggleControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ToggleControl, Border+ControlProperty(state)*3))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(ToggleControl, Base+ControlProperty(state)*3))), guiAlpha))
		DrawText(text, GetTextBounds(ToggleControl, bounds), TextAlignment(GetStyle(ToggleControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(ToggleControl, Text+ControlProperty(state)*3))), guiAlpha))
	}
	//--------------------------------------------------------------------

	return active
}

const ToggleGroupMaxElements = 32

// Toggle Group control, returns toggled button index
func ToggleGroup(bounds rl.Rectangle, text string, active int) int {
	initBoundsX := bounds.X

	// Get substrings items from text (items pointers)
	var rows [ToggleGroupMaxElements]int
	itemCount := 0
	items := TextSplit(text, &itemCount, rows[:])

	prevRow := rows[0]

	for i := 0; i < itemCount; i++ {
		if prevRow != rows[i] {
			bounds.X = initBoundsX
			bounds.Y += bounds.Height + float32(GetStyle(ToggleControl, GroupPadding))
			prevRow = rows[i]
		}

		if i == active {
			Toggle(bounds, items[i], true)
		} else if Toggle(bounds, items[i], false) {
			active = i
		}

		bounds.X += bounds.Width + float32(GetStyle(ToggleControl, GroupPadding))
	}

	return active
}

// Check Box control, returns true when active
func CheckBox(bounds rl.Rectangle, text string, checked bool) bool {
	state := guiState

	textBounds := rl.Rectangle{
		Width:  float32(GetTextWidth(text)),
		Height: float32(GetStyle(Default, TextSizeProp)),
		X:      bounds.X + bounds.Width + float32(GetStyle(CheckBoxControl, TextPaddingProp)),
		Y:      bounds.Y + bounds.Height/2 - float32(GetStyle(Default, TextSizeProp)/2),
	}
	if TextAlignment(GetStyle(CheckBoxControl, TextAlignmentProp)) == TextAlignLeft {
		textBounds.X = bounds.X - textBounds.Width - float32(GetStyle(CheckBoxControl, TextPaddingProp))
	}

	// Update control
	//--------------------------------------------------------------------
	if state != StateDisabled && !guiLocked {
		mousePoint := GetMousePositionWorld()

		x := bounds.X
		if TextAlignment(GetStyle(CheckBoxControl, TextAlignmentProp)) == TextAlignLeft {
			x = textBounds.X
		}
		totalBounds := rl.Rectangle{
			X:      x,
			Y:      bounds.Y,
			Width:  bounds.Width + textBounds.Width + float32(GetStyle(CheckBoxControl, TextPaddingProp)),
			Height: bounds.Height,
		}

		// Check checkbox state
		if rl.CheckCollisionPointRec(mousePoint, totalBounds) {
			if rl.IsMouseButtonDown(rl.MouseLeftButton) {
				state = StatePressed
			} else {
				state = StateFocused
			}

			if rl.IsMouseButtonReleased(rl.MouseLeftButton) {
				checked = !checked
			}
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	DrawRectangle(bounds, int(GetStyle(CheckBoxControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(CheckBoxControl, Border+(ControlProperty(state)*3)))), guiAlpha), rl.Blank)

	if checked {
		check := rl.Rectangle{
			X:      bounds.X + float32(GetStyle(CheckBoxControl, BorderWidthProp)) + float32(GetStyle(CheckBoxControl, CheckPadding)),
			Y:      bounds.Y + float32(GetStyle(CheckBoxControl, BorderWidthProp)) + float32(GetStyle(CheckBoxControl, CheckPadding)),
			Width:  bounds.Width - 2*(float32(GetStyle(CheckBoxControl, BorderWidthProp))+float32(GetStyle(CheckBoxControl, CheckPadding))),
			Height: bounds.Height - 2*(float32(GetStyle(CheckBoxControl, BorderWidthProp))+float32(GetStyle(CheckBoxControl, CheckPadding))),
		}
		DrawRectangle(check, 0, rl.Blank, rl.Fade(rl.GetColor(int32(GetStyle(CheckBoxControl, Text+ControlProperty(state)*3))), guiAlpha))
	}

	var align TextAlignment
	if TextAlignment(GetStyle(CheckBoxControl, TextAlignmentProp)) == TextAlignRight {
		align = TextAlignLeft
	} else {
		align = TextAlignRight
	}
	DrawText(text, textBounds, align, rl.Fade(rl.GetColor(int32(GetStyle(LabelControl, Text+(ControlProperty(state)*3)))), guiAlpha))
	//--------------------------------------------------------------------

	return checked
}

// Combo Box control, returns selected item index
func ComboBox(bounds rl.Rectangle, text string, active int) int {
	state := guiState

	bounds.Width -= float32(GetStyle(ComboBoxControl, ComboButtonWidth)) + float32(GetStyle(ComboBoxControl, ComboButtonPadding))

	selector := rl.Rectangle{
		X:      bounds.X + bounds.Width + float32(GetStyle(ComboBoxControl, ComboButtonPadding)),
		Y:      bounds.Y,
		Width:  float32(GetStyle(ComboBoxControl, ComboButtonWidth)),
		Height: bounds.Height,
	}

	// Get substrings items from text (items pointers, lengths and count)
	itemCount := 0
	items := TextSplit(text, &itemCount, nil)

	if active < 0 {
		active = 0
	} else if active > itemCount-1 {
		active = itemCount - 1
	}

	// Update control
	//--------------------------------------------------------------------
	if state != StateDisabled && !guiLocked && itemCount > 1 {
		mousePoint := GetMousePositionWorld()

		if rl.CheckCollisionPointRec(mousePoint, bounds) || rl.CheckCollisionPointRec(mousePoint, selector) {
			if rl.IsMouseButtonPressed(rl.MouseLeftButton) {
				active += 1
				if active >= itemCount {
					active = 0
				}
			}

			if rl.IsMouseButtonDown(rl.MouseLeftButton) {
				state = StatePressed
			} else {
				state = StateFocused
			}
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	// Draw combo box main
	DrawRectangle(bounds, int(GetStyle(ComboBoxControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ComboBoxControl, Border+(ControlProperty(state)*3)))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(ComboBoxControl, Base+(ControlProperty(state)*3)))), guiAlpha))
	DrawText(items[active], GetTextBounds(ComboBoxControl, bounds), TextAlignment(GetStyle(ComboBoxControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(ComboBoxControl, Text+(ControlProperty(state)*3)))), guiAlpha))

	// Draw selector using a custom button
	// NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
	tempBorderWidth := GetStyle(ButtonControl, BorderWidthProp)
	tempTextAlign := GetStyle(ButtonControl, TextAlignmentProp)
	SetStyle(ButtonControl, BorderWidthProp, 1)
	SetStyle(ButtonControl, TextAlignmentProp, uint(TextAlignCenter))

	Button(selector, fmt.Sprintf("%d/%d", active+1, itemCount))

	SetStyle(ButtonControl, TextAlignmentProp, tempTextAlign)
	SetStyle(ButtonControl, BorderWidthProp, tempBorderWidth)
	//--------------------------------------------------------------------

	return active
}

// Dropdown Box control
// NOTE: Returns mouse click
func DropdownBox(bounds rl.Rectangle, text string, active *int, editMode bool) bool {
	state := guiState
	itemSelected := *active
	itemFocused := -1

	// Get substrings items from text (items pointers, lengths and count)
	itemCount := 0
	items := TextSplit(text, &itemCount, nil)

	boundsOpen := bounds
	boundsOpen.Height = float32(itemCount+1) * (bounds.Height + float32(GetStyle(DropdownBoxControl, DropdownItemsPadding)))

	itemBounds := bounds

	pressed := false // Check mouse button pressed

	// Update control
	//--------------------------------------------------------------------
	if state != StateDisabled && !guiLocked && itemCount > 1 {
		mousePoint := GetMousePositionWorld()

		if editMode {
			state = StatePressed

			// Check if mouse has been pressed or released outside limits
			if !rl.CheckCollisionPointRec(mousePoint, boundsOpen) {
				if rl.IsMouseButtonPressed(rl.MouseLeftButton) || rl.IsMouseButtonReleased(rl.MouseLeftButton) {
					pressed = true
				}
			}

			// Check if already selected item has been pressed again
			if rl.CheckCollisionPointRec(mousePoint, bounds) && rl.IsMouseButtonPressed(rl.MouseLeftButton) {
				pressed = true
			}

			// Check focused and selected item
			for i := 0; i < itemCount; i++ {
				// Update item rectangle y position for next item
				itemBounds.Y += bounds.Height + float32(GetStyle(DropdownBoxControl, DropdownItemsPadding))

				if rl.CheckCollisionPointRec(mousePoint, itemBounds) {
					itemFocused = i
					if rl.IsMouseButtonReleased(rl.MouseLeftButton) {
						itemSelected = i
						pressed = true // Item selected, change to editMode = false
					}
					break
				}
			}

			itemBounds = bounds
		} else {
			if rl.CheckCollisionPointRec(mousePoint, bounds) {
				if rl.IsMouseButtonPressed(rl.MouseLeftButton) {
					pressed = true
					state = StatePressed
				} else {
					state = StateFocused
				}
			}
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	if editMode {
		Panel(boundsOpen)
	}

	DrawRectangle(bounds, int(GetStyle(DropdownBoxControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, Border+ControlProperty(state)*3))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, Base+ControlProperty(state)*3))), guiAlpha))
	DrawText(items[itemSelected], GetTextBounds(Default, bounds), TextAlignment(GetStyle(DropdownBoxControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, Text+ControlProperty(state)*3))), guiAlpha))

	if editMode {
		// Draw visible items
		for i := 0; i < itemCount; i++ {
			// Update item rectangle y position for next item
			itemBounds.Y += bounds.Height + float32(GetStyle(DropdownBoxControl, DropdownItemsPadding))

			if i == itemSelected {
				DrawRectangle(itemBounds, int(GetStyle(DropdownBoxControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, BorderColorPressedProp))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, BaseColorPressedProp))), guiAlpha))
				DrawText(items[i], GetTextBounds(Default, itemBounds), TextAlignment(GetStyle(DropdownBoxControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, TextColorPressedProp))), guiAlpha))
			} else if i == itemFocused {
				DrawRectangle(itemBounds, int(GetStyle(DropdownBoxControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, BorderColorFocusedProp))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, BaseColorFocusedProp))), guiAlpha))
				DrawText(items[i], GetTextBounds(Default, itemBounds), TextAlignment(GetStyle(DropdownBoxControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, TextColorFocusedProp))), guiAlpha))
			} else {
				DrawText(items[i], GetTextBounds(Default, itemBounds), TextAlignment(GetStyle(DropdownBoxControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, TextColorNormalProp))), guiAlpha))
			}
		}
	}

	// TODO: Avoid this function, use icon instead or 'v'
	rl.DrawTriangle(
		rl.Vector2{bounds.X + bounds.Width - float32(GetStyle(DropdownBoxControl, ArrowPadding)), bounds.Y + bounds.Height/2 - 2},
		rl.Vector2{bounds.X + bounds.Width - float32(GetStyle(DropdownBoxControl, ArrowPadding)) + 5, bounds.Y + bounds.Height/2 - 2 + 5},
		rl.Vector2{bounds.X + bounds.Width - float32(GetStyle(DropdownBoxControl, ArrowPadding)) + 10, bounds.Y + bounds.Height/2 - 2},
		rl.Fade(rl.GetColor(int32(GetStyle(DropdownBoxControl, Text+(ControlProperty(state)*3)))), guiAlpha),
	)

	//GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 },
	//            GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha));
	//--------------------------------------------------------------------

	*active = itemSelected
	return pressed
}

// Text Box control, updates input text
// NOTE 2: Returns if KEY_ENTER pressed (useful for data validation)
//
// NOTE(port): The signature of this method is different because of differences
// in how strings work between C and Go.
func TextBox(bounds rl.Rectangle, text string, textSize int, editMode bool) (string, bool) {
	state := guiState
	pressed := false

	cursor := rl.Rectangle{
		X:      bounds.X + float32(GetStyle(TextBoxControl, TextPaddingProp)) + float32(GetTextWidth(text)) + 2,
		Y:      bounds.Y + float32(GetStyle(TextBoxControl, TextPaddingProp)), // MODIFIED
		Width:  4,
		Height: bounds.Height - float32(GetStyle(TextBoxControl, TextPaddingProp))*2, // MODIFIED
	}

	// Update control
	//--------------------------------------------------------------------
	if state != StateDisabled && !guiLocked {
		mousePoint := GetMousePositionWorld()

		if editMode {
			state = StatePressed

			key := rl.GetCharPressed() // Returns codepoint as Unicode
			keyCount := len(text)

			// Only allow keys in range [32..125]
			if keyCount < (textSize - 1) {
				maxWidth := bounds.Width - float32(GetStyle(TextBoxControl, TextInnerPadding)*2)

				if float32(GetTextWidth(text)) < maxWidth-float32(GetStyle(Default, TextSizeProp)) && (key >= 32) {
					byteSize := 0
					textUTF8 := CodepointToUTF8(key, &byteSize)
					text = text + textUTF8
					keyCount += byteSize
				}
			}

			// Delete text
			if keyCount > 0 {
				if rl.IsKeyPressed(rl.KeyBackspace) {
					keyCount--
					text = text[:len(text)-1]
					if keyCount < 0 {
						keyCount = 0
					}
				}
			}

			if rl.IsKeyPressed(rl.KeyEnter) || (!rl.CheckCollisionPointRec(mousePoint, bounds) && rl.IsMouseButtonPressed(rl.MouseLeftButton)) {
				pressed = true
			}

			// Check text alignment to position cursor properly
			textAlignment := TextAlignment(GetStyle(TextBoxControl, TextAlignmentProp))
			if textAlignment == TextAlignCenter {
				cursor.X = bounds.X + float32(GetTextWidth(text)/2) + bounds.Width/2 + 1
			} else if textAlignment == TextAlignRight {
				cursor.X = bounds.X + bounds.Width - float32(GetStyle(TextBoxControl, TextInnerPadding))
			}
		} else {
			if rl.CheckCollisionPointRec(mousePoint, bounds) {
				state = StateFocused
				if rl.IsMouseButtonPressed(rl.MouseLeftButton) {
					pressed = true
				}
			}
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	if state == StatePressed {
		DrawRectangle(bounds, int(GetStyle(TextBoxControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(TextBoxControl, Border+(ControlProperty(state)*3)))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(TextBoxControl, BaseColorPressedProp))), guiAlpha))
	} else if state == StateDisabled {
		DrawRectangle(bounds, int(GetStyle(TextBoxControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(TextBoxControl, Border+(ControlProperty(state)*3)))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(TextBoxControl, BaseColorDisabledProp))), guiAlpha))
	} else if state == StateNormal {
		DrawRectangle(bounds, int(GetStyle(TextBoxControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(TextBoxControl, Border+(ControlProperty(state)*3)))), guiAlpha), rl.Blank)
	} else {
		DrawRectangle(bounds, int(GetStyle(TextBoxControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(TextBoxControl, Border+(ControlProperty(state)*3)))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(TextBoxControl, Base+(ControlProperty(state)*3)))), guiAlpha))
	}

	DrawText(text, GetTextBounds(TextBoxControl, bounds), TextAlignment(GetStyle(TextBoxControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(TextBoxControl, Text+(ControlProperty(state)*3)))), guiAlpha))

	// Draw cursor
	if editMode {
		DrawRectangle(cursor, 0, rl.Blank, rl.Fade(rl.GetColor(int32(GetStyle(TextBoxControl, BorderColorPressedProp))), guiAlpha))
	}
	//--------------------------------------------------------------------

	return text, pressed
}

// Status Bar control
func StatusBar(bounds rl.Rectangle, text string) {
	state := guiState

	// Draw control
	//--------------------------------------------------------------------
	var borderColorProp ControlProperty
	var baseColorProp ControlProperty
	var textColorProp ControlProperty
	if state != StateDisabled {
		borderColorProp = BorderColorNormalProp
		baseColorProp = BaseColorNormalProp
		textColorProp = TextColorNormalProp
	} else {
		borderColorProp = BorderColorDisabledProp
		baseColorProp = BaseColorDisabledProp
		textColorProp = TextColorDisabledProp
	}
	DrawRectangle(bounds, int(GetStyle(StatusBarControl, BorderWidthProp)),
		rl.Fade(rl.GetColor(int32(GetStyle(StatusBarControl, borderColorProp))), guiAlpha),
		rl.Fade(rl.GetColor(int32(GetStyle(StatusBarControl, baseColorProp))), guiAlpha),
	)
	DrawText(text, GetTextBounds(StatusBarControl, bounds), TextAlignment(GetStyle(StatusBarControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(StatusBarControl, textColorProp))), guiAlpha))
	//--------------------------------------------------------------------
}

// Scroll Bar control
// TODO: I feel GuiScrollBar could be simplified...
func ScrollBar(bounds rl.Rectangle, value, minValue, maxValue int) int {
	state := guiState

	// Is the scrollbar horizontal or vertical?
	isVertical := bounds.Width <= bounds.Height

	// The size (width or height depending on scrollbar type) of the spinner buttons
	spinnerSize := 0
	if GetStyle(ScrollBarControl, ArrowsVisible) > 0 {
		if isVertical {
			spinnerSize = int(bounds.Width - float32(2*GetStyle(ScrollBarControl, BorderWidthProp)))
		} else {
			spinnerSize = int(bounds.Height - float32(2*GetStyle(ScrollBarControl, BorderWidthProp)))
		}
	}

	// Arrow buttons [<] [>] [∧] [∨]
	var arrowUpLeft rl.Rectangle
	var arrowDownRight rl.Rectangle

	// Actual area of the scrollbar excluding the arrow buttons
	var scrollbar rl.Rectangle

	// Slider bar that moves     --[///]-----
	var slider rl.Rectangle

	// Normalize value
	if value > maxValue {
		value = maxValue
	}
	if value < minValue {
		value = minValue
	}

	_range := maxValue - minValue
	sliderSize := int(GetStyle(ScrollBarControl, ScrollSliderSize))

	// Calculate rectangles for all of the components
	arrowUpLeft = rl.Rectangle{
		bounds.X + float32(GetStyle(ScrollBarControl, BorderWidthProp)),
		bounds.Y + float32(GetStyle(ScrollBarControl, BorderWidthProp)),
		float32(spinnerSize),
		float32(spinnerSize),
	}

	if isVertical {
		arrowDownRight = rl.Rectangle{bounds.X + float32(GetStyle(ScrollBarControl, BorderWidthProp)), bounds.Y + bounds.Height - float32(spinnerSize) - float32(GetStyle(ScrollBarControl, BorderWidthProp)), float32(spinnerSize), float32(spinnerSize)}
		scrollbar = rl.Rectangle{bounds.X + float32(GetStyle(ScrollBarControl, BorderWidthProp)) + float32(GetStyle(ScrollBarControl, ScrollPadding)), arrowUpLeft.Y + arrowUpLeft.Height, bounds.Width - 2*(float32(GetStyle(ScrollBarControl, BorderWidthProp))+float32(GetStyle(ScrollBarControl, ScrollPadding))), bounds.Height - arrowUpLeft.Height - arrowDownRight.Height - float32(2*GetStyle(ScrollBarControl, BorderWidthProp))}
		if float32(sliderSize) >= scrollbar.Height {
			sliderSize = int(scrollbar.Height) - 2 // Make sure the slider won't get outside of the scrollbar
		}
		slider = rl.Rectangle{bounds.X + float32(GetStyle(ScrollBarControl, BorderWidthProp)) + float32(GetStyle(ScrollBarControl, ScrollSliderPadding)), scrollbar.Y + floor32((float32(value-minValue)/float32(_range))*(scrollbar.Height-float32(sliderSize))), bounds.Width - 2*(float32(GetStyle(ScrollBarControl, BorderWidthProp))+float32(GetStyle(ScrollBarControl, ScrollSliderPadding))), float32(sliderSize)}
	} else {
		arrowDownRight = rl.Rectangle{bounds.X + bounds.Width - float32(spinnerSize) - float32(GetStyle(ScrollBarControl, BorderWidthProp)), bounds.Y + float32(GetStyle(ScrollBarControl, BorderWidthProp)), float32(spinnerSize), float32(spinnerSize)}
		scrollbar = rl.Rectangle{arrowUpLeft.X + arrowUpLeft.Width, bounds.Y + float32(GetStyle(ScrollBarControl, BorderWidthProp)) + float32(GetStyle(ScrollBarControl, ScrollPadding)), bounds.Width - arrowUpLeft.Width - arrowDownRight.Width - float32(2*GetStyle(ScrollBarControl, BorderWidthProp)), bounds.Height - 2*(float32(GetStyle(ScrollBarControl, BorderWidthProp))+float32(GetStyle(ScrollBarControl, ScrollPadding)))}
		if float32(sliderSize) >= scrollbar.Width {
			sliderSize = int(scrollbar.Width) - 2 // Make sure the slider won't get outside of the scrollbar
		}
		slider = rl.Rectangle{scrollbar.X + floor32((float32(value-minValue)/float32(_range))*(scrollbar.Width-float32(sliderSize))), bounds.Y + float32(GetStyle(ScrollBarControl, BorderWidthProp)) + float32(GetStyle(ScrollBarControl, ScrollSliderPadding)), float32(sliderSize), bounds.Height - 2*(float32(GetStyle(ScrollBarControl, BorderWidthProp))+float32(GetStyle(ScrollBarControl, ScrollSliderPadding)))}
	}

	// Update control
	//--------------------------------------------------------------------
	if (state != StateDisabled) && !guiLocked {
		mousePoint := GetMousePositionWorld()

		if rl.CheckCollisionPointRec(mousePoint, bounds) {
			state = StateFocused

			// Handle mouse wheel
			wheel := int(rl.GetMouseWheelMove())
			if wheel != 0 {
				value += wheel
			}

			if rl.IsMouseButtonPressed(rl.MouseLeftButton) {
				if rl.CheckCollisionPointRec(mousePoint, arrowUpLeft) {
					value -= _range / int(GetStyle(ScrollBarControl, ScrollSpeed))
				} else if rl.CheckCollisionPointRec(mousePoint, arrowDownRight) {
					value += _range / int(GetStyle(ScrollBarControl, ScrollSpeed))
				}

				state = StatePressed
			} else if rl.IsMouseButtonDown(rl.MouseLeftButton) {
				if !isVertical {
					scrollArea := rl.Rectangle{arrowUpLeft.X + arrowUpLeft.Width, arrowUpLeft.Y, scrollbar.Width, bounds.Height - float32(2*GetStyle(ScrollBarControl, BorderWidthProp))}
					if rl.CheckCollisionPointRec(mousePoint, scrollArea) {
						value = int(((mousePoint.X-scrollArea.X-slider.Width/2)*float32(_range))/(scrollArea.Width-slider.Width) + float32(minValue))
					}
				} else {
					scrollArea := rl.Rectangle{arrowUpLeft.X, arrowUpLeft.Y + arrowUpLeft.Height, bounds.Width - float32(2*GetStyle(ScrollBarControl, BorderWidthProp)), scrollbar.Height}
					if rl.CheckCollisionPointRec(mousePoint, scrollArea) {
						value = int(((mousePoint.Y-scrollArea.Y-slider.Height/2)*float32(_range))/(scrollArea.Height-slider.Height) + float32(minValue))
					}
				}
			}
		}

		// Normalize value
		if value > maxValue {
			value = maxValue
		}
		if value < minValue {
			value = minValue
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	DrawRectangle(bounds, int(GetStyle(ScrollBarControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, Border+ControlProperty(state)*3))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(Default, BorderColorDisabledProp))), guiAlpha)) // Draw the background

	DrawRectangle(scrollbar, 0, rl.Blank, rl.Fade(rl.GetColor(int32(GetStyle(ButtonControl, BaseColorNormalProp))), guiAlpha))          // Draw the scrollbar active area background
	DrawRectangle(slider, 0, rl.Blank, rl.Fade(rl.GetColor(int32(GetStyle(SliderControl, Base+ControlProperty(state)*3))), guiAlpha)) // Draw the slider bar

	// Draw arrows
	padding := (spinnerSize - int(GetStyle(ScrollBarControl, ArrowsSize))) / 2
	lineCoords := []rl.Vector2{
		// Coordinates for <     0,1,2
		{arrowUpLeft.X + float32(padding), arrowUpLeft.Y + float32(spinnerSize/2)},
		{arrowUpLeft.X + float32(spinnerSize) - float32(padding), arrowUpLeft.Y + float32(padding)},
		{arrowUpLeft.X + float32(spinnerSize) - float32(padding), arrowUpLeft.Y + float32(spinnerSize) - float32(padding)},

		// Coordinates for >     3,4,5
		{arrowDownRight.X + float32(padding), arrowDownRight.Y + float32(padding)},
		{arrowDownRight.X + float32(spinnerSize) - float32(padding), arrowDownRight.Y + float32(spinnerSize/2)},
		{arrowDownRight.X + float32(padding), arrowDownRight.Y + float32(spinnerSize) - float32(padding)},

		// Coordinates for ∧     6,7,8
		{arrowUpLeft.X + float32(spinnerSize/2), arrowUpLeft.Y + float32(padding)},
		{arrowUpLeft.X + float32(padding), arrowUpLeft.Y + float32(spinnerSize) - float32(padding)},
		{arrowUpLeft.X + float32(spinnerSize) - float32(padding), arrowUpLeft.Y + float32(spinnerSize) - float32(padding)},

		// Coordinates for ∨     9,10,11
		{arrowDownRight.X + float32(padding), arrowDownRight.Y + float32(padding)},
		{arrowDownRight.X + float32(spinnerSize/2), arrowDownRight.Y + float32(spinnerSize) - float32(padding)},
		{arrowDownRight.X + float32(spinnerSize) - float32(padding), arrowDownRight.Y + float32(padding)},
	}

	lineColor := rl.Fade(rl.GetColor(int32(GetStyle(ButtonControl, Text+ControlProperty(state)*3))), guiAlpha)

	if GetStyle(ScrollBarControl, ArrowsVisible) > 0 {
		if isVertical {
			rl.DrawTriangle(lineCoords[6], lineCoords[7], lineCoords[8], lineColor)
			rl.DrawTriangle(lineCoords[9], lineCoords[10], lineCoords[11], lineColor)
		} else {
			rl.DrawTriangle(lineCoords[2], lineCoords[1], lineCoords[0], lineColor)
			rl.DrawTriangle(lineCoords[5], lineCoords[4], lineCoords[3], lineColor)
		}
	}
	//--------------------------------------------------------------------

	return value
}

// List View control
func ListView(bounds rl.Rectangle, text string, scrollIndex *int, active int) int {
	itemCount := 0
	var items []string

	items = TextSplit(text, &itemCount, nil)

	return ListViewEx(bounds, items, itemCount, nil, scrollIndex, active)
}

// List View control with extended parameters
func ListViewEx(bounds rl.Rectangle, text []string, count int, focus *int, scrollIndex *int, active int) int {
	state := guiState
	itemFocused := -1
	if focus != nil {
		itemFocused = *focus
	}
	itemSelected := active

	// Check if we need a scroll bar
	useScrollBar := false
	if float32(GetStyle(ListViewControl, ListItemsHeight)+GetStyle(ListViewControl, ListItemsPadding))*float32(count) > bounds.Height {
		useScrollBar = true
	}

	// Define base item rectangle [0]
	var itemBounds rl.Rectangle
	itemBounds.X = bounds.X + float32(GetStyle(ListViewControl, ListItemsPadding))
	itemBounds.Y = bounds.Y + float32(GetStyle(ListViewControl, ListItemsPadding)) + float32(GetStyle(Default, BorderWidthProp))
	itemBounds.Width = bounds.Width - 2*float32(GetStyle(ListViewControl, ListItemsPadding)) - float32(GetStyle(Default, BorderWidthProp))
	itemBounds.Height = float32(GetStyle(ListViewControl, ListItemsHeight))
	if useScrollBar {
		itemBounds.Width -= float32(GetStyle(ListViewControl, ScrollBarWidth))
	}

	// Get items on the list
	visibleItems := int(bounds.Height) / int(GetStyle(ListViewControl, ListItemsHeight)+GetStyle(ListViewControl, ListItemsPadding))
	if visibleItems > count {
		visibleItems = count
	}

	startIndex := 0
	if scrollIndex != nil {
		startIndex = *scrollIndex
	}
	if (startIndex < 0) || (startIndex > (count - visibleItems)) {
		startIndex = 0
	}
	endIndex := startIndex + visibleItems

	// Update control
	//--------------------------------------------------------------------
	if (state != StateDisabled) && !guiLocked {
		mousePoint := GetMousePositionWorld()

		// Check mouse inside list view
		if rl.CheckCollisionPointRec(mousePoint, bounds) {
			state = StateFocused

			// Check focused and selected item
			for i := 0; i < visibleItems; i++ {
				if rl.CheckCollisionPointRec(mousePoint, itemBounds) {
					itemFocused = startIndex + i
					if rl.IsMouseButtonPressed(rl.MouseLeftButton) {
						if itemSelected == (startIndex + i) {
							itemSelected = -1
						} else {
							itemSelected = startIndex + i
						}
					}
					break
				}

				// Update item rectangle y position for next item
				itemBounds.Y += float32((GetStyle(ListViewControl, ListItemsHeight) + GetStyle(ListViewControl, ListItemsPadding)))
			}

			if useScrollBar {
				wheelMove := int(rl.GetMouseWheelMove())
				startIndex -= wheelMove

				if startIndex < 0 {
					startIndex = 0
				} else if startIndex > (count - visibleItems) {
					startIndex = count - visibleItems
				}

				endIndex = startIndex + visibleItems
				if endIndex > count {
					endIndex = count
				}
			}
		} else {
			itemFocused = -1
		}

		// Reset item rectangle y to [0]
		itemBounds.Y = bounds.Y + float32(GetStyle(ListViewControl, ListItemsPadding)) + float32(GetStyle(Default, BorderWidthProp))
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	DrawRectangle(bounds, int(GetStyle(Default, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, Border+ControlProperty(state)*3))), guiAlpha), rl.GetColor(int32(GetStyle(Default, BackgroundColorProp)))) // Draw background

	// Draw visible items
	for i := 0; i < visibleItems; i++ {
		if state == StateDisabled {
			if (startIndex + i) == itemSelected {
				DrawRectangle(itemBounds, int(GetStyle(ListViewControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, BorderColorDisabledProp))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, BaseColorDisabledProp))), guiAlpha))
			}

			DrawText(text[startIndex+i], GetTextBounds(Default, itemBounds), TextAlignment(GetStyle(ListViewControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, TextColorDisabledProp))), guiAlpha))
		} else {
			if (startIndex + i) == itemSelected {
				// Draw item selected
				DrawRectangle(itemBounds, int(GetStyle(ListViewControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, BorderColorPressedProp))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, BaseColorPressedProp))), guiAlpha))
				DrawText(text[startIndex+i], GetTextBounds(Default, itemBounds), TextAlignment(GetStyle(ListViewControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, TextColorPressedProp))), guiAlpha))
			} else if (startIndex + i) == itemFocused {
				// Draw item focused
				DrawRectangle(itemBounds, int(GetStyle(ListViewControl, BorderWidthProp)), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, BorderColorFocusedProp))), guiAlpha), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, BaseColorFocusedProp))), guiAlpha))
				DrawText(text[startIndex+i], GetTextBounds(Default, itemBounds), TextAlignment(GetStyle(ListViewControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, TextColorFocusedProp))), guiAlpha))
			} else {
				// Draw item normal
				DrawText(text[startIndex+i], GetTextBounds(Default, itemBounds), TextAlignment(GetStyle(ListViewControl, TextAlignmentProp)), rl.Fade(rl.GetColor(int32(GetStyle(ListViewControl, TextColorNormalProp))), guiAlpha))
			}
		}

		// Update item rectangle y position for next item
		itemBounds.Y += float32((GetStyle(ListViewControl, ListItemsHeight) + GetStyle(ListViewControl, ListItemsPadding)))
	}

	if useScrollBar {
		scrollBarBounds := rl.Rectangle{
			bounds.X + bounds.Width - float32(GetStyle(ListViewControl, BorderWidthProp)) - float32(GetStyle(ListViewControl, ScrollBarWidth)),
			bounds.Y + float32(GetStyle(ListViewControl, BorderWidthProp)),
			float32(GetStyle(ListViewControl, ScrollBarWidth)),
			bounds.Height - 2*float32(GetStyle(Default, BorderWidthProp)),
		}

		// Calculate percentage of visible items and apply same percentage to scrollbar
		percentVisible := float32(endIndex-startIndex) / float32(count)
		sliderSize := bounds.Height * percentVisible

		prevSliderSize := GetStyle(ScrollBarControl, ScrollSliderSize)    // Save default slider size
		prevScrollSpeed := GetStyle(ScrollBarControl, ScrollSpeed)        // Save default scroll speed
		SetStyle(ScrollBarControl, ScrollSliderSize, uint(sliderSize))    // Change slider size
		SetStyle(ScrollBarControl, ScrollSpeed, uint(count-visibleItems)) // Change scroll speed

		startIndex = ScrollBar(scrollBarBounds, startIndex, 0, count-visibleItems)

		SetStyle(ScrollBarControl, ScrollSpeed, prevScrollSpeed)     // Reset scroll speed to default
		SetStyle(ScrollBarControl, ScrollSliderSize, prevSliderSize) // Reset slider size to default
	}
	//--------------------------------------------------------------------

	if focus != nil {
		*focus = itemFocused
	}
	if scrollIndex != nil {
		*scrollIndex = startIndex
	}

	return itemSelected
}

// Color Panel control
func ColorPanelEx(bounds rl.Rectangle, color rl.Color, hue float32) rl.Color {
	state := guiState
	var pickerSelector rl.Vector2

	vcolor := rl.Vector3{float32(color.R) / 255, float32(color.G) / 255, float32(color.B) / 255}
	hsv := ConvertRGBtoHSV(vcolor)

	pickerSelector.X = bounds.X + float32(hsv.Y)*bounds.Width      // HSV: Saturation
	pickerSelector.Y = bounds.Y + (1-float32(hsv.Z))*bounds.Height // HSV: Value

	x := hsv.X
	if hue >= 0 {
		x = hue
	}
	maxHue := rl.Vector3{x, 1, 1}
	rgbHue := ConvertHSVtoRGB(maxHue)
	maxHueCol := rl.Color{byte(255 * rgbHue.X),
		byte(255 * rgbHue.Y),
		byte(255 * rgbHue.Z), 255}

	colWhite := rl.Color{255, 255, 255, 255}
	colBlack := rl.Color{0, 0, 0, 255}

	// Update control
	//--------------------------------------------------------------------
	if (state != StateDisabled) && !guiLocked {
		mousePoint := GetMousePositionWorld()

		if rl.CheckCollisionPointRec(mousePoint, bounds) {
			if rl.IsMouseButtonDown(rl.MouseLeftButton) {
				state = StatePressed
				pickerSelector = mousePoint

				// Calculate color from picker
				colorPick := rl.Vector2{pickerSelector.X - bounds.X, pickerSelector.Y - bounds.Y}

				colorPick.X /= bounds.Width  // Get normalized value on x
				colorPick.Y /= bounds.Height // Get normalized value on y

				hsv.Y = colorPick.X
				hsv.Z = 1 - colorPick.Y

				rgb := ConvertHSVtoRGB(hsv)

				// NOTE: Vector3ToColor() only available on raylib 1.8.1
				color = rl.Color{byte(255 * rgb.X),
					byte(255 * rgb.Y),
					byte(255 * rgb.Z),
					byte(255 * float32(color.A) / 255)}

			} else {
				state = StateFocused
			}
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	if state != StateDisabled {
		rl.DrawRectangleGradientEx(bounds, rl.Fade(colWhite, guiAlpha), rl.Fade(colWhite, guiAlpha), rl.Fade(maxHueCol, guiAlpha), rl.Fade(maxHueCol, guiAlpha))
		rl.DrawRectangleGradientEx(bounds, rl.Fade(colBlack, 0), rl.Fade(colBlack, guiAlpha), rl.Fade(colBlack, guiAlpha), rl.Fade(colBlack, 0))

		// Draw color picker: selector
		selector := rl.Rectangle{pickerSelector.X - float32(GetStyle(ColorPickerControl, ColorSelectorSize))/2, pickerSelector.Y - float32(GetStyle(ColorPickerControl, ColorSelectorSize))/2, float32(GetStyle(ColorPickerControl, ColorSelectorSize)), float32(GetStyle(ColorPickerControl, ColorSelectorSize))}
		DrawRectangle(selector, 0, rl.Blank, rl.Fade(colWhite, guiAlpha))
	} else {
		rl.DrawRectangleGradientEx(bounds, rl.Fade(rl.Fade(rl.GetColor(int32(GetStyle(ColorPickerControl, BaseColorDisabledProp))), 0.1), guiAlpha), rl.Fade(rl.Fade(colBlack, 0.6), guiAlpha), rl.Fade(rl.Fade(colBlack, 0.6), guiAlpha), rl.Fade(rl.Fade(rl.GetColor(int32(GetStyle(ColorPickerControl, BorderColorDisabledProp))), 0.6), guiAlpha))
	}

	DrawRectangle(bounds, 1, rl.Fade(rl.GetColor(int32(GetStyle(ColorPickerControl, Border+ControlProperty(state)*3))), guiAlpha), rl.Blank)
	//--------------------------------------------------------------------

	return color
}

func ColorPanel(bounds rl.Rectangle, color rl.Color) rl.Color {
	return ColorPanelEx(bounds, color, -1)
}

// TODO(port): GuiColorBarAlpha

// TODO(port): GuiColorBarHue

// TODO(port): GuiColorPicker

// TODO(port): GuiMessageBox

// TODO(port): GuiTextInputBox

// Grid control
// NOTE: Returns grid mouse-hover selected cell
// About drawing lines at subpixel spacing, simple put, not easy solution:
// https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster
func Grid(bounds rl.Rectangle, spacing float32, subdivs int) rl.Vector2 {
	const GridColorAlpha = 0.15 // Grid lines alpha amount

	state := guiState
	mousePoint := GetMousePositionWorld()
	currentCell := rl.Vector2{-1, -1}

	linesV := (int(bounds.Width/spacing))*subdivs + 1
	linesH := (int(bounds.Height/spacing))*subdivs + 1

	// Update control
	//--------------------------------------------------------------------
	if (state != StateDisabled) && !guiLocked {
		if rl.CheckCollisionPointRec(mousePoint, bounds) {
			currentCell.X = (mousePoint.X - bounds.X) / spacing
			currentCell.Y = (mousePoint.Y - bounds.Y) / spacing
		}
	}
	//--------------------------------------------------------------------

	// Draw control
	//--------------------------------------------------------------------
	switch state {
	case StateNormal:
		if subdivs > 0 {
			// Draw vertical grid lines
			for i := 0; i < linesV; i++ {
				var lineColor rl.Color
				if i%subdivs == 0 {
					lineColor = rl.Fade(rl.GetColor(int32(GetStyle(Default, LineColorProp))), GridColorAlpha*4)
				} else {
					lineColor = rl.Fade(rl.GetColor(int32(GetStyle(Default, LineColorProp))), GridColorAlpha)
				}
				lineV := rl.Rectangle{bounds.X + spacing*float32(i)/float32(subdivs), bounds.Y, 1, bounds.Height}
				DrawRectangle(lineV, 0, rl.Blank, lineColor)
			}

			// Draw horizontal grid lines
			for i := 0; i < linesH; i++ {
				var lineColor rl.Color
				if i%subdivs == 0 {
					lineColor = rl.Fade(rl.GetColor(int32(GetStyle(Default, LineColorProp))), GridColorAlpha*4)
				} else {
					lineColor = rl.Fade(rl.GetColor(int32(GetStyle(Default, LineColorProp))), GridColorAlpha)
				}
				lineH := rl.Rectangle{bounds.X, bounds.Y + spacing*float32(i)/float32(subdivs), bounds.Width, 1}
				DrawRectangle(lineH, 0, rl.Blank, lineColor)
			}
		}
	default:
	}

	return currentCell
}

//----------------------------------------------------------------------------------
// Styles loading functions
//----------------------------------------------------------------------------------

// TODO(port): GuiLoadStyle

// Load style default over global style
func LoadStyleDefault() {
	// We set this variable first to avoid cyclic function calls
	// when calling GuiSetStyle() and GuiGetStyle()
	guiStyleLoaded = true

	// Initialize default LIGHT style property values
	SetStyle(Default, BorderColorNormalProp, 0x838383ff)
	SetStyle(Default, BaseColorNormalProp, 0xc9c9c9ff)
	SetStyle(Default, TextColorNormalProp, 0x686868ff)
	SetStyle(Default, BorderColorFocusedProp, 0x5bb2d9ff)
	SetStyle(Default, BaseColorFocusedProp, 0xc9effeff)
	SetStyle(Default, TextColorFocusedProp, 0x6c9bbcff)
	SetStyle(Default, BorderColorPressedProp, 0x0492c7ff)
	SetStyle(Default, BaseColorPressedProp, 0x97e8ffff)
	SetStyle(Default, TextColorPressedProp, 0x368bafff)
	SetStyle(Default, BorderColorDisabledProp, 0xb5c1c2ff)
	SetStyle(Default, BaseColorDisabledProp, 0xe6e9e9ff)
	SetStyle(Default, TextColorDisabledProp, 0xaeb7b8ff)
	SetStyle(Default, BorderWidthProp, 1)                       // WARNING: Some controls use other values
	SetStyle(Default, TextPaddingProp, 0)                       // WARNING: Some controls use other values
	SetStyle(Default, TextAlignmentProp, uint(TextAlignCenter)) // WARNING: Some controls use other values

	// Initialize control-specific property values
	// NOTE: Those properties are in default list but require specific values by control type
	SetStyle(LabelControl, TextAlignmentProp, uint(TextAlignLeft))
	SetStyle(ButtonControl, BorderWidthProp, 2)
	SetStyle(SliderControl, TextPaddingProp, 5)
	SetStyle(CheckBoxControl, TextPaddingProp, 5)
	SetStyle(CheckBoxControl, TextAlignmentProp, uint(TextAlignRight))
	SetStyle(TextBoxControl, TextPaddingProp, 5)
	SetStyle(TextBoxControl, TextAlignmentProp, uint(TextAlignLeft))
	SetStyle(ValueBoxControl, TextPaddingProp, 4)
	SetStyle(ValueBoxControl, TextAlignmentProp, uint(TextAlignLeft))
	SetStyle(SpinnerControl, TextPaddingProp, 4)
	SetStyle(SpinnerControl, TextAlignmentProp, uint(TextAlignLeft))
	SetStyle(StatusBarControl, TextPaddingProp, 6)
	SetStyle(StatusBarControl, TextAlignmentProp, uint(TextAlignLeft))

	// Initialize extended property values
	// NOTE: By default, extended property values are initialized to 0
	SetStyle(Default, TextSizeProp, 10)                // Default, shared by all controls
	SetStyle(Default, TextSpacingProp, 1)              // Default, shared by all controls
	SetStyle(Default, LineColorProp, 0x90abb5ff)       // Default specific property
	SetStyle(Default, BackgroundColorProp, 0xf5f5f5ff) // Default specific property
	SetStyle(ToggleControl, GroupPadding, 2)
	SetStyle(SliderControl, SliderWidth, 15)
	SetStyle(SliderControl, SliderPadding, 1)
	SetStyle(ProgressBarControl, ProgressPadding, 1)
	SetStyle(CheckBoxControl, CheckPadding, 1)
	SetStyle(ComboBoxControl, ComboButtonWidth, 30)
	SetStyle(ComboBoxControl, ComboButtonPadding, 2)
	SetStyle(DropdownBoxControl, ArrowPadding, 16)
	SetStyle(DropdownBoxControl, DropdownItemsPadding, 2)
	SetStyle(TextBoxControl, TextLinesPadding, 5)
	SetStyle(TextBoxControl, TextInnerPadding, 4)
	SetStyle(TextBoxControl, ColorSelectedFG, 0xf0fffeff)
	SetStyle(TextBoxControl, ColorSelectedBG, 0x839affe0)
	SetStyle(SpinnerControl, SpinButtonWidth, 20)
	SetStyle(SpinnerControl, SpinButtonPadding, 2)
	SetStyle(ScrollBarControl, BorderWidthProp, 0)
	SetStyle(ScrollBarControl, ArrowsVisible, 0)
	SetStyle(ScrollBarControl, ArrowsSize, 6)
	SetStyle(ScrollBarControl, ScrollSliderPadding, 0)
	SetStyle(ScrollBarControl, ScrollSliderSize, 16)
	SetStyle(ScrollBarControl, ScrollPadding, 0)
	SetStyle(ScrollBarControl, ScrollSpeed, 10)
	SetStyle(ListViewControl, ListItemsHeight, 0x1e)
	SetStyle(ListViewControl, ListItemsPadding, 2)
	SetStyle(ListViewControl, ScrollBarWidth, 10)
	SetStyle(ListViewControl, ScrollBarSideProp, uint(ScrollBarRightSide))
	SetStyle(ColorPickerControl, ColorSelectorSize, 6)
	SetStyle(ColorPickerControl, HueBarWidth, 0x14)
	SetStyle(ColorPickerControl, HueBarPadding, 0xa)
	SetStyle(ColorPickerControl, HueBarSelectorHeight, 6)
	SetStyle(ColorPickerControl, HueBarSelectorOverflow, 2)

	guiFont = rl.GetFontDefault() // Initialize default font
}

func bitCheck(a, b uint32) uint32 {
	return a & 1 << b
}

// Draw selected icon using rectangles pixel-by-pixel
func DrawIcon(iconId int, position rl.Vector2, pixelSize int, color rl.Color) {
	i := 0
	y := 0
	for ; i < RIconSize*RIconSize/32; i++ {
		for k := 0; k < 32; k++ {
			if bitCheck(guiIcons[iconId*RIconDataElements+i], uint32(k)) > 0 {
				rl.DrawRectangle(int32(position.X+float32((k%RIconSize)*pixelSize)), int32(position.Y+float32(y*pixelSize)), int32(pixelSize), int32(pixelSize), color)
			}

			if (k == 15) || (k == 31) {
				y++
			}
		}
	}
}

//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------

// Gui get text width using default font
func GetTextWidth(text string) int {
	var size rl.Vector2

	if text != "" {
		size = rl.MeasureTextEx(guiFont, text, float32(GetStyle(Default, TextSizeProp)), float32(GetStyle(Default, TextSpacingProp)))
	}

	// TODO: Consider text icon width here???

	return int(size.X)
}

// Get text bounds considering control bounds
func GetTextBounds(control Control, bounds rl.Rectangle) rl.Rectangle {
	textBounds := bounds

	textBounds.X = bounds.X + float32(GetStyle(control, BorderWidthProp))
	textBounds.Y = bounds.Y + float32(GetStyle(control, BorderWidthProp))
	textBounds.Width = bounds.Width - 2*float32(GetStyle(control, BorderWidthProp))
	textBounds.Height = bounds.Height - 2*float32(GetStyle(control, BorderWidthProp))

	// Consider TEXT_PADDING properly, depends on control type and TEXT_ALIGNMENT
	switch control {
	case ComboBoxControl:
		bounds.Width -= float32(GetStyle(control, ComboButtonWidth)) + float32(GetStyle(control, ComboButtonPadding))
	case ValueBoxControl: // NOTE: ValueBox text value always centered, text padding applies to label
	default:
		if TextAlignment(GetStyle(control, TextAlignmentProp)) == TextAlignRight {
			textBounds.X -= float32(GetStyle(control, TextPaddingProp))
		} else {
			textBounds.X += float32(GetStyle(control, TextPaddingProp))
		}
	}

	// TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW (scrollbar?)
	// More special cases (label side): CHECKBOX, SLIDER, VALUEBOX, SPINNER

	return textBounds
}

// Get text icon if provided and move text cursor
// NOTE: We support up to 999 values for iconId
func GetTextIcon(text string, iconId *int) string {
	*iconId = -1
	if text[0] == '#' { // Maybe we have an icon!
		var iconValue [4]byte // Maximum length for icon value: 3 digits + '\0'

		pos := 1
		for (pos < 4) && (text[pos] >= '0') && (text[pos] <= '9') {
			iconValue[pos-1] = text[pos]
			pos++
		}

		if text[pos] == '#' {
			*iconId = TextToInteger(string(iconValue[:]))

			// Move text pointer after icon
			// WARNING: If only icon provided, it could point to EOL character!
			if *iconId >= 0 {
				text = text[pos+1:]
			}
		}
	}

	return text
}

func textValignPixelOffset(h float32) int {
	return int(h) % 2
}

const RIconTextPadding = 4

// Gui draw text using default font
func DrawText(text string, bounds rl.Rectangle, alignment TextAlignment, tint rl.Color) {
	if text != "" {
		iconId := 0
		text = GetTextIcon(text, &iconId) // Check text for icon and move cursor

		// Get text position depending on alignment and iconId
		//---------------------------------------------------------------------------------
		position := rl.Vector2{bounds.X, bounds.Y}

		// NOTE: We get text size after icon been processed
		textWidth := GetTextWidth(text)
		textHeight := int(GetStyle(Default, TextSizeProp))

		// If text requires an icon, add size to measure
		if iconId >= 0 {
			textWidth += RIconSize

			// WARNING: If only icon provided, text could be pointing to eof character!
			if text != "" {
				textWidth += RIconTextPadding
			}
		}

		// Check guiTextAlign global variables
		switch alignment {
		case TextAlignLeft:
			position.X = bounds.X
			position.Y = bounds.Y + bounds.Height/2 - float32(textHeight)/2 + float32(textValignPixelOffset(bounds.Height))
		case TextAlignCenter:
			position.X = bounds.X + bounds.Width/2 - float32(textWidth)/2
			position.Y = bounds.Y + bounds.Height/2 - float32(textHeight)/2 + float32(textValignPixelOffset(bounds.Height))
		case TextAlignRight:
			position.X = bounds.X + bounds.Width - float32(textWidth)
			position.Y = bounds.Y + bounds.Height/2 - float32(textHeight)/2 + float32(textValignPixelOffset(bounds.Height))
		}

		// NOTE: Make sure we get pixel-perfect coordinates,
		// In case of decimals we got weird text positioning
		position.X = floor32(position.X)
		position.Y = floor32(position.Y)
		//---------------------------------------------------------------------------------

		// Draw text (with icon if available)
		//---------------------------------------------------------------------------------
		if iconId >= 0 {
			// NOTE: We consider icon height, probably different than text size
			DrawIcon(iconId, rl.Vector2{position.X, bounds.Y + bounds.Height/2 - RIconSize/2 + float32(textValignPixelOffset(bounds.Height))}, 1, tint)
			position.X += RIconSize + RIconTextPadding
		}
		rl.DrawTextEx(guiFont, text, position, float32(GetStyle(Default, TextSizeProp)), float32(GetStyle(Default, TextSpacingProp)), tint)
		//---------------------------------------------------------------------------------
	}
}

// Gui draw rectangle using default raygui plain style with borders
func DrawRectangle(rec rl.Rectangle, borderWidth int, borderColor, color rl.Color) {
	if color.A > 0 {
		// Draw rectangle filled with color
		rl.DrawRectangle(int32(rec.X), int32(rec.Y), int32(rec.Width), int32(rec.Height), color)
	}

	if borderWidth > 0 {
		// Draw rectangle border lines with color
		rl.DrawRectangle(int32(rec.X), int32(rec.Y), int32(rec.Width), int32(borderWidth), borderColor)
		rl.DrawRectangle(int32(rec.X), int32(rec.Y)+int32(borderWidth), int32(borderWidth), int32(rec.Height)-2*int32(borderWidth), borderColor)
		rl.DrawRectangle(int32(rec.X)+int32(rec.Width)-int32(borderWidth), int32(rec.Y)+int32(borderWidth), int32(borderWidth), int32(rec.Height)-2*int32(borderWidth), borderColor)
		rl.DrawRectangle(int32(rec.X), int32(rec.Y)+int32(rec.Height)-int32(borderWidth), int32(rec.Width), int32(borderWidth), borderColor)
	}

	// TODO: For n-patch-based style we would need: [state] and maybe [control]
	// In this case all controls drawing logic should be moved to this function... I don't like it...
}

const TextSplitMaxTextLength = 1024
const TextSplitMaxTextElements = 128

var tsResult [TextSplitMaxTextElements]string
var tsBuffer [TextSplitMaxTextLength]byte

// Split controls text into multiple strings
// Also check for multiple columns (required by GuiToggleGroup())
//
// NOTE(port): This function's implementation is heavily modified from the original C, because
// strings work very differently between C and Go. However, this implementation still uses a fixed
// region of memory and shouldn't allocate.
func TextSplit(text string, count *int, textRow []int) []string {
	// NOTE(port): Go doesn't have memset and I don't want to do the weird hacks I'm finding online
	for i := range tsBuffer {
		tsBuffer[i] = 0
	}

	// result[0] = buffer;
	counter := 0 // NOTE(port): starting at 0, not 1

	if textRow != nil {
		textRow[0] = 0
	}

	// Count how many substrings we have on text and point to every one
	stringStart := 0
	for i := 0; i < len(text) && i < TextSplitMaxTextLength; i++ {
		tsBuffer[i] = text[i]
		if tsBuffer[i] == ';' || tsBuffer[i] == '\n' {
			tsResult[counter] = string(tsBuffer[stringStart:i])
			stringStart = i + 1

			if textRow != nil {
				if tsBuffer[i] == '\n' {
					textRow[counter+1] = textRow[counter] + 1
				} else {
					textRow[counter+1] = textRow[counter]
				}
			}

			counter++
			if counter == TextSplitMaxTextElements {
				break
			}
		}
	}

	remaining := tsBuffer[stringStart:]
	if len(remaining) > 0 && counter < TextSplitMaxTextElements {
		tsResult[counter] = string(remaining)
		counter++
	}

	*count = counter

	return tsResult[:counter]
}

// Get integer value from text
// NOTE: This function replaces atoi() [stdlib.h]
// NOTE(port): This is just implemented with strconv.Atoi lol
func TextToInteger(text string) int {
	res, _ := strconv.Atoi(text)
	return res
}

func CodepointToUTF8(codepoint int32, byteSize *int) string {
	var utf8 [6]byte
	size := 0

	if codepoint <= 0x7f {
		utf8[0] = byte(codepoint)
		size = 1
	} else if codepoint <= 0x7ff {
		utf8[0] = byte(((codepoint >> 6) & 0x1f) | 0xc0)
		utf8[1] = byte((codepoint & 0x3f) | 0x80)
		size = 2
	} else if codepoint <= 0xffff {
		utf8[0] = byte(((codepoint >> 12) & 0x0f) | 0xe0)
		utf8[1] = byte(((codepoint >> 6) & 0x3f) | 0x80)
		utf8[2] = byte((codepoint & 0x3f) | 0x80)
		size = 3
	} else if codepoint <= 0x10ffff {
		utf8[0] = byte(((codepoint >> 18) & 0x07) | 0xf0)
		utf8[1] = byte(((codepoint >> 12) & 0x3f) | 0x80)
		utf8[2] = byte(((codepoint >> 6) & 0x3f) | 0x80)
		utf8[3] = byte((codepoint & 0x3f) | 0x80)
		size = 4
	}

	*byteSize = size

	return string(utf8[:size])
}

func floor32(f float32) float32 {
	return float32(math.Floor(float64(f)))
}
