emote2ss

Animated webp to spritesheets converting tool
git clone git://bsandro.tech/emote2ss
Log | Files | Refs | README | LICENSE

luigi.h (201264B)


      1 // TODO UITextbox features - mouse input, multi-line, clipboard, undo, IME support, number dragging.
      2 // TODO New elements - list view, menu bar.
      3 // TODO Keyboard navigation - menus, dialogs, tables.
      4 // TODO Easier to use fonts; GDI font support.
      5 // TODO Formalize the notion of size-stability? See _UIExpandPaneButtonInvoke.
      6 
      7 #include <stdint.h>
      8 #include <stddef.h>
      9 #include <stdbool.h>
     10 #include <stdarg.h>
     11 
     12 #ifdef UI_LINUX
     13 #include <X11/Xlib.h>
     14 #include <X11/Xutil.h>
     15 #include <X11/Xatom.h>
     16 #include <X11/cursorfont.h>
     17 
     18 #if defined(__x86_64__) || defined(_M_X64)
     19 #include <xmmintrin.h>
     20 #endif
     21 
     22 #endif
     23 
     24 #define _UI_TO_STRING_1(x) #x
     25 #define _UI_TO_STRING_2(x) _UI_TO_STRING_1(x)
     26 
     27 #ifdef UI_WINDOWS
     28 #undef _UNICODE
     29 #undef UNICODE
     30 #include <windows.h>
     31 
     32 #define UI_ASSERT(x) do { if (!(x)) { ui.assertionFailure = true; \
     33 	MessageBox(0, "Assertion failure on line " _UI_TO_STRING_2(__LINE__), 0, 0); \
     34 	ExitProcess(1); } } while (0)
     35 #define UI_CALLOC(x) HeapAlloc(ui.heap, HEAP_ZERO_MEMORY, (x))
     36 #define UI_FREE(x) HeapFree(ui.heap, 0, (x))
     37 #define UI_MALLOC(x) HeapAlloc(ui.heap, 0, (x))
     38 #define UI_REALLOC _UIHeapReAlloc
     39 #define UI_CLOCK GetTickCount
     40 #define UI_CLOCKS_PER_SECOND (1000)
     41 #define UI_CLOCK_T DWORD
     42 #endif
     43 
     44 #if defined(UI_LINUX)
     45 #include <stdlib.h>
     46 #include <string.h>
     47 #include <assert.h>
     48 #include <time.h>
     49 #include <math.h>
     50 
     51 #define UI_ASSERT assert
     52 #define UI_CALLOC(x) calloc(1, (x))
     53 #define UI_FREE free
     54 #define UI_MALLOC malloc
     55 #define UI_REALLOC realloc
     56 #define UI_CLOCK clock
     57 #define UI_CLOCKS_PER_SECOND CLOCKS_PER_SEC
     58 #define UI_CLOCK_T clock_t
     59 #endif
     60 
     61 #if defined(UI_ESSENCE)
     62 #include <essence.h>
     63 
     64 #define UI_ASSERT EsAssert
     65 #define UI_CALLOC(x) EsHeapAllocate((x), true)
     66 #define UI_FREE EsHeapFree
     67 #define UI_MALLOC(x) EsHeapAllocate((x), false)
     68 #define UI_REALLOC(x, y) EsHeapReallocate((x), (y), false)
     69 #define UI_CLOCK EsTimeStampMs
     70 #define UI_CLOCKS_PER_SECOND 1000
     71 #define UI_CLOCK_T uint64_t
     72 
     73 // Callback to allow the application to process messages.
     74 void _UIMessageProcess(EsMessage *message);
     75 #endif
     76 
     77 #ifdef UI_DEBUG
     78 #include <stdio.h>
     79 #endif
     80 
     81 #ifdef UI_FREETYPE
     82 #include <ft2build.h>
     83 #include FT_FREETYPE_H
     84 #include <freetype/ftbitmap.h>
     85 #endif
     86 
     87 #define UI_SIZE_BUTTON_MINIMUM_WIDTH (100)
     88 #define UI_SIZE_BUTTON_PADDING (16)
     89 #define UI_SIZE_BUTTON_HEIGHT (27)
     90 #define UI_SIZE_BUTTON_CHECKED_AREA (4)
     91 
     92 #define UI_SIZE_CHECKBOX_BOX (14)
     93 #define UI_SIZE_CHECKBOX_GAP (8)
     94 
     95 #define UI_SIZE_MENU_ITEM_HEIGHT (24)
     96 #define UI_SIZE_MENU_ITEM_MINIMUM_WIDTH (160)
     97 #define UI_SIZE_MENU_ITEM_MARGIN (9)
     98 
     99 #define UI_SIZE_GAUGE_WIDTH (200)
    100 #define UI_SIZE_GAUGE_HEIGHT (22)
    101 
    102 #define UI_SIZE_SLIDER_WIDTH (200)
    103 #define UI_SIZE_SLIDER_HEIGHT (25)
    104 #define UI_SIZE_SLIDER_THUMB (15)
    105 #define UI_SIZE_SLIDER_TRACK (5)
    106 
    107 #define UI_SIZE_TEXTBOX_MARGIN (3)
    108 #define UI_SIZE_TEXTBOX_WIDTH (200)
    109 #define UI_SIZE_TEXTBOX_HEIGHT (27)
    110 
    111 #define UI_SIZE_TAB_PANE_SPACE_TOP (2)
    112 #define UI_SIZE_TAB_PANE_SPACE_LEFT (4)
    113 
    114 #define UI_SIZE_SPLITTER (8)
    115 
    116 #define UI_SIZE_SCROLL_BAR (16)
    117 #define UI_SIZE_SCROLL_MINIMUM_THUMB (20)
    118 
    119 #define UI_SIZE_CODE_MARGIN (ui.activeFont->glyphWidth * 5)
    120 #define UI_SIZE_CODE_MARGIN_GAP (ui.activeFont->glyphWidth * 1)
    121 
    122 #define UI_SIZE_TABLE_HEADER (26)
    123 #define UI_SIZE_TABLE_COLUMN_GAP (20)
    124 #define UI_SIZE_TABLE_ROW (20)
    125 
    126 #define UI_SIZE_PANE_MEDIUM_BORDER (5)
    127 #define UI_SIZE_PANE_MEDIUM_GAP (5)
    128 #define UI_SIZE_PANE_SMALL_BORDER (3)
    129 #define UI_SIZE_PANE_SMALL_GAP (3)
    130 
    131 #define UI_SIZE_MDI_CHILD_BORDER (6)
    132 #define UI_SIZE_MDI_CHILD_TITLE (30)
    133 #define UI_SIZE_MDI_CHILD_CORNER (12)
    134 #define UI_SIZE_MDI_CHILD_MINIMUM_WIDTH (100)
    135 #define UI_SIZE_MDI_CHILD_MINIMUM_HEIGHT (50)
    136 #define UI_SIZE_MDI_CASCADE (30)
    137 
    138 #define UI_UPDATE_HOVERED (1)
    139 #define UI_UPDATE_PRESSED (2)
    140 #define UI_UPDATE_FOCUSED (3)
    141 
    142 typedef enum UIMessage {
    143 	UI_MSG_PAINT, // dp = pointer to UIPainter
    144 	UI_MSG_LAYOUT,
    145 	UI_MSG_DESTROY,
    146 	UI_MSG_UPDATE, // di = UI_UPDATE_... constant
    147 	UI_MSG_ANIMATE,
    148 	UI_MSG_SCROLLED,
    149 	UI_MSG_GET_WIDTH, // di = height (if known); return width
    150 	UI_MSG_GET_HEIGHT, // di = width (if known); return height
    151 	UI_MSG_FIND_BY_POINT, // dp = pointer to UIFindByPoint; return 1 if handled
    152 	UI_MSG_CLIENT_PARENT, // dp = pointer to UIElement *, set it to the parent for client elements
    153 
    154 	UI_MSG_INPUT_EVENTS_START, // not sent to disabled elements
    155 	UI_MSG_LEFT_DOWN,
    156 	UI_MSG_LEFT_UP,
    157 	UI_MSG_MIDDLE_DOWN,
    158 	UI_MSG_MIDDLE_UP,
    159 	UI_MSG_RIGHT_DOWN,
    160 	UI_MSG_RIGHT_UP,
    161 	UI_MSG_KEY_TYPED, // dp = pointer to UIKeyTyped; return 1 if handled
    162 	UI_MSG_MOUSE_MOVE,
    163 	UI_MSG_MOUSE_DRAG,
    164 	UI_MSG_MOUSE_WHEEL, // di = delta; return 1 if handled
    165 	UI_MSG_CLICKED,
    166 	UI_MSG_GET_CURSOR, // return cursor code
    167 	UI_MSG_PRESSED_DESCENDENT, // dp = pointer to child that is/contains pressed element
    168 	UI_MSG_INPUT_EVENTS_END,
    169 
    170 	UI_MSG_VALUE_CHANGED, // sent to notify that the element's value has changed
    171 	UI_MSG_TABLE_GET_ITEM, // dp = pointer to UITableGetItem; return string length
    172 	UI_MSG_CODE_GET_MARGIN_COLOR, // di = line index (starts at 1); return color
    173 	UI_MSG_CODE_DECORATE_LINE, // dp = pointer to UICodeDecorateLine
    174 	UI_MSG_WINDOW_CLOSE, // return 1 to prevent default (process exit for UIWindow; close for UIMDIChild)
    175 	UI_MSG_TAB_SELECTED, // sent to the tab that was selected (not the tab pane itself)
    176 	UI_MSG_WINDOW_DROP_FILES, // di = count, dp = char ** of paths
    177 	UI_MSG_WINDOW_ACTIVATE,
    178 
    179 	UI_MSG_USER,
    180 } UIMessage;
    181 
    182 #ifdef UI_ESSENCE
    183 #define UIRectangle EsRectangle
    184 #else
    185 typedef struct UIRectangle {
    186 	int l, r, t, b;
    187 } UIRectangle;
    188 #endif
    189 
    190 typedef struct UITheme {
    191 	uint32_t panel1, panel2, selected, border;
    192 	uint32_t text, textDisabled, textSelected;
    193 	uint32_t buttonNormal, buttonHovered, buttonPressed, buttonDisabled;
    194 	uint32_t textboxNormal, textboxFocused;
    195 	uint32_t codeFocused, codeBackground, codeDefault, codeComment, codeString, codeNumber, codeOperator, codePreprocessor;
    196 } UITheme;
    197 
    198 typedef struct UIPainter {
    199 	UIRectangle clip;
    200 	uint32_t *bits;
    201 	int width, height;
    202 #ifdef UI_DEBUG
    203 	int fillCount;
    204 #endif
    205 } UIPainter;
    206 
    207 typedef struct UIFont {
    208 	int glyphWidth, glyphHeight;
    209 
    210 #ifdef UI_FREETYPE
    211 	bool isFreeType;
    212 	FT_Face font;
    213 	FT_Bitmap glyphs[128];
    214 	bool glyphsRendered[128];
    215 	int glyphOffsetsX[128], glyphOffsetsY[128];
    216 #endif
    217 } UIFont;
    218 
    219 typedef struct UIShortcut {
    220 	intptr_t code;
    221 	bool ctrl, shift, alt;
    222 	void (*invoke)(void *cp);
    223 	void *cp;
    224 } UIShortcut;
    225 
    226 typedef struct UIStringSelection {
    227 	int carets[2];
    228 	uint32_t colorText, colorBackground;
    229 } UIStringSelection;
    230 
    231 typedef struct UIKeyTyped {
    232 	char *text;
    233 	int textBytes;
    234 	intptr_t code;
    235 } UIKeyTyped;
    236 
    237 typedef struct UITableGetItem {
    238 	char *buffer;
    239 	size_t bufferBytes;
    240 	int index, column;
    241 	bool isSelected;
    242 } UITableGetItem;
    243 
    244 typedef struct UICodeDecorateLine {
    245 	UIRectangle bounds;
    246 	int index; // Starting at 1!
    247 	int x, y; // Position where additional text can be drawn.
    248 	UIPainter *painter;
    249 } UICodeDecorateLine;
    250 
    251 typedef struct UIFindByPoint {
    252 	int x, y;
    253 	struct UIElement *result;
    254 } UIFindByPoint;
    255 
    256 #define UI_RECT_1(x) ((UIRectangle) { (x), (x), (x), (x) })
    257 #define UI_RECT_1I(x) ((UIRectangle) { (x), -(x), (x), -(x) })
    258 #define UI_RECT_2(x, y) ((UIRectangle) { (x), (x), (y), (y) })
    259 #define UI_RECT_2I(x, y) ((UIRectangle) { (x), -(x), (y), -(y) })
    260 #define UI_RECT_2S(x, y) ((UIRectangle) { 0, (x), 0, (y) })
    261 #define UI_RECT_4(x, y, z, w) ((UIRectangle) { (x), (y), (z), (w) })
    262 #define UI_RECT_WIDTH(_r) ((_r).r - (_r).l)
    263 #define UI_RECT_HEIGHT(_r) ((_r).b - (_r).t)
    264 #define UI_RECT_TOTAL_H(_r) ((_r).r + (_r).l)
    265 #define UI_RECT_TOTAL_V(_r) ((_r).b + (_r).t)
    266 #define UI_RECT_SIZE(_r) UI_RECT_WIDTH(_r), UI_RECT_HEIGHT(_r)
    267 #define UI_RECT_TOP_LEFT(_r) (_r).l, (_r).t
    268 #define UI_RECT_BOTTOM_LEFT(_r) (_r).l, (_r).b
    269 #define UI_RECT_BOTTOM_RIGHT(_r) (_r).r, (_r).b
    270 #define UI_RECT_ALL(_r) (_r).l, (_r).r, (_r).t, (_r).b
    271 #define UI_RECT_VALID(_r) (UI_RECT_WIDTH(_r) > 0 && UI_RECT_HEIGHT(_r) > 0)
    272 
    273 #define UI_COLOR_ALPHA_F(x) ((((x) >> 24) & 0xFF) / 255.0f)
    274 #define UI_COLOR_RED_F(x) ((((x) >> 16) & 0xFF) / 255.0f)
    275 #define UI_COLOR_GREEN_F(x) ((((x) >> 8) & 0xFF) / 255.0f)
    276 #define UI_COLOR_BLUE_F(x) ((((x) >> 0) & 0xFF) / 255.0f)
    277 #define UI_COLOR_ALPHA(x) ((((x) >> 24) & 0xFF))
    278 #define UI_COLOR_RED(x) ((((x) >> 16) & 0xFF))
    279 #define UI_COLOR_GREEN(x) ((((x) >> 8) & 0xFF))
    280 #define UI_COLOR_BLUE(x) ((((x) >> 0) & 0xFF))
    281 #define UI_COLOR_FROM_FLOAT(r, g, b) (((uint32_t) ((r) * 255.0f) << 16) | ((uint32_t) ((g) * 255.0f) << 8) | ((uint32_t) ((b) * 255.0f) << 0))
    282 #define UI_COLOR_FROM_RGBA_F(r, g, b, a) (((uint32_t) ((r) * 255.0f) << 16) | ((uint32_t) ((g) * 255.0f) << 8) \
    283 		| ((uint32_t) ((b) * 255.0f) << 0) | ((uint32_t) ((a) * 255.0f) << 24))
    284 
    285 #define UI_SWAP(s, a, b) do { s t = (a); (a) = (b); (b) = t; } while (0)
    286 
    287 #define UI_CURSOR_ARROW (0)
    288 #define UI_CURSOR_TEXT (1)
    289 #define UI_CURSOR_SPLIT_V (2)
    290 #define UI_CURSOR_SPLIT_H (3)
    291 #define UI_CURSOR_FLIPPED_ARROW (4)
    292 #define UI_CURSOR_CROSS_HAIR (5)
    293 #define UI_CURSOR_HAND (6)
    294 #define UI_CURSOR_RESIZE_UP (7)
    295 #define UI_CURSOR_RESIZE_LEFT (8)
    296 #define UI_CURSOR_RESIZE_UP_RIGHT (9)
    297 #define UI_CURSOR_RESIZE_UP_LEFT (10)
    298 #define UI_CURSOR_RESIZE_DOWN (11)
    299 #define UI_CURSOR_RESIZE_RIGHT (12)
    300 #define UI_CURSOR_RESIZE_DOWN_RIGHT (13)
    301 #define UI_CURSOR_RESIZE_DOWN_LEFT (14)
    302 #define UI_CURSOR_COUNT (15)
    303 
    304 #define UI_ALIGN_LEFT (1)
    305 #define UI_ALIGN_RIGHT (2)
    306 #define UI_ALIGN_CENTER (3)
    307 
    308 extern const int UI_KEYCODE_A;
    309 extern const int UI_KEYCODE_BACKSPACE;
    310 extern const int UI_KEYCODE_DELETE;
    311 extern const int UI_KEYCODE_DOWN;
    312 extern const int UI_KEYCODE_END;
    313 extern const int UI_KEYCODE_ENTER;
    314 extern const int UI_KEYCODE_ESCAPE;
    315 extern const int UI_KEYCODE_F1;
    316 extern const int UI_KEYCODE_HOME;
    317 extern const int UI_KEYCODE_LEFT;
    318 extern const int UI_KEYCODE_RIGHT;
    319 extern const int UI_KEYCODE_SPACE;
    320 extern const int UI_KEYCODE_TAB;
    321 extern const int UI_KEYCODE_UP;
    322 extern const int UI_KEYCODE_INSERT;
    323 extern const int UI_KEYCODE_0;
    324 
    325 #define UI_KEYCODE_LETTER(x) (UI_KEYCODE_A + (x) - 'A')
    326 #define UI_KEYCODE_DIGIT(x) (UI_KEYCODE_0 + (x) - '0')
    327 #define UI_KEYCODE_FKEY(x) (UI_KEYCODE_F1 + (x) - 1)
    328 
    329 typedef struct UIElement {
    330 #define UI_ELEMENT_V_FILL (1 << 16)
    331 #define UI_ELEMENT_H_FILL (1 << 17)
    332 #define UI_ELEMENT_WINDOW (1 << 18)
    333 #define UI_ELEMENT_PARENT_PUSH (1 << 19)
    334 #define UI_ELEMENT_TAB_STOP (1 << 20)
    335 #define UI_ELEMENT_NON_CLIENT (1 << 21) // Don't destroy in UIElementDestroyDescendents, like scroll bars.
    336 #define UI_ELEMENT_DISABLED (1 << 22) // Don't receive input events.
    337 
    338 #define UI_ELEMENT_HIDE (1 << 29)
    339 #define UI_ELEMENT_DESTROY (1 << 30)
    340 #define UI_ELEMENT_DESTROY_DESCENDENT (1 << 31)
    341 
    342 	uint32_t flags; // First 16 bits are element specific.
    343 	uint32_t id;
    344 
    345 	struct UIElement *parent;
    346 	struct UIElement *next;
    347 	struct UIElement *children;
    348 	struct UIWindow *window;
    349 
    350 	UIRectangle bounds, clip;
    351 	
    352 	void *cp; // Context pointer (for user).
    353 
    354 	int (*messageClass)(struct UIElement *element, UIMessage message, int di /* data integer */, void *dp /* data pointer */);
    355 	int (*messageUser)(struct UIElement *element, UIMessage message, int di, void *dp);
    356 
    357 	const char *cClassName;
    358 } UIElement;
    359 
    360 #define UI_SHORTCUT(code, ctrl, shift, alt, invoke, cp) ((UIShortcut) { (code), (ctrl), (shift), (alt), (invoke), (cp) })
    361 
    362 typedef struct UIWindow {
    363 #define UI_WINDOW_MENU (1 << 0)
    364 #define UI_WINDOW_INSPECTOR (1 << 1)
    365 #define UI_WINDOW_CENTER_IN_OWNER (1 << 2)
    366 #define UI_WINDOW_MAXIMIZE (1 << 3)
    367 
    368 	UIElement e;
    369 
    370 	UIElement *dialog;
    371 
    372 	UIShortcut *shortcuts;
    373 	size_t shortcutCount, shortcutAllocated;
    374 
    375 	float scale;
    376 
    377 	uint32_t *bits;
    378 	int width, height;
    379 	struct UIWindow *next;
    380 
    381 	UIElement *hovered, *pressed, *focused, *dialogOldFocus;
    382 	int pressedButton;
    383 
    384 	int cursorX, cursorY;
    385 	int cursorStyle;
    386 
    387 	// Set when a textbox is modified. 
    388 	// Useful for tracking whether changes to the loaded document have been saved.
    389 	bool textboxModifiedFlag; 
    390 
    391 	bool ctrl, shift, alt;
    392 
    393 	UIRectangle updateRegion;
    394 
    395 #ifdef UI_DEBUG
    396 	float lastFullFillCount;
    397 #endif
    398 
    399 #ifdef UI_LINUX
    400 	Window window;
    401 	XImage *image;
    402 	XIC xic;
    403 	unsigned ctrlCode, shiftCode, altCode;
    404 	Window dragSource;
    405 #endif
    406 
    407 #ifdef UI_WINDOWS
    408 	HWND hwnd;
    409 	bool trackingLeave;
    410 #endif
    411 
    412 #ifdef UI_ESSENCE
    413 	EsWindow *window;
    414 	EsElement *canvas;
    415 	int cursor;
    416 #endif
    417 } UIWindow;
    418 
    419 typedef struct UIPanel {
    420 #define UI_PANEL_HORIZONTAL (1 << 0)
    421 #define UI_PANEL_GRAY (1 << 2)
    422 #define UI_PANEL_WHITE (1 << 3)
    423 #define UI_PANEL_EXPAND (1 << 4)
    424 #define UI_PANEL_MEDIUM_SPACING (1 << 5)
    425 #define UI_PANEL_SMALL_SPACING (1 << 6)
    426 #define UI_PANEL_SCROLL (1 << 7)
    427 #define UI_PANEL_BORDER (1 << 8)
    428 	UIElement e;
    429 	struct UIScrollBar *scrollBar;
    430 	UIRectangle border;
    431 	int gap;
    432 } UIPanel;
    433 
    434 typedef struct UIButton {
    435 #define UI_BUTTON_SMALL (1 << 0)
    436 #define UI_BUTTON_MENU_ITEM (1 << 1)
    437 #define UI_BUTTON_CAN_FOCUS (1 << 2)
    438 #define UI_BUTTON_DROP_DOWN (1 << 3)
    439 #define UI_BUTTON_CHECKED (1 << 15)
    440 	UIElement e;
    441 	char *label;
    442 	ptrdiff_t labelBytes;
    443 	void (*invoke)(void *cp);
    444 } UIButton;
    445 
    446 typedef struct UICheckbox {
    447 #define UI_CHECKBOX_ALLOW_INDETERMINATE (1 << 0)
    448 	UIElement e;
    449 #define UI_CHECK_UNCHECKED (0)
    450 #define UI_CHECK_CHECKED (1)
    451 #define UI_CHECK_INDETERMINATE (2)
    452 	uint8_t check;
    453 	char *label;
    454 	ptrdiff_t labelBytes;
    455 	void (*invoke)(void *cp);
    456 } UICheckbox;
    457 
    458 typedef struct UILabel {
    459 	UIElement e;
    460 	char *label;
    461 	ptrdiff_t labelBytes;
    462 } UILabel;
    463 
    464 typedef struct UISpacer {
    465 #define UI_SPACER_LINE (1 << 0)
    466 	UIElement e;
    467 	int width, height;
    468 } UISpacer;
    469 
    470 typedef struct UISplitPane {
    471 #define UI_SPLIT_PANE_VERTICAL (1 << 0)
    472 	UIElement e;
    473 	float weight;
    474 } UISplitPane;
    475 
    476 typedef struct UITabPane {
    477 	UIElement e;
    478 	char *tabs;
    479 	int active;
    480 } UITabPane;
    481 
    482 typedef struct UIScrollBar {
    483 #define UI_SCROLL_BAR_HORIZONTAL (1 << 0)
    484 	UIElement e;
    485 	int64_t maximum, page;
    486 	int64_t dragOffset;
    487 	double position;
    488 	uint64_t lastAnimateTime;
    489 	bool inDrag, horizontal;
    490 } UIScrollBar;
    491 
    492 typedef struct UICodeLine {
    493 	int offset, bytes;
    494 } UICodeLine;
    495 
    496 typedef struct UICode {
    497 #define UI_CODE_NO_MARGIN (1 << 0)
    498 	UIElement e;
    499 	UIScrollBar *vScroll;
    500 	UICodeLine *lines;
    501 	UIFont *font;
    502 	int lineCount, focused;
    503 	bool moveScrollToFocusNextLayout;
    504 	char *content;
    505 	size_t contentBytes;
    506 	int tabSize;
    507 } UICode;
    508 
    509 typedef struct UIGauge {
    510 	UIElement e;
    511 	float position;
    512 } UIGauge;
    513 
    514 typedef struct UITable {
    515 	UIElement e;
    516 	UIScrollBar *vScroll;
    517 	int itemCount;
    518 	char *columns;
    519 	int *columnWidths, columnCount, columnHighlight;
    520 } UITable;
    521 
    522 typedef struct UITextbox {
    523 	UIElement e;
    524 	char *string;
    525 	ptrdiff_t bytes;
    526 	int carets[2];
    527 	int scroll;
    528 	bool rejectNextKey;
    529 } UITextbox;
    530 
    531 #define UI_MENU_PLACE_ABOVE (1 << 0)
    532 #define UI_MENU_NO_SCROLL (1 << 1)
    533 #ifdef UI_ESSENCE
    534 typedef EsMenu UIMenu;
    535 #else
    536 typedef struct UIMenu {
    537 	UIElement e;
    538 	int pointX, pointY;
    539 	UIScrollBar *vScroll;
    540 } UIMenu;
    541 #endif
    542 
    543 typedef struct UISlider {
    544 	UIElement e;
    545 	float position;
    546 	int steps;
    547 } UISlider;
    548 
    549 typedef struct UIColorPicker {
    550 #define UI_COLOR_PICKER_HAS_OPACITY (1 << 0)
    551 	UIElement e;
    552 	float hue, saturation, value, opacity;
    553 } UIColorPicker;
    554 
    555 typedef struct UIMDIClient {
    556 #define UI_MDI_CLIENT_TRANSPARENT (1 << 0)
    557 	UIElement e;
    558 	struct UIMDIChild *active;
    559 	int cascade;
    560 } UIMDIClient;
    561 
    562 typedef struct UIMDIChild {
    563 #define UI_MDI_CHILD_CLOSE_BUTTON (1 << 0)
    564 	UIElement e;
    565 	UIRectangle bounds;
    566 	char *title;
    567 	ptrdiff_t titleBytes;
    568 	int dragHitTest;
    569 	UIRectangle dragOffset;
    570 	struct UIMDIChild *previous;
    571 } UIMDIChild;
    572 
    573 typedef struct UIExpandPane {
    574 	UIElement e;
    575 	UIButton *button;
    576 	UIPanel *panel;
    577 	bool expanded;
    578 } UIExpandPane;
    579 
    580 typedef struct UIImageDisplay {
    581 #define UI_IMAGE_DISPLAY_INTERACTIVE (1 << 0)
    582 #define _UI_IMAGE_DISPLAY_ZOOM_FIT (1 << 1)
    583 
    584 	UIElement e;
    585 	uint32_t *bits;
    586 	int width, height;
    587 	float panX, panY, zoom;
    588 	
    589 	// Internals:
    590 	int previousWidth, previousHeight;
    591 	int previousPanPointX, previousPanPointY;
    592 } UIImageDisplay;
    593 
    594 typedef struct UIWrapPanel {
    595 	UIElement e;
    596 } UIWrapPanel;
    597 
    598 void UIInitialise();
    599 int UIMessageLoop();
    600 
    601 UIElement *UIElementCreate(size_t bytes, UIElement *parent, uint32_t flags, 
    602 	int (*messageClass)(UIElement *, UIMessage, int, void *), const char *cClassName);
    603 
    604 UIButton *UIButtonCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes);
    605 UICheckbox *UICheckboxCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes);
    606 UIColorPicker *UIColorPickerCreate(UIElement *parent, uint32_t flags);
    607 UIExpandPane *UIExpandPaneCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes, uint32_t panelFlags);
    608 UIGauge *UIGaugeCreate(UIElement *parent, uint32_t flags);
    609 UIMDIClient *UIMDIClientCreate(UIElement *parent, uint32_t flags);
    610 UIMDIChild *UIMDIChildCreate(UIElement *parent, uint32_t flags, UIRectangle initialBounds, const char *title, ptrdiff_t titleBytes);
    611 UIPanel *UIPanelCreate(UIElement *parent, uint32_t flags);
    612 UIScrollBar *UIScrollBarCreate(UIElement *parent, uint32_t flags);
    613 UISlider *UISliderCreate(UIElement *parent, uint32_t flags);
    614 UISpacer *UISpacerCreate(UIElement *parent, uint32_t flags, int width, int height);
    615 UISplitPane *UISplitPaneCreate(UIElement *parent, uint32_t flags, float weight);
    616 UITabPane *UITabPaneCreate(UIElement *parent, uint32_t flags, const char *tabs /* separate with \t, terminate with \0 */);
    617 UIWrapPanel *UIWrapPanelCreate(UIElement *parent, uint32_t flags);
    618 
    619 UILabel *UILabelCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes);
    620 void UILabelSetContent(UILabel *code, const char *content, ptrdiff_t byteCount);
    621 
    622 UIImageDisplay *UIImageDisplayCreate(UIElement *parent, uint32_t flags, uint32_t *bits, size_t width, size_t height, size_t stride);
    623 void UIImageDisplaySetContent(UIImageDisplay *display, uint32_t *bits, size_t width, size_t height, size_t stride);
    624 
    625 UIWindow *UIWindowCreate(UIWindow *owner, uint32_t flags, const char *cTitle, int width, int height);
    626 void UIWindowRegisterShortcut(UIWindow *window, UIShortcut shortcut);
    627 void UIWindowPostMessage(UIWindow *window, UIMessage message, void *dp); // Thread-safe.
    628 void UIWindowPack(UIWindow *window, int width); // Change the size of the window to best match its contents.
    629 
    630 typedef void (*UIDialogUserCallback)(UIElement *);
    631 const char *UIDialogShow(UIWindow *window, uint32_t flags, const char *format, ...);
    632 
    633 UIMenu *UIMenuCreate(UIElement *parent, uint32_t flags);
    634 void UIMenuAddItem(UIMenu *menu, uint32_t flags, const char *label, ptrdiff_t labelBytes, void (*invoke)(void *cp), void *cp);
    635 void UIMenuShow(UIMenu *menu);
    636 
    637 UITextbox *UITextboxCreate(UIElement *parent, uint32_t flags);
    638 void UITextboxReplace(UITextbox *textbox, const char *text, ptrdiff_t bytes, bool sendChangedMessage);
    639 void UITextboxClear(UITextbox *textbox, bool sendChangedMessage);
    640 void UITextboxMoveCaret(UITextbox *textbox, bool backward, bool word);
    641 
    642 UITable *UITableCreate(UIElement *parent, uint32_t flags, const char *columns /* separate with \t, terminate with \0 */);
    643 int UITableHitTest(UITable *table, int x, int y); // Returns item index. Returns -1 if not on an item.
    644 int UITableHeaderHitTest(UITable *table, int x, int y); // Returns column index or -1.
    645 bool UITableEnsureVisible(UITable *table, int index); // Returns false if the item was already visible.
    646 void UITableResizeColumns(UITable *table);
    647 
    648 UICode *UICodeCreate(UIElement *parent, uint32_t flags);
    649 void UICodeFocusLine(UICode *code, int index); // Line numbers are 1-indexed!!
    650 int UICodeHitTest(UICode *code, int x, int y); // Returns line number; negates if in margin. Returns 0 if not on a line.
    651 void UICodeInsertContent(UICode *code, const char *content, ptrdiff_t byteCount, bool replace);
    652 
    653 void UIDrawBlock(UIPainter *painter, UIRectangle rectangle, uint32_t color);
    654 void UIDrawInvert(UIPainter *painter, UIRectangle rectangle);
    655 bool UIDrawLine(UIPainter *painter, int x0, int y0, int x1, int y1, uint32_t color); // Returns false if the line was not visible.
    656 void UIDrawTriangle(UIPainter *painter, int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color);
    657 void UIDrawTriangleOutline(UIPainter *painter, int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color);
    658 void UIDrawGlyph(UIPainter *painter, int x, int y, int c, uint32_t color);
    659 void UIDrawRectangle(UIPainter *painter, UIRectangle r, uint32_t mainColor, uint32_t borderColor, UIRectangle borderSize);
    660 void UIDrawBorder(UIPainter *painter, UIRectangle r, uint32_t borderColor, UIRectangle borderSize);
    661 void UIDrawString(UIPainter *painter, UIRectangle r, const char *string, ptrdiff_t bytes, uint32_t color, int align, UIStringSelection *selection);
    662 int UIDrawStringHighlighted(UIPainter *painter, UIRectangle r, const char *string, ptrdiff_t bytes, int tabSize);
    663 
    664 int UIMeasureStringWidth(const char *string, ptrdiff_t bytes);
    665 int UIMeasureStringHeight();
    666 
    667 uint64_t UIAnimateClock(); // In ms.
    668 
    669 bool UIElementAnimate(UIElement *element, bool stop);
    670 void UIElementDestroy(UIElement *element);
    671 void UIElementDestroyDescendents(UIElement *element);
    672 UIElement *UIElementFindByPoint(UIElement *element, int x, int y);
    673 void UIElementFocus(UIElement *element);
    674 UIRectangle UIElementScreenBounds(UIElement *element); // Returns bounds of element in same coordinate system as used by UIWindowCreate.
    675 void UIElementRefresh(UIElement *element);
    676 void UIElementRepaint(UIElement *element, UIRectangle *region);
    677 void UIElementMove(UIElement *element, UIRectangle bounds, bool alwaysLayout);
    678 int UIElementMessage(UIElement *element, UIMessage message, int di, void *dp);
    679 void UIElementChangeParent(UIElement *element, UIElement *newParent, UIElement *insertBefore); // Set insertBefore to null to insert at the end.
    680 
    681 UIElement *UIParentPush(UIElement *element);
    682 UIElement *UIParentPop();
    683 
    684 UIRectangle UIRectangleIntersection(UIRectangle a, UIRectangle b);
    685 UIRectangle UIRectangleBounding(UIRectangle a, UIRectangle b);
    686 UIRectangle UIRectangleAdd(UIRectangle a, UIRectangle b);
    687 UIRectangle UIRectangleTranslate(UIRectangle a, UIRectangle b);
    688 bool UIRectangleEquals(UIRectangle a, UIRectangle b);
    689 bool UIRectangleContains(UIRectangle a, int x, int y);
    690 
    691 bool UIColorToHSV(uint32_t rgb, float *hue, float *saturation, float *value);
    692 void UIColorToRGB(float hue, float saturation, float value, uint32_t *rgb);
    693 
    694 char *UIStringCopy(const char *in, ptrdiff_t inBytes);
    695 
    696 UIFont *UIFontCreate(const char *cPath, uint32_t size);
    697 UIFont *UIFontActivate(UIFont *font); // Returns the previously active font.
    698 
    699 #ifdef UI_DEBUG
    700 void UIInspectorLog(const char *cFormat, ...);
    701 #endif
    702 
    703 #ifdef UI_IMPLEMENTATION
    704 
    705 struct {
    706 	UIWindow *windows;
    707 	UIElement *animating;
    708 	UITheme theme;
    709 
    710 	UIElement *parentStack[16];
    711 	int parentStackCount;
    712 
    713 	bool quit;
    714 	const char *dialogResult;
    715 	UIElement *dialogOldFocus;
    716 
    717 	UIFont *activeFont;
    718 
    719 #ifdef UI_DEBUG
    720 	UIWindow *inspector;
    721 	UITable *inspectorTable;
    722 	UIWindow *inspectorTarget;
    723 	UICode *inspectorLog;
    724 #endif
    725 
    726 #ifdef UI_LINUX
    727 	Display *display;
    728 	Visual *visual;
    729 	XIM xim;
    730 	Atom windowClosedID, primaryID, uriListID, plainTextID;
    731 	Atom dndEnterID, dndPositionID, dndStatusID, dndActionCopyID, dndDropID, dndSelectionID, dndFinishedID, dndAwareID;
    732 	Atom clipboardID, xSelectionDataID, textID, targetID, incrID;
    733 	Cursor cursors[UI_CURSOR_COUNT];
    734 	char *pasteText;
    735 	XEvent copyEvent;
    736 #endif
    737 
    738 #ifdef UI_WINDOWS
    739 	HCURSOR cursors[UI_CURSOR_COUNT];
    740 	HANDLE heap;
    741 	bool assertionFailure;
    742 #endif
    743 
    744 #ifdef UI_ESSENCE
    745 	EsInstance *instance;
    746 
    747 	void *menuData[256]; // HACK This limits the number of menu items to 128.
    748 	uintptr_t menuIndex;
    749 #endif
    750 
    751 #ifdef UI_FREETYPE
    752 	FT_Library ft;
    753 #endif
    754 } ui;
    755 
    756 UITheme _uiThemeClassic = {
    757 	.panel1 = 0xFFF0F0F0,
    758 	.panel2 = 0xFFFFFFFF,
    759 	.selected = 0xFF94BEFE,
    760 	.border = 0xFF404040,
    761 
    762 	.text = 0xFF000000,
    763 	.textDisabled = 0xFF404040,
    764 	.textSelected = 0xFF000000,
    765 
    766 	.buttonNormal = 0xFFE0E0E0,
    767 	.buttonHovered = 0xFFF0F0F0,
    768 	.buttonPressed = 0xFFA0A0A0,
    769 	.buttonDisabled = 0xFFF0F0F0,
    770 
    771 	.textboxNormal = 0xFFF8F8F8,
    772 	.textboxFocused = 0xFFFFFFFF,
    773 
    774 	.codeFocused = 0xFFE0E0E0,
    775 	.codeBackground = 0xFFFFFFFF,
    776 	.codeDefault = 0xFF000000,
    777 	.codeComment = 0xFFA11F20,
    778 	.codeString = 0xFF037E01,
    779 	.codeNumber = 0xFF213EF1,
    780 	.codeOperator = 0xFF7F0480,
    781 	.codePreprocessor = 0xFF545D70,
    782 };
    783 
    784 UITheme _uiThemeDark = {
    785 	.panel1 = 0xFF252B31,
    786 	.panel2 = 0xFF14181E,
    787 	.selected = 0xFF94BEFE,
    788 	.border = 0xFF000000,
    789 
    790 	.text = 0xFFFFFFFF,
    791 	.textDisabled = 0xFF787D81,
    792 	.textSelected = 0xFF000000,
    793 
    794 	.buttonNormal = 0xFF383D41,
    795 	.buttonHovered = 0xFF4B5874,
    796 	.buttonPressed = 0xFF0D0D0F,
    797 	.buttonDisabled = 0xFF1B1F23,
    798 
    799 	.textboxNormal = 0xFF31353C,
    800 	.textboxFocused = 0xFF4D4D59,
    801 
    802 	.codeFocused = 0xFF505055,
    803 	.codeBackground = 0xFF212126,
    804 	.codeDefault = 0xFFFFFFFF,
    805 	.codeComment = 0xFFB4B4B4,
    806 	.codeString = 0xFFF5DDD1,
    807 	.codeNumber = 0xFFC3F5D3,
    808 	.codeOperator = 0xFFF5D499,
    809 	.codePreprocessor = 0xFFF5F3D1,
    810 };
    811 
    812 // Taken from https://commons.wikimedia.org/wiki/File:Codepage-437.png
    813 // Public domain.
    814 
    815 const uint64_t _uiFont[] = {
    816 	0x0000000000000000UL, 0x0000000000000000UL, 0xBD8181A5817E0000UL, 0x000000007E818199UL, 0xC3FFFFDBFF7E0000UL, 0x000000007EFFFFE7UL, 0x7F7F7F3600000000UL, 0x00000000081C3E7FUL, 
    817 	0x7F3E1C0800000000UL, 0x0000000000081C3EUL, 0xE7E73C3C18000000UL, 0x000000003C1818E7UL, 0xFFFF7E3C18000000UL, 0x000000003C18187EUL, 0x3C18000000000000UL, 0x000000000000183CUL, 
    818 	0xC3E7FFFFFFFFFFFFUL, 0xFFFFFFFFFFFFE7C3UL, 0x42663C0000000000UL, 0x00000000003C6642UL, 0xBD99C3FFFFFFFFFFUL, 0xFFFFFFFFFFC399BDUL, 0x331E4C5870780000UL, 0x000000001E333333UL, 
    819 	0x3C666666663C0000UL, 0x0000000018187E18UL, 0x0C0C0CFCCCFC0000UL, 0x00000000070F0E0CUL, 0xC6C6C6FEC6FE0000UL, 0x0000000367E7E6C6UL, 0xE73CDB1818000000UL, 0x000000001818DB3CUL, 
    820 	0x1F7F1F0F07030100UL, 0x000000000103070FUL, 0x7C7F7C7870604000UL, 0x0000000040607078UL, 0x1818187E3C180000UL, 0x0000000000183C7EUL, 0x6666666666660000UL, 0x0000000066660066UL, 
    821 	0xD8DEDBDBDBFE0000UL, 0x00000000D8D8D8D8UL, 0x6363361C06633E00UL, 0x0000003E63301C36UL, 0x0000000000000000UL, 0x000000007F7F7F7FUL, 0x1818187E3C180000UL, 0x000000007E183C7EUL, 
    822 	0x1818187E3C180000UL, 0x0000000018181818UL, 0x1818181818180000UL, 0x00000000183C7E18UL, 0x7F30180000000000UL, 0x0000000000001830UL, 0x7F060C0000000000UL, 0x0000000000000C06UL, 
    823 	0x0303000000000000UL, 0x0000000000007F03UL, 0xFF66240000000000UL, 0x0000000000002466UL, 0x3E1C1C0800000000UL, 0x00000000007F7F3EUL, 0x3E3E7F7F00000000UL, 0x0000000000081C1CUL, 
    824 	0x0000000000000000UL, 0x0000000000000000UL, 0x18183C3C3C180000UL, 0x0000000018180018UL, 0x0000002466666600UL, 0x0000000000000000UL, 0x36367F3636000000UL, 0x0000000036367F36UL, 
    825 	0x603E0343633E1818UL, 0x000018183E636160UL, 0x1830634300000000UL, 0x000000006163060CUL, 0x3B6E1C36361C0000UL, 0x000000006E333333UL, 0x000000060C0C0C00UL, 0x0000000000000000UL, 
    826 	0x0C0C0C0C18300000UL, 0x0000000030180C0CUL, 0x30303030180C0000UL, 0x000000000C183030UL, 0xFF3C660000000000UL, 0x000000000000663CUL, 0x7E18180000000000UL, 0x0000000000001818UL, 
    827 	0x0000000000000000UL, 0x0000000C18181800UL, 0x7F00000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL, 0x0000000018180000UL, 0x1830604000000000UL, 0x000000000103060CUL, 
    828 	0xDBDBC3C3663C0000UL, 0x000000003C66C3C3UL, 0x1818181E1C180000UL, 0x000000007E181818UL, 0x0C183060633E0000UL, 0x000000007F630306UL, 0x603C6060633E0000UL, 0x000000003E636060UL, 
    829 	0x7F33363C38300000UL, 0x0000000078303030UL, 0x603F0303037F0000UL, 0x000000003E636060UL, 0x633F0303061C0000UL, 0x000000003E636363UL, 0x18306060637F0000UL, 0x000000000C0C0C0CUL, 
    830 	0x633E6363633E0000UL, 0x000000003E636363UL, 0x607E6363633E0000UL, 0x000000001E306060UL, 0x0000181800000000UL, 0x0000000000181800UL, 0x0000181800000000UL, 0x000000000C181800UL, 
    831 	0x060C183060000000UL, 0x000000006030180CUL, 0x00007E0000000000UL, 0x000000000000007EUL, 0x6030180C06000000UL, 0x00000000060C1830UL, 0x18183063633E0000UL, 0x0000000018180018UL, 
    832 	0x7B7B63633E000000UL, 0x000000003E033B7BUL, 0x7F6363361C080000UL, 0x0000000063636363UL, 0x663E6666663F0000UL, 0x000000003F666666UL, 0x03030343663C0000UL, 0x000000003C664303UL, 
    833 	0x66666666361F0000UL, 0x000000001F366666UL, 0x161E1646667F0000UL, 0x000000007F664606UL, 0x161E1646667F0000UL, 0x000000000F060606UL, 0x7B030343663C0000UL, 0x000000005C666363UL, 
    834 	0x637F636363630000UL, 0x0000000063636363UL, 0x18181818183C0000UL, 0x000000003C181818UL, 0x3030303030780000UL, 0x000000001E333333UL, 0x1E1E366666670000UL, 0x0000000067666636UL, 
    835 	0x06060606060F0000UL, 0x000000007F664606UL, 0xC3DBFFFFE7C30000UL, 0x00000000C3C3C3C3UL, 0x737B7F6F67630000UL, 0x0000000063636363UL, 0x63636363633E0000UL, 0x000000003E636363UL, 
    836 	0x063E6666663F0000UL, 0x000000000F060606UL, 0x63636363633E0000UL, 0x000070303E7B6B63UL, 0x363E6666663F0000UL, 0x0000000067666666UL, 0x301C0663633E0000UL, 0x000000003E636360UL, 
    837 	0x18181899DBFF0000UL, 0x000000003C181818UL, 0x6363636363630000UL, 0x000000003E636363UL, 0xC3C3C3C3C3C30000UL, 0x00000000183C66C3UL, 0xDBC3C3C3C3C30000UL, 0x000000006666FFDBUL, 
    838 	0x18183C66C3C30000UL, 0x00000000C3C3663CUL, 0x183C66C3C3C30000UL, 0x000000003C181818UL, 0x0C183061C3FF0000UL, 0x00000000FFC38306UL, 0x0C0C0C0C0C3C0000UL, 0x000000003C0C0C0CUL, 
    839 	0x1C0E070301000000UL, 0x0000000040607038UL, 0x30303030303C0000UL, 0x000000003C303030UL, 0x0000000063361C08UL, 0x0000000000000000UL, 0x0000000000000000UL, 0x0000FF0000000000UL, 
    840 	0x0000000000180C0CUL, 0x0000000000000000UL, 0x3E301E0000000000UL, 0x000000006E333333UL, 0x66361E0606070000UL, 0x000000003E666666UL, 0x03633E0000000000UL, 0x000000003E630303UL, 
    841 	0x33363C3030380000UL, 0x000000006E333333UL, 0x7F633E0000000000UL, 0x000000003E630303UL, 0x060F0626361C0000UL, 0x000000000F060606UL, 0x33336E0000000000UL, 0x001E33303E333333UL, 
    842 	0x666E360606070000UL, 0x0000000067666666UL, 0x18181C0018180000UL, 0x000000003C181818UL, 0x6060700060600000UL, 0x003C666660606060UL, 0x1E36660606070000UL, 0x000000006766361EUL, 
    843 	0x18181818181C0000UL, 0x000000003C181818UL, 0xDBFF670000000000UL, 0x00000000DBDBDBDBUL, 0x66663B0000000000UL, 0x0000000066666666UL, 0x63633E0000000000UL, 0x000000003E636363UL, 
    844 	0x66663B0000000000UL, 0x000F06063E666666UL, 0x33336E0000000000UL, 0x007830303E333333UL, 0x666E3B0000000000UL, 0x000000000F060606UL, 0x06633E0000000000UL, 0x000000003E63301CUL, 
    845 	0x0C0C3F0C0C080000UL, 0x00000000386C0C0CUL, 0x3333330000000000UL, 0x000000006E333333UL, 0xC3C3C30000000000UL, 0x00000000183C66C3UL, 0xC3C3C30000000000UL, 0x0000000066FFDBDBUL, 
    846 	0x3C66C30000000000UL, 0x00000000C3663C18UL, 0x6363630000000000UL, 0x001F30607E636363UL, 0x18337F0000000000UL, 0x000000007F63060CUL, 0x180E181818700000UL, 0x0000000070181818UL, 
    847 	0x1800181818180000UL, 0x0000000018181818UL, 0x18701818180E0000UL, 0x000000000E181818UL, 0x000000003B6E0000UL, 0x0000000000000000UL, 0x63361C0800000000UL, 0x00000000007F6363UL, 
    848 };
    849 
    850 void _UIWindowEndPaint(UIWindow *window, UIPainter *painter);
    851 void _UIWindowSetCursor(UIWindow *window, int cursor);
    852 void _UIWindowGetScreenPosition(UIWindow *window, int *x, int *y);
    853 void _UIWindowSetPressed(UIWindow *window, UIElement *element, int button);
    854 void _UIClipboardWriteText(UIWindow *window, char *text);
    855 char *_UIClipboardReadTextStart(UIWindow *window, size_t *bytes);
    856 void _UIClipboardReadTextEnd(UIWindow *window, char *text);
    857 bool _UIMessageLoopSingle(int *result);
    858 void _UIInspectorRefresh();
    859 void _UIUpdate();
    860 
    861 #ifdef UI_WINDOWS
    862 void *_UIHeapReAlloc(void *pointer, size_t size);
    863 #endif
    864 
    865 UIRectangle UIRectangleIntersection(UIRectangle a, UIRectangle b) {
    866 	if (a.l < b.l) a.l = b.l;
    867 	if (a.t < b.t) a.t = b.t;
    868 	if (a.r > b.r) a.r = b.r;
    869 	if (a.b > b.b) a.b = b.b;
    870 	return a;
    871 }
    872 
    873 UIRectangle UIRectangleBounding(UIRectangle a, UIRectangle b) {
    874 	if (a.l > b.l) a.l = b.l;
    875 	if (a.t > b.t) a.t = b.t;
    876 	if (a.r < b.r) a.r = b.r;
    877 	if (a.b < b.b) a.b = b.b;
    878 	return a;
    879 }
    880 
    881 UIRectangle UIRectangleAdd(UIRectangle a, UIRectangle b) {
    882 	a.l += b.l;
    883 	a.t += b.t;
    884 	a.r += b.r;
    885 	a.b += b.b;
    886 	return a;
    887 }
    888 
    889 UIRectangle UIRectangleTranslate(UIRectangle a, UIRectangle b) {
    890 	a.l += b.l;
    891 	a.t += b.t;
    892 	a.r += b.l;
    893 	a.b += b.t;
    894 	return a;
    895 }
    896 
    897 bool UIRectangleEquals(UIRectangle a, UIRectangle b) {
    898 	return a.l == b.l && a.r == b.r && a.t == b.t && a.b == b.b;
    899 }
    900 
    901 bool UIRectangleContains(UIRectangle a, int x, int y) {
    902 	return a.l <= x && a.r > x && a.t <= y && a.b > y;
    903 }
    904 
    905 #if defined(__x86_64__) || defined(_M_X64)
    906 #include <xmmintrin.h>
    907 #endif
    908 
    909 typedef union _UIConvertFloatInteger {
    910 	float f;
    911 	uint32_t i;
    912 } _UIConvertFloatInteger;
    913 
    914 float _UIFloorFloat(float x) {
    915 	_UIConvertFloatInteger convert = {x};
    916 	uint32_t sign = convert.i & 0x80000000;
    917 	int exponent = (int) ((convert.i >> 23) & 0xFF) - 0x7F;
    918 
    919 	if (exponent >= 23) {
    920 		// There aren't any bits representing a fractional part.
    921 	} else if (exponent >= 0) {
    922 		// Positive exponent.
    923 		uint32_t mask = 0x7FFFFF >> exponent;
    924 		if (!(mask & convert.i)) return x; // Already an integer.
    925 		if (sign) convert.i += mask;
    926 		convert.i &= ~mask; // Mask out the fractional bits.
    927 	} else if (exponent < 0) {
    928 		// Negative exponent.
    929 		return sign ? -1.0 : 0.0;
    930 	}
    931 
    932 	return convert.f;
    933 }
    934 
    935 float _UISquareRootFloat(float x) {
    936 #if defined(__x86_64__) || defined(_M_X64)
    937 	float result[4];
    938 	_mm_storeu_ps(result, _mm_sqrt_ps(_mm_set_ps(0, 0, 0, x)));
    939 	return result[0];
    940 #else
    941 //@todo fsqrt.s for risc-v?
    942 //clang already does that with this and -ffast-math
    943 	return sqrtf(x);
    944 #endif
    945 }
    946 
    947 #define _F(x) (((_UIConvertFloatInteger) { .i = (x) }).f)
    948 
    949 float _UIArcTanFloatI(float x) {
    950 	float x2 = x * x;
    951 	return x * (_F(0x3F7FFFF8) + x2 * (_F(0xBEAAA53C) + x2 * (_F(0x3E4BC990) + x2 * (_F(0xBE084A60) + x2 * _F(0x3D8864B0)))));
    952 }
    953 
    954 float _UISinFloatI(float x) {
    955 	float x2 = x * x;
    956 	return x * (_F(0x3F800000) + x2 * (_F(0xBE2AAAA0) + x2 * (_F(0x3C0882C0) + x2 * _F(0xB94C6000))));
    957 }
    958 
    959 float _UICosFloatI(float x) {
    960 	float x2 = x * x;
    961 	return _F(0x3F800000) + x2 * (_F(0xBEFFFFDA) + x2 * (_F(0x3D2A9F60) + x2 * _F(0xBAB22C00)));
    962 }
    963 
    964 #undef _F
    965 
    966 float _UISinFloat(float x) {
    967 	bool negate = false;
    968 	if (x < 0) { x = -x; negate = true; }
    969 	x -= 2 * 3.141592654f * _UIFloorFloat(x / (2 * 3.141592654f));
    970 	if (x < 3.141592654f / 2) {}
    971 	else if (x < 3.141592654f) { x = 3.141592654f - x; }
    972 	else if (x < 3 * 3.141592654f / 2) { x = x - 3.141592654f; negate = !negate; }
    973 	else { x = 3.141592654f * 2 - x; negate = !negate; }
    974 	float y = x < 3.141592654f / 4 ? _UISinFloatI(x) : _UICosFloatI(3.141592654f / 2 - x);
    975 	return negate ? -y : y;
    976 }
    977 
    978 float _UICosFloat(float x) {
    979 	return _UISinFloat(3.141592654f / 2 - x);
    980 }
    981 
    982 float _UIArcTanFloat(float x) {
    983 	bool negate = false, reciprocalTaken = false;
    984 	if (x < 0) { x = -x; negate = true; }
    985 	if (x > 1) { x = 1 / x; reciprocalTaken = true; }
    986 	float y = x < 0.5f ? _UIArcTanFloatI(x) : (0.463647609f + _UIArcTanFloatI((2 * x - 1) / (2 + x)));
    987 	if (reciprocalTaken) { y = 3.141592654f / 2 - y; }
    988 	return negate ? -y : y;
    989 }
    990 
    991 float _UIArcTan2Float(float y, float x) {
    992 	if (x == 0) return y > 0 ? 3.141592654f / 2 : -3.141592654f / 2;
    993 	else if (x > 0) return _UIArcTanFloat(y / x);
    994 	else if (y >= 0) return 3.141592654f + _UIArcTanFloat(y / x);
    995 	else return -3.141592654f + _UIArcTanFloat(y / x);
    996 }
    997 
    998 float _UILinearMap(float value, float inFrom, float inTo, float outFrom, float outTo) {
    999 	float inRange = inTo - inFrom, outRange = outTo - outFrom;
   1000 	float normalisedValue = (value - inFrom) / inRange;
   1001 	return normalisedValue * outRange + outFrom;
   1002 }
   1003 
   1004 bool UIColorToHSV(uint32_t rgb, float *hue, float *saturation, float *value) {
   1005 	float r = UI_COLOR_RED_F(rgb);
   1006 	float g = UI_COLOR_GREEN_F(rgb);
   1007 	float b = UI_COLOR_BLUE_F(rgb);
   1008 
   1009 	float maximum = (r > g && r > b) ? r : (g > b ? g : b),
   1010 	      minimum = (r < g && r < b) ? r : (g < b ? g : b),
   1011 	      difference = maximum - minimum;
   1012 	*value = maximum;
   1013 
   1014 	if (!difference) {
   1015 		*saturation = 0;
   1016 		return false;
   1017 	} else {
   1018 		if (r == maximum) *hue = (g - b) / difference + 0;
   1019 		if (g == maximum) *hue = (b - r) / difference + 2;
   1020 		if (b == maximum) *hue = (r - g) / difference + 4;
   1021 		if (*hue < 0) *hue += 6;
   1022 		*saturation = difference / maximum;
   1023 		return true;
   1024 	}
   1025 }
   1026 
   1027 void UIColorToRGB(float h, float s, float v, uint32_t *rgb) {
   1028 	float r, g, b;
   1029 
   1030 	if (!s) {
   1031 		r = g = b = v;
   1032 	} else {
   1033 		int h0 = ((int) h) % 6;
   1034 		float f = h - _UIFloorFloat(h);
   1035 		float x = v * (1 - s), y = v * (1 - s * f), z = v * (1 - s * (1 - f));
   1036 
   1037 		switch (h0) {
   1038 			case 0:  r = v, g = z, b = x; break;
   1039 			case 1:  r = y, g = v, b = x; break;
   1040 			case 2:  r = x, g = v, b = z; break;
   1041 			case 3:  r = x, g = y, b = v; break;
   1042 			case 4:  r = z, g = x, b = v; break;
   1043 			default: r = v, g = x, b = y; break;
   1044 		}
   1045 	}
   1046 
   1047 	*rgb = UI_COLOR_FROM_FLOAT(r, g, b);
   1048 }
   1049 
   1050 void UIElementRefresh(UIElement *element) {
   1051 	UIElementMessage(element, UI_MSG_LAYOUT, 0, 0);
   1052 	UIElementRepaint(element, NULL);
   1053 }
   1054 
   1055 void UIElementRepaint(UIElement *element, UIRectangle *region) {
   1056 	if (!region) {
   1057 		region = &element->bounds;
   1058 	}
   1059 
   1060 	UIRectangle r = UIRectangleIntersection(*region, element->clip);
   1061 
   1062 	if (!UI_RECT_VALID(r)) {
   1063 		return;
   1064 	}
   1065 
   1066 	if (UI_RECT_VALID(element->window->updateRegion)) {
   1067 		element->window->updateRegion = UIRectangleBounding(element->window->updateRegion, r);
   1068 	} else {
   1069 		element->window->updateRegion = r;
   1070 	}
   1071 }
   1072 
   1073 bool UIElementAnimate(UIElement *element, bool stop) {
   1074 	if (stop) {
   1075 		if (ui.animating != element) {
   1076 			return false;
   1077 		}
   1078 
   1079 		ui.animating = NULL;
   1080 	} else {
   1081 		if (ui.animating && ui.animating != element) {
   1082 			return false;
   1083 		}
   1084 
   1085 		ui.animating = element;
   1086 	}
   1087 
   1088 	return true;
   1089 }
   1090 
   1091 uint64_t UIAnimateClock() {
   1092 	return (uint64_t) UI_CLOCK() * 1000 / UI_CLOCKS_PER_SECOND;
   1093 }
   1094 
   1095 void _UIElementDestroyDescendents(UIElement *element, bool topLevel) {
   1096 	UIElement *child = element->children;
   1097 
   1098 	while (child) {
   1099 		if (!topLevel || (~child->flags & UI_ELEMENT_NON_CLIENT)) {
   1100 			UIElementDestroy(child);
   1101 		}
   1102 
   1103 		child = child->next;
   1104 	}
   1105 
   1106 #ifdef UI_DEBUG
   1107 	_UIInspectorRefresh();
   1108 #endif
   1109 }
   1110 
   1111 void UIElementDestroyDescendents(UIElement *element) {
   1112 	_UIElementDestroyDescendents(element, true);
   1113 }
   1114 
   1115 void UIElementDestroy(UIElement *element) {
   1116 	if (element->flags & UI_ELEMENT_DESTROY) {
   1117 		return;
   1118 	}
   1119 
   1120 	element->flags |= UI_ELEMENT_DESTROY | UI_ELEMENT_HIDE;
   1121 
   1122 	UIElement *ancestor = element->parent;
   1123 
   1124 	while (ancestor) {
   1125 		ancestor->flags |= UI_ELEMENT_DESTROY_DESCENDENT;
   1126 		ancestor = ancestor->parent;
   1127 	}
   1128 
   1129 	_UIElementDestroyDescendents(element, false);
   1130 }
   1131 
   1132 void UIDrawBlock(UIPainter *painter, UIRectangle rectangle, uint32_t color) {
   1133 	rectangle = UIRectangleIntersection(painter->clip, rectangle);
   1134 
   1135 	if (!UI_RECT_VALID(rectangle)) {
   1136 		return;
   1137 	}
   1138 
   1139 #ifdef UI_SSE2
   1140 	__m128i color4 = _mm_set_epi32(color, color, color, color);
   1141 #endif
   1142 
   1143 	for (int line = rectangle.t; line < rectangle.b; line++) {
   1144 		uint32_t *bits = painter->bits + line * painter->width + rectangle.l;
   1145 		int count = UI_RECT_WIDTH(rectangle);
   1146 
   1147 #ifdef UI_SSE2
   1148 		while (count >= 4) {
   1149 			_mm_storeu_si128((__m128i *) bits, color4);
   1150 			bits += 4;
   1151 			count -= 4;
   1152 		} 
   1153 #endif
   1154 
   1155 		while (count--) {
   1156 			*bits++ = color;
   1157 		}
   1158 	}
   1159 
   1160 #ifdef UI_DEBUG
   1161 	painter->fillCount += UI_RECT_WIDTH(rectangle) * UI_RECT_HEIGHT(rectangle);
   1162 #endif
   1163 }
   1164 
   1165 bool UIDrawLine(UIPainter *painter, int x0, int y0, int x1, int y1, uint32_t color) {
   1166 	// Apply the clip.
   1167 
   1168 	UIRectangle c = painter->clip;
   1169 	if (!UI_RECT_VALID(c)) return false;
   1170 	int dx = x1 - x0, dy = y1 - y0;
   1171 	const int p[4] = { -dx, dx, -dy, dy };
   1172 	const int q[4] = { x0 - c.l, c.r - 1 - x0, y0 - c.t, c.b - 1 - y0 };
   1173 	float t0 = 0.0f, t1 = 1.0f; // How far along the line the points end up.
   1174 
   1175 	for (int i = 0; i < 4; i++) {
   1176 		if (!p[i] && q[i] < 0) return false;
   1177 		float r = (float) q[i] / p[i];
   1178 		if (p[i] < 0 && r > t1) return false;
   1179 		if (p[i] > 0 && r < t0) return false;
   1180 		if (p[i] < 0 && r > t0) t0 = r;
   1181 		if (p[i] > 0 && r < t1) t1 = r;
   1182 	}
   1183 
   1184 	x1 = x0 + t1 * dx, y1 = y0 + t1 * dy;
   1185 	x0 += t0 * dx, y0 += t0 * dy;
   1186 
   1187 	// Calculate the delta X and delta Y.
   1188 
   1189 	if (y1 < y0) {
   1190 		int t;
   1191 		t = x0, x0 = x1, x1 = t;
   1192 		t = y0, y0 = y1, y1 = t;
   1193 	}
   1194 
   1195 	dx = x1 - x0, dy = y1 - y0;
   1196 	int dxs = dx < 0 ? -1 : 1;
   1197 	if (dx < 0) dx = -dx;
   1198 
   1199 	// Draw the line using Bresenham's line algorithm.
   1200 
   1201 	uint32_t *bits = painter->bits + y0 * painter->width + x0;
   1202 
   1203 	if (dy * dy < dx * dx) {
   1204 		int m = 2 * dy - dx;
   1205 
   1206 		for (int i = 0; i < dx; i++, bits += dxs) {
   1207 			*bits = color;
   1208 			if (m > 0) bits += painter->width, m -= 2 * dx;
   1209 			m += 2 * dy;
   1210 		}
   1211 	} else {
   1212 		int m = 2 * dx - dy;
   1213 
   1214 		for (int i = 0; i < dy; i++, bits += painter->width) {
   1215 			*bits = color;
   1216 			if (m > 0) bits += dxs, m -= 2 * dy;
   1217 			m += 2 * dx;
   1218 		}
   1219 	}
   1220 
   1221 	return true;
   1222 }
   1223 
   1224 void UIDrawTriangle(UIPainter *painter, int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) {
   1225 	// Step 1: Sort the points by their y-coordinate.
   1226 	if (y1 < y0) { int xt = x0; x0 = x1, x1 = xt; int yt = y0; y0 = y1, y1 = yt; }
   1227 	if (y2 < y1) { int xt = x1; x1 = x2, x2 = xt; int yt = y1; y1 = y2, y2 = yt; }
   1228 	if (y1 < y0) { int xt = x0; x0 = x1, x1 = xt; int yt = y0; y0 = y1, y1 = yt; }
   1229 	if (y2 == y0) return;
   1230 
   1231 	// Step 2: Clip the triangle.
   1232 	if (x0 < painter->clip.l && x1 < painter->clip.l && x2 < painter->clip.l) return;
   1233 	if (x0 >= painter->clip.r && x1 >= painter->clip.r && x2 >= painter->clip.r) return;
   1234 	if (y2 < painter->clip.t || y0 >= painter->clip.b) return;
   1235 	bool needsXClip = x0 < painter->clip.l + 1 || x0 >= painter->clip.r - 1
   1236 		|| x1 < painter->clip.l + 1 || x1 >= painter->clip.r - 1
   1237 		|| x2 < painter->clip.l + 1 || x2 >= painter->clip.r - 1;
   1238 	bool needsYClip = y0 < painter->clip.t + 1 || y2 >= painter->clip.b - 1;
   1239 #define _UI_DRAW_TRIANGLE_APPLY_CLIP(xo, yo) \
   1240 	if (needsYClip && (yi + yo < painter->clip.t || yi + yo >= painter->clip.b)) continue; \
   1241 	if (needsXClip && xf + xo < painter->clip.l) xf = painter->clip.l - xo; \
   1242 	if (needsXClip && xt + xo > painter->clip.r) xt = painter->clip.r - xo;
   1243 
   1244 	// Step 3: Split into 2 triangles with bases aligned with the x-axis.
   1245 	float xm0 = (x2 - x0) * (y1 - y0) / (y2 - y0), xm1 = x1 - x0;
   1246 	if (xm1 < xm0) { float xmt = xm0; xm0 = xm1, xm1 = xmt; }
   1247 	float xe0 = xm0 + x0 - x2, xe1 = xm1 + x0 - x2;
   1248 	int ym = y1 - y0, ye = y2 - y1;
   1249 	float ymr = 1.0f / ym, yer = 1.0f / ye;
   1250 
   1251 	// Step 4: Draw the top part.
   1252 	for (float y = 0; y < ym; y++) {
   1253 		int xf = xm0 * y * ymr, xt = xm1 * y * ymr, yi = (int) y;
   1254 		_UI_DRAW_TRIANGLE_APPLY_CLIP(x0, y0);
   1255 		uint32_t *b = &painter->bits[(yi + y0) * painter->width + x0];
   1256 		for (int x = xf; x < xt; x++) b[x] = color;
   1257 	}
   1258 
   1259 	// Step 5: Draw the bottom part.
   1260 	for (float y = 0; y < ye; y++) {
   1261 		int xf = xe0 * (ye - y) * yer, xt = xe1 * (ye - y) * yer, yi = (int) y;
   1262 		_UI_DRAW_TRIANGLE_APPLY_CLIP(x2, y1);
   1263 		uint32_t *b = &painter->bits[(yi + y1) * painter->width + x2];
   1264 		for (int x = xf; x < xt; x++) b[x] = color;
   1265 	}
   1266 }
   1267 
   1268 void UIDrawTriangleOutline(UIPainter *painter, int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) {
   1269 	UIDrawLine(painter, x0, y0, x1, y1, color);
   1270 	UIDrawLine(painter, x1, y1, x2, y2, color);
   1271 	UIDrawLine(painter, x2, y2, x0, y0, color);
   1272 }
   1273 
   1274 void UIDrawInvert(UIPainter *painter, UIRectangle rectangle) {
   1275 	rectangle = UIRectangleIntersection(painter->clip, rectangle);
   1276 
   1277 	if (!UI_RECT_VALID(rectangle)) {
   1278 		return;
   1279 	}
   1280 
   1281 	for (int line = rectangle.t; line < rectangle.b; line++) {
   1282 		uint32_t *bits = painter->bits + line * painter->width + rectangle.l;
   1283 		int count = UI_RECT_WIDTH(rectangle);
   1284 
   1285 		while (count--) {
   1286 			uint32_t in = *bits;
   1287 			*bits = in ^ 0xFFFFFF;
   1288 			bits++;
   1289 		}
   1290 	}
   1291 }
   1292 
   1293 void UIDrawGlyph(UIPainter *painter, int x0, int y0, int c, uint32_t color) {
   1294 #ifdef UI_FREETYPE
   1295 	UIFont *font = ui.activeFont;
   1296 
   1297 	if (font->isFreeType) {
   1298 		if (c < 0 || c > 127) c = '?';
   1299 		if (c == '\r') c = ' ';
   1300 
   1301 		if (!font->glyphsRendered[c]) {
   1302 			FT_Load_Char(font->font, c == 24 ? 0x2191 : c == 25 ? 0x2193 : c == 26 ? 0x2192 : c == 27 ? 0x2190 : c, FT_LOAD_DEFAULT);
   1303 #ifdef UI_FREETYPE_SUBPIXEL
   1304 			FT_Render_Glyph(font->font->glyph, FT_RENDER_MODE_LCD);
   1305 #else
   1306 			FT_Render_Glyph(font->font->glyph, FT_RENDER_MODE_NORMAL);
   1307 #endif
   1308 			FT_Bitmap_Copy(ui.ft, &font->font->glyph->bitmap, &font->glyphs[c]);
   1309 			font->glyphOffsetsX[c] = font->font->glyph->bitmap_left;
   1310 			font->glyphOffsetsY[c] = font->font->size->metrics.ascender / 64 - font->font->glyph->bitmap_top;
   1311 			font->glyphsRendered[c] = true;
   1312 		}
   1313 
   1314 		FT_Bitmap *bitmap = &font->glyphs[c];
   1315 		x0 += font->glyphOffsetsX[c], y0 += font->glyphOffsetsY[c];
   1316 
   1317 		for (int y = 0; y < (int) bitmap->rows; y++) {
   1318 			if (y0 + y < painter->clip.t) continue;
   1319 			if (y0 + y >= painter->clip.b) break;
   1320 
   1321 			int width = bitmap->width;
   1322 #ifdef UI_FREETYPE_SUBPIXEL
   1323 			width /= 3;
   1324 #endif
   1325 
   1326 			for (int x = 0; x < width; x++) {
   1327 				if (x0 + x < painter->clip.l) continue;
   1328 				if (x0 + x >= painter->clip.r) break;
   1329 
   1330 				uint32_t *destination = painter->bits + (x0 + x) + (y0 + y) * painter->width;
   1331 				uint32_t original = *destination;
   1332 
   1333 #ifdef UI_FREETYPE_SUBPIXEL
   1334 				uint32_t ra = ((uint8_t *) bitmap->buffer)[x * 3 + y * bitmap->pitch + 0];
   1335 				uint32_t ga = ((uint8_t *) bitmap->buffer)[x * 3 + y * bitmap->pitch + 1];
   1336 				uint32_t ba = ((uint8_t *) bitmap->buffer)[x * 3 + y * bitmap->pitch + 2];
   1337 				ra += (ga - ra) / 2, ba += (ga - ba) / 2;
   1338 #else
   1339 				uint32_t ra = ((uint8_t *) bitmap->buffer)[x + y * bitmap->pitch];
   1340 				uint32_t ga = ra, ba = ra;
   1341 #endif
   1342 				uint32_t r2 = (255 - ra) * ((original & 0x000000FF) >> 0);
   1343 				uint32_t g2 = (255 - ga) * ((original & 0x0000FF00) >> 8);
   1344 				uint32_t b2 = (255 - ba) * ((original & 0x00FF0000) >> 16);
   1345 				uint32_t r1 = ra * ((color & 0x000000FF) >> 0);
   1346 				uint32_t g1 = ga * ((color & 0x0000FF00) >> 8);
   1347 				uint32_t b1 = ba * ((color & 0x00FF0000) >> 16);
   1348 
   1349 				uint32_t result = 0xFF000000 | (0x00FF0000 & ((b1 + b2) << 8)) 
   1350 					| (0x0000FF00 & ((g1 + g2) << 0)) 
   1351 					| (0x000000FF & ((r1 + r2) >> 8));
   1352 				*destination = result;
   1353 			}
   1354 		}
   1355 
   1356 		return;
   1357 	}
   1358 #endif
   1359 
   1360 	if (c < 0 || c > 127) c = '?';
   1361 
   1362 	UIRectangle rectangle = UIRectangleIntersection(painter->clip, UI_RECT_4(x0, x0 + 8, y0, y0 + 16));
   1363 
   1364 	const uint8_t *data = (const uint8_t *) _uiFont + c * 16;
   1365 
   1366 	for (int i = rectangle.t; i < rectangle.b; i++) {
   1367 		uint32_t *bits = painter->bits + i * painter->width + rectangle.l;
   1368 		uint8_t byte = data[i - y0];
   1369 
   1370 		for (int j = rectangle.l; j < rectangle.r; j++) {
   1371 			if (byte & (1 << (j - x0))) {
   1372 				*bits = color;
   1373 			}
   1374 
   1375 			bits++;
   1376 		}
   1377 	}
   1378 }
   1379 
   1380 ptrdiff_t _UIStringLength(const char *cString) {
   1381 	if (!cString) return 0;
   1382 	ptrdiff_t length;
   1383 	for (length = 0; cString[length]; length++);
   1384 	return length;
   1385 }
   1386 
   1387 char *UIStringCopy(const char *in, ptrdiff_t inBytes) {
   1388 	if (inBytes == -1) {
   1389 		inBytes = _UIStringLength(in);
   1390 	}
   1391 
   1392 	char *buffer = (char *) UI_MALLOC(inBytes + 1);
   1393 	
   1394 	for (intptr_t i = 0; i < inBytes; i++) {
   1395 		buffer[i] = in[i];
   1396 	}
   1397 	
   1398 	buffer[inBytes] = 0;
   1399 	return buffer;
   1400 }
   1401 
   1402 int UIMeasureStringWidth(const char *string, ptrdiff_t bytes) {
   1403 	if (bytes == -1) {
   1404 		bytes = _UIStringLength(string);
   1405 	}
   1406 	
   1407 	return bytes * ui.activeFont->glyphWidth;
   1408 }
   1409 
   1410 int UIMeasureStringHeight() {
   1411 	return ui.activeFont->glyphHeight;
   1412 }
   1413 
   1414 void UIDrawString(UIPainter *painter, UIRectangle r, const char *string, ptrdiff_t bytes, uint32_t color, int align, UIStringSelection *selection) {
   1415 	UIRectangle oldClip = painter->clip;
   1416 	painter->clip = UIRectangleIntersection(r, oldClip);
   1417 
   1418 	if (!UI_RECT_VALID(painter->clip)) {
   1419 		painter->clip = oldClip;
   1420 		return;
   1421 	}
   1422 
   1423 	if (bytes == -1) {
   1424 		bytes = _UIStringLength(string);
   1425 	}
   1426 
   1427 	int width = UIMeasureStringWidth(string, bytes);
   1428 	int height = UIMeasureStringHeight();
   1429 	int x = align == UI_ALIGN_CENTER ? ((r.l + r.r - width) / 2) : align == UI_ALIGN_RIGHT ? (r.r - width) : r.l;
   1430 	int y = (r.t + r.b - height) / 2;
   1431 	int i = 0, j = 0;
   1432 
   1433 	int selectFrom = -1, selectTo = -1;
   1434 
   1435 	if (selection) {
   1436 		selectFrom = selection->carets[0];
   1437 		selectTo = selection->carets[1];
   1438 		
   1439 		if (selectFrom > selectTo) {
   1440 			UI_SWAP(int, selectFrom, selectTo);
   1441 		}
   1442 	}
   1443 
   1444 	for (; j < bytes; j++) {
   1445 		char c = *string++;
   1446 		uint32_t colorText = color;
   1447 
   1448 		if (j >= selectFrom && j < selectTo) {
   1449 			UIDrawBlock(painter, UI_RECT_4(x, x + ui.activeFont->glyphWidth, y, y + height), selection->colorBackground);
   1450 			colorText = selection->colorText;
   1451 		}
   1452 
   1453 		if (c != '\t') {
   1454 			UIDrawGlyph(painter, x, y, c, colorText);
   1455 		}
   1456 
   1457 		if (selection && selection->carets[0] == j) {
   1458 			UIDrawInvert(painter, UI_RECT_4(x, x + 1, y, y + height));
   1459 		}
   1460 
   1461 		x += ui.activeFont->glyphWidth, i++;
   1462 
   1463 		if (c == '\t') {
   1464 			while (i & 3) x += ui.activeFont->glyphWidth, i++;
   1465 		}
   1466 	}
   1467 
   1468 	if (selection && selection->carets[0] == j) {
   1469 		UIDrawInvert(painter, UI_RECT_4(x, x + 1, y, y + height));
   1470 	}
   1471 
   1472 	painter->clip = oldClip;
   1473 }
   1474 
   1475 void UIDrawBorder(UIPainter *painter, UIRectangle r, uint32_t borderColor, UIRectangle borderSize) {
   1476 	UIDrawBlock(painter, UI_RECT_4(r.l, r.r, r.t, r.t + borderSize.t), borderColor);
   1477 	UIDrawBlock(painter, UI_RECT_4(r.l, r.l + borderSize.l, r.t + borderSize.t, r.b - borderSize.b), borderColor);
   1478 	UIDrawBlock(painter, UI_RECT_4(r.r - borderSize.r, r.r, r.t + borderSize.t, r.b - borderSize.b), borderColor);
   1479 	UIDrawBlock(painter, UI_RECT_4(r.l, r.r, r.b - borderSize.b, r.b), borderColor);
   1480 }
   1481 
   1482 void UIDrawRectangle(UIPainter *painter, UIRectangle r, uint32_t mainColor, uint32_t borderColor, UIRectangle borderSize) {
   1483 	UIDrawBorder(painter, r, borderColor, borderSize);
   1484 	UIDrawBlock(painter, UI_RECT_4(r.l + borderSize.l, r.r - borderSize.r, r.t + borderSize.t, r.b - borderSize.b), mainColor);
   1485 }
   1486 
   1487 void UIElementMove(UIElement *element, UIRectangle bounds, bool alwaysLayout) {
   1488 	UIRectangle oldClip = element->clip;
   1489 	element->clip = UIRectangleIntersection(element->parent->clip, bounds);
   1490 
   1491 	if (!UIRectangleEquals(element->bounds, bounds) || !UIRectangleEquals(element->clip, oldClip) || alwaysLayout) {
   1492 		element->bounds = bounds;
   1493 		UIElementMessage(element, UI_MSG_LAYOUT, 0, 0);
   1494 	}
   1495 }
   1496 
   1497 int UIElementMessage(UIElement *element, UIMessage message, int di, void *dp) {
   1498 	if (message != UI_MSG_DESTROY && (element->flags & UI_ELEMENT_DESTROY)) {
   1499 		return 0;
   1500 	}
   1501 
   1502 	if (message >= UI_MSG_INPUT_EVENTS_START && message <= UI_MSG_INPUT_EVENTS_END && (element->flags & UI_ELEMENT_DISABLED)) {
   1503 		return 0;
   1504 	}
   1505 
   1506 	if (element->messageUser) {
   1507 		int result = element->messageUser(element, message, di, dp);
   1508 
   1509 		if (result) {
   1510 			return result;
   1511 		}
   1512 	}
   1513 
   1514 	if (element->messageClass) {
   1515 		return element->messageClass(element, message, di, dp);
   1516 	} else {
   1517 		return 0;
   1518 	}
   1519 }
   1520 
   1521 void UIElementChangeParent(UIElement *element, UIElement *newParent, UIElement *insertBefore) {
   1522 	UIElement **link = &element->parent->children;
   1523 
   1524 	while (true) {
   1525 		if (*link == element) {
   1526 			*link = element->next;
   1527 			break;
   1528 		} else {
   1529 			link = &(*link)->next;
   1530 		}
   1531 	}
   1532 
   1533 	link = &newParent->children;
   1534 	element->next = insertBefore;
   1535 
   1536 	while (true) {
   1537 		if ((*link) == insertBefore) {
   1538 			*link = element;
   1539 			break;
   1540 		} else {
   1541 			link = &(*link)->next;
   1542 		}
   1543 	}
   1544 
   1545 	element->parent = newParent;
   1546 	element->window = newParent->window;
   1547 }
   1548 
   1549 UIElement *UIElementCreate(size_t bytes, UIElement *parent, uint32_t flags, int (*message)(UIElement *, UIMessage, int, void *), const char *cClassName) {
   1550 	UI_ASSERT(bytes >= sizeof(UIElement));
   1551 	UIElement *element = (UIElement *) UI_CALLOC(bytes);
   1552 	element->flags = flags;
   1553 	element->messageClass = message;
   1554 
   1555 	if (!parent && (~flags & UI_ELEMENT_WINDOW)) {
   1556 		UI_ASSERT(ui.parentStackCount);
   1557 		parent = ui.parentStack[ui.parentStackCount - 1];
   1558 	}
   1559 
   1560 	if ((~flags & UI_ELEMENT_NON_CLIENT) && parent) {
   1561 		UIElementMessage(parent, UI_MSG_CLIENT_PARENT, 0, &parent);
   1562 	}
   1563 
   1564 	if (parent) {
   1565 		element->window = parent->window;
   1566 		element->parent = parent;
   1567 
   1568 		if (parent->children) {
   1569 			UIElement *sibling = parent->children;
   1570 
   1571 			while (sibling->next) {
   1572 				sibling = sibling->next;
   1573 			}
   1574 
   1575 			sibling->next = element;
   1576 		} else {
   1577 			parent->children = element;
   1578 		}
   1579 
   1580 		UI_ASSERT(~parent->flags & UI_ELEMENT_DESTROY);
   1581 	}
   1582 
   1583 	element->cClassName = cClassName;
   1584 	static uint32_t id = 0;
   1585 	element->id = ++id;
   1586 
   1587 #ifdef UI_DEBUG
   1588 	_UIInspectorRefresh();
   1589 #endif
   1590 
   1591 	if (flags & UI_ELEMENT_PARENT_PUSH) {
   1592 		UIParentPush(element);
   1593 	}
   1594 
   1595 	return element;
   1596 }
   1597 
   1598 UIElement *UIParentPush(UIElement *element) {
   1599 	UI_ASSERT(ui.parentStackCount != sizeof(ui.parentStack) / sizeof(ui.parentStack[0]));
   1600 	ui.parentStack[ui.parentStackCount++] = element;
   1601 	return element;
   1602 }
   1603 
   1604 UIElement *UIParentPop() {
   1605 	UI_ASSERT(ui.parentStackCount);
   1606 	ui.parentStackCount--;
   1607 	return ui.parentStack[ui.parentStackCount];
   1608 }
   1609 
   1610 int _UIPanelMeasure(UIPanel *panel) {
   1611 	bool horizontal = panel->e.flags & UI_PANEL_HORIZONTAL;
   1612 	int size = 0;
   1613 	UIElement *child = panel->e.children;
   1614 
   1615 	while (child) {
   1616 		if (~child->flags & UI_ELEMENT_HIDE) {
   1617 			if (horizontal) {
   1618 				int height = UIElementMessage(child, UI_MSG_GET_HEIGHT, 0, 0);
   1619 
   1620 				if (height > size) {
   1621 					size = height;
   1622 				}
   1623 			} else {
   1624 				int width = UIElementMessage(child, UI_MSG_GET_WIDTH, 0, 0);
   1625 
   1626 				if (width > size) {
   1627 					size = width;
   1628 				}
   1629 			}
   1630 		}
   1631 
   1632 		child = child->next;
   1633 	}
   1634 
   1635 	int border = 0;
   1636 
   1637 	if (horizontal) {
   1638 		border = panel->border.t + panel->border.b;
   1639 	} else {
   1640 		border = panel->border.l + panel->border.r;
   1641 	}
   1642 
   1643 	return size + border * panel->e.window->scale;
   1644 }
   1645 
   1646 int _UIPanelLayout(UIPanel *panel, UIRectangle bounds, bool measure) {
   1647 	bool horizontal = panel->e.flags & UI_PANEL_HORIZONTAL;
   1648 	float scale = panel->e.window->scale;
   1649 	int position = (horizontal ? panel->border.l : panel->border.t) * scale;
   1650 	if (panel->scrollBar && !measure) position -= panel->scrollBar->position;
   1651 	int hSpace = UI_RECT_WIDTH(bounds) - UI_RECT_TOTAL_H(panel->border) * scale;
   1652 	int vSpace = UI_RECT_HEIGHT(bounds) - UI_RECT_TOTAL_V(panel->border) * scale;
   1653 
   1654 	int available = horizontal ? hSpace : vSpace;
   1655 	int fill = 0, count = 0, perFill = 0;
   1656 
   1657 	for (UIElement *child = panel->e.children; child; child = child->next) {
   1658 		if (child->flags & (UI_ELEMENT_HIDE | UI_ELEMENT_NON_CLIENT)) {
   1659 			continue;
   1660 		}
   1661 
   1662 		count++;
   1663 
   1664 		if (horizontal) {
   1665 			if (child->flags & UI_ELEMENT_H_FILL) {
   1666 				fill++;
   1667 			} else if (available > 0) {
   1668 				available -= UIElementMessage(child, UI_MSG_GET_WIDTH, vSpace, 0);
   1669 			}
   1670 		} else {
   1671 			if (child->flags & UI_ELEMENT_V_FILL) {
   1672 				fill++;
   1673 			} else if (available > 0) {
   1674 				available -= UIElementMessage(child, UI_MSG_GET_HEIGHT, hSpace, 0);
   1675 			}
   1676 		}
   1677 	}
   1678 
   1679 	if (count) {
   1680 		available -= (count - 1) * (int) (panel->gap * scale);
   1681 	}
   1682 
   1683 	if (available > 0 && fill) {
   1684 		perFill = available / fill;
   1685 	}
   1686 
   1687 	bool expand = panel->e.flags & UI_PANEL_EXPAND;
   1688 	int scaledBorder2 = (horizontal ? panel->border.t : panel->border.l) * panel->e.window->scale;
   1689 
   1690 	for (UIElement *child = panel->e.children; child; child = child->next) {
   1691 		if (child->flags & (UI_ELEMENT_HIDE | UI_ELEMENT_NON_CLIENT)) {
   1692 			continue;
   1693 		}
   1694 
   1695 		if (horizontal) {
   1696 			int height = ((child->flags & UI_ELEMENT_V_FILL) || expand) ? vSpace : UIElementMessage(child, UI_MSG_GET_HEIGHT, 0, 0);
   1697 			int width = (child->flags & UI_ELEMENT_H_FILL) ? perFill : UIElementMessage(child, UI_MSG_GET_WIDTH, height, 0);
   1698 			UIRectangle relative = UI_RECT_4(position, position + width, 
   1699 					scaledBorder2 + (vSpace - height) / 2, 
   1700 					scaledBorder2 + (vSpace + height) / 2);
   1701 			if (!measure) UIElementMove(child, UIRectangleTranslate(relative, bounds), false);
   1702 			position += width + panel->gap * scale;
   1703 		} else {
   1704 			int width = ((child->flags & UI_ELEMENT_H_FILL) || expand) ? hSpace : UIElementMessage(child, UI_MSG_GET_WIDTH, 0, 0);
   1705 			int height = (child->flags & UI_ELEMENT_V_FILL) ? perFill : UIElementMessage(child, UI_MSG_GET_HEIGHT, width, 0);
   1706 			UIRectangle relative = UI_RECT_4(scaledBorder2 + (hSpace - width) / 2, 
   1707 					scaledBorder2 + (hSpace + width) / 2, position, position + height);
   1708 			if (!measure) UIElementMove(child, UIRectangleTranslate(relative, bounds), false);
   1709 			position += height + panel->gap * scale;
   1710 		}
   1711 	}
   1712 
   1713 	return position - panel->gap * scale + (horizontal ? panel->border.r : panel->border.b) * scale;
   1714 }
   1715 
   1716 int _UIPanelMessage(UIElement *element, UIMessage message, int di, void *dp) {
   1717 	UIPanel *panel = (UIPanel *) element;
   1718 	bool horizontal = element->flags & UI_PANEL_HORIZONTAL;
   1719 
   1720 	if (message == UI_MSG_LAYOUT) {
   1721 		int scrollBarWidth = panel->scrollBar ? (UI_SIZE_SCROLL_BAR * element->window->scale) : 0;
   1722 		UIRectangle bounds = element->bounds;
   1723 		bounds.r -= scrollBarWidth;
   1724 
   1725 		if (panel->scrollBar) {
   1726 			UIRectangle scrollBarBounds = element->bounds;
   1727 			scrollBarBounds.l = scrollBarBounds.r - scrollBarWidth;
   1728 			panel->scrollBar->maximum = _UIPanelLayout(panel, bounds, true);
   1729 			panel->scrollBar->page = UI_RECT_HEIGHT(element->bounds);
   1730 			UIElementMove(&panel->scrollBar->e, scrollBarBounds, true);
   1731 		}
   1732 
   1733 		_UIPanelLayout(panel, bounds, false);
   1734 	} else if (message == UI_MSG_GET_WIDTH) {
   1735 		if (horizontal) {
   1736 			return _UIPanelLayout(panel, UI_RECT_4(0, 0, 0, di), true);
   1737 		} else {
   1738 			return _UIPanelMeasure(panel);
   1739 		}
   1740 	} else if (message == UI_MSG_GET_HEIGHT) {
   1741 		if (horizontal) {
   1742 			return _UIPanelMeasure(panel);
   1743 		} else {
   1744 			int width = di && panel->scrollBar ? (di - UI_SIZE_SCROLL_BAR * element->window->scale) : di;
   1745 			return _UIPanelLayout(panel, UI_RECT_4(0, width, 0, 0), true);
   1746 		}
   1747 	} else if (message == UI_MSG_PAINT) {
   1748 		if (element->flags & UI_PANEL_GRAY) {
   1749 			UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.panel1);
   1750 		} else if (element->flags & UI_PANEL_WHITE) {
   1751 			UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.panel2);
   1752 		} 
   1753 		
   1754 		if (element->flags & UI_PANEL_BORDER) {
   1755 			UIDrawBorder((UIPainter *) dp, element->bounds, ui.theme.border, UI_RECT_1((int) element->window->scale));
   1756 		}
   1757 	} else if (message == UI_MSG_MOUSE_WHEEL && panel->scrollBar) {
   1758 		return UIElementMessage(&panel->scrollBar->e, message, di, dp);
   1759 	} else if (message == UI_MSG_SCROLLED) {
   1760 		UIElementRefresh(element);
   1761 	}
   1762 
   1763 	return 0;
   1764 }
   1765 
   1766 UIPanel *UIPanelCreate(UIElement *parent, uint32_t flags) {
   1767 	UIPanel *panel = (UIPanel *) UIElementCreate(sizeof(UIPanel), parent, flags, _UIPanelMessage, "Panel");
   1768 
   1769 	if (flags & UI_PANEL_MEDIUM_SPACING) {
   1770 		panel->border = UI_RECT_1(UI_SIZE_PANE_MEDIUM_BORDER);
   1771 		panel->gap = UI_SIZE_PANE_MEDIUM_GAP;
   1772 	} else if (flags & UI_PANEL_SMALL_SPACING) {
   1773 		panel->border = UI_RECT_1(UI_SIZE_PANE_SMALL_BORDER);
   1774 		panel->gap = UI_SIZE_PANE_SMALL_GAP;
   1775 	}
   1776 
   1777 	if (flags & UI_PANEL_SCROLL) {
   1778 		panel->scrollBar = UIScrollBarCreate(&panel->e, UI_ELEMENT_NON_CLIENT);
   1779 	}
   1780 
   1781 	return panel;
   1782 }
   1783 
   1784 void _UIWrapPanelLayoutRow(UIWrapPanel *panel, UIElement *child, UIElement *rowEnd, int rowY, int rowHeight) {
   1785 	int rowPosition = 0;
   1786 
   1787 	while (child != rowEnd) {
   1788 		int height = UIElementMessage(child, UI_MSG_GET_HEIGHT, 0, 0);
   1789 		int width = UIElementMessage(child, UI_MSG_GET_WIDTH, 0, 0);
   1790 		UIRectangle relative = UI_RECT_4(rowPosition, rowPosition + width, rowY + rowHeight / 2 - height / 2, rowY + rowHeight / 2 + height / 2);
   1791 		UIElementMove(child, UIRectangleTranslate(relative, panel->e.bounds), false);
   1792 		child = child->next;
   1793 		rowPosition += width;
   1794 	}
   1795 }
   1796 
   1797 int _UIWrapPanelMessage(UIElement *element, UIMessage message, int di, void *dp) {
   1798 	UIWrapPanel *panel = (UIWrapPanel *) element;
   1799 	bool horizontal = element->flags & UI_PANEL_HORIZONTAL;
   1800 
   1801 	if (message == UI_MSG_LAYOUT || message == UI_MSG_GET_HEIGHT) {
   1802 		int totalHeight = 0;
   1803 		int rowPosition = 0;
   1804 		int rowHeight = 0;
   1805 		int rowLimit = message == UI_MSG_LAYOUT ? UI_RECT_WIDTH(element->bounds) : di;
   1806 
   1807 		UIElement *child = panel->e.children;
   1808 		UIElement *rowStart = child;
   1809 
   1810 		while (child) {
   1811 			if (~child->flags & UI_ELEMENT_HIDE) {
   1812 				int height = UIElementMessage(child, UI_MSG_GET_HEIGHT, 0, 0);
   1813 				int width = UIElementMessage(child, UI_MSG_GET_WIDTH, 0, 0);
   1814 
   1815 				if (rowLimit && rowPosition + width > rowLimit) {
   1816 					_UIWrapPanelLayoutRow(panel, rowStart, child, totalHeight, rowHeight);
   1817 					totalHeight += rowHeight;
   1818 					rowPosition = rowHeight = 0;
   1819 					rowStart = child;
   1820 				}
   1821 
   1822 				if (height > rowHeight) {
   1823 					rowHeight = height;
   1824 				}
   1825 
   1826 				rowPosition += width;
   1827 			}
   1828 
   1829 			child = child->next;
   1830 		}
   1831 
   1832 		if (message == UI_MSG_GET_HEIGHT) {
   1833 			return totalHeight + rowHeight;
   1834 		} else {
   1835 			_UIWrapPanelLayoutRow(panel, rowStart, child, totalHeight, rowHeight);
   1836 		}
   1837 	}
   1838 
   1839 	return 0;
   1840 }
   1841 
   1842 UIWrapPanel *UIWrapPanelCreate(UIElement *parent, uint32_t flags) {
   1843 	return (UIWrapPanel *) UIElementCreate(sizeof(UIWrapPanel), parent, flags, _UIWrapPanelMessage, "Wrap Panel");
   1844 }
   1845 
   1846 void _UIButtonCalculateColors(UIElement *element, uint32_t *color, uint32_t *textColor) {
   1847 	bool disabled = element->flags & UI_ELEMENT_DISABLED;
   1848 	bool focused = element == element->window->focused;
   1849 	bool pressed = element == element->window->pressed;
   1850 	bool hovered = element == element->window->hovered;
   1851 	*color = disabled ? ui.theme.buttonDisabled
   1852 		: (pressed && hovered) ? ui.theme.buttonPressed 
   1853 		: (pressed || hovered) ? ui.theme.buttonHovered 
   1854 		: focused ? ui.theme.selected : ui.theme.buttonNormal;
   1855 	*textColor = disabled ? ui.theme.textDisabled 
   1856 		: *color == ui.theme.selected ? ui.theme.textSelected : ui.theme.text;
   1857 }
   1858 
   1859 
   1860 int _UIButtonMessage(UIElement *element, UIMessage message, int di, void *dp) {
   1861 	UIButton *button = (UIButton *) element;
   1862 	bool isMenuItem = element->flags & UI_BUTTON_MENU_ITEM;
   1863 	bool isDropDown = element->flags & UI_BUTTON_DROP_DOWN;
   1864 	
   1865 	if (message == UI_MSG_GET_HEIGHT) {
   1866 		if (isMenuItem) {
   1867 			return UI_SIZE_MENU_ITEM_HEIGHT * element->window->scale;
   1868 		} else {
   1869 			return UI_SIZE_BUTTON_HEIGHT * element->window->scale;
   1870 		}
   1871 	} else if (message == UI_MSG_GET_WIDTH) {
   1872 		int labelSize = UIMeasureStringWidth(button->label, button->labelBytes);
   1873 		int paddedSize = labelSize + UI_SIZE_BUTTON_PADDING * element->window->scale;
   1874 		if (isDropDown) paddedSize += ui.activeFont->glyphWidth * 2;
   1875 		int minimumSize = ((element->flags & UI_BUTTON_SMALL) ? 0 
   1876 				: isMenuItem ? UI_SIZE_MENU_ITEM_MINIMUM_WIDTH 
   1877 				: UI_SIZE_BUTTON_MINIMUM_WIDTH) 
   1878 			* element->window->scale;
   1879 		return paddedSize > minimumSize ? paddedSize : minimumSize;
   1880 	} else if (message == UI_MSG_PAINT) {
   1881 		UIPainter *painter = (UIPainter *) dp;
   1882 
   1883 		uint32_t color, textColor;
   1884 		_UIButtonCalculateColors(element, &color, &textColor);
   1885 
   1886 		UIDrawRectangle(painter, element->bounds, color, ui.theme.border, UI_RECT_1(isMenuItem ? 0 : 1));
   1887 
   1888 		if (element->flags & UI_BUTTON_CHECKED) {
   1889 			UIDrawBlock(painter, UIRectangleAdd(element->bounds, 
   1890 				UI_RECT_1I((int) (UI_SIZE_BUTTON_CHECKED_AREA * element->window->scale))), ui.theme.buttonPressed);
   1891 		}
   1892 
   1893 		UIRectangle bounds = UIRectangleAdd(element->bounds, UI_RECT_2I((int) (UI_SIZE_MENU_ITEM_MARGIN * element->window->scale), 0));
   1894 
   1895 		if (isMenuItem) {
   1896 			if (button->labelBytes == -1) {
   1897 				button->labelBytes = _UIStringLength(button->label);
   1898 			}
   1899 
   1900 			int tab = 0;
   1901 			for (; tab < button->labelBytes && button->label[tab] != '\t'; tab++);
   1902 
   1903 			UIDrawString(painter, bounds, button->label, tab, textColor, UI_ALIGN_LEFT, NULL);
   1904 
   1905 			if (button->labelBytes > tab) {
   1906 				UIDrawString(painter, bounds, button->label + tab + 1, button->labelBytes - tab - 1, textColor, UI_ALIGN_RIGHT, NULL);
   1907 			}
   1908 		} else if (isDropDown) {
   1909 			UIDrawString(painter, bounds, button->label, button->labelBytes, textColor, UI_ALIGN_LEFT, NULL);
   1910 			UIDrawString(painter, bounds, "\x19", 1, textColor, UI_ALIGN_RIGHT, NULL);
   1911 		} else {
   1912 			UIDrawString(painter, element->bounds, button->label, button->labelBytes, textColor, UI_ALIGN_CENTER, NULL);
   1913 		}
   1914 	} else if (message == UI_MSG_UPDATE) {
   1915 		UIElementRepaint(element, NULL);
   1916 	} else if (message == UI_MSG_DESTROY) {
   1917 		UI_FREE(button->label);
   1918 	} else if (message == UI_MSG_LEFT_DOWN) {
   1919 		if (element->flags & UI_BUTTON_CAN_FOCUS) {
   1920 			UIElementFocus(element);
   1921 		}
   1922 	} else if (message == UI_MSG_KEY_TYPED) {
   1923 		UIKeyTyped *m = (UIKeyTyped *) dp;
   1924 		
   1925 		if (m->textBytes == 1 && m->text[0] == ' ') {
   1926 			UIElementMessage(element, UI_MSG_CLICKED, 0, 0);
   1927 			UIElementRepaint(element, NULL);
   1928 		}
   1929 	} else if (message == UI_MSG_CLICKED) {
   1930 		if (button->invoke) {
   1931 			button->invoke(element->cp);
   1932 		}
   1933 	}
   1934 
   1935 	return 0;
   1936 }
   1937 
   1938 UIButton *UIButtonCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes) {
   1939 	UIButton *button = (UIButton *) UIElementCreate(sizeof(UIButton), parent, flags | UI_ELEMENT_TAB_STOP, _UIButtonMessage, "Button");
   1940 	button->label = UIStringCopy(label, (button->labelBytes = labelBytes));
   1941 	return button;
   1942 }
   1943 
   1944 int _UICheckboxMessage(UIElement *element, UIMessage message, int di, void *dp) {
   1945 	UICheckbox *box = (UICheckbox *) element;
   1946 	
   1947 	if (message == UI_MSG_GET_HEIGHT) {
   1948 		return UI_SIZE_BUTTON_HEIGHT * element->window->scale;
   1949 	} else if (message == UI_MSG_GET_WIDTH) {
   1950 		int labelSize = UIMeasureStringWidth(box->label, box->labelBytes);
   1951 		return (labelSize + UI_SIZE_CHECKBOX_BOX + UI_SIZE_CHECKBOX_GAP) * element->window->scale;
   1952 	} else if (message == UI_MSG_PAINT) {
   1953 		UIPainter *painter = (UIPainter *) dp;
   1954 		uint32_t color, textColor;
   1955 		_UIButtonCalculateColors(element, &color, &textColor);
   1956 		int midY = (element->bounds.t + element->bounds.b) / 2;
   1957 		UIRectangle boxBounds = UI_RECT_4(element->bounds.l, element->bounds.l + UI_SIZE_CHECKBOX_BOX, 
   1958 				midY - UI_SIZE_CHECKBOX_BOX / 2, midY + UI_SIZE_CHECKBOX_BOX / 2);
   1959 		UIDrawRectangle(painter, boxBounds, color, ui.theme.border, UI_RECT_1(1));
   1960 		UIDrawString(painter, UIRectangleAdd(boxBounds, UI_RECT_4(1, 0, 0, 0)), 
   1961 				box->check == UI_CHECK_CHECKED ? "*" : box->check == UI_CHECK_INDETERMINATE ? "-" : " ", -1, 
   1962 				textColor, UI_ALIGN_CENTER, NULL);
   1963 		UIDrawString(painter, UIRectangleAdd(element->bounds, UI_RECT_4(UI_SIZE_CHECKBOX_BOX + UI_SIZE_CHECKBOX_GAP, 0, 0, 0)), 
   1964 				box->label, box->labelBytes, textColor, UI_ALIGN_LEFT, NULL);
   1965 	} else if (message == UI_MSG_UPDATE) {
   1966 		UIElementRepaint(element, NULL);
   1967 	} else if (message == UI_MSG_DESTROY) {
   1968 		UI_FREE(box->label);
   1969 	} else if (message == UI_MSG_KEY_TYPED) {
   1970 		UIKeyTyped *m = (UIKeyTyped *) dp;
   1971 		
   1972 		if (m->textBytes == 1 && m->text[0] == ' ') {
   1973 			UIElementMessage(element, UI_MSG_CLICKED, 0, 0);
   1974 			UIElementRepaint(element, NULL);
   1975 		}
   1976 	} else if (message == UI_MSG_CLICKED) {
   1977 		box->check = (box->check + 1) % ((element->flags & UI_CHECKBOX_ALLOW_INDETERMINATE) ? 3 : 2);
   1978 		UIElementRepaint(element, NULL);
   1979 		if (box->invoke) box->invoke(element->cp);
   1980 	}
   1981 
   1982 	return 0;
   1983 }
   1984 
   1985 UICheckbox *UICheckboxCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes) {
   1986 	UICheckbox *box = (UICheckbox *) UIElementCreate(sizeof(UICheckbox), parent, flags | UI_ELEMENT_TAB_STOP, _UICheckboxMessage, "Checkbox");
   1987 	box->label = UIStringCopy(label, (box->labelBytes = labelBytes));
   1988 	return box;
   1989 }
   1990 
   1991 int _UILabelMessage(UIElement *element, UIMessage message, int di, void *dp) {
   1992 	UILabel *label = (UILabel *) element;
   1993 	
   1994 	if (message == UI_MSG_GET_HEIGHT) {
   1995 		return UIMeasureStringHeight();
   1996 	} else if (message == UI_MSG_GET_WIDTH) {
   1997 		return UIMeasureStringWidth(label->label, label->labelBytes);
   1998 	} else if (message == UI_MSG_PAINT) {
   1999 		UIPainter *painter = (UIPainter *) dp;
   2000 		UIDrawString(painter, element->bounds, label->label, label->labelBytes, ui.theme.text, UI_ALIGN_LEFT, NULL);
   2001 	} else if (message == UI_MSG_DESTROY) {
   2002 		UI_FREE(label->label);
   2003 	}
   2004 
   2005 	return 0;
   2006 }
   2007 
   2008 void UILabelSetContent(UILabel *label, const char *string, ptrdiff_t stringBytes) {
   2009 	UI_FREE(label->label);
   2010 	label->label = UIStringCopy(string, (label->labelBytes = stringBytes));
   2011 }
   2012 
   2013 UILabel *UILabelCreate(UIElement *parent, uint32_t flags, const char *string, ptrdiff_t stringBytes) {
   2014 	UILabel *label = (UILabel *) UIElementCreate(sizeof(UILabel), parent, flags, _UILabelMessage, "Label");
   2015 	label->label = UIStringCopy(string, (label->labelBytes = stringBytes));
   2016 	return label;
   2017 }
   2018 
   2019 int _UISplitPaneMessage(UIElement *element, UIMessage message, int di, void *dp);
   2020 
   2021 int _UISplitterMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2022 	UISplitPane *splitPane = (UISplitPane *) element->parent;
   2023 	bool vertical = splitPane->e.flags & UI_SPLIT_PANE_VERTICAL;
   2024 
   2025 	if (message == UI_MSG_PAINT) {
   2026 		UIRectangle borders = vertical ? UI_RECT_2(0, 1) : UI_RECT_2(1, 0);
   2027 		UIDrawRectangle((UIPainter *) dp, element->bounds, ui.theme.buttonNormal, ui.theme.border, borders);
   2028 	} else if (message == UI_MSG_GET_CURSOR) {
   2029 		return vertical ? UI_CURSOR_SPLIT_V : UI_CURSOR_SPLIT_H;
   2030 	} else if (message == UI_MSG_MOUSE_DRAG) {
   2031 		int cursor = vertical ? element->window->cursorY : element->window->cursorX;
   2032 		int splitterSize = UI_SIZE_SPLITTER * element->window->scale;
   2033 		int space = (vertical ? UI_RECT_HEIGHT(splitPane->e.bounds) : UI_RECT_WIDTH(splitPane->e.bounds)) - splitterSize;
   2034 		float oldWeight = splitPane->weight;
   2035 		splitPane->weight = (float) (cursor - splitterSize / 2 - (vertical ? splitPane->e.bounds.t : splitPane->e.bounds.l)) / space;
   2036 		if (splitPane->weight < 0.05f) splitPane->weight = 0.05f;
   2037 		if (splitPane->weight > 0.95f) splitPane->weight = 0.95f;
   2038 
   2039 		if (element->next->next->messageClass == _UISplitPaneMessage 
   2040 				&& (element->next->next->flags & UI_SPLIT_PANE_VERTICAL) == (splitPane->e.flags & UI_SPLIT_PANE_VERTICAL)) {
   2041 			UISplitPane *subSplitPane = (UISplitPane *) element->next->next;
   2042 			subSplitPane->weight = (splitPane->weight - oldWeight - subSplitPane->weight + oldWeight * subSplitPane->weight) / (-1 + splitPane->weight);
   2043 			if (subSplitPane->weight < 0.05f) subSplitPane->weight = 0.05f;
   2044 			if (subSplitPane->weight > 0.95f) subSplitPane->weight = 0.95f;
   2045 		}
   2046 
   2047 		UIElementRefresh(&splitPane->e);
   2048 	}
   2049 
   2050 	return 0;
   2051 }
   2052 
   2053 int _UISplitPaneMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2054 	UISplitPane *splitPane = (UISplitPane *) element;
   2055 	bool vertical = splitPane->e.flags & UI_SPLIT_PANE_VERTICAL;
   2056 
   2057 	if (message == UI_MSG_LAYOUT) {
   2058 		UIElement *splitter = element->children;
   2059 		UI_ASSERT(splitter);
   2060 		UIElement *left = splitter->next;
   2061 		UI_ASSERT(left);
   2062 		UIElement *right = left->next;
   2063 		UI_ASSERT(right);
   2064 		UI_ASSERT(!right->next);
   2065 
   2066 		int splitterSize = UI_SIZE_SPLITTER * element->window->scale;
   2067 		int space = (vertical ? UI_RECT_HEIGHT(element->bounds) : UI_RECT_WIDTH(element->bounds)) - splitterSize;
   2068 		int leftSize = space * splitPane->weight;
   2069 		int rightSize = space - leftSize;
   2070 
   2071 		if (vertical) {
   2072 			UIElementMove(left, UI_RECT_4(element->bounds.l, element->bounds.r, element->bounds.t, element->bounds.t + leftSize), false);
   2073 			UIElementMove(splitter, UI_RECT_4(element->bounds.l, element->bounds.r, element->bounds.t + leftSize, element->bounds.t + leftSize + splitterSize), false);
   2074 			UIElementMove(right, UI_RECT_4(element->bounds.l, element->bounds.r, element->bounds.b - rightSize, element->bounds.b), false);
   2075 		} else {
   2076 			UIElementMove(left, UI_RECT_4(element->bounds.l, element->bounds.l + leftSize, element->bounds.t, element->bounds.b), false);
   2077 			UIElementMove(splitter, UI_RECT_4(element->bounds.l + leftSize, element->bounds.l + leftSize + splitterSize, element->bounds.t, element->bounds.b), false);
   2078 			UIElementMove(right, UI_RECT_4(element->bounds.r - rightSize, element->bounds.r, element->bounds.t, element->bounds.b), false);
   2079 		}
   2080 	}
   2081 
   2082 	return 0;
   2083 }
   2084 
   2085 UISplitPane *UISplitPaneCreate(UIElement *parent, uint32_t flags, float weight) {
   2086 	UISplitPane *splitPane = (UISplitPane *) UIElementCreate(sizeof(UISplitPane), parent, flags, _UISplitPaneMessage, "Split Pane");
   2087 	splitPane->weight = weight;
   2088 	UIElementCreate(sizeof(UIElement), &splitPane->e, 0, _UISplitterMessage, "Splitter");
   2089 	return splitPane;
   2090 }
   2091 
   2092 int _UITabPaneMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2093 	UITabPane *tabPane = (UITabPane *) element;
   2094 	
   2095 	if (message == UI_MSG_PAINT) {
   2096 		UIPainter *painter = (UIPainter *) dp;
   2097 		UIRectangle top = element->bounds;
   2098 		top.b = top.t + UI_SIZE_BUTTON_HEIGHT * element->window->scale;
   2099 		UIDrawRectangle(painter, top, ui.theme.panel1, ui.theme.border, UI_RECT_4(0, 0, 0, 1));
   2100 
   2101 		UIRectangle tab = top;
   2102 		tab.l += UI_SIZE_TAB_PANE_SPACE_LEFT * element->window->scale;
   2103 		tab.t += UI_SIZE_TAB_PANE_SPACE_TOP * element->window->scale;
   2104 
   2105 		int position = 0;
   2106 		int index = 0;
   2107 
   2108 		while (true) {
   2109 			int end = position;
   2110 			for (; tabPane->tabs[end] != '\t' && tabPane->tabs[end]; end++);
   2111 
   2112 			int width = UIMeasureStringWidth(tabPane->tabs, end - position);
   2113 			tab.r = tab.l + width + UI_SIZE_BUTTON_PADDING;
   2114 
   2115 			uint32_t color = tabPane->active == index ? ui.theme.buttonPressed : ui.theme.buttonNormal;
   2116 
   2117 			UIRectangle t = tab;
   2118 
   2119 			if (tabPane->active == index) {
   2120 				t.b++;
   2121 				t.t--;
   2122 			} else {
   2123 				t.t++;
   2124 			}
   2125 
   2126 			UIDrawRectangle(painter, t, color, ui.theme.border, UI_RECT_1(1));
   2127 			UIDrawString(painter, tab, tabPane->tabs + position, end - position, ui.theme.text, UI_ALIGN_CENTER, NULL);
   2128 			tab.l = tab.r - 1;
   2129 
   2130 			if (tabPane->tabs[end] == '\t') {
   2131 				position = end + 1;
   2132 				index++;
   2133 			} else {
   2134 				break;
   2135 			}
   2136 		}
   2137 	} else if (message == UI_MSG_LEFT_DOWN) {
   2138 		UIRectangle tab = element->bounds;
   2139 		tab.b = tab.t + UI_SIZE_BUTTON_HEIGHT * element->window->scale;
   2140 		tab.l += UI_SIZE_TAB_PANE_SPACE_LEFT * element->window->scale;
   2141 		tab.t += UI_SIZE_TAB_PANE_SPACE_TOP * element->window->scale;
   2142 
   2143 		int position = 0;
   2144 		int index = 0;
   2145 
   2146 		while (true) {
   2147 			int end = position;
   2148 			for (; tabPane->tabs[end] != '\t' && tabPane->tabs[end]; end++);
   2149 
   2150 			int width = UIMeasureStringWidth(tabPane->tabs, end - position);
   2151 			tab.r = tab.l + width + UI_SIZE_BUTTON_PADDING;
   2152 
   2153 			if (UIRectangleContains(tab, element->window->cursorX, element->window->cursorY)) {
   2154 				tabPane->active = index;
   2155 				UIElementMessage(element, UI_MSG_LAYOUT, 0, 0);
   2156 				UIElementRepaint(element, NULL);
   2157 				break;
   2158 			}
   2159 
   2160 			tab.l = tab.r - 1;
   2161 
   2162 			if (tabPane->tabs[end] == '\t') {
   2163 				position = end + 1;
   2164 				index++;
   2165 			} else {
   2166 				break;
   2167 			}
   2168 		}
   2169 	} else if (message == UI_MSG_LAYOUT) {
   2170 		UIElement *child = element->children;
   2171 		int index = 0;
   2172 
   2173 		UIRectangle content = element->bounds;
   2174 		content.t += UI_SIZE_BUTTON_HEIGHT * element->window->scale;
   2175 
   2176 		while (child) {
   2177 			if (tabPane->active == index) {
   2178 				child->flags &= ~UI_ELEMENT_HIDE;
   2179 				UIElementMove(child, content, false);
   2180 				UIElementMessage(child, UI_MSG_TAB_SELECTED, 0, 0);
   2181 			} else {
   2182 				child->flags |= UI_ELEMENT_HIDE;
   2183 			}
   2184 
   2185 			child = child->next;
   2186 			index++;
   2187 		}
   2188 	} else if (message == UI_MSG_GET_HEIGHT) {
   2189 		UIElement *child = element->children;
   2190 		int index = 0;
   2191 		int baseHeight = UI_SIZE_BUTTON_HEIGHT * element->window->scale;
   2192 
   2193 		while (child) {
   2194 			if (tabPane->active == index) {
   2195 				return baseHeight + UIElementMessage(child, UI_MSG_GET_HEIGHT, di, dp);
   2196 			}
   2197 
   2198 			child = child->next;
   2199 			index++;
   2200 		}
   2201 	} else if (message == UI_MSG_DESTROY) {
   2202 		UI_FREE(tabPane->tabs);
   2203 	}
   2204 
   2205 	return 0;
   2206 }
   2207 
   2208 UITabPane *UITabPaneCreate(UIElement *parent, uint32_t flags, const char *tabs) {
   2209 	UITabPane *tabPane = (UITabPane *) UIElementCreate(sizeof(UITabPane), parent, flags, _UITabPaneMessage, "Tab Pane");
   2210 	tabPane->tabs = UIStringCopy(tabs, -1);
   2211 	return tabPane;
   2212 }
   2213 
   2214 int _UISpacerMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2215 	UISpacer *spacer = (UISpacer *) element;
   2216 	
   2217 	if (message == UI_MSG_GET_HEIGHT) {
   2218 		return spacer->height * element->window->scale;
   2219 	} else if (message == UI_MSG_GET_WIDTH) {
   2220 		return spacer->width * element->window->scale;
   2221 	} else if (message == UI_MSG_PAINT && (element->flags & UI_SPACER_LINE)) {
   2222 		UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.border);
   2223 	}
   2224 
   2225 	return 0;
   2226 }
   2227 
   2228 UISpacer *UISpacerCreate(UIElement *parent, uint32_t flags, int width, int height) {
   2229 	UISpacer *spacer = (UISpacer *) UIElementCreate(sizeof(UISpacer), parent, flags, _UISpacerMessage, "Spacer");
   2230 	spacer->width = width;
   2231 	spacer->height = height;
   2232 	return spacer;
   2233 }
   2234 
   2235 int _UIScrollBarMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2236 	UIScrollBar *scrollBar = (UIScrollBar *) element;
   2237 
   2238 	if (message == UI_MSG_GET_WIDTH || message == UI_MSG_GET_HEIGHT) {
   2239 		return UI_SIZE_SCROLL_BAR * element->window->scale;
   2240 	} else if (message == UI_MSG_LAYOUT) {
   2241 		UIElement *up = element->children;
   2242 		UIElement *thumb = up->next;
   2243 		UIElement *down = thumb->next;
   2244 
   2245 		if (scrollBar->page >= scrollBar->maximum || scrollBar->maximum <= 0 || scrollBar->page <= 0) {
   2246 			up->flags |= UI_ELEMENT_HIDE;
   2247 			thumb->flags |= UI_ELEMENT_HIDE;
   2248 			down->flags |= UI_ELEMENT_HIDE;
   2249 
   2250 			scrollBar->position = 0;
   2251 		} else {
   2252 			up->flags &= ~UI_ELEMENT_HIDE;
   2253 			thumb->flags &= ~UI_ELEMENT_HIDE;
   2254 			down->flags &= ~UI_ELEMENT_HIDE;
   2255 
   2256 			int size = scrollBar->horizontal ? UI_RECT_WIDTH(element->bounds) : UI_RECT_HEIGHT(element->bounds);
   2257 			int thumbSize = size * scrollBar->page / scrollBar->maximum;
   2258 
   2259 			if (thumbSize < UI_SIZE_SCROLL_MINIMUM_THUMB * element->window->scale) {
   2260 				thumbSize = UI_SIZE_SCROLL_MINIMUM_THUMB * element->window->scale;
   2261 			}
   2262 
   2263 			if (scrollBar->position < 0) {
   2264 				scrollBar->position = 0;
   2265 			} else if (scrollBar->position > scrollBar->maximum - scrollBar->page) {
   2266 				scrollBar->position = scrollBar->maximum - scrollBar->page;
   2267 			}
   2268 
   2269 			int thumbPosition = scrollBar->position / (scrollBar->maximum - scrollBar->page) * (size - thumbSize);
   2270 
   2271 			if (scrollBar->position == scrollBar->maximum - scrollBar->page) {
   2272 				thumbPosition = size - thumbSize;
   2273 			}
   2274 
   2275 			if (scrollBar->horizontal) {
   2276 				UIRectangle r = element->bounds;
   2277 				r.r = r.l + thumbPosition;
   2278 				UIElementMove(up, r, false);
   2279 				r.l = r.r, r.r = r.l + thumbSize;
   2280 				UIElementMove(thumb, r, false);
   2281 				r.l = r.r, r.r = element->bounds.r;
   2282 				UIElementMove(down, r, false);
   2283 			} else {
   2284 				UIRectangle r = element->bounds;
   2285 				r.b = r.t + thumbPosition;
   2286 				UIElementMove(up, r, false);
   2287 				r.t = r.b, r.b = r.t + thumbSize;
   2288 				UIElementMove(thumb, r, false);
   2289 				r.t = r.b, r.b = element->bounds.b;
   2290 				UIElementMove(down, r, false);
   2291 			}
   2292 		}
   2293 	} else if (message == UI_MSG_PAINT) {
   2294 		if (scrollBar->page >= scrollBar->maximum || scrollBar->maximum <= 0 || scrollBar->page <= 0) {
   2295 			UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.panel1);
   2296 		}
   2297 	} else if (message == UI_MSG_MOUSE_WHEEL) {
   2298 		scrollBar->position += di;
   2299 		UIElementRefresh(element);
   2300 		UIElementMessage(element->parent, UI_MSG_SCROLLED, 0, 0);
   2301 		return 1;
   2302 	}
   2303 
   2304 	return 0;
   2305 }
   2306 
   2307 int _UIScrollUpDownMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2308 	UIScrollBar *scrollBar = (UIScrollBar *) element->parent;
   2309 	bool isDown = element->cp;
   2310 
   2311 	if (message == UI_MSG_PAINT) {
   2312 		UIPainter *painter = (UIPainter *) dp;
   2313 		uint32_t color = element == element->window->pressed ? ui.theme.buttonPressed 
   2314 			: element == element->window->hovered ? ui.theme.buttonHovered : ui.theme.panel2;
   2315 		UIDrawRectangle(painter, element->bounds, color, ui.theme.border, UI_RECT_1(0));
   2316 		
   2317 		if (scrollBar->horizontal) {
   2318 			UIDrawGlyph(painter, isDown ? (element->bounds.r - ui.activeFont->glyphWidth - 2 * element->window->scale) 
   2319 					: (element->bounds.l + 2 * element->window->scale), 
   2320 				(element->bounds.t + element->bounds.b - ui.activeFont->glyphHeight) / 2,
   2321 				isDown ? 26 : 27, ui.theme.text);
   2322 		} else {
   2323 			UIDrawGlyph(painter, (element->bounds.l + element->bounds.r - ui.activeFont->glyphWidth) / 2 + 1, 
   2324 				isDown ? (element->bounds.b - ui.activeFont->glyphHeight - 2 * element->window->scale) 
   2325 					: (element->bounds.t + 2 * element->window->scale), 
   2326 				isDown ? 25 : 24, ui.theme.text);
   2327 		}
   2328 	} else if (message == UI_MSG_UPDATE) {
   2329 		UIElementRepaint(element, NULL);
   2330 	} else if (message == UI_MSG_LEFT_DOWN) {
   2331 		UIElementAnimate(element, false);
   2332 		scrollBar->lastAnimateTime = UI_CLOCK();
   2333 	} else if (message == UI_MSG_LEFT_UP) {
   2334 		UIElementAnimate(element, true);
   2335 	} else if (message == UI_MSG_ANIMATE) {
   2336 		UI_CLOCK_T previous = scrollBar->lastAnimateTime;
   2337 		UI_CLOCK_T current = UI_CLOCK();
   2338 		UI_CLOCK_T delta = current - previous;
   2339 		double deltaSeconds = (double) delta / UI_CLOCKS_PER_SECOND;
   2340 		if (deltaSeconds > 0.1) deltaSeconds = 0.1;
   2341 		double deltaPixels = deltaSeconds * scrollBar->page * 3;
   2342 		scrollBar->lastAnimateTime = current;
   2343 		if (isDown) scrollBar->position += deltaPixels;
   2344 		else scrollBar->position -= deltaPixels;
   2345 		UIElementRefresh(&scrollBar->e);
   2346 		UIElementMessage(scrollBar->e.parent, UI_MSG_SCROLLED, 0, 0);
   2347 	}
   2348 
   2349 	return 0;
   2350 }
   2351 
   2352 int _UIScrollThumbMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2353 	UIScrollBar *scrollBar = (UIScrollBar *) element->parent;
   2354 
   2355 	if (message == UI_MSG_PAINT) {
   2356 		UIPainter *painter = (UIPainter *) dp;
   2357 		uint32_t color = element == element->window->pressed ? ui.theme.buttonPressed 
   2358 			: element == element->window->hovered ? ui.theme.buttonHovered : ui.theme.buttonNormal;
   2359 		UIDrawRectangle(painter, element->bounds, color, ui.theme.border, UI_RECT_1(2));
   2360 	} else if (message == UI_MSG_UPDATE) {
   2361 		UIElementRepaint(element, NULL);
   2362 	} else if (message == UI_MSG_MOUSE_DRAG && element->window->pressedButton == 1) {
   2363 		if (!scrollBar->inDrag) {
   2364 			scrollBar->inDrag = true;
   2365 			
   2366 			if (scrollBar->horizontal) {
   2367 				scrollBar->dragOffset = element->bounds.l - scrollBar->e.bounds.l - element->window->cursorX;
   2368 			} else {
   2369 				scrollBar->dragOffset = element->bounds.t - scrollBar->e.bounds.t - element->window->cursorY;
   2370 			}
   2371 		}
   2372 
   2373 		int thumbPosition = (scrollBar->horizontal ? element->window->cursorX : element->window->cursorY) + scrollBar->dragOffset;
   2374 		int size = scrollBar->horizontal ? (UI_RECT_WIDTH(scrollBar->e.bounds) - UI_RECT_WIDTH(element->bounds))
   2375 				: (UI_RECT_HEIGHT(scrollBar->e.bounds) - UI_RECT_HEIGHT(element->bounds));
   2376 		scrollBar->position = (double) thumbPosition / size * (scrollBar->maximum - scrollBar->page);
   2377 		UIElementRefresh(&scrollBar->e);
   2378 		UIElementMessage(scrollBar->e.parent, UI_MSG_SCROLLED, 0, 0);
   2379 	} else if (message == UI_MSG_LEFT_UP) {
   2380 		scrollBar->inDrag = false;
   2381 	}
   2382 
   2383 	return 0;
   2384 }
   2385 
   2386 UIScrollBar *UIScrollBarCreate(UIElement *parent, uint32_t flags) {
   2387 	UIScrollBar *scrollBar = (UIScrollBar *) UIElementCreate(sizeof(UIScrollBar), parent, flags, _UIScrollBarMessage, "Scroll Bar");
   2388 	bool horizontal = scrollBar->horizontal = flags & UI_SCROLL_BAR_HORIZONTAL;
   2389 	UIElementCreate(sizeof(UIElement), &scrollBar->e, flags, _UIScrollUpDownMessage, !horizontal ? "Scroll Up" : "Scroll Left")->cp = (void *) (uintptr_t) 0;
   2390 	UIElementCreate(sizeof(UIElement), &scrollBar->e, flags, _UIScrollThumbMessage, "Scroll Thumb");
   2391 	UIElementCreate(sizeof(UIElement), &scrollBar->e, flags, _UIScrollUpDownMessage, !horizontal ? "Scroll Down" : "Scroll Right")->cp = (void *) (uintptr_t) 1;
   2392 	return scrollBar;
   2393 }
   2394 
   2395 bool _UICharIsAlpha(char c) {
   2396 	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
   2397 }
   2398 
   2399 bool _UICharIsDigit(char c) {
   2400 	return c >= '0' && c <= '9';
   2401 }
   2402 
   2403 bool _UICharIsAlphaOrDigitOrUnderscore(char c) {
   2404 	return _UICharIsAlpha(c) || _UICharIsDigit(c) || c == '_';
   2405 }
   2406 
   2407 int UICodeHitTest(UICode *code, int x, int y) {
   2408 	x -= code->e.bounds.l;
   2409 
   2410 	if (x < 0 || x >= UI_RECT_WIDTH(code->e.bounds) - UI_SIZE_SCROLL_BAR * code->e.window->scale) {
   2411 		return 0;
   2412 	}
   2413 
   2414 	y -= code->e.bounds.t - code->vScroll->position;
   2415 
   2416 	UIFont *previousFont = UIFontActivate(code->font);
   2417 	int lineHeight = UIMeasureStringHeight();
   2418 	bool inMargin = x < UI_SIZE_CODE_MARGIN + UI_SIZE_CODE_MARGIN_GAP / 2 && (~code->e.flags & UI_CODE_NO_MARGIN);
   2419 	UIFontActivate(previousFont);
   2420 
   2421 	if (y < 0 || y >= lineHeight * code->lineCount) {
   2422 		return 0;
   2423 	}
   2424 
   2425 	int line = y / lineHeight + 1;
   2426 	return inMargin ? -line : line;
   2427 }
   2428 
   2429 int UIDrawStringHighlighted(UIPainter *painter, UIRectangle lineBounds, const char *string, ptrdiff_t bytes, int tabSize) {
   2430 	if (bytes == -1) bytes = _UIStringLength(string);
   2431 	if (bytes > 10000) bytes = 10000;
   2432 
   2433 	uint32_t colors[] = {
   2434 		ui.theme.codeDefault,
   2435 		ui.theme.codeComment,
   2436 		ui.theme.codeString,
   2437 		ui.theme.codeNumber,
   2438 		ui.theme.codeOperator,
   2439 		ui.theme.codePreprocessor,
   2440 	};
   2441 
   2442 	int x = lineBounds.l;
   2443 	int y = (lineBounds.t + lineBounds.b - UIMeasureStringHeight()) / 2;
   2444 	int ti = 0;
   2445 	int lexState = 0;
   2446 	bool inComment = false, inIdentifier = false, inChar = false, startedString = false;
   2447 	uint32_t last = 0;
   2448 
   2449 	while (bytes--) {
   2450 		char c = *string++;
   2451 
   2452 		last <<= 8;
   2453 		last |= c;
   2454 
   2455 		if (lexState == 4) {
   2456 			lexState = 0;
   2457 		} else if (lexState == 1) {
   2458 			if ((last & 0xFF0000) == ('*' << 16) && (last & 0xFF00) == ('/' << 8) && inComment) {
   2459 				lexState = 0, inComment = false;
   2460 			}
   2461 		} else if (lexState == 3) {
   2462 			if (!_UICharIsAlpha(c) && !_UICharIsDigit(c)) {
   2463 				lexState = 0;
   2464 			}
   2465 		} else if (lexState == 2) {
   2466 			if (!startedString) {
   2467 				if (!inChar && ((last >> 8) & 0xFF) == '"' && ((last >> 16) & 0xFF) != '\\') {
   2468 					lexState = 0;
   2469 				} else if (inChar && ((last >> 8) & 0xFF) == '\'' && ((last >> 16) & 0xFF) != '\\') {
   2470 					lexState = 0;
   2471 				}
   2472 			}
   2473 
   2474 			startedString = false;
   2475 		}
   2476 
   2477 		if (lexState == 0) {
   2478 			if (c == '#') {
   2479 				lexState = 5;
   2480 			} else if (c == '/' && *string == '/') {
   2481 				lexState = 1;
   2482 			} else if (c == '/' && *string == '*') {
   2483 				lexState = 1, inComment = true;
   2484 			} else if (c == '"') {
   2485 				lexState = 2;
   2486 				inChar = false;
   2487 				startedString = true;
   2488 			} else if (c == '\'') {
   2489 				lexState = 2;
   2490 				inChar = true;
   2491 				startedString = true;
   2492 			} else if (_UICharIsDigit(c) && !inIdentifier) {
   2493 				lexState = 3;
   2494 			} else if (!_UICharIsAlpha(c) && !_UICharIsDigit(c)) {
   2495 				lexState = 4;
   2496 				inIdentifier = false;
   2497 			} else {
   2498 				inIdentifier = true;
   2499 			}
   2500 		}
   2501 
   2502 		if (c == '\t') {
   2503 			x += ui.activeFont->glyphWidth, ti++;
   2504 			while (ti % tabSize) x += ui.activeFont->glyphWidth, ti++;
   2505 		} else {
   2506 			UIDrawGlyph(painter, x, y, c, colors[lexState]);
   2507 			x += ui.activeFont->glyphWidth, ti++;
   2508 		}
   2509 	}
   2510 
   2511 	return x;
   2512 }
   2513 
   2514 int _UICodeMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2515 	UICode *code = (UICode *) element;
   2516 	
   2517 	if (message == UI_MSG_LAYOUT) {
   2518 		UIFont *previousFont = UIFontActivate(code->font);
   2519 
   2520 		if (code->moveScrollToFocusNextLayout) {
   2521 			code->vScroll->position = (code->focused + 0.5) * UIMeasureStringHeight() - UI_RECT_HEIGHT(code->e.bounds) / 2;
   2522 		}
   2523 
   2524 		UIRectangle scrollBarBounds = element->bounds;
   2525 		scrollBarBounds.l = scrollBarBounds.r - UI_SIZE_SCROLL_BAR * code->e.window->scale;
   2526 		code->vScroll->maximum = code->lineCount * UIMeasureStringHeight();
   2527 		code->vScroll->page = UI_RECT_HEIGHT(element->bounds);
   2528 		UIFontActivate(previousFont);
   2529 		UIElementMove(&code->vScroll->e, scrollBarBounds, true);
   2530 	} else if (message == UI_MSG_PAINT) {
   2531 		UIFont *previousFont = UIFontActivate(code->font);
   2532 
   2533 		UIPainter *painter = (UIPainter *) dp;
   2534 		UIRectangle lineBounds = element->bounds;
   2535 		lineBounds.r -= UI_SIZE_SCROLL_BAR * code->e.window->scale;
   2536 
   2537 		if (~code->e.flags & UI_CODE_NO_MARGIN) {
   2538 			lineBounds.l += UI_SIZE_CODE_MARGIN + UI_SIZE_CODE_MARGIN_GAP;
   2539 		}
   2540 
   2541 		int lineHeight = UIMeasureStringHeight();
   2542 		lineBounds.t -= (int64_t) code->vScroll->position % lineHeight;
   2543 
   2544 		UIDrawBlock(painter, element->bounds, ui.theme.codeBackground);
   2545 
   2546 		for (int i = code->vScroll->position / lineHeight; i < code->lineCount; i++) {
   2547 			if (lineBounds.t > element->clip.b) {
   2548 				break;
   2549 			}
   2550 
   2551 			lineBounds.b = lineBounds.t + lineHeight;
   2552 
   2553 			if (~code->e.flags & UI_CODE_NO_MARGIN) {
   2554 				char string[16];
   2555 				int p = 16;
   2556 				int lineNumber = i + 1;
   2557 
   2558 				while (lineNumber) {
   2559 					string[--p] = (lineNumber % 10) + '0';
   2560 					lineNumber /= 10;
   2561 				}
   2562 
   2563 				UIRectangle marginBounds = lineBounds;
   2564 				marginBounds.r = marginBounds.l - UI_SIZE_CODE_MARGIN_GAP;
   2565 				marginBounds.l -= UI_SIZE_CODE_MARGIN + UI_SIZE_CODE_MARGIN_GAP;
   2566 
   2567 				uint32_t marginColor = UIElementMessage(element, UI_MSG_CODE_GET_MARGIN_COLOR, i + 1, 0);
   2568 
   2569 				if (marginColor) {
   2570 					UIDrawBlock(painter, marginBounds, marginColor);
   2571 				}
   2572 
   2573 				UIDrawString(painter, marginBounds, string + p, 16 - p, ui.theme.codeDefault, UI_ALIGN_RIGHT, NULL);
   2574 			}
   2575 
   2576 			if (code->focused == i) {
   2577 				UIDrawBlock(painter, lineBounds, ui.theme.codeFocused);
   2578 			}
   2579 
   2580 			int x = UIDrawStringHighlighted(painter, lineBounds, code->content + code->lines[i].offset, code->lines[i].bytes, code->tabSize);
   2581 			int y = (lineBounds.t + lineBounds.b - UIMeasureStringHeight()) / 2;
   2582 
   2583 			UICodeDecorateLine m = { 0 };
   2584 			m.x = x, m.y = y, m.bounds = lineBounds, m.index = i + 1, m.painter = painter;
   2585 			UIElementMessage(element, UI_MSG_CODE_DECORATE_LINE, 0, &m);
   2586 
   2587 			lineBounds.t += lineHeight;
   2588 		}
   2589 
   2590 		UIFontActivate(previousFont);
   2591 	} else if (message == UI_MSG_SCROLLED) {
   2592 		code->moveScrollToFocusNextLayout = false;
   2593 		UIElementRefresh(element);
   2594 	} else if (message == UI_MSG_MOUSE_WHEEL) {
   2595 		return UIElementMessage(&code->vScroll->e, message, di, dp);
   2596 	} else if (message == UI_MSG_GET_CURSOR) {
   2597 		if (UICodeHitTest(code, element->window->cursorX, element->window->cursorY) < 0) {
   2598 			return UI_CURSOR_FLIPPED_ARROW;
   2599 		}
   2600 	} else if (message == UI_MSG_DESTROY) {
   2601 		UI_FREE(code->content);
   2602 		UI_FREE(code->lines);
   2603 	}
   2604 
   2605 	return 0;
   2606 }
   2607 
   2608 void UICodeFocusLine(UICode *code, int index) {
   2609 	code->focused = index - 1;
   2610 	code->moveScrollToFocusNextLayout = true;
   2611 }
   2612 
   2613 void UICodeInsertContent(UICode *code, const char *content, ptrdiff_t byteCount, bool replace) {
   2614 	UIFont *previousFont = UIFontActivate(code->font);
   2615 
   2616 	if (byteCount == -1) {
   2617 		byteCount = _UIStringLength(content);
   2618 	}
   2619 
   2620 	if (byteCount > 1000000000) {
   2621 		byteCount = 1000000000;
   2622 	}
   2623 
   2624 	if (replace) {
   2625 		UI_FREE(code->content);
   2626 		UI_FREE(code->lines);
   2627 		code->content = NULL;
   2628 		code->lines = NULL;
   2629 		code->contentBytes = 0;
   2630 		code->lineCount = 0;
   2631 	}
   2632 
   2633 	code->content = (char *) UI_REALLOC(code->content, code->contentBytes + byteCount);
   2634 
   2635 	if (!byteCount) {
   2636 		return;
   2637 	}
   2638 
   2639 	int lineCount = content[byteCount - 1] != '\n';
   2640 
   2641 	for (int i = 0; i < byteCount; i++) {
   2642 		code->content[i + code->contentBytes] = content[i];
   2643 
   2644 		if (content[i] == '\n') {
   2645 			lineCount++;
   2646 		}
   2647 	}
   2648 
   2649 	code->lines = (UICodeLine *) UI_REALLOC(code->lines, sizeof(UICodeLine) * (code->lineCount + lineCount));
   2650 	int offset = 0, lineIndex = 0;
   2651 
   2652 	for (intptr_t i = 0; i <= byteCount && lineIndex < lineCount; i++) {
   2653 		if (content[i] == '\n' || i == byteCount) {
   2654 			UICodeLine line = { 0 };
   2655 			line.offset = offset + code->contentBytes;
   2656 			line.bytes = i - offset;
   2657 			code->lines[code->lineCount + lineIndex] = line;
   2658 			lineIndex++;
   2659 			offset = i + 1;
   2660 		}
   2661 	}
   2662 
   2663 	code->lineCount += lineCount;
   2664 	code->contentBytes += byteCount;
   2665 
   2666 	if (!replace) {
   2667 		code->vScroll->position = code->lineCount * UIMeasureStringHeight();
   2668 	}
   2669 
   2670 	UIFontActivate(previousFont);
   2671 }
   2672 
   2673 UICode *UICodeCreate(UIElement *parent, uint32_t flags) {
   2674 	UICode *code = (UICode *) UIElementCreate(sizeof(UICode), parent, flags, _UICodeMessage, "Code");
   2675 	code->font = ui.activeFont;
   2676 	code->vScroll = UIScrollBarCreate(&code->e, 0);
   2677 	code->focused = -1;
   2678 	code->tabSize = 4;
   2679 	return code;
   2680 }
   2681 
   2682 int _UIGaugeMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2683 	UIGauge *gauge = (UIGauge *) element;
   2684 
   2685 	if (message == UI_MSG_GET_HEIGHT) {
   2686 		return UI_SIZE_GAUGE_HEIGHT * element->window->scale;
   2687 	} else if (message == UI_MSG_GET_WIDTH) {
   2688 		return UI_SIZE_GAUGE_WIDTH * element->window->scale;
   2689 	} else if (message == UI_MSG_PAINT) {
   2690 		UIPainter *painter = (UIPainter *) dp;
   2691 		UIDrawRectangle(painter, element->bounds, ui.theme.buttonNormal, ui.theme.border, UI_RECT_1(1));
   2692 		UIRectangle filled = UIRectangleAdd(element->bounds, UI_RECT_1I(1));
   2693 		filled.r = filled.l + UI_RECT_WIDTH(filled) * gauge->position;
   2694 		UIDrawBlock(painter, filled, ui.theme.selected);
   2695 	}
   2696 
   2697 	return 0;
   2698 }
   2699 
   2700 UIGauge *UIGaugeCreate(UIElement *parent, uint32_t flags) {
   2701 	return (UIGauge *) UIElementCreate(sizeof(UIGauge), parent, flags, _UIGaugeMessage, "Gauge");
   2702 }
   2703 
   2704 int _UISliderMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2705 	UISlider *slider = (UISlider *) element;
   2706 
   2707 	if (message == UI_MSG_GET_HEIGHT) {
   2708 		return UI_SIZE_SLIDER_HEIGHT * element->window->scale;
   2709 	} else if (message == UI_MSG_GET_WIDTH) {
   2710 		return UI_SIZE_SLIDER_WIDTH * element->window->scale;
   2711 	} else if (message == UI_MSG_PAINT) {
   2712 		UIPainter *painter = (UIPainter *) dp;
   2713 		UIRectangle bounds = element->bounds;
   2714 		int centerY = (bounds.t + bounds.b) / 2;
   2715 		int trackSize = UI_SIZE_SLIDER_TRACK * element->window->scale;
   2716 		int thumbSize = UI_SIZE_SLIDER_THUMB * element->window->scale;
   2717 		int thumbPosition = (UI_RECT_WIDTH(bounds) - thumbSize) * slider->position;
   2718 		UIRectangle track = UI_RECT_4(bounds.l, bounds.r, centerY - (trackSize + 1) / 2, centerY + trackSize / 2);
   2719 		UIDrawRectangle(painter, track, ui.theme.buttonNormal, ui.theme.border, UI_RECT_1(1));
   2720 		bool pressed = element == element->window->pressed;
   2721 		bool hovered = element == element->window->hovered;
   2722 		bool disabled = element->flags & UI_ELEMENT_DISABLED;
   2723 		uint32_t color = disabled ? ui.theme.buttonDisabled : pressed ? ui.theme.buttonPressed : hovered ? ui.theme.buttonHovered : ui.theme.buttonNormal;
   2724 		UIRectangle thumb = UI_RECT_4(bounds.l + thumbPosition, bounds.l + thumbPosition + thumbSize, centerY - (thumbSize + 1) / 2, centerY + thumbSize / 2);
   2725 		UIDrawRectangle(painter, thumb, color, ui.theme.border, UI_RECT_1(1));
   2726 	} else if (message == UI_MSG_LEFT_DOWN || (message == UI_MSG_MOUSE_DRAG && element->window->pressedButton == 1)) {
   2727 		UIRectangle bounds = element->bounds;
   2728 		int thumbSize = UI_SIZE_SLIDER_THUMB * element->window->scale;
   2729 		slider->position = (float) (element->window->cursorX - thumbSize / 2 - bounds.l) / (UI_RECT_WIDTH(bounds) - thumbSize);
   2730 		if (slider->steps > 1) slider->position = (int) (slider->position * (slider->steps - 1) + 0.5f) / (float) (slider->steps - 1);
   2731 		if (slider->position < 0) slider->position = 0;
   2732 		if (slider->position > 1) slider->position = 1;
   2733 		UIElementMessage(element, UI_MSG_VALUE_CHANGED, 0, 0);
   2734 		UIElementRepaint(element, NULL);
   2735 	} else if (message == UI_MSG_UPDATE) {
   2736 		UIElementRepaint(element, NULL);
   2737 	}
   2738 
   2739 	return 0;
   2740 }
   2741 
   2742 UISlider *UISliderCreate(UIElement *parent, uint32_t flags) {
   2743 	return (UISlider *) UIElementCreate(sizeof(UISlider), parent, flags, _UISliderMessage, "Slider");
   2744 }
   2745 
   2746 int UITableHitTest(UITable *table, int x, int y) {
   2747 	x -= table->e.bounds.l;
   2748 
   2749 	if (x < 0 || x >= UI_RECT_WIDTH(table->e.bounds) - UI_SIZE_SCROLL_BAR * table->e.window->scale) {
   2750 		return -1;
   2751 	}
   2752 
   2753 	y -= (table->e.bounds.t + UI_SIZE_TABLE_HEADER * table->e.window->scale) - table->vScroll->position;
   2754 
   2755 	int rowHeight = UI_SIZE_TABLE_ROW * table->e.window->scale;
   2756 
   2757 	if (y < 0 || y >= rowHeight * table->itemCount) {
   2758 		return -1;
   2759 	}
   2760 
   2761 	return y / rowHeight;
   2762 }
   2763 
   2764 int UITableHeaderHitTest(UITable *table, int x, int y) {
   2765 	if (!table->columnCount) return -1;
   2766 	UIRectangle header = table->e.bounds;
   2767 	header.b = header.t + UI_SIZE_TABLE_HEADER * table->e.window->scale;
   2768 	header.l += UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale;
   2769 	int position = 0, index = 0;
   2770 
   2771 	while (true) {
   2772 		int end = position;
   2773 		for (; table->columns[end] != '\t' && table->columns[end]; end++);
   2774 		header.r = header.l + table->columnWidths[index];
   2775 		if (UIRectangleContains(header, x, y)) return index;
   2776 		header.l += table->columnWidths[index] + UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale;
   2777 		if (table->columns[end] != '\t') break;
   2778 		position = end + 1, index++;
   2779 	}
   2780 
   2781 	return -1;
   2782 }
   2783 
   2784 bool UITableEnsureVisible(UITable *table, int index) {
   2785 	int rowHeight = UI_SIZE_TABLE_ROW * table->e.window->scale;
   2786 	int y = index * rowHeight;
   2787 	y -= table->vScroll->position;
   2788 	int height = UI_RECT_HEIGHT(table->e.bounds) - UI_SIZE_TABLE_HEADER * table->e.window->scale - rowHeight;
   2789 
   2790 	if (y < 0) {
   2791 		table->vScroll->position += y;
   2792 		UIElementRefresh(&table->e);
   2793 		return true;
   2794 	} else if (y > height) {
   2795 		table->vScroll->position -= height - y;
   2796 		UIElementRefresh(&table->e);
   2797 		return true;
   2798 	} else {
   2799 		return false;
   2800 	}
   2801 }
   2802 
   2803 void UITableResizeColumns(UITable *table) {
   2804 	int position = 0;
   2805 	int count = 0;
   2806 
   2807 	while (true) {
   2808 		int end = position;
   2809 		for (; table->columns[end] != '\t' && table->columns[end]; end++);
   2810 		count++;
   2811 		if (table->columns[end] == '\t') position = end + 1;
   2812 		else break;
   2813 	}
   2814 
   2815 	UI_FREE(table->columnWidths);
   2816 	table->columnWidths = (int *) UI_MALLOC(count * sizeof(int));
   2817 	table->columnCount = count;
   2818 
   2819 	position = 0;
   2820 
   2821 	char buffer[256];
   2822 	UITableGetItem m = { 0 };
   2823 	m.buffer = buffer;
   2824 	m.bufferBytes = sizeof(buffer);
   2825 
   2826 	while (true) {
   2827 		int end = position;
   2828 		for (; table->columns[end] != '\t' && table->columns[end]; end++);
   2829 
   2830 		int longest = UIMeasureStringWidth(table->columns + position, end - position);
   2831 
   2832 		for (int i = 0; i < table->itemCount; i++) {
   2833 			m.index = i;
   2834 			int bytes = UIElementMessage(&table->e, UI_MSG_TABLE_GET_ITEM, 0, &m);
   2835 			int width = UIMeasureStringWidth(buffer, bytes);
   2836 
   2837 			if (width > longest) {
   2838 				longest = width;
   2839 			}
   2840 		}
   2841 
   2842 		table->columnWidths[m.column] = longest;
   2843 		m.column++;
   2844 		if (table->columns[end] == '\t') position = end + 1;
   2845 		else break;
   2846 	}
   2847 }
   2848 
   2849 int _UITableMessage(UIElement *element, UIMessage message, int di, void *dp) {
   2850 	UITable *table = (UITable *) element;
   2851 
   2852 	if (message == UI_MSG_PAINT) {
   2853 		UIPainter *painter = (UIPainter *) dp;
   2854 		UIRectangle bounds = element->bounds;
   2855 		bounds.r -= UI_SIZE_SCROLL_BAR * element->window->scale;
   2856 		UIDrawBlock(painter, bounds, ui.theme.panel2);
   2857 		char buffer[256];
   2858 		UIRectangle row = bounds;
   2859 		int rowHeight = UI_SIZE_TABLE_ROW * element->window->scale;
   2860 		UITableGetItem m = { 0 };
   2861 		m.buffer = buffer;
   2862 		m.bufferBytes = sizeof(buffer);
   2863 		row.t += UI_SIZE_TABLE_HEADER * table->e.window->scale;
   2864 		row.t -= (int64_t) table->vScroll->position % rowHeight;
   2865 		int hovered = UITableHitTest(table, element->window->cursorX, element->window->cursorY);
   2866 
   2867 		for (int i = table->vScroll->position / rowHeight; i < table->itemCount; i++) {
   2868 			if (row.t > element->clip.b) {
   2869 				break;
   2870 			}
   2871 			
   2872 			row.b = row.t + rowHeight;
   2873 			m.index = i;
   2874 			m.isSelected = false;
   2875 			m.column = 0;
   2876 			int bytes = UIElementMessage(element, UI_MSG_TABLE_GET_ITEM, 0, &m);
   2877 			uint32_t textColor = ui.theme.text;
   2878 
   2879 			if (m.isSelected) {
   2880 				UIDrawBlock(painter, row, ui.theme.selected);
   2881 				textColor = ui.theme.textSelected;
   2882 			} else if (hovered == i) {
   2883 				UIDrawBlock(painter, row, ui.theme.buttonHovered);
   2884 			}
   2885 
   2886 			UIRectangle cell = row;
   2887 			cell.l += UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale;
   2888 
   2889 			for (int j = 0; j < table->columnCount; j++) {
   2890 				if (j) {
   2891 					m.column = j;
   2892 					bytes = UIElementMessage(element, UI_MSG_TABLE_GET_ITEM, 0, &m);
   2893 				}
   2894 
   2895 				cell.r = cell.l + table->columnWidths[j];
   2896 				if ((size_t) bytes > m.bufferBytes && bytes > 0) bytes = m.bufferBytes;
   2897 				UIDrawString(painter, cell, buffer, bytes, textColor, UI_ALIGN_LEFT, NULL);
   2898 				cell.l += table->columnWidths[j] + UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale;
   2899 			}
   2900 
   2901 			row.t += rowHeight;
   2902 		}
   2903 
   2904 		UIRectangle header = bounds;
   2905 		header.b = header.t + UI_SIZE_TABLE_HEADER * table->e.window->scale;
   2906 		UIDrawRectangle(painter, header, ui.theme.panel1, ui.theme.border, UI_RECT_4(0, 0, 0, 1));
   2907 		header.l += UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale;
   2908 
   2909 		int position = 0;
   2910 		int index = 0;
   2911 
   2912 		if (table->columnCount) {
   2913 			while (true) {
   2914 				int end = position;
   2915 				for (; table->columns[end] != '\t' && table->columns[end]; end++);
   2916 
   2917 				header.r = header.l + table->columnWidths[index];
   2918 				UIDrawString(painter, header, table->columns + position, end - position, ui.theme.text, UI_ALIGN_LEFT, NULL);
   2919 				if (index == table->columnHighlight) UIDrawInvert(painter, header);
   2920 				header.l += table->columnWidths[index] + UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale;
   2921 
   2922 				if (table->columns[end] == '\t') {
   2923 					position = end + 1;
   2924 					index++;
   2925 				} else {
   2926 					break;
   2927 				}
   2928 			}
   2929 		}
   2930 	} else if (message == UI_MSG_LAYOUT) {
   2931 		UIRectangle scrollBarBounds = element->bounds;
   2932 		scrollBarBounds.l = scrollBarBounds.r - UI_SIZE_SCROLL_BAR * element->window->scale;
   2933 		table->vScroll->maximum = table->itemCount * UI_SIZE_TABLE_ROW * element->window->scale;
   2934 		table->vScroll->page = UI_RECT_HEIGHT(element->bounds) - UI_SIZE_TABLE_HEADER * table->e.window->scale;
   2935 		UIElementMove(&table->vScroll->e, scrollBarBounds, true);
   2936 	} else if (message == UI_MSG_MOUSE_MOVE || message == UI_MSG_UPDATE) {
   2937 		UIElementRepaint(element, NULL);
   2938 	} else if (message == UI_MSG_SCROLLED) {
   2939 		UIElementRefresh(element);
   2940 	} else if (message == UI_MSG_MOUSE_WHEEL) {
   2941 		return UIElementMessage(&table->vScroll->e, message, di, dp);
   2942 	} else if (message == UI_MSG_DESTROY) {
   2943 		UI_FREE(table->columns);
   2944 		UI_FREE(table->columnWidths);
   2945 	}
   2946 
   2947 	return 0;
   2948 }
   2949 
   2950 UITable *UITableCreate(UIElement *parent, uint32_t flags, const char *columns) {
   2951 	UITable *table = (UITable *) UIElementCreate(sizeof(UITable), parent, flags, _UITableMessage, "Table");
   2952 	table->vScroll = UIScrollBarCreate(&table->e, 0);
   2953 	table->columns = UIStringCopy(columns, -1);
   2954 	table->columnHighlight = -1;
   2955 	return table;
   2956 }
   2957 
   2958 void UITextboxReplace(UITextbox *textbox, const char *text, ptrdiff_t bytes, bool sendChangedMessage) {
   2959 	if (bytes == -1) {
   2960 		bytes = _UIStringLength(text);
   2961 	}
   2962 
   2963 	int deleteFrom = textbox->carets[0], deleteTo = textbox->carets[1];
   2964 
   2965 	if (deleteFrom > deleteTo) {
   2966 		UI_SWAP(int, deleteFrom, deleteTo);
   2967 	}
   2968 
   2969 	for (int i = deleteTo; i < textbox->bytes; i++) {
   2970 		textbox->string[i - deleteTo + deleteFrom] = textbox->string[i];
   2971 	}
   2972 
   2973 	textbox->bytes -= deleteTo - deleteFrom;
   2974 	textbox->carets[0] = textbox->carets[1] = deleteFrom;
   2975 
   2976 	textbox->string = (char *) UI_REALLOC(textbox->string, textbox->bytes + bytes);
   2977 
   2978 	for (int i = textbox->bytes + bytes - 1; i >= textbox->carets[0] + bytes; i--) {
   2979 		textbox->string[i] = textbox->string[i - bytes];
   2980 	}
   2981 
   2982 	for (int i = textbox->carets[0]; i < textbox->carets[0] + bytes; i++) {
   2983 		textbox->string[i] = text[i - textbox->carets[0]];
   2984 	}
   2985 
   2986 	textbox->bytes += bytes;
   2987 	textbox->carets[0] += bytes;
   2988 	textbox->carets[1] = textbox->carets[0];
   2989 
   2990 	if (sendChangedMessage) {
   2991 		UIElementMessage(&textbox->e, UI_MSG_VALUE_CHANGED, 0, 0);
   2992 	}
   2993 
   2994 	textbox->e.window->textboxModifiedFlag = true;
   2995 }
   2996 
   2997 void UITextboxClear(UITextbox *textbox, bool sendChangedMessage) {
   2998 	textbox->carets[1] = 0;
   2999 	textbox->carets[0] = textbox->bytes;
   3000 	UITextboxReplace(textbox, "", 0, sendChangedMessage);
   3001 }
   3002 
   3003 void UITextboxMoveCaret(UITextbox *textbox, bool backward, bool word) {
   3004 	while (true) {
   3005 		if (textbox->carets[0] > 0 && backward) {
   3006 			textbox->carets[0]--;
   3007 		} else if (textbox->carets[0] < textbox->bytes && !backward) {
   3008 			textbox->carets[0]++;
   3009 		} else {
   3010 			return;
   3011 		}
   3012 
   3013 		if (!word) {
   3014 			return;
   3015 		} else if (textbox->carets[0] != textbox->bytes && textbox->carets[0] != 0) {
   3016 			char c1 = textbox->string[textbox->carets[0] - 1];
   3017 			char c2 = textbox->string[textbox->carets[0]];
   3018 
   3019 			if (_UICharIsAlphaOrDigitOrUnderscore(c1) != _UICharIsAlphaOrDigitOrUnderscore(c2)) {
   3020 				return;
   3021 			}
   3022 		}
   3023 	}
   3024 }
   3025 
   3026 int _UITextboxMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3027 	UITextbox *textbox = (UITextbox *) element;
   3028 
   3029 	if (message == UI_MSG_GET_HEIGHT) {
   3030 		return UI_SIZE_TEXTBOX_HEIGHT * element->window->scale;
   3031 	} else if (message == UI_MSG_GET_WIDTH) {
   3032 		return UI_SIZE_TEXTBOX_WIDTH * element->window->scale;
   3033 	} else if (message == UI_MSG_PAINT) {
   3034 		int scaledMargin = UI_SIZE_TEXTBOX_MARGIN * element->window->scale;
   3035 		int totalWidth = UIMeasureStringWidth(textbox->string, textbox->bytes) + scaledMargin * 2;
   3036 		UIRectangle textBounds = UIRectangleAdd(element->bounds, UI_RECT_1I(scaledMargin));
   3037 
   3038 		if (textbox->scroll > totalWidth - UI_RECT_WIDTH(textBounds)) {
   3039 			textbox->scroll = totalWidth - UI_RECT_WIDTH(textBounds);
   3040 		}
   3041 
   3042 		if (textbox->scroll < 0) {
   3043 			textbox->scroll = 0;
   3044 		}
   3045 
   3046 		int caretX = UIMeasureStringWidth(textbox->string, textbox->carets[0]) - textbox->scroll;
   3047 
   3048 		if (caretX < 0) {
   3049 			textbox->scroll = caretX + textbox->scroll;
   3050 		} else if (caretX > UI_RECT_WIDTH(textBounds)) {
   3051 			textbox->scroll = caretX - UI_RECT_WIDTH(textBounds) + textbox->scroll + 1;
   3052 		}
   3053 
   3054 		UIPainter *painter = (UIPainter *) dp;
   3055 		bool focused = element->window->focused == element;
   3056 		bool disabled = element->flags & UI_ELEMENT_DISABLED;
   3057 		UIDrawRectangle(painter, element->bounds, 
   3058 			disabled ? ui.theme.buttonDisabled : focused ? ui.theme.textboxFocused : ui.theme.textboxNormal, 
   3059 			ui.theme.border, UI_RECT_1(1));
   3060 #ifdef __cplusplus
   3061 		UIStringSelection selection = {};
   3062 #else
   3063 		UIStringSelection selection = { 0 };
   3064 #endif
   3065 		selection.carets[0] = textbox->carets[0];
   3066 		selection.carets[1] = textbox->carets[1];
   3067 		selection.colorBackground = ui.theme.selected;
   3068 		selection.colorText = ui.theme.textSelected;
   3069 		textBounds.l -= textbox->scroll;
   3070 		UIDrawString(painter, textBounds, textbox->string, textbox->bytes, 
   3071 			disabled ? ui.theme.textDisabled : ui.theme.text, UI_ALIGN_LEFT, focused ? &selection : NULL);
   3072 	} else if (message == UI_MSG_GET_CURSOR) {
   3073 		return UI_CURSOR_TEXT;
   3074 	} else if (message == UI_MSG_LEFT_DOWN) {
   3075 		UIElementFocus(element);
   3076 	} else if (message == UI_MSG_UPDATE) {
   3077 		UIElementRepaint(element, NULL);
   3078 	} else if (message == UI_MSG_DESTROY) {
   3079 		UI_FREE(textbox->string);
   3080 	} else if (message == UI_MSG_KEY_TYPED) {
   3081 		UIKeyTyped *m = (UIKeyTyped *) dp;
   3082 		bool handled = true;
   3083 
   3084 		if (textbox->rejectNextKey) {
   3085 			textbox->rejectNextKey = false;
   3086 			handled = false;
   3087 		} else if (m->code == UI_KEYCODE_BACKSPACE || m->code == UI_KEYCODE_DELETE) {
   3088 			if (textbox->carets[0] == textbox->carets[1]) {
   3089 				UITextboxMoveCaret(textbox, m->code == UI_KEYCODE_BACKSPACE, element->window->ctrl);
   3090 			}
   3091 
   3092 			UITextboxReplace(textbox, NULL, 0, true);
   3093 		} else if (m->code == UI_KEYCODE_LEFT || m->code == UI_KEYCODE_RIGHT) {
   3094 			UITextboxMoveCaret(textbox, m->code == UI_KEYCODE_LEFT, element->window->ctrl);
   3095 
   3096 			if (!element->window->shift) {
   3097 				textbox->carets[1] = textbox->carets[0];
   3098 			}
   3099 		} else if (m->code == UI_KEYCODE_HOME || m->code == UI_KEYCODE_END) {
   3100 			if (m->code == UI_KEYCODE_HOME) {
   3101 				textbox->carets[0] = 0;
   3102 			} else {
   3103 				textbox->carets[0] = textbox->bytes;
   3104 			}
   3105 
   3106 			if (!element->window->shift) {
   3107 				textbox->carets[1] = textbox->carets[0];
   3108 			}
   3109 		} else if (m->code == UI_KEYCODE_LETTER('A') && element->window->ctrl) {
   3110 			textbox->carets[1] = 0;
   3111 			textbox->carets[0] = textbox->bytes;
   3112 		} else if (m->textBytes && !element->window->alt && !element->window->ctrl && m->text[0] >= 0x20) {
   3113 			UITextboxReplace(textbox, m->text, m->textBytes, true);
   3114 		} else if ((m->code == UI_KEYCODE_LETTER('C') || m->code == UI_KEYCODE_LETTER('X') || m->code == UI_KEYCODE_INSERT) 
   3115 				&& element->window->ctrl && !element->window->alt && !element->window->shift) {
   3116 			int   to = textbox->carets[0] > textbox->carets[1] ? textbox->carets[0] : textbox->carets[1];
   3117 			int from = textbox->carets[0] < textbox->carets[1] ? textbox->carets[0] : textbox->carets[1];
   3118 
   3119 			if (from != to) {
   3120 				char *pasteText = (char *) UI_CALLOC(to - from + 1);
   3121 				for (int i = from; i < to; i++) pasteText[i - from] = textbox->string[i];
   3122 				_UIClipboardWriteText(element->window, pasteText);
   3123 			}
   3124 			
   3125 			if (m->code == UI_KEYCODE_LETTER('X')) {
   3126 				UITextboxReplace(textbox, NULL, 0, true);
   3127 			}
   3128 		} else if ((m->code == UI_KEYCODE_LETTER('V') && element->window->ctrl && !element->window->alt && !element->window->shift)
   3129 				|| (m->code == UI_KEYCODE_INSERT && !element->window->ctrl && !element->window->alt && element->window->shift)) {
   3130 			size_t bytes;
   3131 			char *text = _UIClipboardReadTextStart(element->window, &bytes);
   3132 			if (text) UITextboxReplace(textbox, text, bytes, true);
   3133 			_UIClipboardReadTextEnd(element->window, text);
   3134 		} else {
   3135 			handled = false;
   3136 		}
   3137 
   3138 		if (handled) {
   3139 			UIElementRepaint(element, NULL);
   3140 			return 1;
   3141 		}
   3142 	}
   3143 
   3144 	return 0;
   3145 }
   3146 
   3147 UITextbox *UITextboxCreate(UIElement *parent, uint32_t flags) {
   3148 	return (UITextbox *) UIElementCreate(sizeof(UITextbox), parent, flags | UI_ELEMENT_TAB_STOP, _UITextboxMessage, "Textbox");
   3149 }
   3150 
   3151 int _UIColorCircleMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3152 	UIColorPicker *colorPicker = (UIColorPicker *) element->parent;
   3153 
   3154 	if (message == UI_MSG_PAINT) {
   3155 		UIPainter *painter = (UIPainter *) dp;
   3156 
   3157 		int startY = element->bounds.t, endY = element->bounds.b;
   3158 		int startX = element->bounds.l, endX = element->bounds.r;
   3159 		int size = endY - startY;
   3160 
   3161 		for (int i = startY; i < endY; i++) {
   3162 			uint32_t *out = painter->bits + i * painter->width + startX;
   3163 			int j = startX;
   3164 			float y0 = i - startY - size / 2, x0 = -size / 2;
   3165 			float angle = _UIArcTan2Float((i - startY) * 2.0f / size - 1, -1);
   3166 
   3167 			do {
   3168 				float distanceFromCenterSquared = x0 * x0 + y0 * y0;
   3169 				float hue = (angle + 3.14159f) * 0.954929658f;
   3170 				float saturation = _UISquareRootFloat(distanceFromCenterSquared * 4.0f / size / size);
   3171 
   3172 				if (saturation <= 1 && UIRectangleContains(painter->clip, j, i)) {
   3173 					UIColorToRGB(hue, saturation, colorPicker->value, out);
   3174 					*out |= 0xFF000000;
   3175 				}
   3176 
   3177 				out++, j++, x0++;
   3178 
   3179 				if (distanceFromCenterSquared) {
   3180 					angle -= y0 / distanceFromCenterSquared;
   3181 				} else {
   3182 					angle = _UIArcTan2Float((i - startY) * 2.0f / size - 1, 0.01f);
   3183 				}
   3184 			} while (j < endX);
   3185 		}
   3186 
   3187 		float angle = colorPicker->hue / 0.954929658f - 3.14159f;
   3188 		float radius = colorPicker->saturation * size / 2;
   3189 		int cx = (startX + endX) / 2 + radius * _UICosFloat(angle);
   3190 		int cy = (startY + endY) / 2 + radius * _UISinFloat(angle);
   3191 		UIDrawInvert(painter, UI_RECT_4(cx - 1, cx + 1, startY, endY));
   3192 		UIDrawInvert(painter, UI_RECT_4(startX, endX, cy - 1, cy + 1));
   3193 	} else if (message == UI_MSG_GET_CURSOR) {
   3194 		return UI_CURSOR_CROSS_HAIR;
   3195 	} else if (message == UI_MSG_LEFT_DOWN || message == UI_MSG_MOUSE_DRAG) {
   3196 		int startY = element->bounds.t, endY = element->bounds.b, cursorY = element->window->cursorY;
   3197 		int startX = element->bounds.l, endX = element->bounds.r, cursorX = element->window->cursorX;
   3198 		int dx = (startX + endX) / 2, dy = (startY + endY) / 2;
   3199 		int size = endY - startY;
   3200 
   3201 		float angle = _UIArcTan2Float((cursorY - startY) * 2.0f / size - 1, (cursorX - startX) * 2.0f / size - 1);
   3202 		float distanceFromCenterSquared = (cursorX - dx) * (cursorX - dx) + (cursorY - dy) * (cursorY - dy);
   3203 		colorPicker->hue = (angle + 3.14159f) * 0.954929658f;
   3204 		colorPicker->saturation = _UISquareRootFloat(distanceFromCenterSquared * 4.0f / size / size);;
   3205 		if (colorPicker->saturation > 1) colorPicker->saturation = 1;
   3206 
   3207 		UIElementMessage(&colorPicker->e, UI_MSG_VALUE_CHANGED, 0, 0);
   3208 		UIElementRepaint(&colorPicker->e, NULL);
   3209 	}
   3210 
   3211 	return 0;
   3212 }
   3213 
   3214 int _UIColorSliderMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3215 	UIColorPicker *colorPicker = (UIColorPicker *) element->parent;
   3216 	float opacitySlider = element->flags & 1;
   3217 
   3218 	if (message == UI_MSG_PAINT) {
   3219 		UIPainter *painter = (UIPainter *) dp;
   3220 
   3221 		int startY = element->bounds.t, endY = element->bounds.b;
   3222 		int startX = element->bounds.l, endX = element->bounds.r;
   3223 		int size = endY - startY;
   3224 
   3225 		for (int i = startY; i < endY; i++) {
   3226 			if (i < painter->clip.t || i >= painter->clip.b) continue;
   3227 			uint32_t *out = painter->bits + i * painter->width + startX;
   3228 			int j = element->clip.l;
   3229 			uint32_t color;
   3230 			float p = 1.0f - (float) (i - startY) / size;
   3231 
   3232 			if (opacitySlider) {
   3233 				UIColorToRGB(colorPicker->hue, colorPicker->saturation, colorPicker->value, &color);
   3234 				color = UI_COLOR_FROM_FLOAT(p * (UI_COLOR_RED_F(color) - 0.5f) + 0.5f, 
   3235 					p * (UI_COLOR_GREEN_F(color) - 0.5f) + 0.5f, 
   3236 					p * (UI_COLOR_BLUE_F(color) - 0.5f) + 0.5f);
   3237 			} else {
   3238 				UIColorToRGB(colorPicker->hue, colorPicker->saturation, p, &color);
   3239 			}
   3240 
   3241 			color |= 0xFF000000;
   3242 
   3243 			do {
   3244 				*out = color;
   3245 				out++, j++;
   3246 			} while (j < element->clip.r);
   3247 		}
   3248 
   3249 		int cy = (size - 1) * (1 - (opacitySlider ? colorPicker->opacity : colorPicker->value)) + startY;
   3250 		UIDrawInvert(painter, UI_RECT_4(startX, endX, cy - 1, cy + 1));
   3251 	} else if (message == UI_MSG_GET_CURSOR) {
   3252 		return UI_CURSOR_CROSS_HAIR;
   3253 	} else if (message == UI_MSG_LEFT_DOWN || message == UI_MSG_MOUSE_DRAG) {
   3254 		int startY = element->bounds.t, endY = element->bounds.b, cursorY = element->window->cursorY;
   3255 		float *value = opacitySlider ? &colorPicker->opacity : &colorPicker->value;
   3256 		*value = 1 - (float) (cursorY - startY) / (endY - startY);
   3257 		if (*value < 0) *value = 0;
   3258 		if (*value > 1) *value = 1;
   3259 		UIElementMessage(&colorPicker->e, UI_MSG_VALUE_CHANGED, 0, 0);
   3260 		UIElementRepaint(&colorPicker->e, NULL);
   3261 	}
   3262 
   3263 	return 0;
   3264 }
   3265 
   3266 int _UIColorPickerMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3267 	bool hasOpacity = element->flags & UI_COLOR_PICKER_HAS_OPACITY;
   3268 
   3269 	if (message == UI_MSG_GET_WIDTH) {
   3270 		return (hasOpacity ? 280 : 240) * element->window->scale;
   3271 	} else if (message == UI_MSG_GET_HEIGHT) {
   3272 		return 200 * element->window->scale;
   3273 	} else if (message == UI_MSG_LAYOUT) {
   3274 		UIRectangle bounds = element->bounds;
   3275 
   3276 		int sliderSize = 35 * element->window->scale;
   3277 		int gap = 5 * element->window->scale;
   3278 
   3279 		if (hasOpacity) {
   3280 			UIElementMove(element->children, UI_RECT_4(bounds.l, bounds.r - (sliderSize + gap) * 2, bounds.t, bounds.b), false);
   3281 			UIElementMove(element->children->next, UI_RECT_4(bounds.r - sliderSize * 2 - gap, bounds.r - sliderSize - gap, bounds.t, bounds.b), false);
   3282 			UIElementMove(element->children->next->next, UI_RECT_4(bounds.r - sliderSize, bounds.r, bounds.t, bounds.b), false);
   3283 		} else {
   3284 			UIElementMove(element->children, UI_RECT_4(bounds.l, bounds.r - sliderSize - gap, bounds.t, bounds.b), false);
   3285 			UIElementMove(element->children->next, UI_RECT_4(bounds.r - sliderSize, bounds.r, bounds.t, bounds.b), false);
   3286 		}
   3287 	}
   3288 
   3289 	return 0;
   3290 }
   3291 
   3292 UIColorPicker *UIColorPickerCreate(UIElement *parent, uint32_t flags) {
   3293 	UIColorPicker *colorPicker = (UIColorPicker *) UIElementCreate(sizeof(UIColorPicker), parent, flags, _UIColorPickerMessage, "ColorPicker");
   3294 	UIElementCreate(sizeof(UIElement), &colorPicker->e, 0, _UIColorCircleMessage, "ColorCircle");
   3295 	UIElementCreate(sizeof(UIElement), &colorPicker->e, 0, _UIColorSliderMessage, "ColorSlider");
   3296 
   3297 	if (flags & UI_COLOR_PICKER_HAS_OPACITY) {
   3298 		UIElementCreate(sizeof(UIElement), &colorPicker->e, 1, _UIColorSliderMessage, "ColorSlider");
   3299 	}
   3300 
   3301 	return colorPicker;
   3302 }
   3303 
   3304 #define UI_MDI_CHILD_CALCULATE_LAYOUT() \
   3305 	int titleSize = UI_SIZE_MDI_CHILD_TITLE * element->window->scale; \
   3306 	int borderSize = UI_SIZE_MDI_CHILD_BORDER * element->window->scale; \
   3307 	UIRectangle title = UIRectangleAdd(element->bounds, UI_RECT_4(borderSize, -borderSize, 0, 0)); \
   3308 	title.b = title.t + titleSize; \
   3309 	UIRectangle content = UIRectangleAdd(element->bounds, UI_RECT_4(borderSize, -borderSize, titleSize, -borderSize));
   3310 
   3311 int _UIMDIChildHitTest(UIMDIChild *mdiChild, int x, int y) {
   3312 	UIElement *element = &mdiChild->e;
   3313 	UI_MDI_CHILD_CALCULATE_LAYOUT();
   3314 	int cornerSize = UI_SIZE_MDI_CHILD_CORNER * element->window->scale;
   3315 	if (!UIRectangleContains(element->bounds, x, y) || UIRectangleContains(content, x, y)) return -1;
   3316 	else if (x < element->bounds.l + cornerSize && y < element->bounds.t + cornerSize) return 0b1010;
   3317 	else if (x > element->bounds.r - cornerSize && y < element->bounds.t + cornerSize) return 0b0110;
   3318 	else if (x < element->bounds.l + cornerSize && y > element->bounds.b - cornerSize) return 0b1001;
   3319 	else if (x > element->bounds.r - cornerSize && y > element->bounds.b - cornerSize) return 0b0101;
   3320 	else if (x < element->bounds.l + borderSize) return 0b1000;
   3321 	else if (x > element->bounds.r - borderSize) return 0b0100;
   3322 	else if (y < element->bounds.t + borderSize) return 0b0010;
   3323 	else if (y > element->bounds.b - borderSize) return 0b0001;
   3324 	else if (UIRectangleContains(title, x, y)) return 0b1111;
   3325 	else return -1;
   3326 }
   3327 
   3328 void _UIMDIChildCloseButton(void *_child) {
   3329 	UIElement *child = (UIElement *) _child;
   3330 	
   3331 	if (!UIElementMessage(child, UI_MSG_WINDOW_CLOSE, 0, 0)) {
   3332 		UIElementDestroy(child);
   3333 		UIElementRefresh(child->parent);
   3334 	}
   3335 }
   3336 
   3337 int _UIMDIChildMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3338 	UIMDIChild *mdiChild = (UIMDIChild *) element;
   3339 
   3340 	if (message == UI_MSG_PAINT) {
   3341 		UI_MDI_CHILD_CALCULATE_LAYOUT();
   3342 		UIPainter *painter = (UIPainter *) dp;
   3343 		UIRectangle borders = UI_RECT_4(borderSize, borderSize, titleSize, borderSize);
   3344 		UIDrawBorder(painter, element->bounds, ui.theme.buttonNormal, borders);
   3345 		UIDrawBorder(painter, element->bounds, ui.theme.border, UI_RECT_1((int) element->window->scale));
   3346 		UIDrawBorder(painter, UIRectangleAdd(content, UI_RECT_1I(-1)), ui.theme.border, UI_RECT_1((int) element->window->scale));
   3347 		UIDrawString(painter, title, mdiChild->title, mdiChild->titleBytes, ui.theme.text, UI_ALIGN_LEFT, NULL);
   3348 	} else if (message == UI_MSG_GET_WIDTH) {
   3349 		UIElement *child = element->children;
   3350 		while (child && child->next) child = child->next;
   3351 		int width = 2 * UI_SIZE_MDI_CHILD_BORDER;
   3352 		width += (child ? UIElementMessage(child, message, di ? (di - UI_SIZE_MDI_CHILD_TITLE + UI_SIZE_MDI_CHILD_BORDER) : 0, dp) : 0);
   3353 		if (width < UI_SIZE_MDI_CHILD_MINIMUM_WIDTH) width = UI_SIZE_MDI_CHILD_MINIMUM_WIDTH;
   3354 		return width;
   3355 	} else if (message == UI_MSG_GET_HEIGHT) {
   3356 		UIElement *child = element->children;
   3357 		while (child && child->next) child = child->next;
   3358 		int height = UI_SIZE_MDI_CHILD_TITLE + UI_SIZE_MDI_CHILD_BORDER;
   3359 		height += (child ? UIElementMessage(child, message, di ? (di - 2 * UI_SIZE_MDI_CHILD_BORDER) : 0, dp) : 0);
   3360 		if (height < UI_SIZE_MDI_CHILD_MINIMUM_HEIGHT) height = UI_SIZE_MDI_CHILD_MINIMUM_HEIGHT;
   3361 		return height;
   3362 	} else if (message == UI_MSG_LAYOUT) {
   3363 		UI_MDI_CHILD_CALCULATE_LAYOUT();
   3364 
   3365 		UIElement *child = element->children;
   3366 		int position = title.r;
   3367 
   3368 		while (child && child->next) {
   3369 			int width = UIElementMessage(child, UI_MSG_GET_WIDTH, 0, 0);
   3370 			UIElementMove(child, UI_RECT_4(position - width, position, title.t, title.b), false);
   3371 			position -= width, child = child->next;
   3372 		}
   3373 
   3374 		if (child) {
   3375 			UIElementMove(child, content, false);
   3376 		}
   3377 	} else if (message == UI_MSG_GET_CURSOR) {
   3378 		int hitTest = _UIMDIChildHitTest(mdiChild, element->window->cursorX, element->window->cursorY);
   3379 		if (hitTest == 0b1000) return UI_CURSOR_RESIZE_LEFT;
   3380 		if (hitTest == 0b0010) return UI_CURSOR_RESIZE_UP;
   3381 		if (hitTest == 0b0110) return UI_CURSOR_RESIZE_UP_RIGHT;
   3382 		if (hitTest == 0b1010) return UI_CURSOR_RESIZE_UP_LEFT;
   3383 		if (hitTest == 0b0100) return UI_CURSOR_RESIZE_RIGHT;
   3384 		if (hitTest == 0b0001) return UI_CURSOR_RESIZE_DOWN;
   3385 		if (hitTest == 0b1001) return UI_CURSOR_RESIZE_DOWN_LEFT;
   3386 		if (hitTest == 0b0101) return UI_CURSOR_RESIZE_DOWN_RIGHT;
   3387 		return UI_CURSOR_ARROW;
   3388 	} else if (message == UI_MSG_LEFT_DOWN) {
   3389 		mdiChild->dragHitTest = _UIMDIChildHitTest(mdiChild, element->window->cursorX, element->window->cursorY);
   3390 		mdiChild->dragOffset = UIRectangleAdd(element->bounds, UI_RECT_2(-element->window->cursorX, -element->window->cursorY));
   3391 	} else if (message == UI_MSG_LEFT_UP) {
   3392 		if (mdiChild->bounds.l < 0) mdiChild->bounds.r -= mdiChild->bounds.l, mdiChild->bounds.l = 0;
   3393 		if (mdiChild->bounds.t < 0) mdiChild->bounds.b -= mdiChild->bounds.t, mdiChild->bounds.t = 0;
   3394 		UIElementRefresh(element->parent);
   3395 	} else if (message == UI_MSG_MOUSE_DRAG) {
   3396 		if (mdiChild->dragHitTest > 0) {
   3397 #define _UI_MDI_CHILD_MOVE_EDGE(bit, edge, cursor, size, opposite, negate, minimum, offset) \
   3398 	if (mdiChild->dragHitTest & bit) mdiChild->bounds.edge = mdiChild->dragOffset.edge + element->window->cursor - element->parent->bounds.offset; \
   3399 	if ((mdiChild->dragHitTest & bit) && size(mdiChild->bounds) < minimum) mdiChild->bounds.edge = mdiChild->bounds.opposite negate minimum;
   3400 			_UI_MDI_CHILD_MOVE_EDGE(0b1000, l, cursorX, UI_RECT_WIDTH, r, -, UI_SIZE_MDI_CHILD_MINIMUM_WIDTH, l);
   3401 			_UI_MDI_CHILD_MOVE_EDGE(0b0100, r, cursorX, UI_RECT_WIDTH, l, +, UI_SIZE_MDI_CHILD_MINIMUM_WIDTH, l);
   3402 			_UI_MDI_CHILD_MOVE_EDGE(0b0010, t, cursorY, UI_RECT_HEIGHT, b, -, UI_SIZE_MDI_CHILD_MINIMUM_HEIGHT, t);
   3403 			_UI_MDI_CHILD_MOVE_EDGE(0b0001, b, cursorY, UI_RECT_HEIGHT, t, +, UI_SIZE_MDI_CHILD_MINIMUM_HEIGHT, t);
   3404 			UIElementRefresh(element->parent);
   3405 		}
   3406 	} else if (message == UI_MSG_DESTROY) {
   3407 		UI_FREE(mdiChild->title);
   3408 		UIMDIClient *client = (UIMDIClient *) element->parent;
   3409 		if (client->e.children == element) client->e.children = element->next;
   3410 		if (mdiChild->previous) mdiChild->previous->e.next = element->next;
   3411 		if (element->next) ((UIMDIChild *) element->next)->previous = mdiChild->previous;
   3412 		if (client->active == mdiChild) client->active = mdiChild->previous;
   3413 	}
   3414 
   3415 	return 0;
   3416 }
   3417 
   3418 int _UIMDIClientMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3419 	UIMDIClient *client = (UIMDIClient *) element;
   3420 
   3421 	if (message == UI_MSG_PAINT) {
   3422 		UIDrawBlock((UIPainter *) dp, element->bounds, (element->flags & UI_MDI_CLIENT_TRANSPARENT) ? 0 : ui.theme.panel2);
   3423 	} else if (message == UI_MSG_LAYOUT) {
   3424 		UIElement *child = element->children;
   3425 
   3426 		while (child) {
   3427 			UI_ASSERT(child->messageClass == _UIMDIChildMessage);
   3428 
   3429 			UIMDIChild *mdiChild = (UIMDIChild *) child;
   3430 
   3431 			if (UIRectangleEquals(mdiChild->bounds, UI_RECT_1(0))) {
   3432 				int width = UIElementMessage(&mdiChild->e, UI_MSG_GET_WIDTH, 0, 0);
   3433 				int height = UIElementMessage(&mdiChild->e, UI_MSG_GET_HEIGHT, width, 0);
   3434 				if (client->cascade + width > element->bounds.r || client->cascade + height > element->bounds.b) client->cascade = 0;
   3435 				mdiChild->bounds = UI_RECT_4(client->cascade, client->cascade + width, client->cascade, client->cascade + height);
   3436 				client->cascade += UI_SIZE_MDI_CASCADE * element->window->scale;
   3437 			}
   3438 
   3439 			UIRectangle bounds = UIRectangleAdd(mdiChild->bounds, UI_RECT_2(element->bounds.l, element->bounds.t));
   3440 			UIElementMove(child, bounds, false);
   3441 			child = child->next;
   3442 		}
   3443 	} else if (message == UI_MSG_FIND_BY_POINT) {
   3444 		UIFindByPoint *m = (UIFindByPoint *) dp;
   3445 		UIMDIChild *child = client->active;
   3446 
   3447 		while (child) {
   3448 			if (UIRectangleContains(child->e.bounds, m->x, m->y)) {
   3449 				m->result = UIElementFindByPoint(&child->e, m->x, m->y);
   3450 				return 1;
   3451 			}
   3452 
   3453 			child = child->previous;
   3454 		}
   3455 
   3456 		return 1;
   3457 	} else if (message == UI_MSG_PRESSED_DESCENDENT) {
   3458 		UIMDIChild *child = (UIMDIChild *) dp;
   3459 
   3460 		if (child && child != client->active) {
   3461 			if (client->e.children == &child->e) client->e.children = child->e.next;
   3462 			if (child->previous) child->previous->e.next = child->e.next;
   3463 			if (child->e.next) ((UIMDIChild *) child->e.next)->previous = child->previous;
   3464 			if (client->active) client->active->e.next = &child->e;
   3465 			child->previous = client->active;
   3466 			child->e.next = NULL;
   3467 			client->active = child;
   3468 			((UIMDIChild *) client->e.children)->previous = NULL;
   3469 			UIElementRefresh(element);
   3470 		}
   3471 	}
   3472 
   3473 	return 0;
   3474 }
   3475 
   3476 UIMDIChild *UIMDIChildCreate(UIElement *parent, uint32_t flags, UIRectangle initialBounds, const char *title, ptrdiff_t titleBytes) {
   3477 	UI_ASSERT(parent->messageClass == _UIMDIClientMessage);
   3478 
   3479 	UIMDIChild *mdiChild = (UIMDIChild *) UIElementCreate(sizeof(UIMDIChild), parent, flags, _UIMDIChildMessage, "MDIChild");
   3480 	UIMDIClient *mdiClient = (UIMDIClient *) parent;
   3481 
   3482 	mdiChild->bounds = initialBounds;
   3483 	mdiChild->title = UIStringCopy(title, (mdiChild->titleBytes = titleBytes));
   3484 	mdiChild->previous = mdiClient->active;
   3485 	mdiClient->active = mdiChild;
   3486 
   3487 	if (flags & UI_MDI_CHILD_CLOSE_BUTTON) {
   3488 		UIButton *closeButton = UIButtonCreate(&mdiChild->e, UI_BUTTON_SMALL | UI_ELEMENT_NON_CLIENT, "X", 1);
   3489 		closeButton->invoke = _UIMDIChildCloseButton;
   3490 		closeButton->e.cp = mdiChild;
   3491 	}
   3492 
   3493 	return mdiChild;
   3494 }
   3495 
   3496 UIMDIClient *UIMDIClientCreate(UIElement *parent, uint32_t flags) {
   3497 	return (UIMDIClient *) UIElementCreate(sizeof(UIMDIClient), parent, flags, _UIMDIClientMessage, "MDIClient");
   3498 }
   3499 
   3500 int _UIExpandPaneMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3501 	UIExpandPane *pane = (UIExpandPane *) element;
   3502 	
   3503 	if (message == UI_MSG_GET_HEIGHT) {
   3504 		int height = UIElementMessage(&pane->button->e, message, di, dp);
   3505 
   3506 		if (pane->expanded) {
   3507 			height += UIElementMessage(&pane->panel->e, message, di, dp);
   3508 		}
   3509 
   3510 		return height;
   3511 	} else if (message == UI_MSG_LAYOUT) {
   3512 		UIRectangle bounds = pane->e.bounds;
   3513 		int buttonHeight = UIElementMessage(&pane->button->e, UI_MSG_GET_HEIGHT, UI_RECT_WIDTH(bounds), NULL);
   3514 		UIElementMove(&pane->button->e, UI_RECT_4(bounds.l, bounds.r, bounds.t, bounds.t + buttonHeight), false);
   3515 
   3516 		if (pane->expanded) {
   3517 			pane->panel->e.flags &= ~UI_ELEMENT_HIDE;
   3518 			UIElementMove(&pane->panel->e, UI_RECT_4(bounds.l, bounds.r, bounds.t + buttonHeight, bounds.b), false);
   3519 		} else {
   3520 			pane->panel->e.flags |= UI_ELEMENT_HIDE;
   3521 		}
   3522 	} else if (message == UI_MSG_CLIENT_PARENT) {
   3523 		*(UIElement **) dp = &pane->panel->e;
   3524 	}
   3525 
   3526 	return 0;
   3527 }
   3528 
   3529 void _UIExpandPaneButtonInvoke(void *cp) {
   3530 	UIExpandPane *pane = (UIExpandPane *) cp;
   3531 	pane->expanded = !pane->expanded;
   3532 	if (pane->expanded) pane->button->e.flags |= UI_BUTTON_CHECKED;
   3533 	else pane->button->e.flags &= ~UI_BUTTON_CHECKED;
   3534 
   3535 	UIElement *ancestor = &pane->e;
   3536 
   3537 	while (ancestor) {
   3538 		UIElementRefresh(ancestor);
   3539 
   3540 		if ((ancestor->messageClass == _UIPanelMessage && (ancestor->flags & UI_PANEL_SCROLL)) 
   3541 				|| (ancestor->messageClass == _UIMDIChildMessage)
   3542 				|| (ancestor->flags & UI_ELEMENT_V_FILL)) {
   3543 			break;
   3544 		}
   3545 
   3546 		ancestor = ancestor->parent;
   3547 	}
   3548 }
   3549 
   3550 UIExpandPane *UIExpandPaneCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes, uint32_t panelFlags) {
   3551 	UIExpandPane *pane = (UIExpandPane *) UIElementCreate(sizeof(UIExpandPane), parent, flags, _UIExpandPaneMessage, "ExpandPane");
   3552 	pane->button = UIButtonCreate(parent, UI_ELEMENT_NON_CLIENT, label, labelBytes);
   3553 	pane->button->e.cp = pane;
   3554 	pane->button->invoke = _UIExpandPaneButtonInvoke;
   3555 	pane->panel = UIPanelCreate(parent, UI_ELEMENT_NON_CLIENT | panelFlags);
   3556 	return pane;
   3557 }
   3558 
   3559 void _UIImageDisplayUpdateViewport(UIImageDisplay *display) {
   3560 	UIRectangle bounds = display->e.bounds;
   3561 	bounds.r -= bounds.l, bounds.b -= bounds.t;
   3562 	
   3563 	float minimumZoomX = 1, minimumZoomY = 1;
   3564 	if (display->width  > bounds.r) minimumZoomX = (float) bounds.r / display->width;
   3565 	if (display->height > bounds.b) minimumZoomY = (float) bounds.b / display->height;
   3566 	float minimumZoom = minimumZoomX < minimumZoomY ? minimumZoomX : minimumZoomY;
   3567 	
   3568 	if (display->zoom < minimumZoom || (display->e.flags & _UI_IMAGE_DISPLAY_ZOOM_FIT)) {
   3569 		display->zoom = minimumZoom;
   3570 		display->e.flags |= _UI_IMAGE_DISPLAY_ZOOM_FIT;
   3571 	}
   3572 	
   3573 	if (display->panX < 0) display->panX = 0;
   3574 	if (display->panY < 0) display->panY = 0;
   3575 	if (display->panX > display->width  - bounds.r / display->zoom) display->panX = display->width  - bounds.r / display->zoom;
   3576 	if (display->panY > display->height - bounds.b / display->zoom) display->panY = display->height - bounds.b / display->zoom;
   3577 	
   3578 	if (bounds.r && display->width  * display->zoom <= bounds.r) display->panX = display->width  / 2 - bounds.r / display->zoom / 2;
   3579 	if (bounds.b && display->height * display->zoom <= bounds.b) display->panY = display->height / 2 - bounds.b / display->zoom / 2;
   3580 }
   3581 
   3582 int _UIImageDisplayMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3583 	UIImageDisplay *display = (UIImageDisplay *) element;
   3584 	
   3585 	if (message == UI_MSG_GET_HEIGHT) {
   3586 		return display->height;
   3587 	} else if (message == UI_MSG_GET_WIDTH) {
   3588 		return display->width;
   3589 	} else if (message == UI_MSG_DESTROY) {
   3590 		UI_FREE(display->bits);
   3591 	} else if (message == UI_MSG_PAINT) {
   3592 		UIPainter *painter = (UIPainter *) dp;
   3593 		
   3594 		int w = UI_RECT_WIDTH(element->bounds), h = UI_RECT_HEIGHT(element->bounds);
   3595 		int x = _UILinearMap(0, display->panX, display->panX + w / display->zoom, 0, w) + element->bounds.l;
   3596 		int y = _UILinearMap(0, display->panY, display->panY + h / display->zoom, 0, h) + element->bounds.t;
   3597 		
   3598 		UIRectangle image = UI_RECT_4(x, x + (int) (display->width * display->zoom), y, (int) (y + display->height * display->zoom));
   3599 		UIRectangle bounds = UIRectangleIntersection(painter->clip, UIRectangleIntersection(display->e.bounds, image));
   3600 		if (!UI_RECT_VALID(bounds)) return 0;
   3601 		
   3602 		if (display->zoom == 1) {
   3603 			uint32_t *lineStart = (uint32_t *) painter->bits + bounds.t * painter->width + bounds.l;
   3604 			uint32_t *sourceLineStart = display->bits + (bounds.l - image.l) + display->width * (bounds.t - image.t);
   3605 	
   3606 			for (int i = 0; i < bounds.b - bounds.t; i++, lineStart += painter->width, sourceLineStart += display->width) {
   3607 				uint32_t *destination = lineStart;
   3608 				uint32_t *source = sourceLineStart;
   3609 				int j = bounds.r - bounds.l;
   3610 	
   3611 				do {
   3612 					*destination = *source;
   3613 					destination++;
   3614 					source++;
   3615 				} while (--j);
   3616 			}
   3617 		} else {
   3618 			float zr = 1.0f / display->zoom;
   3619 			uint32_t *destination = (uint32_t *) painter->bits;
   3620 			
   3621 			for (int i = bounds.t; i < bounds.b; i++) {
   3622 				int ty = (i - image.t) * zr;
   3623 				
   3624 				for (int j = bounds.l; j < bounds.r; j++) {
   3625 					int tx = (j - image.l) * zr;
   3626 					destination[i * painter->width + j] = display->bits[ty * display->width + tx];
   3627 				}
   3628 			}
   3629 		}
   3630 	} else if (message == UI_MSG_MOUSE_WHEEL && (element->flags & UI_IMAGE_DISPLAY_INTERACTIVE)) {
   3631 		display->e.flags &= ~_UI_IMAGE_DISPLAY_ZOOM_FIT;
   3632 		int divisions = -di / 72;
   3633 		float factor = 1;
   3634 		float perDivision = element->window->ctrl ? 2.0f : element->window->alt ? 1.01f : 1.2f;
   3635 		while (divisions > 0) factor *= perDivision, divisions--;
   3636 		while (divisions < 0) factor /= perDivision, divisions++;
   3637 		if (display->zoom * factor > 64) factor = 64 / display->zoom;
   3638 		int mx = element->window->cursorX - element->bounds.l;
   3639 		int my = element->window->cursorY - element->bounds.t;
   3640 		display->zoom *= factor;
   3641 		display->panX -= mx / display->zoom * (1 - factor);
   3642 		display->panY -= my / display->zoom * (1 - factor);
   3643 		_UIImageDisplayUpdateViewport(display);
   3644 		UIElementRepaint(&display->e, NULL);
   3645 	} else if (message == UI_MSG_LAYOUT && (element->flags & UI_IMAGE_DISPLAY_INTERACTIVE)) {
   3646 		UIRectangle bounds = display->e.bounds;
   3647 		bounds.r -= bounds.l, bounds.b -= bounds.t;
   3648 		display->panX -= (bounds.r - display->previousWidth ) / 2 / display->zoom;
   3649 		display->panY -= (bounds.b - display->previousHeight) / 2 / display->zoom;
   3650 		display->previousWidth = bounds.r, display->previousHeight = bounds.b;
   3651 		_UIImageDisplayUpdateViewport(display);
   3652 	} else if (message == UI_MSG_GET_CURSOR && (element->flags & UI_IMAGE_DISPLAY_INTERACTIVE)
   3653 			&& (UI_RECT_WIDTH(element->bounds) < display->width * display->zoom 
   3654 				|| UI_RECT_HEIGHT(element->bounds) < display->height * display->zoom)) {
   3655 		return UI_CURSOR_HAND;
   3656 	} else if (message == UI_MSG_MOUSE_DRAG) {
   3657 		display->panX -= (element->window->cursorX - display->previousPanPointX) / display->zoom;
   3658 		display->panY -= (element->window->cursorY - display->previousPanPointY) / display->zoom;
   3659 		_UIImageDisplayUpdateViewport(display);
   3660 		display->previousPanPointX = element->window->cursorX;
   3661 		display->previousPanPointY = element->window->cursorY;
   3662 		UIElementRepaint(element, NULL);
   3663 	} else if (message == UI_MSG_LEFT_DOWN) {           
   3664 		display->e.flags &= ~_UI_IMAGE_DISPLAY_ZOOM_FIT;  
   3665 		display->previousPanPointX = element->window->cursorX;
   3666 		display->previousPanPointY = element->window->cursorY;
   3667 	}
   3668 
   3669 	return 0;
   3670 }
   3671 
   3672 void UIImageDisplaySetContent(UIImageDisplay *display, uint32_t *bits, size_t width, size_t height, size_t stride) {
   3673 	UI_FREE(display->bits);
   3674 
   3675 	display->bits = (uint32_t *) UI_MALLOC(width * height * 4);
   3676 	display->width = width;
   3677 	display->height = height;
   3678 
   3679 	uint32_t *destination = display->bits;
   3680 	uint32_t *source = bits;
   3681 
   3682 	for (uintptr_t row = 0; row < height; row++, source += stride / 4) {
   3683 		for (uintptr_t i = 0; i < width; i++) {
   3684 			*destination++ = source[i];
   3685 		}
   3686 	}
   3687 }
   3688 
   3689 UIImageDisplay *UIImageDisplayCreate(UIElement *parent, uint32_t flags, uint32_t *bits, size_t width, size_t height, size_t stride) {
   3690 	UIImageDisplay *display = (UIImageDisplay *) UIElementCreate(sizeof(UIImageDisplay), parent, flags, _UIImageDisplayMessage, "ImageDisplay");
   3691 	display->zoom = 1.0f;
   3692 	UIImageDisplaySetContent(display, bits, width, height, stride);
   3693 	return display;
   3694 }
   3695 
   3696 int _UIDialogWrapperMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3697 	if (message == UI_MSG_LAYOUT) {
   3698 		int width = UIElementMessage(element->children, UI_MSG_GET_WIDTH, 0, 0);
   3699 		int height = UIElementMessage(element->children, UI_MSG_GET_HEIGHT, width, 0);
   3700 		int cx = (element->bounds.l + element->bounds.r) / 2;
   3701 		int cy = (element->bounds.t + element->bounds.b) / 2;
   3702 		UIRectangle bounds = UI_RECT_4(cx - (width + 1) / 2, cx + width / 2, cy - (height + 1) / 2, cy + height / 2);
   3703 		UIElementMove(element->children, bounds, false);
   3704 		UIElementRepaint(element, NULL);
   3705 	} else if (message == UI_MSG_PAINT) {
   3706 		UIRectangle bounds = UIRectangleAdd(element->children->bounds, UI_RECT_1I(-1));
   3707 		UIDrawBorder((UIPainter *) dp, bounds, ui.theme.border, UI_RECT_1(1));
   3708 		UIDrawBorder((UIPainter *) dp, UIRectangleAdd(bounds, UI_RECT_1(1)), ui.theme.border, UI_RECT_1(1));
   3709 	} else if (message == UI_MSG_KEY_TYPED) {
   3710 		UIKeyTyped *typed = (UIKeyTyped *) dp;
   3711 
   3712 		if (element->window->ctrl) return 0;
   3713 		if (element->window->shift) return 0;
   3714 
   3715 		char c0 = 0, c1 = 0;
   3716 
   3717 		if (typed->textBytes == 1 && typed->text[0] >= 'a' && typed->text[0] <= 'z') {
   3718 			c0 = typed->text[0], c1 = typed->text[0] - 'a' + 'A';
   3719 		} else {
   3720 			return 0;
   3721 		}
   3722 
   3723 		UIElement *row = element->children->children;
   3724 		UIElement *target = NULL;
   3725 		bool duplicate = false;
   3726 
   3727 		while (row) {
   3728 			UIElement *item = row->children;
   3729 
   3730 			while (item) {
   3731 				if (item->messageClass == _UIButtonMessage) {
   3732 					UIButton *button = (UIButton *) item;
   3733 
   3734 					if (button->label && button->labelBytes && (button->label[0] == c0 || button->label[0] == c1)) {
   3735 						if (!target) {
   3736 							target = &button->e;
   3737 						} else {
   3738 							duplicate = true;
   3739 						}
   3740 					}
   3741 				}
   3742 
   3743 				item = item->next;
   3744 			}
   3745 
   3746 			row = row->next;
   3747 		}
   3748 
   3749 		if (target) {
   3750 			if (duplicate) {
   3751 				UIElementFocus(target);
   3752 			} else {
   3753 				UIElementMessage(target, UI_MSG_CLICKED, 0, 0);
   3754 			}
   3755 
   3756 			return 1;
   3757 		}
   3758 	}
   3759 
   3760 	return 0;
   3761 }
   3762 
   3763 void _UIDialogButtonInvoke(void *cp) {
   3764 	ui.dialogResult = (const char *) cp;
   3765 }
   3766 
   3767 int _UIDialogTextboxMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3768 	if (message == UI_MSG_VALUE_CHANGED) {
   3769 		UITextbox *textbox = (UITextbox *) element;
   3770 		char **buffer = (char **) element->cp;
   3771 		*buffer = (char *) UI_REALLOC(*buffer, textbox->bytes + 1);
   3772 		(*buffer)[textbox->bytes] = 0;
   3773 
   3774 		for (ptrdiff_t i = 0; i < textbox->bytes; i++) {
   3775 			(*buffer)[i] = textbox->string[i];
   3776 		}
   3777 	}
   3778 
   3779 	return 0;
   3780 }
   3781 
   3782 const char *UIDialogShow(UIWindow *window, uint32_t flags, const char *format, ...) {
   3783 	// TODO Enter and escape.
   3784 
   3785 	// Create the dialog wrapper and panel.
   3786 
   3787 	UI_ASSERT(!window->dialog);
   3788 	window->dialog = UIElementCreate(sizeof(UIElement), &window->e, 0, _UIDialogWrapperMessage, "DialogWrapper");
   3789 	UIPanel *panel = UIPanelCreate(window->dialog, UI_PANEL_MEDIUM_SPACING | UI_PANEL_GRAY | UI_PANEL_EXPAND);
   3790 	panel->border = UI_RECT_1(UI_SIZE_PANE_MEDIUM_BORDER * 2);
   3791 	window->e.children->flags |= UI_ELEMENT_DISABLED;
   3792 
   3793 	// Create the dialog contents.
   3794 
   3795 	va_list arguments;
   3796 	va_start(arguments, format);
   3797 	UIPanel *row = NULL;
   3798 	UIElement *focus = NULL;
   3799 
   3800 	for (int i = 0; format[i]; i++) {
   3801 		if (i == 0 || format[i - 1] == '\n') {
   3802 			row = UIPanelCreate(&panel->e, UI_PANEL_HORIZONTAL);
   3803 			row->gap = UI_SIZE_PANE_SMALL_GAP;
   3804 		}
   3805 
   3806 		if (format[i] == ' ' || format[i] == '\n') {
   3807 		} else if (format[i] == '%') {
   3808 			i++;
   3809 
   3810 			if (format[i] == 'b' /* button */) {
   3811 				const char *label = va_arg(arguments, const char *);
   3812 				UIButton *button = UIButtonCreate(&row->e, 0, label, -1);
   3813 				if (!focus) focus = &button->e;
   3814 				button->invoke = _UIDialogButtonInvoke;
   3815 				button->e.cp = (void *) label;
   3816 			} else if (format[i] == 's' /* label from string */) {
   3817 				const char *label = va_arg(arguments, const char *);
   3818 				UILabelCreate(&row->e, 0, label, -1);
   3819 			} else if (format[i] == 't' /* textbox */) {
   3820 				char **buffer = va_arg(arguments, char **);
   3821 				UITextbox *textbox = UITextboxCreate(&row->e, UI_ELEMENT_H_FILL);
   3822 				if (!focus) focus = &textbox->e;
   3823 				if (*buffer) UITextboxReplace(textbox, *buffer, _UIStringLength(*buffer), false);
   3824 				textbox->e.cp = buffer;
   3825 				textbox->e.messageUser = _UIDialogTextboxMessage;
   3826 			} else if (format[i] == 'f' /* horizontal fill */) {
   3827 				UISpacerCreate(&row->e, UI_ELEMENT_H_FILL, 0, 0);
   3828 			} else if (format[i] == 'l' /* horizontal line */) {
   3829 				UISpacerCreate(&row->e, UI_SPACER_LINE | UI_ELEMENT_H_FILL, 0, 1);
   3830 			} else if (format[i] == 'u' /* user */) {
   3831 				UIDialogUserCallback callback = va_arg(arguments, UIDialogUserCallback);
   3832 				callback(&row->e);
   3833 			}
   3834 		} else {
   3835 			int j = i;
   3836 			while (format[j] && format[j] != '%' && format[j] != '\n') j++;
   3837 			UILabelCreate(&row->e, 0, format + i, j - i);
   3838 			i = j - 1;
   3839 		}
   3840 	}
   3841 
   3842 	va_end(arguments);
   3843 
   3844 	window->dialogOldFocus = window->focused;
   3845 	UIElementFocus(focus ? focus : window->dialog);
   3846 
   3847 	// Run the modal message loop.
   3848 
   3849 	int result;
   3850 	ui.dialogResult = NULL;
   3851 	for (int i = 1; i <= 3; i++) _UIWindowSetPressed(window, NULL, i);
   3852 	UIElementRefresh(&window->e);
   3853 	_UIUpdate();
   3854 	while (!ui.dialogResult && _UIMessageLoopSingle(&result));
   3855 	ui.quit = !ui.dialogResult;
   3856 
   3857 	// Destroy the dialog.
   3858 
   3859 	window->e.children->flags &= ~UI_ELEMENT_DISABLED;
   3860 	UIElementDestroy(window->dialog);
   3861 	window->dialog = NULL;
   3862 	UIElementRefresh(&window->e);
   3863 	if (window->dialogOldFocus) UIElementFocus(window->dialogOldFocus);
   3864 	return ui.dialogResult ? ui.dialogResult : "";
   3865 }
   3866 
   3867 bool _UIMenusClose() {
   3868 	UIWindow *window = ui.windows;
   3869 	bool anyClosed = false;
   3870 
   3871 	while (window) {
   3872 		if (window->e.flags & UI_WINDOW_MENU) {
   3873 			UIElementDestroy(&window->e);
   3874 			anyClosed = true;
   3875 		}
   3876 
   3877 		window = window->next;
   3878 	}
   3879 
   3880 	return anyClosed;
   3881 }
   3882 
   3883 #ifndef UI_ESSENCE
   3884 int _UIMenuItemMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3885 	if (message == UI_MSG_CLICKED) {
   3886 		_UIMenusClose();
   3887 	}
   3888 
   3889 	return 0;
   3890 }
   3891 
   3892 int _UIMenuMessage(UIElement *element, UIMessage message, int di, void *dp) {
   3893 	UIMenu *menu = (UIMenu *) element;
   3894 
   3895 	if (message == UI_MSG_GET_WIDTH) {
   3896 		UIElement *child = element->children;
   3897 		int width = 0;
   3898 
   3899 		while (child) {
   3900 			if (~child->flags & UI_ELEMENT_NON_CLIENT) {
   3901 				int w = UIElementMessage(child, UI_MSG_GET_WIDTH, 0, 0);
   3902 				if (w > width) width = w;
   3903 			}
   3904 
   3905 			child = child->next;
   3906 		}
   3907 
   3908 		return width + 4 + UI_SIZE_SCROLL_BAR;
   3909 	} else if (message == UI_MSG_GET_HEIGHT) {
   3910 		UIElement *child = element->children;
   3911 		int height = 0;
   3912 
   3913 		while (child) {
   3914 			if (~child->flags & UI_ELEMENT_NON_CLIENT) {
   3915 				height += UIElementMessage(child, UI_MSG_GET_HEIGHT, 0, 0);
   3916 			}
   3917 
   3918 			child = child->next;
   3919 		}
   3920 
   3921 		return height + 4;
   3922 	} else if (message == UI_MSG_PAINT) {
   3923 		UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.border);
   3924 	} else if (message == UI_MSG_LAYOUT) {
   3925 		UIElement *child = element->children;
   3926 		int position = element->bounds.t + 2 - menu->vScroll->position;
   3927 		int totalHeight = 0;
   3928 		int scrollBarSize = (menu->e.flags & UI_MENU_NO_SCROLL) ? 0 : UI_SIZE_SCROLL_BAR;
   3929 
   3930 		while (child) {
   3931 			if (~child->flags & UI_ELEMENT_NON_CLIENT) {
   3932 				int height = UIElementMessage(child, UI_MSG_GET_HEIGHT, 0, 0);
   3933 				UIElementMove(child, UI_RECT_4(element->bounds.l + 2, element->bounds.r - scrollBarSize - 2, 
   3934 							position, position + height), false);
   3935 				position += height;
   3936 				totalHeight += height;
   3937 			}
   3938 
   3939 			child = child->next;
   3940 		}
   3941 
   3942 		UIRectangle scrollBarBounds = element->bounds;
   3943 		scrollBarBounds.l = scrollBarBounds.r - scrollBarSize * element->window->scale;
   3944 		menu->vScroll->maximum = totalHeight;
   3945 		menu->vScroll->page = UI_RECT_HEIGHT(element->bounds);
   3946 		UIElementMove(&menu->vScroll->e, scrollBarBounds, true);
   3947 	} else if (message == UI_MSG_KEY_TYPED) {
   3948 		UIKeyTyped *m = (UIKeyTyped *) dp;
   3949 
   3950 		if (m->code == UI_KEYCODE_ESCAPE) {
   3951 			_UIMenusClose();
   3952 			return 1;
   3953 		}
   3954 	} else if (message == UI_MSG_MOUSE_WHEEL) {
   3955 		return UIElementMessage(&menu->vScroll->e, message, di, dp);
   3956 	} else if (message == UI_MSG_SCROLLED) {
   3957 		UIElementRefresh(element);
   3958 	}
   3959 
   3960 	return 0;
   3961 }
   3962 
   3963 void UIMenuAddItem(UIMenu *menu, uint32_t flags, const char *label, ptrdiff_t labelBytes, void (*invoke)(void *cp), void *cp) {
   3964 	UIButton *button = UIButtonCreate(&menu->e, flags | UI_BUTTON_MENU_ITEM, label, labelBytes);
   3965 	button->invoke = invoke;
   3966 	button->e.messageUser = _UIMenuItemMessage;
   3967 	button->e.cp = cp;
   3968 }
   3969 
   3970 void _UIMenuPrepare(UIMenu *menu, int *width, int *height) {
   3971 	*width = UIElementMessage(&menu->e, UI_MSG_GET_WIDTH, 0, 0);
   3972 	*height = UIElementMessage(&menu->e, UI_MSG_GET_HEIGHT, 0, 0);
   3973 
   3974 	if (menu->e.flags & UI_MENU_PLACE_ABOVE) {
   3975 		menu->pointY -= *height;
   3976 	}
   3977 }
   3978 
   3979 UIMenu *UIMenuCreate(UIElement *parent, uint32_t flags) {
   3980 	UIWindow *window = UIWindowCreate(parent->window, UI_WINDOW_MENU, 0, 0, 0);
   3981 	UIMenu *menu = (UIMenu *) UIElementCreate(sizeof(UIMenu), &window->e, flags, _UIMenuMessage, "Menu");
   3982 	menu->vScroll = UIScrollBarCreate(&menu->e, UI_ELEMENT_NON_CLIENT);
   3983 
   3984 	if (parent->parent) {
   3985 		UIRectangle screenBounds = UIElementScreenBounds(parent);
   3986 		menu->pointX = screenBounds.l;
   3987 		menu->pointY = (flags & UI_MENU_PLACE_ABOVE) ? (screenBounds.t + 1) : (screenBounds.b - 1);
   3988 	} else {
   3989 		int x = 0, y = 0;
   3990 		_UIWindowGetScreenPosition(parent->window, &x, &y);
   3991 
   3992 		menu->pointX = parent->window->cursorX + x;
   3993 		menu->pointY = parent->window->cursorY + y;
   3994 	}
   3995 
   3996 	return menu;
   3997 }
   3998 #endif
   3999 
   4000 UIRectangle UIElementScreenBounds(UIElement *element) {
   4001 	int x = 0, y = 0;
   4002 	_UIWindowGetScreenPosition(element->window, &x, &y);
   4003 	return UIRectangleAdd(element->bounds, UI_RECT_2(x, y));
   4004 }
   4005 
   4006 void UIWindowRegisterShortcut(UIWindow *window, UIShortcut shortcut) {
   4007 	if (window->shortcutCount + 1 > window->shortcutAllocated) {
   4008 		window->shortcutAllocated = (window->shortcutCount + 1) * 2;
   4009 		window->shortcuts = (UIShortcut *) UI_REALLOC(window->shortcuts, window->shortcutAllocated * sizeof(UIShortcut));
   4010 	}
   4011 
   4012 	window->shortcuts[window->shortcutCount++] = shortcut;
   4013 }
   4014 
   4015 void _UIElementPaint(UIElement *element, UIPainter *painter) {
   4016 	if (element->flags & UI_ELEMENT_HIDE) {
   4017 		return;
   4018 	}
   4019 
   4020 	// Clip painting to the element's clip.
   4021 
   4022 	painter->clip = UIRectangleIntersection(element->clip, painter->clip);
   4023 
   4024 	if (!UI_RECT_VALID(painter->clip)) {
   4025 		return;
   4026 	}
   4027 
   4028 	// Paint the element.
   4029 
   4030 	UIElementMessage(element, UI_MSG_PAINT, 0, painter);
   4031 
   4032 	// Paint its children.
   4033 
   4034 	UIElement *child = element->children;
   4035 	UIRectangle previousClip = painter->clip;
   4036 
   4037 	while (child) {
   4038 		painter->clip = previousClip;
   4039 		_UIElementPaint(child, painter);
   4040 		child = child->next;
   4041 	}
   4042 }
   4043 
   4044 void UIElementFocus(UIElement *element) {
   4045 	UIElement *previous = element->window->focused;
   4046 	if (previous == element) return;
   4047 	element->window->focused = element;
   4048 	if (previous) UIElementMessage(previous, UI_MSG_UPDATE, UI_UPDATE_FOCUSED, 0);
   4049 	if (element) UIElementMessage(element, UI_MSG_UPDATE, UI_UPDATE_FOCUSED, 0);
   4050 
   4051 #ifdef UI_DEBUG
   4052 	_UIInspectorRefresh();
   4053 #endif
   4054 }
   4055 
   4056 void _UIWindowSetPressed(UIWindow *window, UIElement *element, int button) {
   4057 	UIElement *previous = window->pressed;
   4058 	window->pressed = element;
   4059 	window->pressedButton = button;
   4060 	if (previous) UIElementMessage(previous, UI_MSG_UPDATE, UI_UPDATE_PRESSED, 0);
   4061 	if (element) UIElementMessage(element, UI_MSG_UPDATE, UI_UPDATE_PRESSED, 0);
   4062 
   4063 	UIElement *ancestor = element;
   4064 	UIElement *child = NULL;
   4065 
   4066 	while (ancestor) {
   4067 		UIElementMessage(ancestor, UI_MSG_PRESSED_DESCENDENT, 0, child);
   4068 		child = ancestor;
   4069 		ancestor = ancestor->parent;
   4070 	}
   4071 }
   4072 
   4073 bool _UIDestroy(UIElement *element) {
   4074 	if (element->flags & UI_ELEMENT_DESTROY_DESCENDENT) {
   4075 		element->flags &= ~UI_ELEMENT_DESTROY_DESCENDENT;
   4076 
   4077 		UIElement *child = element->children;
   4078 		UIElement **link = &element->children;
   4079 
   4080 		while (child) {
   4081 			UIElement *next = child->next;
   4082 
   4083 			if (_UIDestroy(child)) {
   4084 				*link = next;
   4085 			} else {
   4086 				link = &child->next;
   4087 			}
   4088 
   4089 			child = next;
   4090 		}
   4091 	}
   4092 
   4093 	if (element->flags & UI_ELEMENT_DESTROY) {
   4094 		UIElementMessage(element, UI_MSG_DESTROY, 0, 0);
   4095 
   4096 		if (element->window->pressed == element) {
   4097 			_UIWindowSetPressed(element->window, NULL, 0);
   4098 		}
   4099 
   4100 		if (element->window->hovered == element) {
   4101 			element->window->hovered = &element->window->e;
   4102 		}
   4103 
   4104 		if (element->window->focused == element) {
   4105 			element->window->focused = NULL;
   4106 		}
   4107 
   4108 		if (element->window->dialogOldFocus == element) {
   4109 			element->window->dialogOldFocus = NULL;
   4110 		}
   4111 
   4112 		if (ui.animating == element) {
   4113 			ui.animating = NULL;
   4114 		}
   4115 
   4116 		UI_FREE(element);
   4117 		return true;
   4118 	} else {
   4119 		return false;
   4120 	}
   4121 }
   4122 
   4123 void _UIUpdate() {
   4124 	UIWindow *window = ui.windows;
   4125 	UIWindow **link = &ui.windows;
   4126 
   4127 	while (window) {
   4128 		UIWindow *next = window->next;
   4129 
   4130 		if (_UIDestroy(&window->e)) {
   4131 			*link = next;
   4132 		} else {
   4133 			link = &window->next;
   4134 
   4135 			if (UI_RECT_VALID(window->updateRegion)) {
   4136 #ifdef __cplusplus
   4137 				UIPainter painter = {};
   4138 #else
   4139 				UIPainter painter = { 0 };
   4140 #endif
   4141 				painter.bits = window->bits;
   4142 				painter.width = window->width;
   4143 				painter.height = window->height;
   4144 				painter.clip = UIRectangleIntersection(UI_RECT_2S(window->width, window->height), window->updateRegion);
   4145 				_UIElementPaint(&window->e, &painter);
   4146 				_UIWindowEndPaint(window, &painter);
   4147 				window->updateRegion = UI_RECT_1(0);
   4148 
   4149 #ifdef UI_DEBUG
   4150 				window->lastFullFillCount = (float) painter.fillCount / (UI_RECT_WIDTH(window->updateRegion) * UI_RECT_HEIGHT(window->updateRegion));
   4151 #endif
   4152 			}
   4153 		}
   4154 
   4155 		window = next;
   4156 	}
   4157 }
   4158 
   4159 UIElement *UIElementFindByPoint(UIElement *element, int x, int y) {
   4160 	UIFindByPoint m = { 0 };
   4161 	m.x = x, m.y = y;
   4162 
   4163 	if (UIElementMessage(element, UI_MSG_FIND_BY_POINT, 0, &m)) {
   4164 		return m.result ? m.result : element;
   4165 	}
   4166 
   4167 	UIElement *child = element->children;
   4168 
   4169 	while (child) {
   4170 		if ((~child->flags & UI_ELEMENT_HIDE) && UIRectangleContains(child->clip, x, y)) {
   4171 			return UIElementFindByPoint(child, x, y);
   4172 		}
   4173 
   4174 		child = child->next;
   4175 	}
   4176 
   4177 	return element;
   4178 }
   4179 
   4180 void _UIProcessAnimations() {
   4181 	if (ui.animating) {
   4182 		UIElementMessage(ui.animating, UI_MSG_ANIMATE, 0, 0);
   4183 		_UIUpdate();
   4184 	}
   4185 }
   4186 
   4187 bool _UIMenusOpen() {
   4188 	UIWindow *window = ui.windows;
   4189 
   4190 	while (window) {
   4191 		if (window->e.flags & UI_WINDOW_MENU) {
   4192 			return true;
   4193 		}
   4194 
   4195 		window = window->next;
   4196 	}
   4197 
   4198 	return false;
   4199 }
   4200 
   4201 void _UIWindowDestroyCommon(UIWindow *window) {
   4202 	UI_FREE(window->bits);
   4203 	UI_FREE(window->shortcuts);
   4204 }
   4205 
   4206 UIElement *_UIElementLastChild(UIElement *element) {
   4207 	if (!element->children) {
   4208 		return NULL;
   4209 	}
   4210 
   4211 	UIElement *child = element->children;
   4212 
   4213 	while (child->next) {
   4214 		child = child->next;
   4215 	}
   4216 
   4217 	return child;
   4218 }
   4219 
   4220 UIElement *_UIElementPreviousSibling(UIElement *element) {
   4221 	if (!element->parent) {
   4222 		return NULL;
   4223 	}
   4224 
   4225 	UIElement *sibling = element->parent->children;
   4226 
   4227 	if (sibling == element) {
   4228 		return NULL;
   4229 	}
   4230 
   4231 	while (sibling->next != element) {
   4232 		sibling = sibling->next;
   4233 		UI_ASSERT(sibling);
   4234 	}
   4235 	
   4236 	return sibling;
   4237 }
   4238 
   4239 bool _UIWindowInputEvent(UIWindow *window, UIMessage message, int di, void *dp) {
   4240 	bool handled = true;
   4241 
   4242 	if (window->pressed) {
   4243 		if (message == UI_MSG_MOUSE_MOVE) {
   4244 			UIElementMessage(window->pressed, UI_MSG_MOUSE_DRAG, di, dp);
   4245 		} else if (message == UI_MSG_LEFT_UP && window->pressedButton == 1) {
   4246 			if (window->hovered == window->pressed) {
   4247 				UIElementMessage(window->pressed, UI_MSG_CLICKED, di, dp);
   4248 				if (ui.quit || ui.dialogResult) goto end;
   4249 			}
   4250 
   4251 			if (window->pressed) {
   4252 				UIElementMessage(window->pressed, UI_MSG_LEFT_UP, di, dp);
   4253 				if (ui.quit || ui.dialogResult) goto end;
   4254 				_UIWindowSetPressed(window, NULL, 1);
   4255 			}
   4256 		} else if (message == UI_MSG_MIDDLE_UP && window->pressedButton == 2) {
   4257 			UIElementMessage(window->pressed, UI_MSG_MIDDLE_UP, di, dp);
   4258 			if (ui.quit || ui.dialogResult) goto end;
   4259 			_UIWindowSetPressed(window, NULL, 2);
   4260 		} else if (message == UI_MSG_RIGHT_UP && window->pressedButton == 3) {
   4261 			UIElementMessage(window->pressed, UI_MSG_RIGHT_UP, di, dp);
   4262 			if (ui.quit || ui.dialogResult) goto end;
   4263 			_UIWindowSetPressed(window, NULL, 3);
   4264 		}
   4265 	}
   4266 
   4267 	if (window->pressed) {
   4268 		bool inside = UIRectangleContains(window->pressed->clip, window->cursorX, window->cursorY);
   4269 
   4270 		if (inside && window->hovered == &window->e) {
   4271 			window->hovered = window->pressed;
   4272 			UIElementMessage(window->pressed, UI_MSG_UPDATE, UI_UPDATE_HOVERED, 0);
   4273 		} else if (!inside && window->hovered == window->pressed) {
   4274 			window->hovered = &window->e;
   4275 			UIElementMessage(window->pressed, UI_MSG_UPDATE, UI_UPDATE_HOVERED, 0);
   4276 		}
   4277 
   4278 		if (ui.quit || ui.dialogResult) goto end;
   4279 	}
   4280 
   4281 	if (!window->pressed) {
   4282 		UIElement *hovered = UIElementFindByPoint(&window->e, window->cursorX, window->cursorY);
   4283 
   4284 		if (message == UI_MSG_MOUSE_MOVE) {
   4285 			UIElementMessage(hovered, UI_MSG_MOUSE_MOVE, di, dp);
   4286 
   4287 			int cursor = UIElementMessage(window->hovered, UI_MSG_GET_CURSOR, di, dp);
   4288 
   4289 			if (cursor != window->cursorStyle) {
   4290 				window->cursorStyle = cursor;
   4291 				_UIWindowSetCursor(window, cursor);
   4292 			}
   4293 		} else if (message == UI_MSG_LEFT_DOWN) {
   4294 			if ((window->e.flags & UI_WINDOW_MENU) || !_UIMenusClose()) {
   4295 				_UIWindowSetPressed(window, hovered, 1);
   4296 				UIElementMessage(hovered, UI_MSG_LEFT_DOWN, di, dp);
   4297 			}
   4298 		} else if (message == UI_MSG_MIDDLE_DOWN) {
   4299 			if ((window->e.flags & UI_WINDOW_MENU) || !_UIMenusClose()) {
   4300 				_UIWindowSetPressed(window, hovered, 2);
   4301 				UIElementMessage(hovered, UI_MSG_MIDDLE_DOWN, di, dp);
   4302 			}
   4303 		} else if (message == UI_MSG_RIGHT_DOWN) {
   4304 			if ((window->e.flags & UI_WINDOW_MENU) || !_UIMenusClose()) {
   4305 				_UIWindowSetPressed(window, hovered, 3);
   4306 				UIElementMessage(hovered, UI_MSG_RIGHT_DOWN, di, dp);
   4307 			}
   4308 		} else if (message == UI_MSG_MOUSE_WHEEL) {
   4309 			UIElement *element = hovered;
   4310 
   4311 			while (element) {
   4312 				if (UIElementMessage(element, UI_MSG_MOUSE_WHEEL, di, dp)) {
   4313 					break;
   4314 				}
   4315 
   4316 				element = element->parent;
   4317 			}
   4318 		} else if (message == UI_MSG_KEY_TYPED) {
   4319 			handled = false;
   4320 
   4321 			if (window->focused) {
   4322 				UIElement *element = window->focused;
   4323 
   4324 				while (element) {
   4325 					if (UIElementMessage(element, UI_MSG_KEY_TYPED, di, dp)) {
   4326 						handled = true;
   4327 						break;
   4328 					}
   4329 
   4330 					element = element->parent;
   4331 				}
   4332 			} else {
   4333 				if (UIElementMessage(&window->e, UI_MSG_KEY_TYPED, di, dp)) {
   4334 					handled = true;
   4335 				}
   4336 			}
   4337 
   4338 			if (!handled && !_UIMenusOpen()) {
   4339 				UIKeyTyped *m = (UIKeyTyped *) dp;
   4340 
   4341 				if (m->code == UI_KEYCODE_TAB && !window->ctrl && !window->alt) {
   4342 					UIElement *start = window->focused ? window->focused : &window->e;
   4343 					UIElement *element = start;
   4344 
   4345 					do {
   4346 						if (element->children && !(element->flags & (UI_ELEMENT_HIDE | UI_ELEMENT_DISABLED))) {
   4347 							element = window->shift ? _UIElementLastChild(element) : element->children;
   4348 							continue;
   4349 						} 
   4350 
   4351 						while (element) {
   4352 							if (window->shift ? (element->parent && element->parent->children != element) : !!element->next) {
   4353 								element = window->shift ? _UIElementPreviousSibling(element) : element->next;
   4354 								break;
   4355 							} else {
   4356 								element = element->parent;
   4357 							}
   4358 						}
   4359 
   4360 						if (!element) {
   4361 							element = &window->e;
   4362 						}
   4363 					} while (element != start && ((~element->flags & UI_ELEMENT_TAB_STOP) 
   4364 						|| (element->flags & (UI_ELEMENT_HIDE | UI_ELEMENT_DISABLED))));
   4365 
   4366 					if (~element->flags & UI_ELEMENT_WINDOW) {
   4367 						UIElementFocus(element);
   4368 					}
   4369 
   4370 					handled = true;
   4371 				} else if (!window->dialog) {
   4372 					for (intptr_t i = window->shortcutCount - 1; i >= 0; i--) {
   4373 						UIShortcut *shortcut = window->shortcuts + i;
   4374 
   4375 						if (shortcut->code == m->code && shortcut->ctrl == window->ctrl 
   4376 								&& shortcut->shift == window->shift && shortcut->alt == window->alt) {
   4377 							shortcut->invoke(shortcut->cp);
   4378 							handled = true;
   4379 							break;
   4380 						}
   4381 					}
   4382 				}
   4383 			}
   4384 		}
   4385 
   4386 		if (ui.quit || ui.dialogResult) goto end;
   4387 
   4388 		if (hovered != window->hovered) {
   4389 			UIElement *previous = window->hovered;
   4390 			window->hovered = hovered;
   4391 			UIElementMessage(previous, UI_MSG_UPDATE, UI_UPDATE_HOVERED, 0);
   4392 			UIElementMessage(window->hovered, UI_MSG_UPDATE, UI_UPDATE_HOVERED, 0);
   4393 		}
   4394 	}
   4395 
   4396 	end: _UIUpdate();
   4397 	return handled;
   4398 }
   4399 
   4400 UIFont *UIFontCreate(const char *cPath, uint32_t size) {
   4401 	UIFont *font = (UIFont *) UI_CALLOC(sizeof(UIFont));
   4402 
   4403 #ifdef UI_FREETYPE
   4404 	if (cPath) {
   4405 		if (!FT_New_Face(ui.ft, cPath, 0, &font->font)) {
   4406 			FT_Set_Char_Size(font->font, 0, size * 64, 100, 100);
   4407 			FT_Load_Char(font->font, 'a', FT_LOAD_DEFAULT);
   4408 			font->glyphWidth = font->font->glyph->advance.x / 64;
   4409 			font->glyphHeight = (font->font->size->metrics.ascender - font->font->size->metrics.descender) / 64;
   4410 			font->isFreeType = true;
   4411 			return font;
   4412 		}
   4413 	}
   4414 #endif
   4415 	
   4416 	font->glyphWidth = 9;
   4417 	font->glyphHeight = 16;
   4418 	return font;
   4419 }
   4420 
   4421 UIFont *UIFontActivate(UIFont *font) {
   4422 	UIFont *previous = ui.activeFont;
   4423 	ui.activeFont = font;
   4424 	return previous;
   4425 }
   4426 
   4427 void _UIInitialiseCommon() {
   4428 	ui.theme = _uiThemeDark;
   4429 
   4430 #ifdef UI_FREETYPE
   4431 	FT_Init_FreeType(&ui.ft);
   4432 	UIFontActivate(UIFontCreate(_UI_TO_STRING_2(UI_FONT_PATH), 11));
   4433 #else
   4434 	UIFontActivate(UIFontCreate(0, 0));
   4435 #endif
   4436 }
   4437 
   4438 void _UIWindowAdd(UIWindow *window) {
   4439 	window->scale = 1.0f;
   4440 	window->e.window = window;
   4441 	window->hovered = &window->e;
   4442 	window->next = ui.windows;
   4443 	ui.windows = window;
   4444 }
   4445 
   4446 int _UIWindowMessageCommon(UIElement *element, UIMessage message, int di, void *dp) {
   4447 	if (message == UI_MSG_LAYOUT && element->children) {
   4448 		UIElementMove(element->children, element->bounds, false);
   4449 		if (element->window->dialog) UIElementMove(element->window->dialog, element->bounds, false);
   4450 		UIElementRepaint(element, NULL);
   4451 	} else if (message == UI_MSG_FIND_BY_POINT) {
   4452 		UIFindByPoint *m = (UIFindByPoint *) dp;
   4453 		if (element->window->dialog) m->result = UIElementFindByPoint(element->window->dialog, m->x, m->y);
   4454 		else if (!element->children) m->result = NULL;
   4455 		else m->result = UIElementFindByPoint(element->children, m->x, m->y);
   4456 		return 1;
   4457 	}
   4458 
   4459 	return 0;
   4460 }
   4461 
   4462 #ifdef UI_DEBUG
   4463 
   4464 void UIInspectorLog(const char *cFormat, ...) {
   4465 	va_list arguments;
   4466 	va_start(arguments, cFormat);
   4467 	char buffer[4096];
   4468 	vsnprintf(buffer, sizeof(buffer), cFormat, arguments);
   4469 	UICodeInsertContent(ui.inspectorLog, buffer, -1, false);
   4470 	va_end(arguments);
   4471 	UIElementRefresh(&ui.inspectorLog->e);
   4472 }
   4473 
   4474 UIElement *_UIInspectorFindNthElement(UIElement *element, int *index, int *depth) {
   4475 	if (*index == 0) {
   4476 		return element;
   4477 	}
   4478 
   4479 	*index = *index - 1;
   4480 	
   4481 	UIElement *child = element->children;
   4482 
   4483 	while (child) {
   4484 		if (!(child->flags & (UI_ELEMENT_DESTROY | UI_ELEMENT_HIDE))) {
   4485 			UIElement *result = _UIInspectorFindNthElement(child, index, depth);
   4486 
   4487 			if (result) {
   4488 				if (depth) {
   4489 					*depth = *depth + 1;
   4490 				}
   4491 
   4492 				return result;
   4493 			}
   4494 		}
   4495 
   4496 		child = child->next;
   4497 	}
   4498 
   4499 	return NULL;
   4500 }
   4501 
   4502 int _UIInspectorTableMessage(UIElement *element, UIMessage message, int di, void *dp) {
   4503 	if (!ui.inspectorTarget) {
   4504 		return 0;
   4505 	}
   4506 
   4507 	if (message == UI_MSG_TABLE_GET_ITEM) {
   4508 		UITableGetItem *m = (UITableGetItem *) dp;
   4509 		int index = m->index;
   4510 		int depth = 0;
   4511 		UIElement *element = _UIInspectorFindNthElement(&ui.inspectorTarget->e, &index, &depth);
   4512 		if (!element) return 0;
   4513 
   4514 		if (m->column == 0) {
   4515 			return snprintf(m->buffer, m->bufferBytes, "%.*s%s", depth * 2, "                ", element->cClassName);
   4516 		} else if (m->column == 1) {
   4517 			return snprintf(m->buffer, m->bufferBytes, "%d:%d, %d:%d", UI_RECT_ALL(element->bounds));
   4518 		} else if (m->column == 2) {
   4519 			return snprintf(m->buffer, m->bufferBytes, "%d%c", element->id, element->window->focused == element ? '*' : ' ');
   4520 		}
   4521 	} else if (message == UI_MSG_MOUSE_MOVE) {
   4522 		int index = UITableHitTest(ui.inspectorTable, element->window->cursorX, element->window->cursorY);
   4523 		UIElement *element = NULL;
   4524 		if (index >= 0) element = _UIInspectorFindNthElement(&ui.inspectorTarget->e, &index, NULL);
   4525 		UIWindow *window = ui.inspectorTarget;
   4526 		UIPainter painter = { 0 };
   4527 		window->updateRegion = window->e.bounds;
   4528 		painter.bits = window->bits;
   4529 		painter.width = window->width;
   4530 		painter.height = window->height;
   4531 		painter.clip = UI_RECT_2S(window->width, window->height);
   4532 
   4533 		for (int i = 0; i < window->width * window->height; i++) {
   4534 			window->bits[i] = 0xFF00FF;
   4535 		}
   4536 
   4537 		_UIElementPaint(&window->e, &painter);
   4538 		painter.clip = UI_RECT_2S(window->width, window->height);
   4539 
   4540 		if (element) {
   4541 			UIDrawInvert(&painter, element->bounds);
   4542 			UIDrawInvert(&painter, UIRectangleAdd(element->bounds, UI_RECT_1I(4)));
   4543 		}
   4544 
   4545 		_UIWindowEndPaint(window, &painter);
   4546 	}
   4547 
   4548 	return 0;
   4549 }
   4550 
   4551 void _UIInspectorCreate() {
   4552 	ui.inspector = UIWindowCreate(0, UI_WINDOW_INSPECTOR, "Inspector", 0, 0);
   4553 	UISplitPane *splitPane = UISplitPaneCreate(&ui.inspector->e, 0, 0.5f);
   4554 	ui.inspectorTable = UITableCreate(&splitPane->e, 0, "Class\tBounds\tID");
   4555 	ui.inspectorTable->e.messageUser = _UIInspectorTableMessage;
   4556 	ui.inspectorLog = UICodeCreate(&splitPane->e, 0);
   4557 }
   4558 
   4559 int _UIInspectorCountElements(UIElement *element) {
   4560 	UIElement *child = element->children;
   4561 	int count = 1;
   4562 
   4563 	while (child) {
   4564 		if (!(child->flags & (UI_ELEMENT_DESTROY | UI_ELEMENT_HIDE))) {
   4565 			count += _UIInspectorCountElements(child);
   4566 		}
   4567 
   4568 		child = child->next;
   4569 	}
   4570 
   4571 	return count;
   4572 }
   4573 
   4574 void _UIInspectorRefresh() {
   4575 	if (!ui.inspectorTarget || !ui.inspector || !ui.inspectorTable) return;
   4576 	ui.inspectorTable->itemCount = _UIInspectorCountElements(&ui.inspectorTarget->e);
   4577 	UITableResizeColumns(ui.inspectorTable);
   4578 	UIElementRefresh(&ui.inspectorTable->e);
   4579 }
   4580 
   4581 void _UIInspectorSetFocusedWindow(UIWindow *window) {
   4582 	if (!ui.inspector || !ui.inspectorTable) return;
   4583 
   4584 	if (window->e.flags & UI_WINDOW_INSPECTOR) {
   4585 		return;
   4586 	}
   4587 
   4588 	if (ui.inspectorTarget != window) {
   4589 		ui.inspectorTarget = window;
   4590 		_UIInspectorRefresh();
   4591 	}
   4592 }
   4593 
   4594 #else
   4595 
   4596 void _UIInspectorCreate() {}
   4597 void _UIInspectorSetFocusedWindow(UIWindow *window) {}
   4598 void _UIInspectorRefresh() {}
   4599 
   4600 #endif
   4601 
   4602 #ifdef UI_AUTOMATION_TESTS
   4603 
   4604 int UIAutomationRunTests();
   4605 
   4606 void UIAutomationProcessMessage() {
   4607 	int result;
   4608 	_UIMessageLoopSingle(&result);
   4609 }
   4610 
   4611 void UIAutomationKeyboardTypeSingle(intptr_t code, bool ctrl, bool shift, bool alt) {
   4612 	UIWindow *window = ui.windows; // TODO Get the focused window.
   4613 	UIKeyTyped m = { 0 };
   4614 	m.code = code;
   4615 	window->ctrl = ctrl;
   4616 	window->alt = alt;
   4617 	window->shift = shift;
   4618 	_UIWindowInputEvent(window, UI_MSG_KEY_TYPED, 0, &m);
   4619 	window->ctrl = false;
   4620 	window->alt = false;
   4621 	window->shift = false;
   4622 }
   4623 
   4624 void UIAutomationKeyboardType(const char *string) {
   4625 	UIWindow *window = ui.windows; // TODO Get the focused window.
   4626 
   4627 	UIKeyTyped m = { 0 };
   4628 	char c[2];
   4629 	m.text = c;
   4630 	m.textBytes = 1;
   4631 	c[1] = 0;
   4632 
   4633 	for (int i = 0; string[i]; i++) {
   4634 		window->ctrl = false;
   4635 		window->alt = false;
   4636 		window->shift = (c[0] >= 'A' && c[0] <= 'Z');
   4637 		c[0] = string[i];
   4638 		m.code = (c[0] >= 'A' && c[0] <= 'Z') ? UI_KEYCODE_LETTER(c[0]) 
   4639 			: c[0] == '\n' ? UI_KEYCODE_ENTER 
   4640 			: c[0] == '\t' ? UI_KEYCODE_TAB 
   4641 			: c[0] == ' ' ? UI_KEYCODE_SPACE 
   4642 			: (c[0] >= '0' && c[0] <= '9') ? UI_KEYCODE_DIGIT(c[0]) : 0;
   4643 		_UIWindowInputEvent(window, UI_MSG_KEY_TYPED, 0, &m);
   4644 	}
   4645 
   4646 	window->ctrl = false;
   4647 	window->alt = false;
   4648 	window->shift = false;
   4649 }
   4650 
   4651 bool UIAutomationCheckCodeLineMatches(UICode *code, int lineIndex, const char *input) {
   4652 	if (lineIndex < 1 || lineIndex > code->lineCount) return false;
   4653 	int bytes = 0;
   4654 	for (int i = 0; input[i]; i++) bytes++;
   4655 	if (bytes != code->lines[lineIndex - 1].bytes) return false;
   4656 	for (int i = 0; input[i]; i++) if (code->content[code->lines[lineIndex - 1].offset + i] != input[i]) return false;
   4657 	return true;
   4658 }
   4659 
   4660 bool UIAutomationCheckTableItemMatches(UITable *table, int row, int column, const char *input) {
   4661 	int bytes = 0;
   4662 	for (int i = 0; input[i]; i++) bytes++;
   4663 	if (row < 0 || row >= table->itemCount) return false;
   4664 	if (column < 0 || column >= table->columnCount) return false;
   4665 	char *buffer = (char *) UI_MALLOC(bytes + 1);
   4666 	UITableGetItem m = { 0 };
   4667 	m.buffer = buffer;
   4668 	m.bufferBytes = bytes + 1;
   4669 	m.column = column;
   4670 	m.index = row;
   4671 	int length = UIElementMessage(&table->e, UI_MSG_TABLE_GET_ITEM, 0, &m);
   4672 	if (length != bytes) return false;
   4673 	for (int i = 0; input[i]; i++) if (buffer[i] != input[i]) return false;
   4674 	return true;
   4675 }
   4676 
   4677 #endif
   4678 
   4679 int UIMessageLoop() {
   4680 	_UIInspectorCreate();
   4681 	_UIUpdate();
   4682 #ifdef UI_AUTOMATION_TESTS
   4683 	return UIAutomationRunTests();
   4684 #else
   4685 	int result = 0;
   4686 	while (!ui.quit && _UIMessageLoopSingle(&result)) ui.dialogResult = NULL;
   4687 	return result;
   4688 #endif
   4689 }
   4690 
   4691 #ifdef UI_LINUX
   4692 
   4693 const int UI_KEYCODE_A = XK_a;
   4694 const int UI_KEYCODE_BACKSPACE = XK_BackSpace;
   4695 const int UI_KEYCODE_DELETE = XK_Delete;
   4696 const int UI_KEYCODE_DOWN = XK_Down;
   4697 const int UI_KEYCODE_END = XK_End;
   4698 const int UI_KEYCODE_ENTER = XK_Return;
   4699 const int UI_KEYCODE_ESCAPE = XK_Escape;
   4700 const int UI_KEYCODE_F1 = XK_F1;
   4701 const int UI_KEYCODE_HOME = XK_Home;
   4702 const int UI_KEYCODE_LEFT = XK_Left;
   4703 const int UI_KEYCODE_RIGHT = XK_Right;
   4704 const int UI_KEYCODE_SPACE = XK_space;
   4705 const int UI_KEYCODE_TAB = XK_Tab;
   4706 const int UI_KEYCODE_UP = XK_Up;
   4707 const int UI_KEYCODE_INSERT = XK_Insert;
   4708 const int UI_KEYCODE_0 = XK_0;
   4709 
   4710 int _UIWindowMessage(UIElement *element, UIMessage message, int di, void *dp) {
   4711 	if (message == UI_MSG_DESTROY) {
   4712 		UIWindow *window = (UIWindow *) element;
   4713 		_UIWindowDestroyCommon(window);
   4714 		window->image->data = NULL;
   4715 		XDestroyImage(window->image);
   4716 		XDestroyIC(window->xic);
   4717 		XDestroyWindow(ui.display, ((UIWindow *) element)->window);
   4718 	}
   4719 
   4720 	return _UIWindowMessageCommon(element, message, di, dp);
   4721 }
   4722 
   4723 UIWindow *UIWindowCreate(UIWindow *owner, uint32_t flags, const char *cTitle, int _width, int _height) {
   4724 	_UIMenusClose();
   4725 
   4726 	UIWindow *window = (UIWindow *) UIElementCreate(sizeof(UIWindow), NULL, flags | UI_ELEMENT_WINDOW, _UIWindowMessage, "Window");
   4727 	_UIWindowAdd(window);
   4728 	if (owner) window->scale = owner->scale;
   4729 
   4730 	int width = (flags & UI_WINDOW_MENU) ? 1 : _width ? _width : 800;
   4731 	int height = (flags & UI_WINDOW_MENU) ? 1 : _height ? _height : 600;
   4732 
   4733 	XSetWindowAttributes attributes = {};
   4734 	attributes.override_redirect = flags & UI_WINDOW_MENU;
   4735 
   4736 	window->window = XCreateWindow(ui.display, DefaultRootWindow(ui.display), 0, 0, width, height, 0, 0, 
   4737 		InputOutput, CopyFromParent, CWOverrideRedirect, &attributes);
   4738 	if (cTitle) XStoreName(ui.display, window->window, cTitle);
   4739 	XSelectInput(ui.display, window->window, SubstructureNotifyMask | ExposureMask | PointerMotionMask 
   4740 		| ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask
   4741 		| EnterWindowMask | LeaveWindowMask | ButtonMotionMask | KeymapStateMask | FocusChangeMask | PropertyChangeMask);
   4742 
   4743 	if (flags & UI_WINDOW_MAXIMIZE) {
   4744 		Atom atoms[2] = { XInternAtom(ui.display, "_NET_WM_STATE_MAXIMIZED_HORZ", 0), XInternAtom(ui.display, "_NET_WM_STATE_MAXIMIZED_VERT", 0) };
   4745 		XChangeProperty(ui.display, window->window, XInternAtom(ui.display, "_NET_WM_STATE", 0), XA_ATOM, 32, PropModeReplace, (unsigned char *) atoms, 2);
   4746 	}
   4747 
   4748 	if (~flags & UI_WINDOW_MENU) {
   4749 		XMapRaised(ui.display, window->window);
   4750 	}
   4751 
   4752 	if (flags & UI_WINDOW_CENTER_IN_OWNER) {
   4753 		int x = 0, y = 0;
   4754 		_UIWindowGetScreenPosition(owner, &x, &y);
   4755 		XMoveResizeWindow(ui.display, window->window, x + owner->width / 2 - width / 2, y + owner->height / 2 - height / 2, width, height);
   4756 	}
   4757 
   4758 	XSetWMProtocols(ui.display, window->window, &ui.windowClosedID, 1);
   4759 	window->image = XCreateImage(ui.display, ui.visual, 24, ZPixmap, 0, NULL, 10, 10, 32, 0);
   4760 
   4761 	window->xic = XCreateIC(ui.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, window->window, XNFocusWindow, window->window, NULL);
   4762 
   4763 	int dndVersion = 4;
   4764 	XChangeProperty(ui.display, window->window, ui.dndAwareID, XA_ATOM, 32 /* bits */, PropModeReplace, (uint8_t *) &dndVersion, 1);
   4765 
   4766 	return window;
   4767 }
   4768 
   4769 Display *_UIX11GetDisplay() {
   4770 	return ui.display;
   4771 }
   4772 
   4773 UIWindow *_UIFindWindow(Window window) {
   4774 	UIWindow *w = ui.windows;
   4775 
   4776 	while (w) {
   4777 		if (w->window == window) {
   4778 			return w;
   4779 		}
   4780 
   4781 		w = w->next;
   4782 	}
   4783 
   4784 	return NULL;
   4785 }
   4786 
   4787 void _UIClipboardWriteText(UIWindow *window, char *text) {
   4788 	UI_FREE(ui.pasteText);
   4789 	ui.pasteText = text;
   4790 	XSetSelectionOwner(ui.display, ui.clipboardID, window->window, 0);
   4791 }
   4792 
   4793 char *_UIClipboardReadTextStart(UIWindow *window, size_t *bytes) {
   4794 	Window clipboardOwner = XGetSelectionOwner(ui.display, ui.clipboardID);
   4795 
   4796 	if (clipboardOwner == None) {
   4797 		return NULL;
   4798 	}
   4799 
   4800 	if (_UIFindWindow(clipboardOwner)) {
   4801 		*bytes = strlen(ui.pasteText);
   4802 		char *copy = (char *) UI_MALLOC(*bytes);
   4803 		memcpy(copy, ui.pasteText, *bytes);
   4804 		return copy;
   4805 	}
   4806 
   4807 	XConvertSelection(ui.display, ui.clipboardID, XA_STRING, ui.xSelectionDataID, window->window, CurrentTime);
   4808 	XSync(ui.display, 0);
   4809 	XNextEvent(ui.display, &ui.copyEvent);
   4810 
   4811 	// Hack to get around the fact that PropertyNotify arrives before SelectionNotify.
   4812 	// We need PropertyNotify for incremental transfers.
   4813 	while (ui.copyEvent.type == PropertyNotify) {
   4814 		XNextEvent(ui.display, &ui.copyEvent);
   4815 	}
   4816 
   4817 	if (ui.copyEvent.type == SelectionNotify && ui.copyEvent.xselection.selection == ui.clipboardID && ui.copyEvent.xselection.property) {
   4818 		Atom target;
   4819 		// This `itemAmount` is actually `bytes_after_return`
   4820 		unsigned long size, itemAmount;
   4821 		char *data;
   4822 		int format;
   4823 		XGetWindowProperty(ui.copyEvent.xselection.display, ui.copyEvent.xselection.requestor, ui.copyEvent.xselection.property, 0L, ~0L, 0, 
   4824 				AnyPropertyType, &target, &format, &size, &itemAmount, (unsigned char **) &data);
   4825 
   4826 		// We have to allocate for incremental transfers but we don't have to allocate for non-incremental transfers.
   4827 		// I'm allocating for both here to make _UIClipboardReadTextEnd work the same for both
   4828 		if (target != ui.incrID) {
   4829 			*bytes = size;
   4830 			char *copy = (char *) UI_MALLOC(*bytes);
   4831 			memcpy(copy, data, *bytes);
   4832 			XFree(data);
   4833 			XDeleteProperty(ui.copyEvent.xselection.display, ui.copyEvent.xselection.requestor, ui.copyEvent.xselection.property);
   4834 			return copy;
   4835 		}
   4836 
   4837 		XFree(data);
   4838 		XDeleteProperty(ui.display, ui.copyEvent.xselection.requestor, ui.copyEvent.xselection.property);
   4839 		XSync(ui.display, 0);
   4840 
   4841 		*bytes = 0;
   4842 		char *fullData = NULL;
   4843 
   4844 		while (true) {
   4845 			// TODO Timeout.
   4846 			XNextEvent(ui.display, &ui.copyEvent);
   4847 
   4848 			if (ui.copyEvent.type == PropertyNotify) {
   4849 				// The other case - PropertyDelete would be caused by us and can be ignored
   4850 				if (ui.copyEvent.xproperty.state == PropertyNewValue) {
   4851 					unsigned long chunkSize;
   4852 
   4853 					// Note that this call deletes the property.
   4854 					XGetWindowProperty(ui.display, ui.copyEvent.xproperty.window, ui.copyEvent.xproperty.atom, 0L, ~0L, 
   4855 						True, AnyPropertyType, &target, &format, &chunkSize, &itemAmount, (unsigned char **) &data);
   4856 					
   4857 					if (chunkSize == 0) {
   4858 						return fullData;
   4859 					} else {
   4860 						ptrdiff_t currentOffset = *bytes;
   4861 						*bytes += chunkSize;
   4862 						fullData = (char *) UI_REALLOC(fullData, *bytes);
   4863 						memcpy(fullData + currentOffset, data, chunkSize);
   4864 					}
   4865 
   4866 					XFree(data);
   4867 				}
   4868 			}
   4869 		}
   4870 	} else {
   4871 		// TODO What should happen in this case? Is the next event always going to be the selection event?
   4872 		return NULL;
   4873 	}
   4874 }
   4875 
   4876 void _UIClipboardReadTextEnd(UIWindow *window, char *text) {
   4877 	if (text) {
   4878 		//XFree(text);
   4879 		//XDeleteProperty(ui.copyEvent.xselection.display, ui.copyEvent.xselection.requestor, ui.copyEvent.xselection.property);
   4880 		UI_FREE(text);
   4881 	}
   4882 }
   4883 
   4884 void UIInitialise() {
   4885 	_UIInitialiseCommon();
   4886 
   4887 	XInitThreads();
   4888 
   4889 	ui.display = XOpenDisplay(NULL);
   4890 	ui.visual = XDefaultVisual(ui.display, 0);
   4891 
   4892 	ui.windowClosedID = XInternAtom(ui.display, "WM_DELETE_WINDOW", 0);
   4893 	ui.primaryID = XInternAtom(ui.display, "PRIMARY", 0);
   4894 	ui.dndEnterID = XInternAtom(ui.display, "XdndEnter", 0);
   4895 	ui.dndPositionID = XInternAtom(ui.display, "XdndPosition", 0);
   4896 	ui.dndStatusID = XInternAtom(ui.display, "XdndStatus", 0);
   4897 	ui.dndActionCopyID = XInternAtom(ui.display, "XdndActionCopy", 0);
   4898 	ui.dndDropID = XInternAtom(ui.display, "XdndDrop", 0);
   4899 	ui.dndSelectionID = XInternAtom(ui.display, "XdndSelection", 0);
   4900 	ui.dndFinishedID = XInternAtom(ui.display, "XdndFinished", 0);
   4901 	ui.dndAwareID = XInternAtom(ui.display, "XdndAware", 0);
   4902 	ui.uriListID = XInternAtom(ui.display, "text/uri-list", 0);
   4903 	ui.plainTextID = XInternAtom(ui.display, "text/plain", 0);
   4904 	ui.clipboardID = XInternAtom(ui.display, "CLIPBOARD", 0);
   4905 	ui.xSelectionDataID = XInternAtom(ui.display, "XSEL_DATA", 0);
   4906 	ui.textID = XInternAtom(ui.display, "TEXT", 0);
   4907 	ui.targetID = XInternAtom(ui.display, "TARGETS", 0);
   4908 	ui.incrID = XInternAtom(ui.display, "INCR", 0);
   4909 
   4910 	ui.cursors[UI_CURSOR_ARROW] = XCreateFontCursor(ui.display, XC_left_ptr);
   4911 	ui.cursors[UI_CURSOR_TEXT] = XCreateFontCursor(ui.display, XC_xterm);
   4912 	ui.cursors[UI_CURSOR_SPLIT_V] = XCreateFontCursor(ui.display, XC_sb_v_double_arrow);
   4913 	ui.cursors[UI_CURSOR_SPLIT_H] = XCreateFontCursor(ui.display, XC_sb_h_double_arrow);
   4914 	ui.cursors[UI_CURSOR_FLIPPED_ARROW] = XCreateFontCursor(ui.display, XC_right_ptr);
   4915 	ui.cursors[UI_CURSOR_CROSS_HAIR] = XCreateFontCursor(ui.display, XC_crosshair);
   4916 	ui.cursors[UI_CURSOR_HAND] = XCreateFontCursor(ui.display, XC_hand1);
   4917 	ui.cursors[UI_CURSOR_RESIZE_UP] = XCreateFontCursor(ui.display, XC_top_side);
   4918 	ui.cursors[UI_CURSOR_RESIZE_LEFT] = XCreateFontCursor(ui.display, XC_left_side);
   4919 	ui.cursors[UI_CURSOR_RESIZE_UP_RIGHT] = XCreateFontCursor(ui.display, XC_top_right_corner);
   4920 	ui.cursors[UI_CURSOR_RESIZE_UP_LEFT] = XCreateFontCursor(ui.display, XC_top_left_corner);
   4921 	ui.cursors[UI_CURSOR_RESIZE_DOWN] = XCreateFontCursor(ui.display, XC_bottom_side);
   4922 	ui.cursors[UI_CURSOR_RESIZE_RIGHT] = XCreateFontCursor(ui.display, XC_right_side);
   4923 	ui.cursors[UI_CURSOR_RESIZE_DOWN_LEFT] = XCreateFontCursor(ui.display, XC_bottom_left_corner);
   4924 	ui.cursors[UI_CURSOR_RESIZE_DOWN_RIGHT] = XCreateFontCursor(ui.display, XC_bottom_right_corner);
   4925 
   4926 	XSetLocaleModifiers("");
   4927 
   4928 	ui.xim = XOpenIM(ui.display, 0, 0, 0);
   4929 
   4930 	if(!ui.xim){
   4931 		XSetLocaleModifiers("@im=none");
   4932 		ui.xim = XOpenIM(ui.display, 0, 0, 0);
   4933 	}
   4934 }
   4935 
   4936 void _UIWindowSetCursor(UIWindow *window, int cursor) {
   4937 	XDefineCursor(ui.display, window->window, ui.cursors[cursor]);
   4938 }
   4939 
   4940 void _UIX11ResetCursor(UIWindow *window) {
   4941 	XDefineCursor(ui.display, window->window, ui.cursors[UI_CURSOR_ARROW]);
   4942 }
   4943 
   4944 void _UIWindowEndPaint(UIWindow *window, UIPainter *painter) {
   4945 	(void) painter;
   4946 
   4947 	XPutImage(ui.display, window->window, DefaultGC(ui.display, 0), window->image, 
   4948 		UI_RECT_TOP_LEFT(window->updateRegion), UI_RECT_TOP_LEFT(window->updateRegion),
   4949 		UI_RECT_SIZE(window->updateRegion));
   4950 }
   4951 
   4952 void _UIWindowGetScreenPosition(UIWindow *window, int *_x, int *_y) {
   4953 	Window child;
   4954 	XTranslateCoordinates(ui.display, window->window, DefaultRootWindow(ui.display), 0, 0, _x, _y, &child);
   4955 }
   4956 
   4957 void UIMenuShow(UIMenu *menu) {
   4958 	int width, height;
   4959 	_UIMenuPrepare(menu, &width, &height);
   4960 
   4961 	for (int i = 0; i < ScreenCount(ui.display); i++) {
   4962 		Screen *screen = ScreenOfDisplay(ui.display, i);
   4963 
   4964 		int x, y;
   4965 		Window child;
   4966 		XTranslateCoordinates(ui.display, screen->root, DefaultRootWindow(ui.display), 0, 0, &x, &y, &child);
   4967 
   4968 		if (menu->pointX >= x && menu->pointX < x + screen->width 
   4969 				&& menu->pointY >= y && menu->pointY < y + screen->height) {
   4970 			if (menu->pointX + width > x + screen->width) menu->pointX = x + screen->width - width;
   4971 			if (menu->pointY + height > y + screen->height) menu->pointY = y + screen->height - height;
   4972 			if (menu->pointX < x) menu->pointX = x;
   4973 			if (menu->pointY < y) menu->pointY = y;
   4974 			if (menu->pointX + width > x + screen->width) width = x + screen->width - menu->pointX;
   4975 			if (menu->pointY + height > y + screen->height) height = y + screen->height - menu->pointY;
   4976 			break;
   4977 		}
   4978 	}
   4979 
   4980 	Atom properties[] = {
   4981 		XInternAtom(ui.display, "_NET_WM_WINDOW_TYPE", true),
   4982 		XInternAtom(ui.display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", true),
   4983 		XInternAtom(ui.display, "_MOTIF_WM_HINTS", true),
   4984 	};
   4985 
   4986 	XChangeProperty(ui.display, menu->e.window->window, properties[0], XA_ATOM, 32, PropModeReplace, (uint8_t *) properties, 2);
   4987 	XSetTransientForHint(ui.display, menu->e.window->window, DefaultRootWindow(ui.display));
   4988 
   4989 	struct Hints {
   4990 		int flags;
   4991 		int functions;
   4992 		int decorations;
   4993 		int inputMode;
   4994 		int status;
   4995 	};
   4996 
   4997 	struct Hints hints = { 0 };
   4998 	hints.flags = 2;
   4999 	XChangeProperty(ui.display, menu->e.window->window, properties[2], properties[2], 32, PropModeReplace, (uint8_t *) &hints, 5);
   5000 
   5001 	XMapWindow(ui.display, menu->e.window->window);
   5002 	XMoveResizeWindow(ui.display, menu->e.window->window, menu->pointX, menu->pointY, width, height);
   5003 }
   5004 
   5005 void UIWindowPack(UIWindow *window, int _width) {
   5006 	int width = _width ? _width : UIElementMessage(window->e.children, UI_MSG_GET_WIDTH, 0, 0);
   5007 	int height = UIElementMessage(window->e.children, UI_MSG_GET_HEIGHT, width, 0);
   5008 	XResizeWindow(ui.display, window->window, width, height);
   5009 }
   5010 
   5011 bool _UIProcessEvent(XEvent *event) {
   5012 	if (event->type == ClientMessage && (Atom) event->xclient.data.l[0] == ui.windowClosedID) {
   5013 		UIWindow *window = _UIFindWindow(event->xclient.window);
   5014 		if (!window) return false;
   5015 		bool exit = !UIElementMessage(&window->e, UI_MSG_WINDOW_CLOSE, 0, 0);
   5016 		if (exit) return true;
   5017 		_UIUpdate();
   5018 		return false;
   5019 	} else if (event->type == Expose) {
   5020 		UIWindow *window = _UIFindWindow(event->xexpose.window);
   5021 		if (!window) return false;
   5022 		XPutImage(ui.display, window->window, DefaultGC(ui.display, 0), window->image, 0, 0, 0, 0, window->width, window->height);
   5023 	} else if (event->type == ConfigureNotify) {
   5024 		UIWindow *window = _UIFindWindow(event->xconfigure.window);
   5025 		if (!window) return false;
   5026 
   5027 		if (window->width != event->xconfigure.width || window->height != event->xconfigure.height) {
   5028 			window->width = event->xconfigure.width;
   5029 			window->height = event->xconfigure.height;
   5030 			window->bits = (uint32_t *) UI_REALLOC(window->bits, window->width * window->height * 4);
   5031 			window->image->width = window->width;
   5032 			window->image->height = window->height;
   5033 			window->image->bytes_per_line = window->width * 4;
   5034 			window->image->data = (char *) window->bits;
   5035 			window->e.bounds = UI_RECT_2S(window->width, window->height);
   5036 			window->e.clip = UI_RECT_2S(window->width, window->height);
   5037 #ifdef UI_DEBUG
   5038 			for (int i = 0; i < window->width * window->height; i++) window->bits[i] = 0xFF00FF;
   5039 #endif
   5040 			UIElementMessage(&window->e, UI_MSG_LAYOUT, 0, 0);
   5041 			_UIUpdate();
   5042 		}
   5043 	} else if (event->type == MotionNotify) {
   5044 		UIWindow *window = _UIFindWindow(event->xmotion.window);
   5045 		if (!window) return false;
   5046 		window->cursorX = event->xmotion.x;
   5047 		window->cursorY = event->xmotion.y;
   5048 		_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5049 	} else if (event->type == LeaveNotify) {
   5050 		UIWindow *window = _UIFindWindow(event->xcrossing.window);
   5051 		if (!window) return false;
   5052 
   5053 		if (!window->pressed) {
   5054 			window->cursorX = -1;
   5055 			window->cursorY = -1;
   5056 		}
   5057 
   5058 		_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5059 	} else if (event->type == ButtonPress || event->type == ButtonRelease) {
   5060 		UIWindow *window = _UIFindWindow(event->xbutton.window);
   5061 		if (!window) return false;
   5062 		window->cursorX = event->xbutton.x;
   5063 		window->cursorY = event->xbutton.y;
   5064 
   5065 		if (event->xbutton.button >= 1 && event->xbutton.button <= 3) {
   5066 			_UIWindowInputEvent(window, (UIMessage) ((event->type == ButtonPress ? UI_MSG_LEFT_DOWN : UI_MSG_LEFT_UP) 
   5067 				+ event->xbutton.button * 2 - 2), 0, 0);
   5068 		} else if (event->xbutton.button == 4) {
   5069 			_UIWindowInputEvent(window, UI_MSG_MOUSE_WHEEL, -72, 0);
   5070 		} else if (event->xbutton.button == 5) {
   5071 			_UIWindowInputEvent(window, UI_MSG_MOUSE_WHEEL, 72, 0);
   5072 		}
   5073 
   5074 		_UIInspectorSetFocusedWindow(window);
   5075 	} else if (event->type == KeyPress) {
   5076 		UIWindow *window = _UIFindWindow(event->xkey.window);
   5077 		if (!window) return false;
   5078 
   5079 		if (event->xkey.x == 0x7123 && event->xkey.y == 0x7456) {
   5080 			// HACK! See UIWindowPostMessage.
   5081 			UIElementMessage(&window->e, (UIMessage) event->xkey.state, 0, 
   5082 				(void *) (((uintptr_t) (event->xkey.time & 0xFFFFFFFF) << 32) 
   5083 					| ((uintptr_t) (event->xkey.x_root & 0xFFFF) << 0) 
   5084 					| ((uintptr_t) (event->xkey.y_root & 0xFFFF) << 16)));
   5085 			_UIUpdate();
   5086 		} else {
   5087 			char text[32];
   5088 			KeySym symbol = NoSymbol;
   5089 			Status status;
   5090 			// printf("%ld, %s\n", symbol, text);
   5091 			UIKeyTyped m = { 0 };
   5092 			m.textBytes = Xutf8LookupString(window->xic, &event->xkey, text, sizeof(text) - 1, &symbol, &status); 
   5093 			m.text = text;
   5094 			m.code = XLookupKeysym(&event->xkey, 0);
   5095 
   5096 			if (symbol == XK_Control_L || symbol == XK_Control_R) {
   5097 				window->ctrl = true;
   5098 				window->ctrlCode = event->xkey.keycode;
   5099 				_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5100 			} else if (symbol == XK_Shift_L || symbol == XK_Shift_R) {
   5101 				window->shift = true;
   5102 				window->shiftCode = event->xkey.keycode;
   5103 				_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5104 			} else if (symbol == XK_Alt_L || symbol == XK_Alt_R) {
   5105 				window->alt = true;
   5106 				window->altCode = event->xkey.keycode;
   5107 				_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5108 			} else if (symbol == XK_KP_Left) {
   5109 				m.code = UI_KEYCODE_LEFT;
   5110 			} else if (symbol == XK_KP_Right) {
   5111 				m.code = UI_KEYCODE_RIGHT;
   5112 			} else if (symbol == XK_KP_Up) {
   5113 				m.code = UI_KEYCODE_UP;
   5114 			} else if (symbol == XK_KP_Down) {
   5115 				m.code = UI_KEYCODE_DOWN;
   5116 			} else if (symbol == XK_KP_Home) {
   5117 				m.code = UI_KEYCODE_HOME;
   5118 			} else if (symbol == XK_KP_End) {
   5119 				m.code = UI_KEYCODE_END;
   5120 			} else if (symbol == XK_KP_Enter) {
   5121 				m.code = UI_KEYCODE_ENTER;
   5122 			} else if (symbol == XK_KP_Delete) {
   5123 				m.code = UI_KEYCODE_DELETE;
   5124 			}
   5125 
   5126 			_UIWindowInputEvent(window, UI_MSG_KEY_TYPED, 0, &m);
   5127 		}
   5128 	} else if (event->type == KeyRelease) {
   5129 		UIWindow *window = _UIFindWindow(event->xkey.window);
   5130 		if (!window) return false;
   5131 
   5132 		if (event->xkey.keycode == window->ctrlCode) {
   5133 			window->ctrl = false;
   5134 			_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5135 		} else if (event->xkey.keycode == window->shiftCode) {
   5136 			window->shift = false;
   5137 			_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5138 		} else if (event->xkey.keycode == window->altCode) {
   5139 			window->alt = false;
   5140 			_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5141 		}
   5142 	} else if (event->type == FocusIn) {
   5143 		UIWindow *window = _UIFindWindow(event->xfocus.window);
   5144 		if (!window) return false;
   5145 		window->ctrl = window->shift = window->alt = false;
   5146 		UIElementMessage(&window->e, UI_MSG_WINDOW_ACTIVATE, 0, 0);
   5147 	} else if (event->type == ClientMessage && event->xclient.message_type == ui.dndEnterID) {
   5148 		UIWindow *window = _UIFindWindow(event->xclient.window);
   5149 		if (!window) return false;
   5150 		window->dragSource = (Window) event->xclient.data.l[0];
   5151 	} else if (event->type == ClientMessage && event->xclient.message_type == ui.dndPositionID) {
   5152 		UIWindow *window = _UIFindWindow(event->xclient.window);
   5153 		if (!window) return false;
   5154 		XClientMessageEvent m = { 0 };
   5155 		m.type = ClientMessage;
   5156 		m.display = event->xclient.display;
   5157 		m.window = (Window) event->xclient.data.l[0];
   5158 		m.message_type = ui.dndStatusID;
   5159 		m.format = 32;
   5160 		m.data.l[0] = window->window;
   5161 		m.data.l[1] = true;
   5162 		m.data.l[4] = ui.dndActionCopyID;
   5163 		XSendEvent(ui.display, m.window, False, NoEventMask, (XEvent *) &m);
   5164 		XFlush(ui.display);
   5165 	} else if (event->type == ClientMessage && event->xclient.message_type == ui.dndDropID) {
   5166 		UIWindow *window = _UIFindWindow(event->xclient.window);
   5167 		if (!window) return false;
   5168 
   5169 		// TODO Dropping text.
   5170 
   5171 		if (!XConvertSelection(ui.display, ui.dndSelectionID, ui.uriListID, ui.primaryID, window->window, event->xclient.data.l[2])) {
   5172 			XClientMessageEvent m = { 0 };
   5173 			m.type = ClientMessage;
   5174 			m.display = ui.display;
   5175 			m.window = window->dragSource;
   5176 			m.message_type = ui.dndFinishedID;
   5177 			m.format = 32;
   5178 			m.data.l[0] = window->window;
   5179 			m.data.l[1] = 0;
   5180 			m.data.l[2] = ui.dndActionCopyID;
   5181 			XSendEvent(ui.display, m.window, False, NoEventMask, (XEvent *) &m);
   5182 			XFlush(ui.display);
   5183 		}
   5184 	} else if (event->type == SelectionNotify) {
   5185 		UIWindow *window = _UIFindWindow(event->xselection.requestor);
   5186 		if (!window) return false;
   5187 		if (!window->dragSource) return false;
   5188 
   5189 		Atom type = None;
   5190 		int format = 0;
   5191 		uint64_t count = 0, bytesLeft = 0;
   5192 		uint8_t *data = NULL;
   5193 		XGetWindowProperty(ui.display, window->window, ui.primaryID, 0, 65536, False, AnyPropertyType, &type, &format, &count, &bytesLeft, &data);
   5194 
   5195 		if (format == 8 /* bits per character */) {
   5196 			if (event->xselection.target == ui.uriListID) {
   5197 				char *copy = (char *) UI_MALLOC(count);
   5198 				int fileCount = 0;
   5199 
   5200 				for (int i = 0; i < (int) count; i++) {
   5201 					copy[i] = data[i];
   5202 
   5203 					if (i && data[i - 1] == '\r' && data[i] == '\n') {
   5204 						fileCount++;
   5205 					}
   5206 				}
   5207 
   5208 				char **files = (char **) UI_MALLOC(sizeof(char *) * fileCount);
   5209 				fileCount = 0;
   5210 
   5211 				for (int i = 0; i < (int) count; i++) {
   5212 					char *s = copy + i;
   5213 					while (!(i && data[i - 1] == '\r' && data[i] == '\n' && i < (int) count)) i++;
   5214 					copy[i - 1] = 0;
   5215 
   5216 					for (int j = 0; s[j]; j++) {
   5217 						if (s[j] == '%' && s[j + 1] && s[j + 2]) {
   5218 							char n[3];
   5219 							n[0] = s[j + 1], n[1] = s[j + 2], n[2] = 0;
   5220 							s[j] = strtol(n, NULL, 16);
   5221 							if (!s[j]) break;
   5222 							memmove(s + j + 1, s + j + 3, strlen(s) - j - 2);
   5223 						}
   5224 					}
   5225 
   5226 					if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e' && s[4] == ':' && s[5] == '/' && s[6] == '/') {
   5227 						files[fileCount++] = s + 7;
   5228 					}
   5229 				}
   5230 
   5231 				UIElementMessage(&window->e, UI_MSG_WINDOW_DROP_FILES, fileCount, files);
   5232 
   5233 				UI_FREE(files);
   5234 				UI_FREE(copy);
   5235 			} else if (event->xselection.target == ui.plainTextID) {
   5236 				// TODO.
   5237 			}
   5238 		}
   5239 
   5240 		XFree(data);
   5241 
   5242 		XClientMessageEvent m = { 0 };
   5243 		m.type = ClientMessage;
   5244 		m.display = ui.display;
   5245 		m.window = window->dragSource;
   5246 		m.message_type = ui.dndFinishedID;
   5247 		m.format = 32;
   5248 		m.data.l[0] = window->window;
   5249 		m.data.l[1] = true;
   5250 		m.data.l[2] = ui.dndActionCopyID;
   5251 		XSendEvent(ui.display, m.window, False, NoEventMask, (XEvent *) &m);
   5252 		XFlush(ui.display);
   5253 
   5254 		window->dragSource = 0; // Drag complete.
   5255 		_UIUpdate();
   5256 	} else if (event->type == SelectionRequest) {
   5257 		UIWindow *window = _UIFindWindow(event->xclient.window);
   5258 		if (!window) return false;
   5259 
   5260 		if ((XGetSelectionOwner(ui.display, ui.clipboardID) == window->window) 
   5261 				&& (event->xselectionrequest.selection == ui.clipboardID)) {
   5262 			XSelectionRequestEvent requestEvent = event->xselectionrequest;
   5263 			Atom utf8ID = XInternAtom(ui.display, "UTF8_STRING", 1);
   5264 			if (utf8ID == None) utf8ID = XA_STRING;
   5265 
   5266 			Atom type = requestEvent.target;
   5267 			type = (type == ui.textID) ? XA_STRING : type;
   5268 			int changePropertyResult = 0;
   5269 
   5270 			if(requestEvent.target == XA_STRING || requestEvent.target == ui.textID || requestEvent.target == utf8ID) {
   5271 				changePropertyResult = XChangeProperty(requestEvent.display, requestEvent.requestor, requestEvent.property, 
   5272 						type, 8, PropModeReplace, (const unsigned char *) ui.pasteText, strlen(ui.pasteText));
   5273 			} else if (requestEvent.target == ui.targetID) {
   5274 				changePropertyResult = XChangeProperty(requestEvent.display, requestEvent.requestor, requestEvent.property, 
   5275 						XA_ATOM, 32, PropModeReplace, (unsigned char *) &utf8ID, 1);
   5276 			}
   5277 
   5278 			if(changePropertyResult == 0 || changePropertyResult == 1) {
   5279 				XSelectionEvent sendEvent = {
   5280 					.type = SelectionNotify,
   5281 					.serial = requestEvent.serial,
   5282 					.send_event = requestEvent.send_event,
   5283 					.display = requestEvent.display,
   5284 					.requestor = requestEvent.requestor,
   5285 					.selection = requestEvent.selection,
   5286 					.target = requestEvent.target,
   5287 					.property = requestEvent.property,
   5288 					.time = requestEvent.time
   5289 				};
   5290 
   5291 				XSendEvent(ui.display, requestEvent.requestor, 0, 0, (XEvent *) &sendEvent);
   5292 			}
   5293 		}
   5294 	}
   5295 
   5296 	return false;
   5297 }
   5298 
   5299 bool _UIMessageLoopSingle(int *result) {
   5300 	XEvent events[64];
   5301 
   5302 	if (ui.animating) {
   5303 		if (XPending(ui.display)) {
   5304 			XNextEvent(ui.display, events + 0);
   5305 		} else {
   5306 			_UIProcessAnimations();
   5307 			return true;
   5308 		}
   5309 	} else {
   5310 		XNextEvent(ui.display, events + 0);
   5311 	}
   5312 
   5313 	int p = 1;
   5314 
   5315 	int configureIndex = -1, motionIndex = -1, exposeIndex = -1;
   5316 
   5317 	while (p < 64 && XPending(ui.display)) {
   5318 		XNextEvent(ui.display, events + p);
   5319 
   5320 #define _UI_MERGE_EVENTS(a, b) \
   5321 	if (events[p].type == a) { \
   5322 		if (b != -1) events[b].type = 0; \
   5323 		b = p; \
   5324 	}
   5325 
   5326 		_UI_MERGE_EVENTS(ConfigureNotify, configureIndex);
   5327 		_UI_MERGE_EVENTS(MotionNotify, motionIndex);
   5328 		_UI_MERGE_EVENTS(Expose, exposeIndex);
   5329 
   5330 		p++;
   5331 	}
   5332 
   5333 	for (int i = 0; i < p; i++) {
   5334 		if (!events[i].type) {
   5335 			continue;
   5336 		}
   5337 
   5338 		if (_UIProcessEvent(events + i)) {
   5339 			return false;
   5340 		}
   5341 	}
   5342 
   5343 	return true;
   5344 }
   5345 
   5346 void UIWindowPostMessage(UIWindow *window, UIMessage message, void *_dp) {
   5347 	// HACK! Xlib doesn't seem to have a nice way to do this,
   5348 	// so send a specially crafted key press event instead.
   5349 	// TODO Maybe ClientMessage is what this should use?
   5350 	uintptr_t dp = (uintptr_t) _dp;
   5351 	XKeyEvent event = { 0 };
   5352 	event.display = ui.display;
   5353 	event.window = window->window;
   5354 	event.root = DefaultRootWindow(ui.display);
   5355 	event.subwindow = None;
   5356 	event.time = dp >> 32;
   5357 	event.x = 0x7123;
   5358 	event.y = 0x7456;
   5359 	event.x_root = (dp >> 0) & 0xFFFF;
   5360 	event.y_root = (dp >> 16) & 0xFFFF;
   5361 	event.same_screen = True;
   5362 	event.keycode = 1;
   5363 	event.state = message;
   5364 	event.type = KeyPress;
   5365 	XSendEvent(ui.display, window->window, True, KeyPressMask, (XEvent *) &event);
   5366 	XFlush(ui.display);
   5367 }
   5368 
   5369 #endif
   5370 
   5371 #ifdef UI_WINDOWS
   5372 
   5373 const int UI_KEYCODE_A = 'A';
   5374 const int UI_KEYCODE_0 = '0';
   5375 const int UI_KEYCODE_BACKSPACE = VK_BACK;
   5376 const int UI_KEYCODE_DELETE = VK_DELETE;
   5377 const int UI_KEYCODE_DOWN = VK_DOWN;
   5378 const int UI_KEYCODE_END = VK_END;
   5379 const int UI_KEYCODE_ENTER = VK_RETURN;
   5380 const int UI_KEYCODE_ESCAPE = VK_ESCAPE;
   5381 const int UI_KEYCODE_F1 = VK_F1;
   5382 const int UI_KEYCODE_HOME = VK_HOME;
   5383 const int UI_KEYCODE_LEFT = VK_LEFT;
   5384 const int UI_KEYCODE_RIGHT = VK_RIGHT;
   5385 const int UI_KEYCODE_SPACE = VK_SPACE;
   5386 const int UI_KEYCODE_TAB = VK_TAB;
   5387 const int UI_KEYCODE_UP = VK_UP;
   5388 const int UI_KEYCODE_INSERT = VK_INSERT;
   5389 
   5390 int _UIWindowMessage(UIElement *element, UIMessage message, int di, void *dp) {
   5391 	if (message == UI_MSG_DESTROY) {
   5392 		UIWindow *window = (UIWindow *) element;
   5393 		_UIWindowDestroyCommon(window);
   5394 		SetWindowLongPtr(window->hwnd, GWLP_USERDATA, 0);
   5395 		DestroyWindow(window->hwnd);
   5396 	}
   5397 
   5398 	return _UIWindowMessageCommon(element, message, di, dp);
   5399 }
   5400 
   5401 LRESULT CALLBACK _UIWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
   5402 	UIWindow *window = (UIWindow *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
   5403 
   5404 	if (!window || ui.assertionFailure) {
   5405 		return DefWindowProc(hwnd, message, wParam, lParam);
   5406 	}
   5407 
   5408 	if (message == WM_CLOSE) {
   5409 		if (UIElementMessage(&window->e, UI_MSG_WINDOW_CLOSE, 0, 0)) {
   5410 			_UIUpdate();
   5411 			return 0;
   5412 		} else {
   5413 			PostQuitMessage(0);
   5414 		}
   5415 	} else if (message == WM_SIZE) {
   5416 		RECT client;
   5417 		GetClientRect(hwnd, &client);
   5418 		window->width = client.right;
   5419 		window->height = client.bottom;
   5420 		window->bits = (uint32_t *) UI_REALLOC(window->bits, window->width * window->height * 4);
   5421 		window->e.bounds = UI_RECT_2S(window->width, window->height);
   5422 		window->e.clip = UI_RECT_2S(window->width, window->height);
   5423 		UIElementMessage(&window->e, UI_MSG_LAYOUT, 0, 0);
   5424 		_UIUpdate();
   5425 	} else if (message == WM_MOUSEMOVE) {
   5426 		if (!window->trackingLeave) {
   5427 			window->trackingLeave = true;
   5428 			TRACKMOUSEEVENT leave = { 0 };
   5429 			leave.cbSize = sizeof(TRACKMOUSEEVENT);
   5430 			leave.dwFlags = TME_LEAVE;
   5431 			leave.hwndTrack = hwnd;
   5432 			TrackMouseEvent(&leave);
   5433 		}
   5434 
   5435 		POINT cursor;
   5436 		GetCursorPos(&cursor);
   5437 		ScreenToClient(hwnd, &cursor);
   5438 		window->cursorX = cursor.x;
   5439 		window->cursorY = cursor.y;
   5440 		_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5441 	} else if (message == WM_MOUSELEAVE) {
   5442 		window->trackingLeave = false;
   5443 
   5444 		if (!window->pressed) {
   5445 			window->cursorX = -1;
   5446 			window->cursorY = -1;
   5447 		}
   5448 
   5449 		_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5450 	} else if (message == WM_LBUTTONDOWN) {
   5451 		SetCapture(hwnd);
   5452 		_UIWindowInputEvent(window, UI_MSG_LEFT_DOWN, 0, 0);
   5453 	} else if (message == WM_LBUTTONUP) {
   5454 		if (window->pressedButton == 1) ReleaseCapture();
   5455 		_UIWindowInputEvent(window, UI_MSG_LEFT_UP, 0, 0);
   5456 	} else if (message == WM_MBUTTONDOWN) {
   5457 		SetCapture(hwnd);
   5458 		_UIWindowInputEvent(window, UI_MSG_MIDDLE_DOWN, 0, 0);
   5459 	} else if (message == WM_MBUTTONUP) {
   5460 		if (window->pressedButton == 2) ReleaseCapture();
   5461 		_UIWindowInputEvent(window, UI_MSG_MIDDLE_UP, 0, 0);
   5462 	} else if (message == WM_RBUTTONDOWN) {
   5463 		SetCapture(hwnd);
   5464 		_UIWindowInputEvent(window, UI_MSG_RIGHT_DOWN, 0, 0);
   5465 	} else if (message == WM_RBUTTONUP) {
   5466 		if (window->pressedButton == 3) ReleaseCapture();
   5467 		_UIWindowInputEvent(window, UI_MSG_RIGHT_UP, 0, 0);
   5468 	} else if (message == WM_MOUSEWHEEL) {
   5469 		int delta = (int) wParam >> 16;
   5470 		_UIWindowInputEvent(window, UI_MSG_MOUSE_WHEEL, -delta, 0);
   5471 	} else if (message == WM_KEYDOWN) {
   5472 		window->ctrl = GetKeyState(VK_CONTROL) & 0x8000;
   5473 		window->shift = GetKeyState(VK_SHIFT) & 0x8000;
   5474 		window->alt = GetKeyState(VK_MENU) & 0x8000;
   5475 
   5476 		UIKeyTyped m = { 0 };
   5477 		m.code = wParam;
   5478 		_UIWindowInputEvent(window, UI_MSG_KEY_TYPED, 0, &m);
   5479 	} else if (message == WM_CHAR) {
   5480 		UIKeyTyped m = { 0 };
   5481 		char c = wParam;
   5482 		m.text = &c;
   5483 		m.textBytes = 1;
   5484 		_UIWindowInputEvent(window, UI_MSG_KEY_TYPED, 0, &m);
   5485 	} else if (message == WM_PAINT) {
   5486 		PAINTSTRUCT paint;
   5487 		HDC dc = BeginPaint(hwnd, &paint);
   5488 		BITMAPINFOHEADER info = { 0 };
   5489 		info.biSize = sizeof(info);
   5490 		info.biWidth = window->width, info.biHeight = -window->height;
   5491 		info.biPlanes = 1, info.biBitCount = 32;
   5492 		StretchDIBits(dc, 0, 0, UI_RECT_SIZE(window->e.bounds), 0, 0, UI_RECT_SIZE(window->e.bounds),
   5493 			window->bits, (BITMAPINFO *) &info, DIB_RGB_COLORS, SRCCOPY);
   5494 		EndPaint(hwnd, &paint);
   5495 	} else if (message == WM_SETCURSOR && LOWORD(lParam) == HTCLIENT) {
   5496 		SetCursor(ui.cursors[window->cursorStyle]);
   5497 		return 1;
   5498 	} else if (message == WM_SETFOCUS || message == WM_KILLFOCUS) {
   5499 		_UIMenusClose();
   5500 
   5501 		if (message == WM_SETFOCUS) {
   5502 			_UIInspectorSetFocusedWindow(window);
   5503 			UIElementMessage(&window->e, UI_MSG_WINDOW_ACTIVATE, 0, 0);
   5504 		}
   5505 	} else if (message == WM_MOUSEACTIVATE && (window->e.flags & UI_WINDOW_MENU)) {
   5506 		return MA_NOACTIVATE;
   5507 	} else if (message == WM_DROPFILES) {
   5508 		HDROP drop = (HDROP) wParam;
   5509 		int count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
   5510 		char **files = (char **) UI_MALLOC(sizeof(char *) * count);
   5511 		
   5512 		for (int i = 0; i < count; i++) {
   5513 			int length = DragQueryFile(drop, i, NULL, 0);
   5514 			files[i] = (char *) UI_MALLOC(length + 1);
   5515 			files[i][length] = 0;
   5516 			DragQueryFile(drop, i, files[i], length + 1);
   5517 		}
   5518 		
   5519 		UIElementMessage(&window->e, UI_MSG_WINDOW_DROP_FILES, count, files);
   5520 		for (int i = 0; i < count; i++) UI_FREE(files[i]);		
   5521 		UI_FREE(files);
   5522 		DragFinish(drop);
   5523 		_UIUpdate();
   5524 	} else if (message == WM_APP + 1) {
   5525 		UIElementMessage(&window->e, (UIMessage) wParam, 0, (void *) lParam);
   5526 		_UIUpdate();
   5527 	} else {
   5528 		if (message == WM_NCLBUTTONDOWN || message == WM_NCMBUTTONDOWN || message == WM_NCRBUTTONDOWN) {
   5529 			if (~window->e.flags & UI_WINDOW_MENU) {
   5530 				_UIMenusClose();
   5531 				_UIUpdate();
   5532 			}
   5533 		}
   5534 
   5535 		return DefWindowProc(hwnd, message, wParam, lParam);
   5536 	}
   5537 
   5538 	return 0;
   5539 }
   5540 
   5541 void UIInitialise() {
   5542 	ui.heap = GetProcessHeap();
   5543 	
   5544 	_UIInitialiseCommon();
   5545 
   5546 	ui.cursors[UI_CURSOR_ARROW] = LoadCursor(NULL, IDC_ARROW);
   5547 	ui.cursors[UI_CURSOR_TEXT] = LoadCursor(NULL, IDC_IBEAM);
   5548 	ui.cursors[UI_CURSOR_SPLIT_V] = LoadCursor(NULL, IDC_SIZENS);
   5549 	ui.cursors[UI_CURSOR_SPLIT_H] = LoadCursor(NULL, IDC_SIZEWE);
   5550 	ui.cursors[UI_CURSOR_FLIPPED_ARROW] = LoadCursor(NULL, IDC_ARROW);
   5551 	ui.cursors[UI_CURSOR_CROSS_HAIR] = LoadCursor(NULL, IDC_CROSS);
   5552 	ui.cursors[UI_CURSOR_HAND] = LoadCursor(NULL, IDC_HAND);
   5553 	ui.cursors[UI_CURSOR_RESIZE_UP] = LoadCursor(NULL, IDC_SIZENS);
   5554 	ui.cursors[UI_CURSOR_RESIZE_LEFT] = LoadCursor(NULL, IDC_SIZEWE);
   5555 	ui.cursors[UI_CURSOR_RESIZE_UP_RIGHT] = LoadCursor(NULL, IDC_SIZENESW);
   5556 	ui.cursors[UI_CURSOR_RESIZE_UP_LEFT] = LoadCursor(NULL, IDC_SIZENWSE);
   5557 	ui.cursors[UI_CURSOR_RESIZE_DOWN] = LoadCursor(NULL, IDC_SIZENS);
   5558 	ui.cursors[UI_CURSOR_RESIZE_RIGHT] = LoadCursor(NULL, IDC_SIZEWE);
   5559 	ui.cursors[UI_CURSOR_RESIZE_DOWN_LEFT] = LoadCursor(NULL, IDC_SIZENESW);
   5560 	ui.cursors[UI_CURSOR_RESIZE_DOWN_RIGHT] = LoadCursor(NULL, IDC_SIZENWSE);
   5561 
   5562 	WNDCLASS windowClass = { 0 };
   5563 	windowClass.lpfnWndProc = _UIWindowProcedure;
   5564 	windowClass.lpszClassName = "normal";
   5565 	RegisterClass(&windowClass);
   5566 	windowClass.style |= CS_DROPSHADOW;
   5567 	windowClass.lpszClassName = "shadow";
   5568 	RegisterClass(&windowClass);
   5569 }
   5570 
   5571 bool _UIMessageLoopSingle(int *result) {
   5572 	MSG message = { 0 };
   5573 
   5574 	if (ui.animating) {
   5575 		if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
   5576 			if (message.message == WM_QUIT) {
   5577 				*result = message.wParam;
   5578 				return false;
   5579 			}
   5580 
   5581 			TranslateMessage(&message);
   5582 			DispatchMessage(&message);
   5583 		} else {
   5584 			_UIProcessAnimations();
   5585 		}
   5586 	} else {
   5587 		if (!GetMessage(&message, NULL, 0, 0)) {
   5588 			*result = message.wParam;
   5589 			return false;
   5590 		}
   5591 
   5592 		TranslateMessage(&message);
   5593 		DispatchMessage(&message);
   5594 	}
   5595 
   5596 	return true;
   5597 }
   5598 
   5599 void UIMenuShow(UIMenu *menu) {
   5600 	int width, height;
   5601 	_UIMenuPrepare(menu, &width, &height);
   5602 	MoveWindow(menu->e.window->hwnd, menu->pointX, menu->pointY, width, height, FALSE);
   5603 	ShowWindow(menu->e.window->hwnd, SW_SHOWNOACTIVATE);
   5604 }
   5605 
   5606 UIWindow *UIWindowCreate(UIWindow *owner, uint32_t flags, const char *cTitle, int width, int height) {
   5607 	_UIMenusClose();
   5608 
   5609 	UIWindow *window = (UIWindow *) UIElementCreate(sizeof(UIWindow), NULL, flags | UI_ELEMENT_WINDOW, _UIWindowMessage, "Window");
   5610 	_UIWindowAdd(window);
   5611 	if (owner) window->scale = owner->scale;
   5612 
   5613 	if (flags & UI_WINDOW_MENU) {
   5614 		UI_ASSERT(owner);
   5615 
   5616 		window->hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_NOACTIVATE, "shadow", 0, WS_POPUP, 
   5617 			0, 0, 0, 0, owner->hwnd, NULL, NULL, NULL);
   5618 	} else {
   5619 		window->hwnd = CreateWindowEx(WS_EX_ACCEPTFILES, "normal", cTitle, WS_OVERLAPPEDWINDOW, 
   5620 			CW_USEDEFAULT, CW_USEDEFAULT, width ? width : CW_USEDEFAULT, height ? height : CW_USEDEFAULT,
   5621 			owner ? owner->hwnd : NULL, NULL, NULL, NULL);
   5622 	}
   5623 
   5624 	SetWindowLongPtr(window->hwnd, GWLP_USERDATA, (LONG_PTR) window);
   5625 
   5626 	if (~flags & UI_WINDOW_MENU) {
   5627 		ShowWindow(window->hwnd, SW_SHOW);
   5628 		PostMessage(window->hwnd, WM_SIZE, 0, 0);
   5629 	}
   5630 
   5631 	return window;
   5632 }
   5633 
   5634 void _UIWindowEndPaint(UIWindow *window, UIPainter *painter) {
   5635 	HDC dc = GetDC(window->hwnd);
   5636 	BITMAPINFOHEADER info = { 0 };
   5637 	info.biSize = sizeof(info);
   5638 	info.biWidth = window->width, info.biHeight = window->height;
   5639 	info.biPlanes = 1, info.biBitCount = 32;
   5640 	StretchDIBits(dc, 
   5641 		UI_RECT_TOP_LEFT(window->updateRegion), UI_RECT_SIZE(window->updateRegion), 
   5642 		window->updateRegion.l, window->updateRegion.b + 1, 
   5643 		UI_RECT_WIDTH(window->updateRegion), -UI_RECT_HEIGHT(window->updateRegion),
   5644 		window->bits, (BITMAPINFO *) &info, DIB_RGB_COLORS, SRCCOPY);
   5645 	ReleaseDC(window->hwnd, dc);
   5646 }
   5647 
   5648 void _UIWindowSetCursor(UIWindow *window, int cursor) {
   5649 	SetCursor(ui.cursors[cursor]);
   5650 }
   5651 
   5652 void _UIWindowGetScreenPosition(UIWindow *window, int *_x, int *_y) {
   5653 	POINT p;
   5654 	p.x = 0;
   5655 	p.y = 0;
   5656 	ClientToScreen(window->hwnd, &p);
   5657 	*_x = p.x;
   5658 	*_y = p.y;
   5659 }
   5660 
   5661 void UIWindowPostMessage(UIWindow *window, UIMessage message, void *_dp) {
   5662 	PostMessage(window->hwnd, WM_APP + 1, (WPARAM) message, (LPARAM) _dp);
   5663 }
   5664 
   5665 void *_UIHeapReAlloc(void *pointer, size_t size) {
   5666 	if (pointer) {
   5667 		if (size) {
   5668 			return HeapReAlloc(ui.heap, 0, pointer, size);
   5669 		} else {
   5670 			UI_FREE(pointer);
   5671 			return NULL;
   5672 		}
   5673 	} else {
   5674 		if (size) {
   5675 			return UI_MALLOC(size);
   5676 		} else {
   5677 			return NULL;
   5678 		}
   5679 	}
   5680 }
   5681 
   5682 void _UIClipboardWriteText(UIWindow *window, char *text) {
   5683 	if (OpenClipboard(window->hwnd)) {
   5684 		EmptyClipboard();
   5685 		HGLOBAL memory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, _UIStringLength(text) + 1);
   5686 		char *copy = (char *) GlobalLock(memory);
   5687 		for (uintptr_t i = 0; text[i]; i++) copy[i] = text[i];
   5688 		GlobalUnlock(copy);
   5689 		SetClipboardData(CF_TEXT, memory);
   5690 		CloseClipboard();
   5691 	}
   5692 }
   5693 
   5694 char *_UIClipboardReadTextStart(UIWindow *window, size_t *bytes) {
   5695 	if (!OpenClipboard(window->hwnd)) {
   5696 		return NULL;
   5697 	}
   5698 	
   5699 	HANDLE memory = GetClipboardData(CF_TEXT);
   5700 	
   5701 	if (!memory) {
   5702 		CloseClipboard();
   5703 		return NULL;
   5704 	}
   5705 	
   5706 	char *buffer = (char *) GlobalLock(memory);
   5707 	
   5708 	if (!buffer) {
   5709 		CloseClipboard();
   5710 		return NULL;
   5711 	}
   5712 	
   5713 	size_t byteCount = GlobalSize(memory);
   5714 	
   5715 	if (byteCount < 1) {
   5716 		GlobalUnlock(memory);
   5717 		CloseClipboard();
   5718 		return NULL;
   5719 	}
   5720 
   5721 	char *copy = (char *) UI_MALLOC(byteCount + 1);
   5722 	for (uintptr_t i = 0; i < byteCount; i++) copy[i] = buffer[i];
   5723 	copy[byteCount] = 0; // Just in case.
   5724 	
   5725 	GlobalUnlock(memory);
   5726 	CloseClipboard();
   5727 	
   5728 	if (bytes) *bytes = _UIStringLength(copy);
   5729 	return copy;
   5730 }
   5731 
   5732 void _UIClipboardReadTextEnd(UIWindow *window, char *text) {
   5733 	UI_FREE(text);
   5734 }
   5735 
   5736 #endif
   5737 
   5738 #ifdef UI_ESSENCE
   5739 
   5740 const int UI_KEYCODE_A = ES_SCANCODE_A;
   5741 const int UI_KEYCODE_0 = ES_SCANCODE_0;
   5742 const int UI_KEYCODE_BACKSPACE = ES_SCANCODE_BACKSPACE;
   5743 const int UI_KEYCODE_DELETE = ES_SCANCODE_DELETE;
   5744 const int UI_KEYCODE_DOWN = ES_SCANCODE_DOWN_ARROW;
   5745 const int UI_KEYCODE_END = ES_SCANCODE_END;
   5746 const int UI_KEYCODE_ENTER = ES_SCANCODE_ENTER;
   5747 const int UI_KEYCODE_ESCAPE = ES_SCANCODE_ESCAPE;
   5748 const int UI_KEYCODE_F1 = ES_SCANCODE_F1;
   5749 const int UI_KEYCODE_HOME = ES_SCANCODE_HOME;
   5750 const int UI_KEYCODE_LEFT = ES_SCANCODE_LEFT_ARROW;
   5751 const int UI_KEYCODE_RIGHT = ES_SCANCODE_RIGHT_ARROW;
   5752 const int UI_KEYCODE_SPACE = ES_SCANCODE_SPACE;
   5753 const int UI_KEYCODE_TAB = ES_SCANCODE_TAB;
   5754 const int UI_KEYCODE_UP = ES_SCANCODE_UP_ARROW;
   5755 const int UI_KEYCODE_INSERT = ES_SCANCODE_INSERT;
   5756 
   5757 int _UIWindowMessage(UIElement *element, UIMessage message, int di, void *dp) {
   5758 	if (message == UI_MSG_DESTROY) {
   5759 		// TODO Non-main windows.
   5760 		element->window = NULL;
   5761 		EsInstanceDestroy(ui.instance);
   5762 	}
   5763 
   5764 	return _UIWindowMessageCommon(element, message, di, dp);
   5765 }
   5766 
   5767 void UIInitialise() {
   5768 	_UIInitialiseCommon();
   5769 
   5770 	while (true) {
   5771 		EsMessage *message = EsMessageReceive();
   5772 
   5773 		if (message->type == ES_MSG_INSTANCE_CREATE) {
   5774 			ui.instance = EsInstanceCreate(message, NULL, 0);
   5775 			break;
   5776 		}
   5777 	}
   5778 }
   5779 
   5780 bool _UIMessageLoopSingle(int *result) {
   5781 	if (ui.animating) {
   5782 		// TODO.
   5783 	} else {
   5784 		_UIMessageProcess(EsMessageReceive());
   5785 	}
   5786 
   5787 	return true;
   5788 }
   5789 
   5790 UIMenu *UIMenuCreate(UIElement *parent, uint32_t flags) {
   5791 	ui.menuIndex = 0;
   5792 	return EsMenuCreate(parent->window->window, ES_MENU_AT_CURSOR);
   5793 }
   5794 
   5795 void _UIMenuItemCallback(EsMenu *menu, EsGeneric context) {
   5796 	((void (*)(void *)) ui.menuData[context.u * 2 + 0])(ui.menuData[context.u * 2 + 1]);
   5797 }
   5798 
   5799 void UIMenuAddItem(UIMenu *menu, uint32_t flags, const char *label, ptrdiff_t labelBytes, void (*invoke)(void *cp), void *cp) {
   5800 	EsAssert(ui.menuIndex < 128);
   5801 	ui.menuData[ui.menuIndex * 2 + 0] = (void *) invoke;
   5802 	ui.menuData[ui.menuIndex * 2 + 1] = cp;
   5803 	EsMenuAddItem(menu, (flags & UI_BUTTON_CHECKED) ? ES_MENU_ITEM_CHECKED : ES_FLAGS_DEFAULT, 
   5804 			label, labelBytes, _UIMenuItemCallback, ui.menuIndex);
   5805 	ui.menuIndex++;
   5806 }
   5807 
   5808 void UIMenuShow(UIMenu *menu) {
   5809 	EsMenuShow(menu);
   5810 }
   5811 
   5812 int _UIWindowCanvasMessage(EsElement *element, EsMessage *message) {
   5813 	UIWindow *window = (UIWindow *) element->window->userData.p;
   5814 
   5815 	if (!window) {
   5816 		return 0;
   5817 	} else if (message->type == ES_MSG_PAINT) {
   5818 		EsRectangle bounds = ES_RECT_4PD(message->painter->offsetX, message->painter->offsetY, window->width, window->height);
   5819 		EsDrawBitmap(message->painter, bounds, window->bits, window->width * 4, 0xFFFF);
   5820 	} else if (message->type == ES_MSG_LAYOUT) {
   5821 		EsElementGetSize(element, &window->width, &window->height);
   5822 		window->bits = (uint32_t *) UI_REALLOC(window->bits, window->width * window->height * 4);
   5823 		window->e.bounds = UI_RECT_2S(window->width, window->height);
   5824 		window->e.clip = UI_RECT_2S(window->width, window->height);
   5825 		UIElementMessage(&window->e, UI_MSG_LAYOUT, 0, 0);
   5826 		_UIUpdate();
   5827 	} else if (message->type == ES_MSG_SCROLL_WHEEL) {
   5828 		_UIWindowInputEvent(window, UI_MSG_MOUSE_WHEEL, -message->scrollWheel.dy, 0);
   5829 	} else if (message->type == ES_MSG_MOUSE_MOVED || message->type == ES_MSG_HOVERED_END
   5830 			|| message->type == ES_MSG_MOUSE_LEFT_DRAG || message->type == ES_MSG_MOUSE_RIGHT_DRAG || message->type == ES_MSG_MOUSE_MIDDLE_DRAG) {
   5831 		EsPoint point = EsMouseGetPosition(element); 
   5832 		window->cursorX = point.x, window->cursorY = point.y;
   5833 		_UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0);
   5834 	} else if (message->type == ES_MSG_KEY_UP) {
   5835 		window->ctrl = EsKeyboardIsCtrlHeld();
   5836 		window->shift = EsKeyboardIsShiftHeld();
   5837 		window->alt = EsKeyboardIsAltHeld();
   5838 	} else if (message->type == ES_MSG_KEY_DOWN) {
   5839 		window->ctrl = EsKeyboardIsCtrlHeld();
   5840 		window->shift = EsKeyboardIsShiftHeld();
   5841 		window->alt = EsKeyboardIsAltHeld();
   5842 		UIKeyTyped m = { 0 };
   5843 		char c[64];
   5844 		m.text = c;
   5845 		m.textBytes = EsMessageGetInputText(message, c);
   5846 		m.code = message->keyboard.scancode;
   5847 		return _UIWindowInputEvent(window, UI_MSG_KEY_TYPED, 0, &m) ? ES_HANDLED : 0;
   5848 	} else if (message->type == ES_MSG_MOUSE_LEFT_CLICK) {
   5849 		_UIInspectorSetFocusedWindow(window);
   5850 	} else if (message->type == ES_MSG_USER_START) {
   5851 		UIElementMessage(&window->e, (UIMessage) message->user.context1.u, 0, (void *) message->user.context2.p);
   5852 		_UIUpdate();
   5853 	} else if (message->type == ES_MSG_GET_CURSOR) {
   5854 		message->cursorStyle = ES_CURSOR_NORMAL;
   5855 		if (window->cursor == UI_CURSOR_TEXT)              message->cursorStyle = ES_CURSOR_TEXT;
   5856 		if (window->cursor == UI_CURSOR_SPLIT_V)           message->cursorStyle = ES_CURSOR_SPLIT_VERTICAL;
   5857 		if (window->cursor == UI_CURSOR_SPLIT_H)           message->cursorStyle = ES_CURSOR_SPLIT_HORIZONTAL;
   5858 		if (window->cursor == UI_CURSOR_FLIPPED_ARROW)     message->cursorStyle = ES_CURSOR_SELECT_LINES;
   5859 		if (window->cursor == UI_CURSOR_CROSS_HAIR)        message->cursorStyle = ES_CURSOR_CROSS_HAIR_PICK;
   5860 		if (window->cursor == UI_CURSOR_HAND)              message->cursorStyle = ES_CURSOR_HAND_HOVER;
   5861 		if (window->cursor == UI_CURSOR_RESIZE_UP)         message->cursorStyle = ES_CURSOR_RESIZE_VERTICAL;
   5862 		if (window->cursor == UI_CURSOR_RESIZE_LEFT)       message->cursorStyle = ES_CURSOR_RESIZE_HORIZONTAL;
   5863 		if (window->cursor == UI_CURSOR_RESIZE_UP_RIGHT)   message->cursorStyle = ES_CURSOR_RESIZE_DIAGONAL_1;
   5864 		if (window->cursor == UI_CURSOR_RESIZE_UP_LEFT)    message->cursorStyle = ES_CURSOR_RESIZE_DIAGONAL_2;
   5865 		if (window->cursor == UI_CURSOR_RESIZE_DOWN)       message->cursorStyle = ES_CURSOR_RESIZE_VERTICAL;
   5866 		if (window->cursor == UI_CURSOR_RESIZE_RIGHT)      message->cursorStyle = ES_CURSOR_RESIZE_HORIZONTAL;
   5867 		if (window->cursor == UI_CURSOR_RESIZE_DOWN_RIGHT) message->cursorStyle = ES_CURSOR_RESIZE_DIAGONAL_1;
   5868 		if (window->cursor == UI_CURSOR_RESIZE_DOWN_LEFT)  message->cursorStyle = ES_CURSOR_RESIZE_DIAGONAL_2;
   5869 	}
   5870 	
   5871 	else if (message->type == ES_MSG_MOUSE_LEFT_DOWN)   _UIWindowInputEvent(window, UI_MSG_LEFT_DOWN, 0, 0);
   5872 	else if (message->type == ES_MSG_MOUSE_LEFT_UP)     _UIWindowInputEvent(window, UI_MSG_LEFT_UP, 0, 0);
   5873 	else if (message->type == ES_MSG_MOUSE_MIDDLE_DOWN) _UIWindowInputEvent(window, UI_MSG_MIDDLE_DOWN, 0, 0);
   5874 	else if (message->type == ES_MSG_MOUSE_MIDDLE_UP)   _UIWindowInputEvent(window, UI_MSG_MIDDLE_UP, 0, 0);
   5875 	else if (message->type == ES_MSG_MOUSE_RIGHT_DOWN)  _UIWindowInputEvent(window, UI_MSG_RIGHT_DOWN, 0, 0);
   5876 	else if (message->type == ES_MSG_MOUSE_RIGHT_UP)    _UIWindowInputEvent(window, UI_MSG_RIGHT_UP, 0, 0);
   5877 
   5878 	else return 0;
   5879 
   5880 	return ES_HANDLED;
   5881 }
   5882 
   5883 UIWindow *UIWindowCreate(UIWindow *owner, uint32_t flags, const char *cTitle, int width, int height) {
   5884 	_UIMenusClose();
   5885 
   5886 	UIWindow *window = (UIWindow *) UIElementCreate(sizeof(UIWindow), NULL, flags | UI_ELEMENT_WINDOW, _UIWindowMessage, "Window");
   5887 	_UIWindowAdd(window);
   5888 	if (owner) window->scale = owner->scale;
   5889 
   5890 	if (flags & UI_WINDOW_MENU) {
   5891 		// TODO.
   5892 	} else {
   5893 		// TODO Non-main windows.
   5894 		window->window = ui.instance->window;
   5895 		window->window->userData = window;
   5896 		window->canvas = EsCustomElementCreate(window->window, ES_CELL_FILL | ES_ELEMENT_FOCUSABLE);
   5897 		window->canvas->messageUser = _UIWindowCanvasMessage;
   5898 		EsWindowSetTitle(window->window, cTitle, -1);
   5899 		EsElementFocus(window->canvas);
   5900 	}
   5901 
   5902 	return window;
   5903 }
   5904 
   5905 void _UIWindowEndPaint(UIWindow *window, UIPainter *painter) {
   5906 	EsElementRepaint(window->canvas, &window->updateRegion);
   5907 }
   5908 
   5909 void _UIWindowSetCursor(UIWindow *window, int cursor) {
   5910 	window->cursor = cursor;
   5911 }
   5912 
   5913 void _UIWindowGetScreenPosition(UIWindow *window, int *_x, int *_y) {
   5914 	EsRectangle r = EsElementGetScreenBounds(window->window);
   5915 	*_x = r.l, *_y = r.t;
   5916 }
   5917 
   5918 void UIWindowPostMessage(UIWindow *window, UIMessage message, void *_dp) {
   5919 	EsMessage m = {};
   5920 	m.type = ES_MSG_USER_START;
   5921 	m.user.context1.u = message;
   5922 	m.user.context2.p = _dp;
   5923 	EsMessagePost(window->canvas, &m);
   5924 }
   5925 
   5926 void _UIClipboardWriteText(UIWindow *window, char *text) {
   5927 	EsClipboardAddText(ES_CLIPBOARD_PRIMARY, text, -1);
   5928 	UI_FREE(text);
   5929 }
   5930 
   5931 char *_UIClipboardReadTextStart(UIWindow *window, size_t *bytes) {
   5932 	return EsClipboardReadText(ES_CLIPBOARD_PRIMARY, bytes, NULL);
   5933 }
   5934 
   5935 void _UIClipboardReadTextEnd(UIWindow *window, char *text) {
   5936 	EsHeapFree(text);
   5937 }
   5938 
   5939 #endif
   5940 
   5941 #endif