/* Generated by: https://www.npmjs.com/package/jsfx-preprocessor */
@init
uix_round = 1;
/* temp */
//uix_hassetup = 0;
//uix_screenstack = 0;
uix_screenstack_step = 10 + 1/*UI_SCREEN: ID*/; // header + 10 vars
uix_screenstack_layercount = 10;
//uix_screenstack_currentlayer = 0;

//uix_drawconfig = 0;
uix_drawconfig_step = 27/*uix_DRAWCONFIG: RED, GREEN, BLUE, ALPHA, FONTBOLD, FONTITALIC, FONTINDEX, FONTFACE, FONTSIZE, RETINA_SCALING, CLIP_SCREEN, CLIP_LEFT, CLIP_WIDTH, CLIP_TOP, CLIP_HEIGHT, CLIP_ALPHA, LEFT, TOP, WIDTH, HEIGHT, HALIGN, VALIGN, HPADDING, VPADDING, SPLIT_DIRECTION, SPLIT_HEIGHT, SPLIT_WIDTH*/;
uix_drawconfig_count = 100;
//uix_drawconfig_current = 0;
//uix_drawconfig_currentindex = -1;
//uix_screen_reservations = 0;

//uix_reserved_end = 0;

//uix_mousecap_prev = 0;
uix_mouseblocked = 0;
uix_doubleclicktime = 0.2;
uix_draglimit = 10;
uix_click1count = uix_click2count = uix_click64count = 0;
uix_click1 = uix_click2 = uix_click64 = 0;
uix_unclick1 = uix_unclick2 = uix_unclick64 = 0;
uix_click1_x = uix_click1_y = uix_click1_t = 0; // Left
uix_click2_x = uix_click2_y = uix_click2_t = 0; // Right
uix_click64_x = uix_click64_y = uix_click64_t = 0; // Middle
uix_mouse_x = uix_prev_mouse_x = 0;
uix_mouse_y = uix_prev_mouse_y = 0;
uix_scroll_y = uix_scroll_x = 0;
uix_scroll_scale = 5000;
uix_drag_scale = 200;
uix_interacted = 0;

uix_default_fontsize = 16;
uix_default_fontface = "Arial";
uix_font_dirty = 0;
uix_latestchar = 0;
uix_char_consumed = 0;

// Used to work around what I think might be a JSFX bug, where srate is sometimes = 0 in @init, but only if @gfx is defined, the UI is displaying, *and* an earlier effect has set latency with pdc_delay.
uix_prev_srate = 44100;

uix_error = 0;
function uix_clamp255(v) (
	min(255, max(0, floor(v + 0.5)));
);
function uix_setgfxcolorrgba(r, g, b, a) local(m, s) (
	// Instead of per-channel clamp, we maintain hue at the expense of saturation and brightness
	m = min(min(0, r), min(g, b));
	r -= m;
	g -= m;
	b -= m;
	s = max(max(255, r), max(g, b));
	gfx_r = r/s;
	gfx_g = g/s;
	gfx_b = b/s;
	gfx_a = min(1, max(0, a));
	0;
);
function uix_setgfxcolor() (
	uix_setgfxcolorrgba(
		uix_drawconfig_current[0/*uix_DRAWCONFIG:RED*/],
		uix_drawconfig_current[1/*uix_DRAWCONFIG:GREEN*/],
		uix_drawconfig_current[2/*uix_DRAWCONFIG:BLUE*/],
		uix_drawconfig_current[3/*uix_DRAWCONFIG:ALPHA*/]
	);
);
function uix_clearcolor(r, g, b) (
	uix_clamp255(r) + 256*uix_clamp255(g) + 65536*uix_clamp255(b);
);
function uix_fontflags() local(bold, italic) (
	bold = uix_drawconfig_current[4/*uix_DRAWCONFIG:FONTBOLD*/];
	italic = uix_drawconfig_current[5/*uix_DRAWCONFIG:FONTITALIC*/];
	bold ? (
		italic ? 'bi' : 'b';
	) : (
		italic ? 'i' : '';
	);
);
function uix_setgfxfont() (
	uix_font_dirty || gfx_getfont() != uix_drawconfig_current[6/*uix_DRAWCONFIG:FONTINDEX*/] ? (
		uix_font_dirty = 0;
		uix_drawconfig_current[7/*uix_DRAWCONFIG:FONTFACE*/] == "bitmap" ? (
			gfx_setfont(0);
		) : (
			gfx_setfont(
				uix_drawconfig_current[6/*uix_DRAWCONFIG:FONTINDEX*/],
				uix_drawconfig_current[7/*uix_DRAWCONFIG:FONTFACE*/],
				uix_drawconfig_current[8/*uix_DRAWCONFIG:FONTSIZE*/]*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/],
				uix_fontflags()
			);
		);
	);
);
function uix_click_block() (
	uix_mouseblocked = 1;
	uix_click1count = uix_click2count = uix_click64count = 0;
	uix_click1 = uix_click2 = uix_click64 = 0;
	uix_unclick1 = uix_unclick2 = uix_unclick64 = 0;
	uix_click1_x = uix_click1_y = uix_click1_t = 0; // Left
	uix_click2_x = uix_click2_y = uix_click2_t = 0; // Right
	uix_click64_x = uix_click64_y = uix_click64_t = 0; // Middle
);
function uix_key_clear() (
	while (
		gfx_getchar() > 0;
	);
);

function ui_error(string) (
	uix_click_block();
	uix_key_clear();
	uix_screenstack_currentlayer = 0;
	uix_screenstack[0/*UI_SCREEN:ID*/] = "error";
	uix_error = uix_screenstack[1/*UI_SCREEN: ID*/] = string; // First argument
	0;
);

function ui_screen() (
	uix_hassetup
		? (uix_screenstack + uix_screenstack_step*uix_screenstack_currentlayer)[0]
		: "error";
);

function ui_screen_level() (
	uix_screenstack_currentlayer;
);

function ui_screen_open(id) local(i, screen) (
	uix_click_block();
	uix_key_clear();
	uix_screenstack_currentlayer += 1;
	uix_screenstack_currentlayer < uix_screenstack_layercount ? (
		screen = (uix_screenstack + uix_screenstack_step*uix_screenstack_currentlayer);
		screen[0] = id;
		i = 1;
		while (
			screen[i] = 0;
			i += 1;
			i < uix_screenstack_step;
		);
	) : ui_error("Too many screens - only 10 dialogs deep")
);

function ui_screen_close() (
	uix_click_block();
	uix_key_clear();
	uix_screenstack_currentlayer > 0 ? (
		uix_screenstack_currentlayer -= 1;
	) : ui_error("Cannot close top-level screen");
);

function ui_screen_arg(index) local(screen, offset) (
	screen = (uix_screenstack + uix_screenstack_step*uix_screenstack_currentlayer);
	offset = index + 1/*UI_SCREEN: ID*/;
	offset < uix_screenstack_step ? (
		screen[offset];
	) : (
		ui_error("Screens only have 10 arguments");
	);
);

function ui_screen_arg(index, value) local(screen, offset) (
	screen = (uix_screenstack + uix_screenstack_step*uix_screenstack_currentlayer);
	offset = index + 1;
	offset < uix_screenstack_step ? (
		screen[offset] = value;
	) : (
		ui_error("Screens only have 10 arguments");
	);
);

function uix_unreserved_screen_below(limit) (
	limit = (limit < 0) ? 127 : limit - 1;
	while (limit > 0 && uix_screen_reservations[limit]) (
		limit -= 1;
	);
	limit;
);

function ui_setup(stackstart) local(uix_screenstack_end, uix_drawconfig_end) (
	// Mitigate some gnarly behaviour - see uix_prev_srate at top
	!srate ? (
		srate = uix_prev_srate;
		debug.gnarly_srate_hack += 1;
	);
	uix_prev_srate = srate;

	!uix_hassetup || stackstart != uix_screenstack ? (
		uix_hassetup = 1;

		uix_screenstack = stackstart;
		uix_screenstack_currentlayer = 0;
		uix_screenstack_end = stackstart + uix_screenstack_step*uix_screenstack_layercount;

		uix_drawconfig = uix_screenstack_end;
		uix_drawconfig_end = uix_drawconfig + uix_drawconfig_step*uix_drawconfig_count;
		uix_reserved_end = uix_drawconfig_end;

		uix_screen_reservations = uix_reserved_end;
		uix_reserved_end += 128;

		// Stop the pre-processor complaining
		4/*UI_SPLIT_DIRECTION: TOP, BOTTOM, LEFT, RIGHT*/;
	);

	uix_reserved_end;
);

function ui_reserve_image(index) (
	uix_screen_reservations[index] = 1;
);

function ui_start(defaultScreen) local(i, click, clickdelta, imgW, imgH, retina_scaling) (
	uix_drawconfig_currentindex = 0;
	uix_drawconfig_current = uix_drawconfig;

	uix_hassetup ? (
		!ui_screen() ? (
			uix_screenstack_currentlayer = 0;
			i = 0;
			while (
				uix_screenstack[i] = 0;
				i += 1;
				i < uix_screenstack_step;
			);
			uix_screenstack[0] = defaultScreen;
		);

		gfx_dest = -1; // Draw to main screen
		gfx_mode = 0;
		gfx_a = 1;
		// Default colours
		gfx_clear = uix_clearcolor(242, 242, 242);

		retina_scaling = gfx_ext_retina ? gfx_ext_retina : 1;
		uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/] = retina_scaling;

		uix_drawconfig_current[10/*uix_DRAWCONFIG:CLIP_SCREEN*/] = -1;
		uix_drawconfig_current[11/*uix_DRAWCONFIG:CLIP_LEFT*/] = 0;
		uix_drawconfig_current[12/*uix_DRAWCONFIG:CLIP_WIDTH*/] = gfx_w;
		uix_drawconfig_current[13/*uix_DRAWCONFIG:CLIP_TOP*/] = 0;
		uix_drawconfig_current[14/*uix_DRAWCONFIG:CLIP_HEIGHT*/] = gfx_h;
		uix_drawconfig_current[15/*uix_DRAWCONFIG:CLIP_ALPHA*/] = 1;

		uix_drawconfig_current[0/*uix_DRAWCONFIG:RED*/] = 0;
		uix_drawconfig_current[1/*uix_DRAWCONFIG:GREEN*/] = 0;
		uix_drawconfig_current[2/*uix_DRAWCONFIG:BLUE*/] = 0;
		uix_drawconfig_current[3/*uix_DRAWCONFIG:ALPHA*/] = 1;

		uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] = 0;
		uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] = 0;
		uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] = gfx_w/retina_scaling;
		uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] = gfx_h/retina_scaling;
		uix_drawconfig_current[20/*uix_DRAWCONFIG:HALIGN*/] = 0.5;
		uix_drawconfig_current[21/*uix_DRAWCONFIG:VALIGN*/] = 0.5;
		uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/] = 10;
		uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/] = 8;

		uix_drawconfig_current[6/*uix_DRAWCONFIG:FONTINDEX*/] = 16;
		uix_drawconfig_current[7/*uix_DRAWCONFIG:FONTFACE*/] = uix_default_fontface;
		uix_drawconfig_current[8/*uix_DRAWCONFIG:FONTSIZE*/] = uix_default_fontsize;
		uix_drawconfig_current[4/*uix_DRAWCONFIG:FONTBOLD*/] = 0;
		uix_drawconfig_current[5/*uix_DRAWCONFIG:FONTITALIC*/] = 0;

		uix_font_dirty = 1;
		uix_setgfxfont();

		uix_interacted = (!!mouse_cap) || (mouse_cap != uix_mousecap_prev);
		uix_undo_pending ? (
			sliderchange(-1);
			uix_undo_pending = 0;
		);

		uix_prev_mouse_x = uix_mouse_x;
		uix_prev_mouse_y = uix_mouse_y;
		uix_mouse_x = mouse_x/retina_scaling;
		uix_mouse_y = mouse_y/retina_scaling;
		(mouse_cap&67) && (uix_mouse_x != uix_prev_mouse_x || uix_mouse_y != uix_prev_mouse_y) ? uix_interacted = 1;

		uix_scroll_y = mouse_wheel;
		uix_scroll_x = mouse_hwheel;
		mouse_wheel = mouse_hwheel = 0;
		uix_scroll_y || uix_scroll_x ? uix_interacted = 1;

		uix_unclick1 = (!(mouse_cap&1) && uix_mousecap_prev&1);
		uix_click1 = (mouse_cap&1 && !(uix_mousecap_prev&1)) ? (
			clickdelta = time_precise() - uix_click1_t;
			uix_click1_x = uix_mouse_x;
			uix_click1_y = uix_mouse_y;
			uix_click1 = 1;
			uix_click1_t = time_precise() - 0.001;
			clickdelta < uix_doubleclicktime ? (
				uix_click1count += 1;
			) : (
				uix_click1count = 1;
			);

		);
		uix_unclick2 = (!(mouse_cap&2) && uix_mousecap_prev&2);
		uix_click2 = (mouse_cap&2 && !(uix_mousecap_prev&2)) ? (
			clickdelta = time_precise() - uix_click2_t;
			uix_click2 = 1;
			uix_click2_x = uix_mouse_x;
			uix_click2_y = uix_mouse_y;
			uix_click2_t = time_precise() - 0.001;
			clickdelta < uix_doubleclicktime ? (
				uix_click2count += 1;
			) : (
				uix_click2count = 1;
			);
		);
		uix_unclick64 = (!(mouse_cap&64) && uix_mousecap_prev&64);
		uix_click64 = (mouse_cap&64 && !(uix_mousecap_prev&64)) ? (
			clickdelta = time_precise() - uix_click64_t;
			uix_click64 = 1;
			uix_click64_x = uix_mouse_x;
			uix_click64_y = uix_mouse_y;
			uix_click64_t = time_precise() - 0.001;
			clickdelta < uix_doubleclicktime ? (
				uix_click64count += 1;
			) : (
				uix_click64count = 1;
			);
		);
		uix_mousecap_prev = mouse_cap;

		uix_mouseblocked ? uix_click_block(); // Must be first, so unclick events get removed too
		!(mouse_cap&1) && !(mouse_cap&2) && !(mouse_cap&64) ? uix_mouseblocked = 0;

		// Keyboard
		!uix_latestchar || !uix_char_consumed ? (
			uix_latestchar = gfx_getchar();
			uix_latestchar == -1 ? uix_latestchar = 0;
		);
		uix_char_consumed = 0;

		uix_latestchar ? uix_interacted = 1;
	) : (
		uix_error = "ui_setup() has not been called";
	);
);

function ui_system() local(text, error, screen) (
	ui_screen() == "error" ? (
		gfx_clear = 255 + 255*256 + 255*65536;
		gfx_r = 64;
		gfx_g = gfx_b = 0;
		gfx_x = gfx_y = gfx_texth;
		screen = uix_screenstack + uix_screenstack_step*uix_screenstack_currentlayer;
		error = screen[1/*UI_SCREEN: ID*/]; // First argument
		strlen(error) ? (
			gfx_printf("Error: %s\n(%f)", error, error);
		) : (
			gfx_printf("Error: #%s", error);
		);
		uix_click1 ? (
			uix_screenstack_currentlayer = -1;
			ui_screen_open(0);
		);
	) : (
		gfx_clear = 255 + 255*256 + 255*65536;
		gfx_r = gfx_g = gfx_b = 0;
		gfx_x = gfx_y = gfx_texth;
		ui_screen() ? (
			gfx_printf("Unknown screen: %s (%f)", ui_screen(), ui_screen());
			uix_click1 ? (
				uix_screenstack_currentlayer = -1;
				ui_screen_open(0);
			);
		) : (
			gfx_drawstr("Current screen is 0 - are you calling ui_start() first?");
		);
	);
);

function uix_undo_point(soft) local(time) (
	time = time_precise();
	// "Soft" means it only registers an undo point after 1.5s of no changes
	!soft || uix_last_unto_time < (time - 1500) ? (
		uix_undo_pending = 1;
	);
	uix_last_undo_time = time;
);

function ui_automate(slidervar*, new_value) (
	slidervar !== new_value ? (
		slidervar = new_value;
		slider_automate(slidervar);
		1
	) : 0;
);

function ui_left() (
	uix_round ? (
		floor(uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] + 0.5);
	) : (
		uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/];
	);
);
function ui_left_retina() (
	uix_round ? (
		floor(uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/]*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/] + 0.5);
	) : (
		uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/]*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	);
);
function ui_top() (
	uix_round ? (
		floor(uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] + 0.5);
	) : (
		uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/];
	);
);
function ui_top_retina() (
	uix_round ? (
		floor(uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/]*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/] + 0.5);
	) : (
		uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/]*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	);
);
function ui_bottom() (
	uix_round ? (
		floor(uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] + uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] + 0.5);
	) : (
		uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] + uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]
	);
);
function ui_bottom_retina() (
	uix_round ? (
		floor((uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] + uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/])*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/] + 0.5);
	) : (
		(uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] + uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/])*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/]
	);
);
function ui_right() (
	uix_round ? (
		floor(uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] + uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] + 0.5);
	) : (
		uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] + uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/];
	);
);
function ui_right_retina() (
	uix_round ? (
		floor((uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] + uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/])*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/] + 0.5);
	) : (
		(uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] + uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/])*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	);
);
function ui_width() (
	uix_round ? (
		ui_right() - ui_left();
	) : (
		uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/];
	);
);
function ui_width_retina() (
	uix_round ? (
		ui_right_retina() - ui_left_retina();
	) : (
		uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/]*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	);
);
function ui_height() (
	uix_round ? (
		ui_bottom() - ui_top();
	) : (
		uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/];
	);
);
function ui_height_retina() (
	uix_round ? (
		ui_bottom_retina() - ui_top_retina();
	) : (
		uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	);
);

/////// Drawing operations ///////

function ui_color_refresh() (
	uix_setgfxcolor();
);

function ui_color(r, g, b, a) (
	uix_drawconfig_current[0/*uix_DRAWCONFIG:RED*/] = r;
	uix_drawconfig_current[1/*uix_DRAWCONFIG:GREEN*/] = g;
	uix_drawconfig_current[2/*uix_DRAWCONFIG:BLUE*/] = b;
	uix_drawconfig_current[3/*uix_DRAWCONFIG:ALPHA*/] = a;
	uix_setgfxcolor();
);
function ui_color(r, g, b) (
	ui_color(r, g, b, 1);
);


function ui_align(halign, valign) (
	halign >= 0 && halign <= 1 ? uix_drawconfig_current[20/*uix_DRAWCONFIG:HALIGN*/] = halign;
	valign >= 0 && valign <= 1 ? uix_drawconfig_current[21/*uix_DRAWCONFIG:VALIGN*/] = valign;
);

function ui_halign() (
	uix_drawconfig_current[20/*uix_DRAWCONFIG:HALIGN*/];
);

function ui_valign() (
	uix_drawconfig_current[21/*uix_DRAWCONFIG:VALIGN*/];
);

function ui_fontsize(size) (
	size ? (
		uix_drawconfig_current[8/*uix_DRAWCONFIG:FONTSIZE*/] = size ? size : uix_default_fontsize;
		uix_font_dirty = 1;
		uix_setgfxfont();
	) : uix_drawconfig_current[8/*uix_DRAWCONFIG:FONTSIZE*/];
);

function ui_fontface(face) (
	uix_drawconfig_current[7/*uix_DRAWCONFIG:FONTFACE*/] = face;
	uix_font_dirty = 1;
	uix_setgfxfont();
);

function ui_fontbold(isBold) (
	uix_drawconfig_current[4/*uix_DRAWCONFIG:FONTBOLD*/] = isBold;
	uix_font_dirty = 1;
	uix_setgfxfont();
);

function ui_fontitalic(isItalic) (
	uix_drawconfig_current[5/*uix_DRAWCONFIG:FONTITALIC*/] = isItalic;
	uix_font_dirty = 1;
	uix_setgfxfont();
);

function ui_font(face, size, isBold, isItalic) (
	face = face >= 0 ? face : uix_drawconfig_current[7/*uix_DRAWCONFIG:FONTFACE*/];
	size = size >= 0 ? size : uix_drawconfig_current[8/*uix_DRAWCONFIG:FONTSIZE*/];

	uix_drawconfig_current[7/*uix_DRAWCONFIG:FONTFACE*/] = face;
	uix_drawconfig_current[8/*uix_DRAWCONFIG:FONTSIZE*/] = size;
	uix_drawconfig_current[4/*uix_DRAWCONFIG:FONTBOLD*/] = isBold;
	uix_drawconfig_current[5/*uix_DRAWCONFIG:FONTITALIC*/] = isItalic;
	uix_font_dirty = 1;
	uix_setgfxfont();
);

function ui_font_refresh() (
	uix_setgfxcolor();
	uix_setgfxfont();
);

function ui_font() (
	uix_font_dirty = 1;
	uix_setgfxcolor();
	uix_setgfxfont();
);

function ui_fill() (
	uix_setgfxcolor();
	gfx_rect(ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
);

function ui_image_fill(imageBuffer, width, height, alpha) local(scaling, visibleWidth, visibleHeight, a) (
	scaling = max(ui_width()/width, ui_height()/height);
	visibleWidth = ui_width()/scaling;
	visibleHeight = ui_height()/scaling;
	a = gfx_a;
	gfx_a = alpha;
	gfx_blit(imageBuffer, scaling, 0, (width - visibleWidth)*uix_drawconfig_current[20/*uix_DRAWCONFIG:HALIGN*/], (height - visibleHeight)*uix_drawconfig_current[21/*uix_DRAWCONFIG:VALIGN*/], visibleWidth, visibleHeight, ui_left(), ui_top(), ui_width(), ui_height());
	gfx_a = a;
);
function ui_image_fill(imageBuffer, width, height) (
	ui_image_fill(imageBuffer, width, height, 1);
);
function ui_image_fill(imageBuffer, alpha) local(width, height) (
	gfx_getimgdim(imageBuffer, width, height);
	ui_image_fill(imageBuffer, width, height, alpha);
);
function ui_image_fill(imageBuffer) (
	ui_image_fill(imageBuffer, 1);
);

function ui_texth_retina() (
	uix_setgfxfont();
	gfx_texth;
);

function ui_texth() (
	ui_texth_retina()/uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
);

function ui_text_width(text) local(text_h, text_w) (
	text >= 0 ? (
		text_w = text_h = 0;
		uix_setgfxfont();
		gfx_measurestr(text, text_w, text_h);
		text_w/uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	) : 0;
);

function ui_text_height(text) local(text_h, text_w) (
	text >= 0 ? (
		uix_setgfxfont();
		gfx_measurestr(text, text_w, text_h);
		text_h/uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	) : ui_texth();
);

function ui_text(text) local (text_h, text_w, boxwidth, boxheight, valign, halign, fontscale, fontsize) (
	textw = texth = 0;
	text >= 0 ? (
		uix_setgfxcolor();
		uix_setgfxfont();
		valign = uix_drawconfig_current[21/*uix_DRAWCONFIG:VALIGN*/];
		halign = uix_drawconfig_current[20/*uix_DRAWCONFIG:HALIGN*/];

		gfx_measurestr(text, text_w, text_h);

		boxwidth = ui_width_retina();
		boxheight = ui_height_retina();

		fontscale = 1;
		text_w > boxwidth ? (
			fontscale = boxwidth/text_w;
		);
		text_h > boxheight ? (
			fontscale = min(boxheight/text_h, fontscale);
		);
		fontscale != 1 ? (
			fontsize = max(8, floor(fontscale*uix_drawconfig_current[8/*uix_DRAWCONFIG:FONTSIZE*/]*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/]));
			// TODO: why is fontscale set here?
			fontscale = fontsize/uix_drawconfig_current[8/*uix_DRAWCONFIG:FONTSIZE*/];
			gfx_setfont(
				16,
				uix_drawconfig_current[7/*uix_DRAWCONFIG:FONTFACE*/],
				fontsize,
				uix_fontflags()
			);
			gfx_measurestr(text, text_w, text_h);
		);

		valign = uix_drawconfig_current[21/*uix_DRAWCONFIG:VALIGN*/];
		halign = uix_drawconfig_current[20/*uix_DRAWCONFIG:HALIGN*/];
		gfx_x = ui_left_retina() + (boxwidth - text_w)*halign;
		gfx_y = ui_top_retina() + (boxheight - text_h)*valign;

		gfx_drawstr(text);
	);
	text_w;
);

function ui_textnumber(number, format) local(text) (
	sprintf(#uix_textnumber, format ? format : "%f", number);
	ui_text(#uix_textnumber);
);
function ui_textnumber(number) (
	ui_textnumber(number, "%f");
);

function ui_parsenumber(text, default) local(text_length, i, char, result, digit, hadDigit, hadDecimal, decimalFactor) (
	text_length = strlen(text);
	i = 0;
	result = 0;
	sign = 1;
	hadDigit = hadDecimal = 0;
	decimalFactor = 1;
	while (i < text_length) (
		char = str_getchar(text, i, 'cu');
		char == 45 && !hadDigit && !hadDecimal ? (
			sign = -1;
		) : char >= 48 && char <= 57 ? ( // 0-9
			hadDigit = 1;
			digit = char - 48;
			result = digit + 10*result;
			hadDecimal ? decimalFactor *= 10;
		) : char == 46 && !hadDecimal ? (
			hadDecimal = 1;
		) : char == 32 || char == 9 ? (
			0; // Whitespace - ignore
		) : (
			i = text_length; // stop on first invalid character
		);
		i += 1;
	);
	hadDigit ? sign*result/decimalFactor : default;
);
function ui_parsenumber(number) (
	ui_parsenumber(number, 0);
);

function uix_fitline(text, start, text_end, width) local(i, result, line, line_end, char, hadspace, overflowed, text_w, text_h) (
	line = #;
	strcpy(line, "");
	line_end = 0;
	hadspace = 0;
	overflowed = 0;
	i = result = start;
	while (!overflowed && i < text_end) (
		char = str_getchar(text, i);
		char == 10 ? (
			result = i;
			overflowed = 1;
		) : (
			!hadspace ? result = i;
			char == 32 || char == 9 ? (
				hadspace = 1;
				gfx_measurestr(line, text_w, text_h);
				overflowed = text_w > width;
				!overflowed ? result = i;
			);
			str_setchar(line, line_end, char);
			line_end += 1;
		);
		i += 1;
	);
	!overflowed ? (
		gfx_measurestr(line, text_w, text_h);
		overflowed = text_w > width;
	);
	overflowed ? result : text_end;
);

function ui_wraptext_height(text) local(text_length, line_start, line_end, width, height) (
	uix_setgfxfont();
	width = ui_width_retina();
	height = 0;

	text_length = strlen(text);
	line_start = 0;
	while (line_start < text_length) (
		line_end = uix_fitline(text, line_start, text_length, width);
		height += gfx_texth;
		line_start = line_end + 1;
	);
	height/uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
);

function ui_wraptext(text) local(text_length, line_start, line_end, width, height, line, halign, valign, text_h, text_w, left_x) (
	uix_setgfxcolor();
	uix_setgfxfont();
	width = ui_width_retina();
	height = 0;

	halign = uix_drawconfig_current[20/*uix_DRAWCONFIG:HALIGN*/];
	valign = uix_drawconfig_current[21/*uix_DRAWCONFIG:VALIGN*/];

	gfx_y = (valign ? (
		ui_top() + (ui_height() - ui_wraptext_height(text))*valign;
	) : ui_top())*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];

	text_length = strlen(text);
	line_start = 0;
	while (line_start < text_length) (
		line_end = uix_fitline(text, line_start, text_length, width);
		line = #;
		strcpy_substr(line, text, line_start, line_end - line_start);
		gfx_measurestr(line, text_w, text_h);
		gfx_x = ui_left_retina() + (ui_width_retina() - text_w)*halign;
		gfx_drawstr(line);
		gfx_y += gfx_texth;
		height += gfx_texth;
		line_start = line_end + 1;
	);
	height/uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
);

function ui_border_top() (
	uix_setgfxcolor();
	gfx_line(ui_left_retina(), ui_top_retina(), ui_right_retina() - 1, ui_top_retina());
);

function ui_border_bottom() (
	uix_setgfxcolor();
	gfx_line(ui_left_retina(), ui_bottom_retina() - 1, ui_right_retina() - 1, ui_bottom_retina() - 1);
);

function ui_border_left() (
	uix_setgfxcolor();
	gfx_line(ui_left_retina(), ui_top_retina(), ui_left_retina(), ui_bottom_retina() - 1);
);

function ui_border_right() (
	uix_setgfxcolor();
	gfx_line(ui_right_retina() - 1, ui_top_retina(), ui_right_retina() - 1, ui_bottom_retina() - 1);
);

function ui_border() (
	uix_setgfxcolor();
	gfx_x = ui_left_retina();
	gfx_y = ui_top_retina();
	gfx_lineto(ui_right_retina() - 1, gfx_y, 0);
	gfx_lineto(gfx_x, ui_bottom_retina() - 1, 0);
	gfx_lineto(ui_left_retina(), gfx_y, 0);
	gfx_lineto(gfx_x, ui_top_retina(), 0);
);

///// Viewport stack operations /////

function ui_push() local(i, oldlayer) (
	uix_drawconfig_currentindex += 1;
	uix_drawconfig_currentindex < uix_drawconfig_count ? (
		i = 0;
		oldlayer = uix_drawconfig_current;
		uix_drawconfig_current = uix_drawconfig + uix_drawconfig_currentindex*uix_drawconfig_step;
		while (
			uix_drawconfig_current[i] = oldlayer[i];
			i += 1;
			i < uix_drawconfig_step;
		);
		// Some things shouldn't just be copied
		uix_drawconfig_current[24/*uix_DRAWCONFIG:SPLIT_DIRECTION*/] = -1;
	);
	0;
);
function ui_set_rect(left, top, width, height) (
	uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] = left;
	uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] = top;
	uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] = width;
	uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] = height;
);
function ui_set_rect_retina(left, top, width, height) (
	uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] = left/uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] = top/uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] = width/uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] = height/uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
);
function ui_retina(new_retina) local(old_retina, factor) (
	new_retina ? (
		old_retina = uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
		factor = old_retina/new_retina;
		uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/] = new_retina;
		uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] *= factor;
		uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] *= factor;
		uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] *= factor;
		uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] *= factor;
		uix_drawconfig_current[8/*uix_DRAWCONFIG:FONTSIZE*/] *= factor;
		old_retina;
	) : uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
);
function ui_push_rect(left, top, width, height) (
	ui_push();
	ui_set_rect(left, top, width, height);
);
function ui_push_rect_retina(left, top, width, height) (
	ui_push();
	ui_set_rect_retina(left, top, width, height);
);
function ui_pop() local(prev) (
	prev = uix_drawconfig_current;
	uix_drawconfig_currentindex > 0 ? (
		uix_drawconfig_currentindex -= 1;
		uix_drawconfig_current = uix_drawconfig + uix_drawconfig_currentindex*uix_drawconfig_step;

		prev[6/*uix_DRAWCONFIG:FONTINDEX*/] != uix_drawconfig_current[6/*uix_DRAWCONFIG:FONTINDEX*/] ? uix_font_dirty = 1;
		prev[7/*uix_DRAWCONFIG:FONTFACE*/] != uix_drawconfig_current[7/*uix_DRAWCONFIG:FONTFACE*/] ? uix_font_dirty = 1;
		prev[8/*uix_DRAWCONFIG:FONTSIZE*/] != uix_drawconfig_current[8/*uix_DRAWCONFIG:FONTSIZE*/] ? uix_font_dirty = 1;
		prev[4/*uix_DRAWCONFIG:FONTBOLD*/] != uix_drawconfig_current[4/*uix_DRAWCONFIG:FONTBOLD*/] ? uix_font_dirty = 1;
		prev[5/*uix_DRAWCONFIG:FONTITALIC*/] != uix_drawconfig_current[5/*uix_DRAWCONFIG:FONTITALIC*/] ? uix_font_dirty = 1;
		uix_font_dirty ? uix_setgfxfont();
		prev[10/*uix_DRAWCONFIG:CLIP_SCREEN*/] != uix_drawconfig_current[10/*uix_DRAWCONFIG:CLIP_SCREEN*/] ? (
			gfx_a = prev[15/*uix_DRAWCONFIG:CLIP_ALPHA*/];
			gfx_dest = uix_drawconfig_current[10/*uix_DRAWCONFIG:CLIP_SCREEN*/];
			gfx_x = prev[11/*uix_DRAWCONFIG:CLIP_LEFT*/];
			gfx_y = prev[13/*uix_DRAWCONFIG:CLIP_TOP*/];
			gfx_blit(prev[10/*uix_DRAWCONFIG:CLIP_SCREEN*/], 1, 0, prev[11/*uix_DRAWCONFIG:CLIP_LEFT*/], prev[13/*uix_DRAWCONFIG:CLIP_TOP*/], prev[12/*uix_DRAWCONFIG:CLIP_WIDTH*/], prev[14/*uix_DRAWCONFIG:CLIP_HEIGHT*/]);
		);
	);
	uix_setgfxcolor();
);
function uix_push_screen() local(oldscreen, newscreen) (
	oldscreen = uix_drawconfig_current[10/*uix_DRAWCONFIG:CLIP_SCREEN*/];
	newscreen = uix_unreserved_screen_below(oldscreen);
	gfx_setimgdim(newscreen, gfx_w, gfx_h);

	ui_push();
	uix_drawconfig_current[15/*uix_DRAWCONFIG:CLIP_ALPHA*/] = 1;
	gfx_dest = uix_drawconfig_current[10/*uix_DRAWCONFIG:CLIP_SCREEN*/] = newscreen;
	gfx_a = 1;
	gfx_mode = 0;
	gfx_x = uix_drawconfig_current[11/*uix_DRAWCONFIG:CLIP_LEFT*/];
	gfx_y = uix_drawconfig_current[13/*uix_DRAWCONFIG:CLIP_TOP*/];
	gfx_blit(oldscreen, 1, 0, uix_drawconfig_current[11/*uix_DRAWCONFIG:CLIP_LEFT*/], uix_drawconfig_current[13/*uix_DRAWCONFIG:CLIP_TOP*/], uix_drawconfig_current[12/*uix_DRAWCONFIG:CLIP_WIDTH*/], uix_drawconfig_current[14/*uix_DRAWCONFIG:CLIP_HEIGHT*/]);
	uix_setgfxcolor();
);
function ui_push_clip(alpha) local(retina) (
	!alpha ? alpha = 1;
	uix_push_screen();
	retina = uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
	uix_drawconfig_current[15/*uix_DRAWCONFIG:CLIP_ALPHA*/] = alpha;
	uix_drawconfig_current[11/*uix_DRAWCONFIG:CLIP_LEFT*/] = uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/]*retina;
	uix_drawconfig_current[13/*uix_DRAWCONFIG:CLIP_TOP*/] = uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/]*retina;
	uix_drawconfig_current[12/*uix_DRAWCONFIG:CLIP_WIDTH*/] = uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/]*retina;
	uix_drawconfig_current[14/*uix_DRAWCONFIG:CLIP_HEIGHT*/] = uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]*retina;
);

function ui_split_top(height) local(oldTop) (
	height == -1 ? height = ui_texth() + uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/]*2;

	height = min(height, uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]);
	oldTop = uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/];
	uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] += height;
	uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] -= height;
	ui_push();
	uix_drawconfig_current[24/*uix_DRAWCONFIG:SPLIT_DIRECTION*/] = 0/*UI_SPLIT_DIRECTION:TOP*/;
	uix_drawconfig_current[25/*uix_DRAWCONFIG:SPLIT_HEIGHT*/] = height;
	uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] = oldTop;
	uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] = height;
	height;
);
function ui_split_topratio(ratio) (
	ui_split_top(ratio*uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]);
);
function ui_split_toptext(text) local(text_height) (
	text_height = max(ui_texth(), ui_text_height(text));
	ui_split_top(text_height + 2*uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/]);
);
function ui_split_bottom(height) local(oldBottom) (
	height == -1 ? height = ui_texth() + uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/]*2;
	height = min(height, uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]);
	oldBottom = uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] + uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/];
	uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] -= height;
	ui_push();
	uix_drawconfig_current[24/*uix_DRAWCONFIG:SPLIT_DIRECTION*/] = 1/*UI_SPLIT_DIRECTION:BOTTOM*/;
	uix_drawconfig_current[25/*uix_DRAWCONFIG:SPLIT_HEIGHT*/] = height;
	uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] = oldBottom - height;
	uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] = height;
	height;
);
function ui_split_bottomratio(ratio) (
	ui_split_bottom(ratio*uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]);
);
function ui_split_bottomtext(text) (
	text_height = max(ui_texth(), ui_text_height(text));
	ui_split_bottom(text_height + 2*uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/]);
);
function ui_split_left(width) local(oldLeft) (
	width == -1 ? width = ui_texth()*4 + uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/]*2;
	width = min(width, uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/]);
	oldLeft = uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/];
	uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] += width;
	uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] -= width;
	ui_push();
	uix_drawconfig_current[24/*uix_DRAWCONFIG:SPLIT_DIRECTION*/] = 2/*UI_SPLIT_DIRECTION:LEFT*/;
	uix_drawconfig_current[26/*uix_DRAWCONFIG:SPLIT_WIDTH*/] = width;
	uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] = oldLeft;
	uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] = width;
	width;
);
function ui_split_leftratio(ratio) (
	ui_split_left(ratio*uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/]);
);
function ui_split_lefttext(text) (
	ui_split_left(ui_text_width(text) + 2*uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/]);
);
function ui_split_right(width) local(oldRight) (
	width == -1 ? width = ui_texth()*4 + uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/]*2;
	width = min(width, uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/]);
	oldRight = uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] + uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/];
	uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] -= width;
	ui_push();
	uix_drawconfig_current[24/*uix_DRAWCONFIG:SPLIT_DIRECTION*/] = 3/*UI_SPLIT_DIRECTION:RIGHT*/;
	uix_drawconfig_current[26/*uix_DRAWCONFIG:SPLIT_WIDTH*/] = width;
	uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] = oldRight - width;
	uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] = width;
	width;
);
function ui_split_rightratio(ratio) (
	ui_split_right(ratio*uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/]);
);
function ui_split_righttext(text) (
	ui_split_right(ui_text_width(text) + 2*uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/]);
);

function ui_split_next() local(direction, width, height) (
	direction = uix_drawconfig_current[24/*uix_DRAWCONFIG:SPLIT_DIRECTION*/];
	width = uix_drawconfig_current[26/*uix_DRAWCONFIG:SPLIT_WIDTH*/];
	height = uix_drawconfig_current[25/*uix_DRAWCONFIG:SPLIT_HEIGHT*/];
	ui_pop();
	direction == 2/*UI_SPLIT_DIRECTION:LEFT*/ ? (
		ui_split_left(width);
	) : direction == 0/*UI_SPLIT_DIRECTION:TOP*/ ? (
		ui_split_top(height);
	) : direction == 3/*UI_SPLIT_DIRECTION:RIGHT*/ ? (
		ui_split_right(width);
	) : direction == 1/*UI_SPLIT_DIRECTION:BOTTOM*/ ? (
		ui_split_bottom(height);
	) : (
		ui_error("Called ui_split_next() without ui_split_*()");
		ui_push();
	)
);

function ui_push_height(height) (
	height == -1 ? height = ui_texth() + uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/]*2;
	ui_push();
	height = min(height, uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]);
	uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] += (uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] - height)*uix_drawconfig_current[21/*uix_DRAWCONFIG:VALIGN*/];
	uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] = height;
	height;
);
function ui_push_heightratio(ratio) (
	ui_push_height(ratio*uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]);
);
function ui_push_heighttext(text) local(text_height) (
	text_height = max(ui_texth(), ui_text_height(text));
	ui_push_height(text_height + 2*uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/]);
);
function ui_push_width(width) (
	width == -1 ? width = ui_texth()*4 + uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/]*2;
	ui_push();
	width = min(width, uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/]);
	uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] += (uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] - width)*uix_drawconfig_current[20/*uix_DRAWCONFIG:HALIGN*/];
	uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] = width;
);
function ui_push_widthratio(ratio) (
	ui_push_width(ratio*uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/]);
);
function ui_push_widthtext(text) local(text_width) (
	text_width = ui_text_width(text);
	ui_push_width(text_width + 2*uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/]);
);

function ui_push_above(height) local(newheight) (
	height == -1 ? height = ui_texth() + uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/]*2;
	ui_push();
	newheight = (uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] - height)*uix_drawconfig_current[21/*uix_DRAWCONFIG:VALIGN*/];
	uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] = newheight;
	newheight;
);
function ui_push_aboveratio(ratio) (
	ui_push_above(ratio*uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]);
);
function ui_push_abovetext(text) local(text_height)  (
	text_height = max(ui_texth(), ui_text_height(text));
	ui_push_above(text_height + 2*uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/]);
);
function ui_push_below(height) local(newheight) (
	height == -1 ? height = ui_texth() + uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/]*2;
	ui_push();
	newheight = (uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] - height)*(1 - uix_drawconfig_current[21/*uix_DRAWCONFIG:VALIGN*/]);
	uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] = uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] + uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] - newheight;
	uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] = newheight;
	newheight;
);
function ui_push_belowratio(ratio) (
	ui_push_below(ratio*uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/]);
);
function ui_push_belowtext(text) local(text_height)  (
	text_height = max(ui_texth(), ui_text_height(text));
	ui_push_below(text_height + 2*uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/]);
);
function ui_push_leftof(width) local(newwidth) (
	width == -1 ? width = ui_texth()*4 + uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/]*2;
	ui_push();
	newwidth = (uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] - width)*uix_drawconfig_current[20/*uix_DRAWCONFIG:HALIGN*/];
	uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] = newwidth;
	newwidth;
);
function ui_push_leftofratio(ratio) (
	ui_push_leftof(ratio*uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/]);
);
function ui_push_leftoftext(text) local(text_width)  (
	text_width = ui_text_width(text);
	ui_push_leftof(text_width + 2*uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/]);
);
function ui_push_rightof(width) local(newwidth) (
	width == -1 ? width = ui_texth()*4 + uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/]*2;
	ui_push();
	newwidth = (uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] - width)*(1 - uix_drawconfig_current[20/*uix_DRAWCONFIG:HALIGN*/]);
	uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] = uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] + uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] - newwidth;
	uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] = newwidth;
	newwidth;
);
function ui_push_rightofratio(ratio) (
	ui_push_rightof(ratio*uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/]);
);
function ui_push_rightoftext(text) local(text_width)  (
	text_width = ui_text_width(text);
	ui_push_rightof(text_width + 2*uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/]);
);

function ui_pad(l, t, r, b) (
	l < 0 ? l = -l*uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/];
	r < 0 ? r = -r*uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/];
	t < 0 ? t = -t*uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/];
	b < 0 ? b = -b*uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/];
	uix_drawconfig_current[16/*uix_DRAWCONFIG:LEFT*/] += l;
	uix_drawconfig_current[17/*uix_DRAWCONFIG:TOP*/] += t;
	uix_drawconfig_current[18/*uix_DRAWCONFIG:WIDTH*/] -= l + r;
	uix_drawconfig_current[19/*uix_DRAWCONFIG:HEIGHT*/] -= t + b;
);
function ui_pad(w, h) (
	ui_pad(w, h, w, h);
);
function ui_pad() (
	ui_pad(-1, -1, -1, -1);
);

function ui_padtop(n) (
	ui_pad(0, n ? n : -1, 0, 0);
);
function ui_padbottom(n) (
	ui_pad(0, 0, 0, n ? n : -1);
);
function ui_padleft(n) (
	ui_pad(n ? n : -1, 0, 0, 0);
);
function ui_padright(n) (
	ui_pad(0, 0, n ? n : -1, 0);
);

function ui_padding(hpadding, vpadding) (
	hpadding >= 0 ? uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/] = hpadding;
	vpadding >= 0 ? uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/] = vpadding;
);

function ui_padding_x() (
	uix_drawconfig_current[22/*uix_DRAWCONFIG:HPADDING*/];
);

function ui_padding_y() (
	uix_drawconfig_current[23/*uix_DRAWCONFIG:VPADDING*/];
);

//////// Mouse functions ////////

function ui_interacted() (
	uix_interacted;
);

function uix_click_x(i) (
	!i || i == 1 ? uix_click1_x : i == 2 ? uix_click2_x : i == 64 ? uix_click64_x : 0;
);

function uix_click_y(i) (
	!i || i == 1 ? uix_click1_y : i == 2 ? uix_click2_y : i == 64 ? uix_click64_y : 0;
);

function uix_click_t(i) (
	!i || i == 1 ? uix_click1_t : i == 2 ? uix_click2_t : i == 64 ? uix_click64_t : 0;
);

function uix_click(i) (
	!i || i == 1 ? uix_click1 : i == 2 ? uix_click2 : i == 64 ? uix_click64 : 0;
);

function uix_unclick(i) (
	!i || i == 1 ? uix_unclick1 : i == 2 ? uix_unclick2 : i == 64 ? uix_unclick64 : 0;
);

function uix_clickcount(i) (
	!i || i == 1 ? uix_click1count : i == 2 ? uix_click2count : i == 64 ? uix_click64count : 0;
);

function uix_clickwasinside(i) (
	!uix_mouseblocked && uix_click_x(i) >= ui_left() && uix_click_x(i) < ui_right() && uix_click_y(i) >= ui_top() && uix_click_y(i) < ui_bottom();
);

function ui_mouse_x() (
	uix_mouse_x - ui_left();
);

function ui_mouse_xratio() (
	ui_mouse_x()/ui_width();
);

function ui_mouse_y() (
	uix_mouse_y - ui_top();
);

function ui_mouse_yratio() (
	ui_mouse_y()/ui_height();
);

function ui_hover() (
	uix_mouse_x >= ui_left() && uix_mouse_x < ui_right() && uix_mouse_y >= ui_top() && uix_mouse_y < ui_bottom();
);

function ui_mouse_down(i) (
	uix_click(i) && ui_hover();
);

function ui_mouse_down_outside(i) (
	uix_click(i) && !ui_hover();
);

function ui_mouse_up(i) (
	uix_unclick(i) && ui_hover();
);

function ui_click_clear() (
	uix_click_block();
);

function ui_drag(i) local(dragtime) (
	!i ? i = 1;
	mouse_cap&i && uix_clickwasinside(i) ? (
		dragtime = time_precise() - uix_click_t(i);
		dragtime >= uix_doubleclicktime || abs(uix_click_x(i) - uix_mouse_x) >= uix_draglimit || abs(uix_click_y(i) - uix_mouse_y) >= uix_draglimit ? (
			dragtime;
		) : 0;
	) : 0;
);

function ui_drag_up(i) local(dragtime) (
	!i ? i = 1;
	uix_unclick(i) && uix_clickwasinside(i) ? (
		dragtime = time_precise() - uix_click_t(i);
		dragtime >= uix_doubleclicktime || abs(uix_click_x(i) - uix_mouse_x) >= uix_draglimit || abs(uix_click_y(i) - uix_mouse_y) >= uix_draglimit ? (
			dragtime;
		) : 0;
	) : 0;
);

function ui_drag_x(i) (
	!i ? i = 1;
	mouse_cap&i && uix_clickwasinside(i) ? (
		uix_mouse_x - uix_click_x(i);
	) : 0;
);

function ui_drag_y(i) (
	!i ? i = 1;
	mouse_cap&i && uix_clickwasinside(i) ? (
		uix_mouse_y - uix_click_y(i);
	) : 0;
);

function ui_mouse_dx() (
	uix_mouse_x - uix_prev_mouse_x;
);


function ui_mouse_dy() (
	uix_mouse_y - uix_prev_mouse_y;
);

function ui_scroll_y() (
	ui_hover() ? uix_scroll_y : 0;
);

function ui_scroll_x() (
	ui_hover() ? uix_scroll_x : 0;
);

function ui_press(i) (
	!i ? i = 1;
	ui_hover() && mouse_cap&i && uix_clickwasinside(i) ? (
		time_precise() - uix_click_t(i);
	) : 0;
);

function ui_clickcount(i) (
	uix_clickcount(i);
);

function ui_click(i) (
	ui_mouse_up(i) && uix_clickwasinside(i) && ui_hover() ? (
		time_precise() - uix_click_t(i);
	) : 0;
);

function ui_key() (
	uix_latestchar;
);

function ui_key_printable() (
	uix_latestchar >= 32 && uix_latestchar < 127 ? (
		uix_latestchar;
	) : 0;
);

function ui_key_next() (
	uix_char_consumed = 1;
	uix_latestchar = gfx_getchar();
	uix_latestchar == -1 ? uix_latestchar = 0;
	uix_latestchar;
);

//////// Fancy graphics ////////

function ui_graph_step(buffer, length, step, offset, modulo_length, low, high) local(i, i2, v, x, y, mid, top, bottom, height, left, width) (
	low == high ? (
		i = 0;
		mid = low;
		while (i < length) (
			v = buffer[i*step];
			low = min(low, v);
			high = max(high, v);
			i += 1;
		);
		// Keep it symmetrical
		low = min(low, 2*mid - high);
		high = max(high, 2*mid - low);
	);
	length < 1 ? length = 1;

	modulo_length = max(1, max(length>>4, modulo_length));

	top = ui_top_retina() + 0.5;
	bottom = ui_bottom_retina() - 0.5;
	height = ui_height_retina() - 1;
	left = ui_left_retina();
	width = ui_width_retina() - 1;
	i = 0;
	while (i < length) (
		i2 = i + offset;
		while (i2 < 0) (i2 += modulo_length);
		while (i2 >= modulo_length) (i2 -= modulo_length);

		v = buffer[i2*step];
		x = left + i/(length - 1)*width;
		y = top + max(0, min(1, (v - high)/(low - high)))*height;
		i == 0 ? (
			gfx_x = x;
			gfx_y = y;
		) : (
			gfx_lineto(x, y);
		);
		i += 1;
	);
	(high - low)/2;
);
function ui_graph_step(buffer, length, step, offset, low, high) (
	ui_graph_step(buffer, length, step, offset, length, low, high);
);
function ui_graph_step(buffer, length, step, low, high) (
	ui_graph_step(buffer, length, step, 0, length, low, high);
);

function ui_graph(buffer, length, offset, modulo_length, low, high) local(points, step) (
	step = 1;
	points = min(length, ui_width()*4);
	step = max(1, ceil(length/points));
	ui_graph_step(buffer + (offset%step), floor(length/step), step, floor(offset/step), floor(modulo_length/step), low, high);
);
function ui_graph(buffer, length, offset, low, high) (
	ui_graph(buffer, length, offset, length, low, high);
);
function ui_graph(buffer, length, low, high) (
	ui_graph(buffer, length, 0, low, high);
);

/////////////// DEBUG/TUTORIAL ///////////////

function ui_debug() local(oldR, oldG, oldB, oldA, oldX, oldY, oldFont, i, corner, config, top, left, bottom, right, textX, textY, textW, textH, hue) (
	oldR = gfx_r;
	oldG = gfx_g;
	oldB = gfx_b;
	oldA = gfx_a;
	oldX = gfx_x;
	oldY = gfx_y;
	oldFont = gfx_getfont();

	gfx_setfont(0);
	gfx_a = 0.6;

	i = 0;
	while (i <= uix_drawconfig_currentindex) (
		config = uix_drawconfig + uix_drawconfig_step*i;

		left = config[16/*uix_DRAWCONFIG:LEFT*/]*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
		top = config[17/*uix_DRAWCONFIG:TOP*/]*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
		right = (config[16/*uix_DRAWCONFIG:LEFT*/] + config[18/*uix_DRAWCONFIG:WIDTH*/])*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/] - 1;
		bottom = (config[17/*uix_DRAWCONFIG:TOP*/] + config[19/*uix_DRAWCONFIG:HEIGHT*/])*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/] - 1;

		sprintf(#uix_debug_text, "%i", i + 1);
		gfx_measurestr(#uix_debug_text, textW, textH);

		corner = 0;
		while (corner < 4) (
			gfx_r = gfx_g = gfx_b = 1;
			textX = left + 2;
			textY = top + 2;
			(corner%4 == 1 || corner%4 == 2) ? (
				textX = right - 1 - textW;
			);
			(corner%4 > 1) ? (
				textY = bottom - 1 - textH;
			);
			gfx_rect(textX - 1, textY - 1, textW + 3, textH + 3);

			hue = $pi*sqrt(2)*i + time_precise()*0.1;
			gfx_r = max(0, min(1, 0.5 + sin(hue)))*0.6;
			gfx_g = max(0, min(1, 0.5 + sin(hue + $pi*2/3)))*0.6;
			gfx_b = max(0, min(1, 0.5 + sin(hue + $pi*4/3)))*0.6;

			gfx_x = textX;
			gfx_y = textY;
			gfx_drawstr(#uix_debug_text);
			corner += 1;
		);

		gfx_line(left, top, right, top);
		gfx_line(right, top, right, bottom);
		gfx_line(right, bottom, left, bottom);
		gfx_line(left, bottom, left, top);

		i += 1;
	);

	gfx_r = oldR;
	gfx_g = oldG;
	gfx_b = oldB;
	gfx_a = oldA;
	gfx_x = oldX;
	gfx_y = oldY;
	gfx_setfont(oldFont);
);

/////////////// LEVEL 2 ///////////////

// Total number of themes: 4/*uix_THEME: TRON, BITMAP_SIMPLE*/
uix_control_theme = 0/*uix_THEME:DEFAULT*/;
uix_control_theme_prev = -1;
uix_control_width_prev = -1;
uix_control_height_prev = -1;
// Claim this screen for our own use
uix_control_reserved_screen = ui_reserve_image(127);

function uix_control_color_from_theme(x, y, a) local(old_dest, r, g, b, old_x, old_y) (
	old_x = gfx_x;
	old_y = gfx_y;
	old_dest = gfx_dest;

	gfx_dest = uix_control_theme_buffer;
	gfx_x = x;
	gfx_y = y;
	gfx_getpixel(r, g, b);

	gfx_dest = old_dest;
	gfx_x = old_x;
	gfx_y = old_y;

	ui_color(r*255, g*255, b*255, a);
);
function uix_control_color_from_theme(x, y) (
	uix_control_color_from_theme(x, y, 1);
);

function control_start(defaultPage, theme, imageBuffer) local(reset, i, x, y) (
	ui_start(defaultPage);
	// TODO: check retina here?
	reset = (uix_control_theme_prev != theme || uix_control_width_prev != gfx_w || uix_control_height_prev != gfx_h);
	uix_control_theme_prev = theme;
	uix_control_width_prev = gfx_w;
	uix_control_height_prev = gfx_h;

	theme == "black" ? (
		uix_control_theme = 1/*uix_THEME:BLACK_AND_WHITE*/;
		gfx_clear = 0;
		ui_color(255, 255, 255);
		ui_fontface("Trebuchet MS");
		ui_fontsize(20);
		ui_padding(10, 10);
	) : theme == "tron" ? (
		uix_control_theme = 2/*uix_THEME:TRON*/;
		gfx_clear = $x454545;
		reset ? (
			gfx_setimgdim(uix_control_reserved_screen, gfx_w, gfx_h);
			gfx_dest = uix_control_reserved_screen;
			ui_color(70, 70, 70);
			ui_fill();
			ui_color(67, 67, 67);
			gfx_y = 0;
			while (gfx_y < gfx_h) (
				gfx_line(0, gfx_y, gfx_w, gfx_y);
				gfx_y += 2;
			);
			gfx_dest = -1;
		);
		gfx_x = gfx_y = 0;
		gfx_blit(uix_control_reserved_screen, 1, 0);
		ui_color(245, 255, 255);
		ui_fontface("Verdana");
	) : theme == "bitmap-simple" ? (
		uix_control_theme = 3/*uix_THEME:BITMAP_SIMPLE*/;
		uix_control_theme_buffer = imageBuffer;

		y = 0;
		while (y < gfx_h) (
			x = 0;
			while (x < gfx_w) (
				gfx_blit(uix_control_theme_buffer, ui_retina(), 0, 20, 20, 120, 120, x, y);
				x += 120*ui_retina();
			);
			y += 120;
		);

		uix_control_color_from_theme(151, 30);
	) : (
		uix_control_theme = 0/*uix_THEME:DEFAULT*/;
		//ui_color(242, 242, 242);
	);
);
function control_start(defaultPage, theme) (
	control_start(defaultPage, theme, 0);
);

function control_state() (
	ui_press() ? "press" : ui_hover() ? "hover" : ui_drag() ? "drag" : "none";
);

function uix_gloss(strength) local(width, height, topalpha, bottomalpha) (
	// White fade
	height = ui_height_retina()*0.5;
	topalpha = strength*0.3;
	bottomalpha = 0;
	gfx_gradrect(
		ui_left_retina(), ui_top_retina(), ui_width_retina(), height,
		1, 1, 1, topalpha,
		0, 0, 0, 0,
		0, 0, 0, (bottomalpha - topalpha)/height
	);
	// Black fade
	height = ui_height_retina()*0.5;
	topalpha = 0;
	bottomalpha = strength*0.1;
	gfx_gradrect(
		ui_left_retina(), ui_bottom_retina() - height, ui_width_retina(), height,
		0, 0, 0, topalpha,
		0, 0, 0, 0,
		0, 0, 0, (bottomalpha - topalpha)/height
	);
	// Black fade 2
	height = ui_height_retina()*0.2;
	topalpha = 0;
	bottomalpha = strength*0.1;
	gfx_gradrect(
		ui_left_retina(), ui_bottom_retina() - height, ui_width_retina(), height,
		0, 0, 0, topalpha,
		0, 0, 0, 0,
		0, 0, 0, (bottomalpha - topalpha)/height
	);

	uix_control_theme == 2/*uix_THEME:TRON*/ ? (
		// Left fade
		width = min(ui_width_retina()*0.3, 5);
		topalpha = strength*0.05;
		bottomalpha = 0;
		gfx_gradrect(
			ui_left_retina(), ui_top_retina(), width, ui_height_retina(),
			1, 1, 1, topalpha,
			0, 0, 0, (bottomalpha - topalpha)/width,
			0, 0, 0, 0
		);
		// Right fade
		topalpha = strength*0.05;
		bottomalpha = 0;
		gfx_gradrect(
			ui_right_retina() - width, ui_top_retina(), width, ui_height_retina(),
			1, 1, 1, 0,
			0, 0, 0, -(bottomalpha - topalpha)/width,
			0, 0, 0, 0
		);
	);

	ui_color(0, 0, 0, 0.1);
	ui_border();
);

function uix_circle_shade(x, y, r, angle, shadowstrength) (
	ui_push();
		ui_color(255, 255, 255, 0.3);
		gfx_arc(x, y + 1, r, -1.5 + angle, 1.5 + angle, 1);
		gfx_arc(x, y + 1, r - 0.3, -1 + angle, 1 + angle, 1);
		gfx_a = 0.15;
		//gfx_arc(x, y + 2, r, -0.5 + angle, 0.5 + angle, 1);

		angle += $pi;
		ui_color(0, 0, 0, 0.2*shadowstrength);
		gfx_arc(x, y - 1, r, -1.2 + angle, 1.2 + angle, 1);
		gfx_arc(x, y - 1, r, -0.8 + angle, 0.8 + angle, 1);
		gfx_a = 0.15;
		//gfx_arc(x, y - 2, r, -0.5 + angle, 0.5 + angle, 1);

		ui_color(0, 0, 0, 0.1);
		gfx_circle(x, y, r, 0, 1);
	ui_pop();
);

function uix_dotted_line(x1, y1, x2, y2, drawlength, skiplength) local(distance, steps, drawR, i, r1, r2) (
	distance = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
	steps = distance/(drawlength + skiplength);

	x1 = floor(x1) + 0.5;
	y1 = floor(y1) + 0.5;
	x2 = floor(x2) + 0.5;
	y2 = floor(y2) + 0.5;

	drawR = (drawlength - 1)/(drawlength + skiplength);
	i = 0;
	while (i < steps) (
		r1 = i/steps;
		r2 = min(1, (i + drawR)/steps);
		gfx_line(x1 + (x2 - x1)*r1, y1 + (y2 - y1)*r1, x1 + (x2 - x1)*r2, y1 + (y2 - y1)*r2, 1);
		i += 1;
	);
);

function uix_control_state(state) (
	(!state || state == "auto") ? control_state() : state;
);

function control_background_enabled(state) local(shade) (
	state = uix_control_state(state);
	shade = (state == "press") ? 0.5 : (state == "hover") ? 0.75 : (state == "drag") ? 0.75 : 1;
	uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
		ui_push();
			ui_color(255*shade, 255*shade, 255*shade);
			ui_pad(2, 2);
			ui_fill();
		ui_pop();
		ui_color(0, 0, 0);
	) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
		shade = 1.5 - shade;
		ui_push();
			ui_color(203*shade, 213*shade, 215*shade);
			ui_pad(2, 2);
			ui_fill();
		ui_pop();
		ui_color(0, 0, 0);
		state == "press" || state == "hover" ? (
			ui_color(200, 240, 255);
		) : (
			ui_color(162, 228, 255);
		);
	) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
		state == "press" ? (
			gfx_blit(uix_control_theme_buffer, 1, 0, 180, 140, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(311, 150);
		) : state == "hover" ? (
			gfx_blit(uix_control_theme_buffer, 1, 0, 180, 260, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(311, 270);
		) : state == "drag" ? (
			gfx_blit(uix_control_theme_buffer, 1, 0, 180, 380, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(311, 390);
		) : (
			gfx_blit(uix_control_theme_buffer, 1, 0, 180, 20, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(311, 30);
		);
	) : (
		ui_color(64*shade, 102*shade, 140*shade);
		ui_fill();
		(state == "press") ? ui_color(230, 230, 230) : ui_color(255, 255, 255);
	);
);

function uix_control_background_enabled_circle(x, y, r, state) local(shade) (
	state = uix_control_state(state);
	shade = (state == "press") ? 0.5 : (state == "hover") ? 0.75 : (state == "drag") ? 0.75 : 1;

	uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
		ui_color(255*shade, 255*shade, 255*shade);
		gfx_circle(x, y, r, 1, 1);
		ui_color(0, 0, 0);
	) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
		shade = 1.5 - shade;
		ui_color(231*shade, 246*shade, 255*shade);
		gfx_circle(x, y, r, 1, 1);
		//ui_color(162, 228, 255);
		ui_color(255, 255, 255);
	) : (
		ui_color(64*shade, 102*shade, 140*shade);
		gfx_circle(x, y, r, 1, 1);
		(state == "press") ? ui_color(230, 230, 230) : ui_color(255, 255, 255);
		ui_color(255, 255, 255);
	);
);
function uix_control_background_enabled_circle(state) (
	uix_control_background_enabled_circle(ui_left_retina() + ui_width_retina()*0.5, ui_top_retina() + ui_height_retina()*0.5, min(ui_height_retina(), ui_width_retina())*0.5, state);
);

function control_finish_enabled(state) (
	uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
		state == "press" ? (
			gfx_blit(uix_control_theme_buffer, 1, 0, 340, 140, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(471, 150);
		) : state == "hover" ? (
			gfx_blit(uix_control_theme_buffer, 1, 0, 340, 260, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(471, 270);
		) : state == "drag" ? (
			gfx_blit(uix_control_theme_buffer, 1, 0, 340, 380, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(471, 390);
		) : (
			gfx_blit(uix_control_theme_buffer, 1, 0, 340, 20, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(471, 30);
		);
	) : (
		ui_push();
			uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
				ui_color(255, 255, 255);
			) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
				uix_gloss(1.8);
				ui_color(0, 0, 0);
			) : (
				uix_gloss(1);
				ui_color(102, 102, 102, 0.25);
				ui_border();
			);
		ui_pop();
	);
);

function uix_control_finish_enabled_circle(x, y, r, state) (
	uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
		0
	) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
		uix_circle_shade(x, y, r, 0, 2);
	) : (
		uix_circle_shade(x, y, r, 0, 1);
	);
);
function uix_control_finish_enabled_circle(state) (
	uix_control_finish_enabled_circle(ui_left() + ui_width()*0.5, ui_top() + ui_height()*0.5, min(ui_height(), ui_width())*0.5, state);
);

function control_background_passive(state) (
	uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
		ui_color(0, 0, 0);
		ui_fill();
		ui_color(255, 255, 255);
	) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
		ui_color(48, 48, 48);
		ui_fill();
		//ui_color(0, 0, 0);
		//ui_color(140, 198, 221);
		ui_color(255, 255, 255);
	) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
		gfx_blit(uix_control_theme_buffer, 1, 0, 500, 140, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
		uix_control_color_from_theme(631, 150);
	) : (
		ui_color(255, 255, 255);
		ui_fill();
		ui_color(0, 0, 0);
	);
);

function control_finish_passive(state) (
	ui_push();
		uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
			ui_color(255, 255, 255);
			uix_dotted_line(ui_left_retina(), ui_top_retina(), ui_right_retina() - 1, ui_top_retina(), 2, 2);
			uix_dotted_line(ui_right_retina() - 1, ui_top_retina(), ui_right_retina() - 1, ui_bottom_retina(), 2, 2);
			uix_dotted_line(ui_right_retina() - 1, ui_bottom_retina(), ui_left_retina(), ui_bottom_retina(), 2, 2);
			uix_dotted_line(ui_left_retina(), ui_bottom_retina(), ui_left_retina(), ui_top_retina(), 2, 2);
		) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
			uix_gloss(1);
		) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
			gfx_blit(uix_control_theme_buffer, 1, 0, 660, 140, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(791, 150);
		) : (
			uix_gloss(0.5);
			ui_color(102, 102, 102, 0.5);
			ui_border();
		);
	ui_pop();
);

function control_background_disabled(state) (
	uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
		ui_color(0, 0, 0);
		ui_fill();
		ui_color(255, 255, 255);
	) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
		ui_color(96, 96, 96);
		ui_fill();
		ui_color(48, 48, 48);
	) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
		gfx_blit(uix_control_theme_buffer, 1, 0, 500, 20, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
		uix_control_color_from_theme(631, 30);
	) : (
		ui_color(180, 180, 180);
		ui_fill();
		ui_color(255, 255, 255);
	);
);

function control_finish_disabled(state) (
	ui_push();
		uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
			ui_color(255, 255, 255);
			uix_dotted_line(ui_left(), ui_top(), ui_right(), ui_top(), 1, 3);
			uix_dotted_line(ui_right(), ui_top(), ui_right(), ui_bottom(), 1, 3);
			uix_dotted_line(ui_right(), ui_bottom(), ui_left(), ui_bottom(), 1, 3);
			uix_dotted_line(ui_left(), ui_bottom(), ui_left(), ui_top(), 1, 3);
		) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
			gfx_blit(uix_control_theme_buffer, 1, 0, 660, 20, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(791, 30);
		) : (
			ui_color(0, 0, 0, 0.1);
			ui_border();
		);
	ui_pop();
);

function control_background_inset(state) (
	uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
		ui_color(0, 0, 0);
		ui_fill();
		ui_color(255, 255, 255);
	) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
		ui_color(0, 0, 0, 0.57);
		ui_fill();
		ui_color(205, 167, 119);
	) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
		gfx_blit(uix_control_theme_buffer, 1, 0, 500, 260, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
		uix_control_color_from_theme(631, 270);
	) : (
		ui_color(255, 255, 255);
		ui_fill();
		ui_color(0, 0, 0);
	);
);

function control_finish_inset() local(strength, height, topalpha, bottomalpha) (
	strength = 1;
	ui_push();
		uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
			ui_color(255, 255, 255);
			ui_border();
		) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
			uix_gloss(-0.2);
			ui_color(0, 0, 0, 0.1);
			ui_border();
			ui_color(32, 32, 32);
		) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
			gfx_blit(uix_control_theme_buffer, 1, 0, 660, 260, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(791, 270);
		) : (
			// Black fade
			height = min(5, ui_height_retina()/2);
			topalpha = strength*0.1;
			bottomalpha = 0;
			gfx_gradrect(
				ui_left_retina(), ui_top_retina(), ui_width_retina(), height,
				0, 0, 0, topalpha,
				0, 0, 0, 0,
				0, 0, 0, (bottomalpha - topalpha)/height
			);
			// White fade
			height = min(5, ui_height_retina()/2);
			topalpha = 0;
			bottomalpha = strength*0.3;
			gfx_gradrect(
				ui_left_retina(), ui_top_retina(), ui_width_retina(), height,
				1, 1, 1, topalpha,
				0, 0, 0, 0,
				0, 0, 0, (bottomalpha - topalpha)/height
			);
			ui_color(102, 102, 102, 0.5);
			ui_border();
		);
	ui_pop();
);

function control_background_technical(state) (
	uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
		ui_color(0, 0, 0);
		ui_fill();
		ui_color(255, 255, 255);
	) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
		ui_color(16, 16, 16);
		ui_fill();
		ui_color(205, 147, 74);
	) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
		gfx_blit(uix_control_theme_buffer, 1, 0, 500, 380, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
		uix_control_color_from_theme(631, 390);
	) : (
		ui_color(32, 32, 32);
		ui_fill();
		ui_color(192, 128, 64);
	);
);

function control_finish_technical(state) (
	ui_push();
		uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
			ui_color(255, 255, 255);
			uix_dotted_line(ui_left(), ui_top(), ui_right() - 1, ui_top(), 2, 2);
			uix_dotted_line(ui_right() - 1, ui_top(), ui_right() - 1, ui_bottom(), 2, 2);
			uix_dotted_line(ui_right() - 1, ui_bottom(), ui_left(), ui_bottom(), 2, 2);
			uix_dotted_line(ui_left(), ui_bottom(), ui_left(), ui_top(), 2, 2);
		) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
			uix_gloss(1.5);
			ui_color(0, 0, 0, 0.2);
			ui_border();
			ui_color(205, 147, 74);
		) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
			gfx_blit(uix_control_theme_buffer, 1, 0, 660, 380, 120, 60, ui_left_retina(), ui_top_retina(), ui_width_retina(), ui_height_retina());
			uix_control_color_from_theme(791, 390);
		) : (
			ui_color(0, 0, 0);
			uix_gloss(1);
			ui_border();
		);
	ui_pop();
);

function control_group(text) local(texth, textw, textl, textr, textv) (
	uix_control_theme == 2/*uix_THEME:TRON*/ ? (
		ui_fontsize(min(min(16, ui_height()*0.2), ui_padding_y()*2));

		ui_pad(ui_padding_x()/2, ui_padding_y()/2);

		ui_push();
			ui_color(128, 128, 128);
			gfx_roundrect(ui_left_retina(), ui_top_retina() + 1, ui_width_retina(), ui_height_retina() - 1, 10*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/], 1);
		ui_pop();

		strlen(text) > 0 ? (
			ui_split_bottom(ui_texth() + ui_padding_y()/2);
				ui_color(128, 128, 128);
				ui_border_top();

				ui_color(255, 255, 255);
				ui_align(0.5, 0.5);
				ui_text(text);
			ui_pop();
		);
		ui_pad();
	) : (
		ui_push();
			uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
				ui_fontsize(min(min(18, ui_height()*0.2), ui_padding_y()*2));
			) : (
				ui_fontsize(min(min(16, ui_height()*0.22), ui_padding_y()*3));
			);

			texth = textw = 0;
			uix_setgfxfont();
			textw = texth = 0;
			text >= 0 ? gfx_measurestr(text, textw, texth);
			!texth ? texth = gfx_texth;
			texth /= uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
			textw /= uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];

			// Border color
			uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
				ui_color(255, 255, 255);
			) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
				uix_control_color_from_theme(151, 30, 0.5);
			) : (
				ui_color(102, 102, 102, 0.5);
			);

			ui_pad(ui_padding_x()/2, 0);
			ui_split_top(texth);
				ui_padleft();
				ui_padright();
				uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
					ui_align(0.5, 0.5);
				) : (
					ui_align(0, 0.5);
				);

				ui_push_width(textw + ui_padding_x());
					textl = ui_left_retina();
					textr = ui_right_retina();
					textv = ui_top_retina() + ui_height_retina()/2;
					textw > 0 ? (
						ui_align(0.5, 0.5);
						ui_text(text);
					);
				ui_pop();
			ui_pop();
			ui_padbottom();

			// Border colour is lighter
			uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
				uix_control_color_from_theme(151, 30, 0.25);
			);

			!textw ? textl = textr = ui_left_retina();
			ui_push();
				gfx_x = textr;
				gfx_y = textv;
				uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
					uix_dotted_line(textr, textv, ui_right_retina() - 1, textv, 1, 1);
					uix_dotted_line(ui_right_retina() - 1, textv, ui_right_retina() - 1, ui_bottom_retina(), 1, 1);
					uix_dotted_line(ui_right_retina() - 1, ui_bottom_retina(), ui_left_retina(), ui_bottom_retina(), 1, 1);
					uix_dotted_line(ui_left_retina(), ui_bottom_retina(), ui_left_retina(), textv, 1, 1);
					uix_dotted_line(ui_left_retina(), textv, textl, textv, 1, 1);
				) : (
					gfx_lineto(ui_right_retina() - 1, gfx_y);
					gfx_lineto(gfx_x, ui_bottom_retina());
					gfx_lineto(ui_left_retina(), gfx_y);
					gfx_lineto(gfx_x, textv);
					gfx_lineto(textl, gfx_y);
				);
			ui_pop();
		ui_pop();
		ui_pad();
		uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
			ui_pad(0, -1, 0, -1);
		) : (
			ui_pad(0, -1);
		);
	);
);

function control_readout(text) local() (
	ui_push();
		control_background_inset();
		ui_text(text);
		control_finish_inset();
	ui_pop();
);

function control_button(text, status) local(click) (
	ui_push();
		status ? control_background_enabled() : control_background_disabled();
		ui_text(text);
		status ? control_finish_enabled() : control_finish_disabled();

		click = status ? ui_click() : 0;
	ui_pop();
	click;
);
function control_button(text) (
	control_button(text, 1);
);

function control_arrow(direction) local(size, tmp, centerx, centery, point1x, point1y, point2x, point2y, point3x, point3y) ( // left, up, right, down
	size = min(ui_height_retina(), ui_width_retina());
	direction == "left" || direction == 0 ? (
		direction = 0;
		centerx = size/2;
		centery = ui_height_retina()/2;
	) : direction == "up" || direction == 1 ? (
		direction = 1;
		centerx = ui_width_retina()/2;
		centery = size/2;
	) : direction == "right" || direction == 2 ? (
		direction = 2;
		centerx = ui_width_retina() - size/2;
		centery = ui_height_retina()/2;
	) : (
		direction = 3;
		centerx = ui_width_retina()/2;
		centery = ui_height_retina() - size/2;
	);
	centerx += ui_left_retina();
	centery += ui_top_retina();

	size = min(size, ui_texth_retina()*2);
	size *= 0.5;
	angle = direction*$pi/2;

	// Draw facing upwards to start
	point1x = 0;
	point1y = 0.5*size*(direction >= 2 ? 1 : -1);
	point2x = -0.5*size;
	point2y = -point1y;
	point3x = 0.5*size;
	point3y = -point1y;
	direction == 0 || direction == 2 ? (
		// Swap X and Y
		tmp = point1x;
		point1x = point1y;
		point1y = tmp;
		tmp = point2x;
		point2x = point2y;
		point2y = tmp;
		tmp = point3x;
		point3x = point3y;
		point3y = tmp;
	);

	ui_color_refresh();
	gfx_triangle(centerx + point1x, centery + point1y, centerx + point2x, centery + point2y, centerx + point3x, centery + point3y);
);

function control_selector(value, text, next_value, prev_value) local(buttonwidth) (
	ui_push_height(ui_texth() + 2*ui_padding_y());
		control_background_inset();
		buttonwidth = min(ui_height()/2, ui_width()/2);

		ui_halign() <= 0.5 ? ui_split_left(buttonwidth) : ui_split_right(buttonwidth);
			ui_color(255, 255, 255, 0.8);
			ui_split_topratio(0.5);
				next_value != value ? control_background_enabled() : control_background_disabled();
				control_arrow("up");
				next_value != value ? control_finish_enabled() : control_finish_disabled();
				ui_click() ? (
					value = next_value;
					uix_undo_point(1);
					ui_click_clear();
				);
			ui_split_next();
				prev_value != value ? control_background_enabled() : control_background_disabled();
				control_arrow("down");
				prev_value != value ? control_finish_enabled() : control_finish_disabled();
				ui_click() ? (
					value = prev_value;
					uix_undo_point(1);
					ui_click_clear();
				);
			ui_pop();
		ui_pop();

		ui_push();
			ui_padleft();
			ui_padright();
			ui_text(text);
		ui_pop();

		control_finish_inset();
	ui_pop();
	value;
);

function control_navbar(title, next_title, next_screen) local(click, direction) (
	direction = 0;
	ui_split_toptext(title);
		control_background_passive();
		title ? (
			ui_text(title);
		);
		control_finish_passive();

		ui_screen_level() > 0 ? (
			ui_split_lefttext("< back");
				control_button("< back") ? (
					direction = -1;
					ui_screen_close();
				);
			ui_pop();
		);
		(next_screen >= 0 || next_title >= 0) ? (
			next_title = next_title ? next_title : "next >";
			ui_split_righttext(next_title);
				control_button(next_title) ? (
					direction = 1;
					next_screen > 0 ? ui_screen_open(next_screen);
				);
			ui_pop();
		);
	ui_pop();
	direction
);
function control_navbar(title) (
	control_navbar(title, -1, -1);
);

function uix_slider_value_to_ratio(value, range_low, range_high, curve_bias) local(valueratio) (
	valueratio = max(0, min(1, (value - range_low)/(range_high - range_low)));
	curve_bias ? (
		log(valueratio*(exp(curve_bias) - 1) + 1)/curve_bias
	) : valueratio;
);

function uix_slider_ratio_to_value(ratio, range_low, range_high, curve_bias) local(valueratio) (
	ratio = max(0, min(1, ratio));
	valueratio = curve_bias ? (
		(exp(ratio*curve_bias) - 1)/(exp(curve_bias) - 1)
	) : ratio;
	range_low + (range_high - range_low)*valueratio;
);

function uix_control_slider_h(value, range_low, range_high, curve_bias, hasDefault, defaultValue, linkToLeft) local(valueratio, screenratio, state, barwidth, handlesize) (
	// We calculate screenratio first (before updating value) because then any rounding/limiting applied to the value is reflected in the UI
	screenratio = uix_slider_value_to_ratio(value, range_low, range_high, curve_bias);

	ui_push_height(ui_texth()*2);
		handlesize = ui_height();
		uix_control_theme == 2/*uix_THEME:TRON*/ ? (
			control_background_technical();
		) : (
			control_background_inset();
			control_finish_inset();
		);
		state = control_state();

		ui_push();
			linkToLeft ? (
				barwidth = floor((ui_width() - 1)*screenratio + 1.5);
				ui_split_left(barwidth);
			) : (
				ui_align(screenratio, 0.5);
				ui_push_width(handlesize);
			);
				uix_control_theme == 2/*uix_THEME:TRON*/ ? (
					ui_color(121, 173, 185);
					ui_fill();
				) : (
					control_background_enabled(state);
					control_finish_enabled(state);
				);
			ui_pop();
		ui_pop();
		uix_control_theme == 2/*uix_THEME:TRON*/ ? (
			control_finish_technical();
		) : (
			0;
		);
	ui_pop();

	ui_mouse_down() || ui_drag() ? (
		screenratio = linkToLeft ? (
			ui_mouse_xratio()
		) : (
			(ui_mouse_x() - handlesize*0.5)/(ui_width() - handlesize);
		);
		value = uix_slider_ratio_to_value(screenratio, range_low, range_high, curve_bias);
	);
	ui_scroll_y() ? (
		valueratio = uix_slider_value_to_ratio(value, range_low, range_high, curve_bias);
		valueratio += ui_scroll_y()/uix_scroll_scale;
		value = uix_slider_ratio_to_value(valueratio, range_low, range_high, curve_bias);
	);
	hasDefault && ui_click() && ui_clickcount() == 2 ? (
		value = defaultValue;
		uix_undo_point();
	);
	ui_scroll_y() ? uix_undo_point(1);
	ui_drag_up() ? uix_undo_point();
	value;
);
function control_slider_left(value, range_low, range_high, curve_bias, default) (
	uix_control_slider_h(value, range_low, range_high, curve_bias, 1, default, 1);
);
function control_slider_left(value, range_low, range_high, curve_bias) (
	uix_control_slider_h(value, range_low, range_high, curve_bias, 0, 0, 1);
);
function control_slider_left(value, range_low, range_high) (
	control_slider_left(value, range_low, range_high, 0);
);
function control_slider_x(value, range_low, range_high, curve_bias, default) (
	uix_control_slider_h(value, range_low, range_high, curve_bias, 1, default, 0);
);
function control_slider_x(value, range_low, range_high, curve_bias) (
	uix_control_slider_h(value, range_low, range_high, curve_bias, 0, 0, 0);
);
function control_slider_x(value, range_low, range_high) (
	control_slider_x(value, range_low, range_high, 0);
);

function uix_control_slider_v(value, range_low, range_high, curve_bias, hasDefault, defaultValue, linkToBottom) local(valueratio, screenratio, state, barheight, 	handlesize) (
	// We calculate screenratio first (before updating value) because then any rounding/limiting applied to the value is reflected in the UI
	screenratio = uix_slider_value_to_ratio(value, range_low, range_high, curve_bias);

	ui_push_width(ui_texth()*2);
		handlesize = ui_width();
		uix_control_theme == 2/*uix_THEME:TRON*/ ? (
			control_background_technical();
		) : (
			control_background_inset();
			control_finish_inset();
		);
		state = control_state();

		ui_push();
			linkToBottom ? (
				barheight = floor((ui_height() - 1)*screenratio + 1.5);
				ui_split_bottom(barheight);
			) : (
				ui_align(0.5, 1 - screenratio);
				ui_push_height(handlesize);
			);
				uix_control_theme == 2/*uix_THEME:TRON*/ ? (
					ui_color(121, 173, 185);
					ui_fill();
				) : (
					control_background_enabled(state);
					control_finish_enabled(state);
				);
			ui_pop();
		ui_pop();
		uix_control_theme == 2/*uix_THEME:TRON*/ ? (
			control_finish_technical();
		) : (
			0;
		);
	ui_pop();

	ui_mouse_down() || ui_drag() ? (
		screenratio = linkToBottom ? (
			1 - ui_mouse_yratio()
		) : (
			(ui_height() - ui_mouse_y() - handlesize*0.5)/(ui_height() - handlesize);
		);
		value = uix_slider_ratio_to_value(screenratio, range_low, range_high, curve_bias);
	);
	ui_scroll_y() ? (
		valueratio = uix_slider_value_to_ratio(value, range_low, range_high, curve_bias);
		valueratio += ui_scroll_y()/uix_scroll_scale;
		value = uix_slider_ratio_to_value(valueratio, range_low, range_high, curve_bias);
	);
	hasDefault && ui_click() && ui_clickcount() == 2 ? (
		value = defaultValue;
		uix_undo_point();
	);
	ui_scroll_y() ? uix_undo_point(1);
	ui_drag_up() ? uix_undo_point();
	value;
);
function control_slider_bottom(value, range_low, range_high, curve_bias, default) (
	uix_control_slider_v(value, range_low, range_high, curve_bias, 1, default, 1);
);
function control_slider_bottom(value, range_low, range_high, curve_bias) (
	uix_control_slider_v(value, range_low, range_high, curve_bias, 0, 0, 1);
);
function control_slider_bottom(value, range_low, range_high) (
	control_slider_bottom(value, range_low, range_high, 0);
);
function control_slider_y(value, range_low, range_high, curve_bias, default) (
	uix_control_slider_v(value, range_low, range_high, curve_bias, 1, default, 0);
);
function control_slider_y(value, range_low, range_high, curve_bias) (
	uix_control_slider_v(value, range_low, range_high, curve_bias, 0, 0, 0);
);
function control_slider_y(value, range_low, range_high) (
	control_slider_y(value, range_low, range_high, 0);
);

function uix_control_dragvalue(value, range_low, range_high, curve_bias) local(valueratio, deltay) (
	ui_drag() || ui_scroll_y() ? (
		valueratio = uix_slider_value_to_ratio(value, range_low, range_high, curve_bias);
		deltay = ui_mouse_dy()/uix_drag_scale*exp(-abs(ui_drag_x())/uix_drag_scale) - ui_scroll_y()/5000;
		value = uix_slider_ratio_to_value(valueratio - deltay, range_low, range_high, curve_bias);
	);
	ui_scroll_y() ? uix_undo_point(1);
	ui_drag_up() ? uix_undo_point();
	value;
);

function uix_thick_arc(centrex, centrey, inner_radius, lowangle, angle) (
	gfx_arc(centrex, centrey, inner_radius, lowangle, angle, 1);
	gfx_arc(centrex + 1, centrey, inner_radius, lowangle, angle, 1);
	gfx_arc(centrex, centrey + 1, inner_radius, lowangle, angle, 1);
	gfx_arc(centrex - 1, centrey, inner_radius, lowangle, angle, 1);
	gfx_arc(centrex, centrey - 1, inner_radius, lowangle, angle, 1);
);

function uix_thick_line(x1, y1, x2, y2) (
	gfx_line(x1, y1, x2, y2, 1);
	gfx_line(x1 + 1, y1, x2 + 1, y2, 1);
	gfx_line(x1, y1 + 1, x2, y2 + 1, 1);
	gfx_line(x1 - 1, y1, x2 - 1, y2, 1);
	gfx_line(x1, y1 - 1, x2, y2 - 1, 1);
);

function uix_control_dial(value, range_low, range_high, curve_bias, hasDefault, defaultValue, linkToLeft)  local(valueratio, screenratio, centrex, centrey, radius, inner_radius, highangle, lowangle, angle, x1, x2, y1, y2) (
	screenratio = uix_slider_value_to_ratio(value, range_low, range_high, curve_bias);

	radius = min(min(ui_width_retina(), ui_height_retina())/2 - 1, 30*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/]);
	centrex = (ui_left_retina() + radius) + (ui_width_retina() - radius*2 - 1)*ui_halign();
	centrey = (ui_top_retina() + radius) + (ui_height_retina() - radius*2 - 1)*ui_valign();
	inner_radius = radius - 2*(1 + ui_retina());

	// Draw arc
	lowangle = -2.3;
	highangle = 2.3;
	angle = lowangle + (highangle - lowangle)*(screenratio*0.98 + 0.01);

	uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
		gfx_blit(uix_control_theme_buffer, 1, 0, 820, 20, 120, 120, centrex - radius + 0.5, centrey - radius + 0.5, radius*2, radius*2);
		gfx_blit(uix_control_theme_buffer, 1, angle, 820, 200, 120, 120, centrex - radius + 0.5, centrey - radius + 0.5, radius*2, radius*2);
	) : (
		uix_control_background_enabled_circle(centrex, centrey, radius, "none");
		uix_control_theme == 2/*uix_THEME:TRON*/ || !linkToLeft ? (
			uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
				ui_color(0, 0, 0);
				x1 = centrex + sin(lowangle)*inner_radius;
				y1 = centrey - cos(lowangle)*inner_radius;
				x2 = centrex + sin(highangle)*inner_radius;
				y2 = centrey - cos(highangle)*inner_radius;
				gfx_circle(x1, y1, 1, 1, 1);
				gfx_circle(x2, y2, 1, 1, 1);
			) : (
				ui_color(131, 184, 206);
				uix_thick_arc(centrex, centrey, inner_radius, lowangle, highangle);
			);

			x1 = centrex + sin(angle)*inner_radius*0.5;
			y1 = centrey - cos(angle)*inner_radius*0.5;
			x2 = centrex + sin(angle)*inner_radius;
			y2 = centrey - cos(angle)*inner_radius;
			uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
				ui_color(0, 0, 0);
			) : (
				ui_color(255, 255, 255);
			);
			uix_thick_line(x1, y1, x2, y2);
		) : (
			gfx_a = 1;
			uix_thick_arc(centrex, centrey, inner_radius, lowangle, angle);
		);
		ui_pad(5, 5);

		uix_control_finish_enabled_circle(centrex, centrey, radius, 0);
	);

	hasDefault && ui_click() && ui_clickcount() == 2 ? (
		value = defaultValue;
	);
	uix_control_dragvalue(value, range_low, range_high, curve_bias);
);
function control_dial_left(value, range_low, range_high, curve_bias, default) (
	uix_control_dial(value, range_low, range_high, curve_bias, 1, default, 1);
);
function control_dial_left(value, range_low, range_high, curve_bias) (
	uix_control_dial(value, range_low, range_high, curve_bias, 0, 0, 1);
);
function control_dial_left(value, range_low, range_high) (
	control_dial_left(value, range_low, range_high, 0);
);
function control_dial(value, range_low, range_high, curve_bias, default) (
	uix_control_dial(value, range_low, range_high, curve_bias, 1, default, 0);
);
function control_dial(value, range_low, range_high, curve_bias) (
	uix_control_dial(value, range_low, range_high, curve_bias, 0, 0, 0);
);
function control_dial(value, range_low, range_high) (
	control_dial(value, range_low, range_high, 0);
);

function uix_control_dial_angle(angle, isUnit) local(display_angle, radius, centrex, centrey, inner_radius, x1, x2, y1, y2) (
	radius = min(min(ui_width_retina(), ui_height_retina())/2 - 1, 30*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/]);
	centrex = (ui_left_retina() + radius) + (ui_width_retina() - radius*2 - 1)*ui_halign();
	centrey = (ui_top_retina() + radius) + (ui_height_retina() - radius*2 - 1)*ui_valign();

	display_angle = isUnit ? 2*$pi*angle : angle;
	uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
		gfx_blit(uix_control_theme_buffer, 1, 0, 980, 20, 120, 120, centrex - radius + 0.5, centrey - radius + 0.5, radius*2, radius*2);
		gfx_blit(uix_control_theme_buffer, 1, display_angle, 980, 200, 120, 120, centrex - radius + 0.5, centrey - radius + 0.5, radius*2, radius*2);
	) : (
		inner_radius = radius - 4;
		uix_control_background_enabled_circle(centrex, centrey, radius, "none");

		x1 = centrex + sin(display_angle)*inner_radius*0.5;
		y1 = centrey - cos(display_angle)*inner_radius*0.5;
		x2 = centrex + sin(display_angle)*inner_radius;
		y2 = centrey - cos(display_angle)*inner_radius;
		uix_thick_line(x1, y1, x2, y2);

		ui_pad(5, 5);

		uix_control_finish_enabled_circle(centrex, centrey, radius, 0);
	);

	isUnit ? (
		angle = uix_control_dragvalue(angle, -0.03, 1.03, 0);
		angle -= floor(angle);
	) : (
		angle = uix_control_dragvalue(angle, -0.1, 2*$pi + 0.1, 0);
		angle < 0 ? angle += 2*$pi;
		angle >= 2*$pi ? angle -= 2*$pi;
	);
	angle;
);
function control_dial_angle(angle) (
	uix_control_dial_angle(angle, 0);
);
function control_dial_angle(angle, default) (
	angle = control_dial_angle(angle);
	ui_click() && ui_clickcount() == 2 ? (
		angle = default;
	);
	angle;
);
function control_dial_angle_unit(angle) (
	angle = uix_control_dial_angle(angle, 1);
);
function control_dial_angle_unit(angle, default) (
	angle = uix_control_dial_angle(angle, 1);
	ui_click() && ui_clickcount() == 2 ? (
		angle = default;
	);
	angle;
);

function control_dialog(title, width, height, doneText, cancelText) local(accepted) (
	accepted = 0;

	ui_push();
		uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
			ui_color(0, 0, 0);
			ui_fill();
		) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
			ui_color(0, 0, 0, 0.5);
			ui_fill();
		) : (
			ui_color(0, 0, 0, 0.2);
			ui_fill();
		);
	ui_pop();

	width <= 0 ? width = min(ui_width()*0.8, 450);
	height <= 0 ? height = min(ui_height()*0.8, 350);

	title >= 0 ? height += ui_text_height(title) + ui_padding_y()*2;

	width = min(width + ui_padding_x()*2, ui_width());
	height = min(height + ui_padding_y()*2, ui_height());
	ui_pad((ui_width() - width)/2, (ui_height() - height)/2);
	uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? ui_push_clip(1) : ui_push();
		uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
			ui_color(0, 0, 0);
			ui_fill();
			ui_color(255, 255, 255);
			ui_border();
		) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
			ui_color($x45, $x45, $x45);
			ui_fill();
			ui_color(255, 255, 255, 0.1);
			ui_border();
		) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
			y = 0;
			while (y < gfx_h) (
				x = 0;
				while (x < gfx_w) (
					gfx_blit(uix_control_theme_buffer, ui_retina(), 0, 20, 20, 120, 120, x, y);
					x += 120*ui_retina();
				);
				y += 120;
			);
		) : (
			ui_color(242, 242, 242);
			ui_fill();
			ui_color(102, 102, 102, 0.5);
			ui_border();
		);
	ui_pop();


	// set main colour
	uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
		ui_color(255, 255, 255);
	) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
		ui_color(255, 255, 255);
	) : uix_control_theme == 3/*uix_THEME:BITMAP_SIMPLE*/ ? (
		uix_control_color_from_theme(151, 30);
		ui_border();
	) : (
		ui_color(12, 12, 12);
	);

	ui_key() == 27 ? (
		accepted = (cancelText >= 0) ? -1 : 1;
	);
	ui_key() == 13 ? accepted = 1;

	doneText >= 0 || cancelText >= 0 ? (
		ui_split_bottomtext(-1);
			cancelText >= 0 && doneText < 0 ? (
				control_background_disabled();
				ui_text(cancelText);
				control_finish_enabled();

				ui_click() ? accepted = -1;
			) : cancelText >= 0 ? (
				ui_push();
					ui_split_leftratio(0.5);
						control_button(doneText) ? accepted = 1;
					ui_split_next();
						control_background_disabled();
						ui_text(cancelText);
						control_finish_enabled();

						ui_click() ? accepted = -1;
					ui_pop();
				ui_pop();
			) : (
				control_button(doneText) ? accepted = 1;
			);
		ui_pop();
	);

	title >= 0 ? (
		ui_split_toptext(title);
			control_background_passive();
			ui_text(title);
			control_finish_passive();
		ui_pop();
	);

	ui_pad();
	accepted ? ui_screen_close();
	accepted;
);

function control_dialog(title, doneText, cancelText) local(accepted) (
	control_dialog(title, -1, -1, doneText, cancelText);
);

function control_dialog(title, doneText) local(accepted) (
	control_dialog(title, doneText, -1);
);

function control_dialog(title) local(accepted) (
	control_dialog(title, "OK");
);

function control_switch(value) local(state) (
	ui_click() ? (
		value = !value;
		uix_undo_point();
	);

	ui_push_height(ui_texth()*2);
		ui_push_width(min(ui_texth()*4, ui_height()*2.5));

			control_background_inset();
			control_finish_inset();

			state = control_state();
			value ? ui_split_rightratio(0.5) : ui_split_leftratio(0.5);
				control_background_enabled(state);
				control_finish_enabled(state);
			ui_pop();
		ui_pop();
	ui_pop();
	value;
);

function control_radio(value, option_value) local(state) (
	ui_click() ? (
		value = option_value;
		uix_undo_point();
	);

	ui_push_height(ui_texth());
		ui_push_width(ui_texth());

			control_background_inset();
			control_finish_inset();

			value == option_value ? (
				ui_pad(2, 2);
				control_background_enabled(state);
				control_finish_enabled(state);
			);
		ui_pop();
	ui_pop();
	value;
);

function uix_control_closest_substring_width(text, targetwidth) local(text_length, best_index, best_width, i, candidatewidth) (
	best_index = 0;
	best_width = 0;

	i = 0;
	text_length = strlen(text);
	while (i <= text_length) (
		strcpy_substr(#uix_control_closest_substring_width, text, 0, i);
		candidatewidth = ui_text_width(#uix_control_closest_substring_width);
		abs(candidatewidth - targetwidth) <= abs(best_width - targetwidth) ? (
			best_width = candidatewidth;
			best_index = i;
		);
		i += 1;
	);
	best_index;
);

function uix_autoselect_char(char) (
	// Alphanumeric (plus "." and "_") in the latin1 charset
	char == '.' || char == '_' || (char >= '0' && char <= '9') || (char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')
		|| (char >= 192 && char <= 255);
);

function uix_control_textinput_pack(focused, start, end) local(packed) (
	packed = start + end*67108864;
	focused ? packed + 1: -packed;
);
function uix_control_textinput_unpack_focused(packed) (
	packed > 0 ? 1 : 0;
);
function uix_control_textinput_unpack_cursor(packed) (
	packed > 0 ? (packed - 1)%67108864 : (-packed)%67108864;
);
function uix_control_textinput_unpack_trail(packed) (
	packed > 0 ? floor((packed - 1)/67108864) : floor(-packed/67108864);
);

function control_textinput_hasfocus(prompt_selectpacked) (
	uix_control_textinput_unpack_focused(prompt_selectpacked);
);

function control_textinput_select(packed, cursor, trail) local(focused) (
	focused = uix_control_textinput_unpack_focused(packed);
	uix_control_textinput_pack(focused, cursor, trail);
);

function control_textinput_focus(packed) local(focused, cursor, trail) (
	cursor = uix_control_textinput_unpack_cursor(packed);
	trail = uix_control_textinput_unpack_trail(packed);

	uix_control_textinput_pack(1, cursor, trail);
);

function control_textinput_unfocus(packed) local(cursor, trail) (
	cursor = uix_control_textinput_unpack_cursor(packed);
	trail = uix_control_textinput_unpack_trail(packed);

	uix_control_textinput_pack(0, cursor, trail);
);

function control_textinput(text, packed) local(text_length, prompt_selectlow, prompt_selecthigh, textx, texty, selectw, t, char, keyinterested, char_index, select_padding) (
	text_length = strlen(text);

	prompt_focused = uix_control_textinput_unpack_focused(packed);
	prompt_selectcursor = uix_control_textinput_unpack_cursor(packed);
	prompt_selecttrail = uix_control_textinput_unpack_trail(packed);

	prompt_selectcursor = min(text_length, prompt_selectcursor);
	prompt_selecttrail = min(text_length, prompt_selecttrail);

	prompt_selecthigh = max(prompt_selectcursor, prompt_selecttrail);
	prompt_selectlow = prompt_selecttrail >= 0 ? min(prompt_selectcursor, prompt_selecttrail) : prompt_selecthigh;

	ui_push();
		ui_align(0, 0.5);
		control_background_inset();

		ui_mouse_down() ? (
			char_index = uix_control_closest_substring_width(text, ui_mouse_x() - ui_padding_x());
			(mouse_cap&8) ? ( // Shift
				prompt_selecttrail = char_index;
			) : (
				prompt_selectcursor = char_index;
				prompt_selecttrail = prompt_selectcursor;
			);
			uix_control_cursortimeoffset = time_precise();
		);
		ui_drag() ? (
			prompt_selecttrail = uix_control_closest_substring_width(text, ui_mouse_x() - ui_padding_x());
			uix_control_cursortimeoffset = time_precise();
		);
		(ui_drag() || ui_click()) && ui_clickcount() == 2 ? (
			while (prompt_selectlow > 0 && uix_autoselect_char(str_getchar(text, prompt_selectlow - 1))) (
				prompt_selectlow -= 1;
			);
			while (prompt_selecthigh < text_length && uix_autoselect_char(str_getchar(text, prompt_selecthigh))) (
				prompt_selecthigh += 1;
			);

			ui_click() ? (
				ui_click_clear();
				prompt_selectcursor = prompt_selectlow;
				prompt_selecttrail = prompt_selecthigh;
			);
		);
		ui_mouse_down_outside() ? (
			prompt_focused = 0;
			uix_undo_point();
		);

		ui_push();
			ui_pad();
			ui_font_refresh();
			textx = ui_left_retina();
			texty = ui_top_retina() + (ui_height_retina() - gfx_texth)/2;
			gfx_x = textx;
			gfx_y = texty;

			strcpy_substr(#control_tmp1, text, 0, prompt_selectlow);
			gfx_drawstr(#control_tmp1);

			prompt_selecthigh > prompt_selectlow ? (
				strcpy_substr(#control_tmp1, text, prompt_selectlow, prompt_selecthigh - prompt_selectlow);
				selectw = ui_text_width(#control_tmp1);

				uix_control_theme == 1/*uix_THEME:BLACK_AND_WHITE*/ ? (
					select_padding = 1*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
				) : uix_control_theme == 2/*uix_THEME:TRON*/ ? (
					select_padding = 2*uix_drawconfig_current[9/*uix_DRAWCONFIG:RETINA_SCALING*/];
				) : (
					select_padding = 0;
				);
				ui_push();
					ui_set_rect_retina(gfx_x - select_padding, gfx_y - select_padding, selectw + select_padding*2, gfx_texth + select_padding*2);
					control_background_enabled();
					gfx_drawstr(#control_tmp1);
				ui_pop();
				ui_font_refresh();
			) : (
				t = time_precise() - uix_control_cursortimeoffset;
				t = t - floor(t);
				prompt_selecttrail == prompt_selectcursor ? t < 0.5 ? (
					gfx_line(gfx_x, gfx_y, gfx_x, gfx_y + gfx_texth);
				);
			);

			strcpy_from(#control_tmp1, text, max(prompt_selectlow, prompt_selecthigh));
			gfx_drawstr(#control_tmp1);
		ui_pop();

		control_finish_inset();

		prompt_focused ? (
			keyinterested = prompt_focused;
			while (prompt_focused && ui_key()) (
				char = ui_key();
				ui_key_printable() ? (
					strcpy_substr(#control_tmp1, text, 0, prompt_selectlow);
					str_setchar(#control_tmp1, prompt_selectlow, char);
					strcpy_from(#control_tmp2, text, prompt_selecthigh);
					strcat(#control_tmp1, #control_tmp2);
					strcpy(text, #control_tmp1);

					prompt_selectcursor += 1;
					prompt_selecttrail = prompt_selectcursor;
					text_length = strlen(text);
					uix_undo_point(1);
				) : char == 8 || char == 6579564 ? ( // Backspace and Delete
					prompt_selectlow == prompt_selecthigh ? (
						char == 8 ? (
							prompt_selectlow = max(prompt_selectlow - 1, 0);
						) : (
							prompt_selecthigh = min(text_length, prompt_selecthigh + 1);
						);
					);
					strcpy_substr(#control_tmp1, text, 0, prompt_selectlow);
					strcpy_from(#control_tmp2, text, prompt_selecthigh);
					strcat(#control_tmp1, #control_tmp2);
					strcpy(text, #control_tmp1);

					prompt_selectcursor = prompt_selecttrail = prompt_selectlow;
					text_length = strlen(text);
					uix_undo_point(1);
				) : char == 1919379572 ? ( // Right
					(mouse_cap&8) ? ( // Shift
						prompt_selectcursor = min(prompt_selectcursor + 1, text_length);
					) : (
						prompt_selectlow == prompt_selecthigh ? (
							// Move cursor right
							prompt_selectcursor = min(prompt_selectcursor + 1, text_length);
						) : (
							// Move to right of selection
							prompt_selectcursor = prompt_selecthigh;
						);
						prompt_selecttrail = prompt_selectcursor;
					);
				) : char == 1818584692 ? ( // Left
					(mouse_cap&8) ? ( // Shift
						prompt_selectcursor = max(prompt_selectcursor - 1, 0);
					) : (
						prompt_selectlow == prompt_selecthigh ? (
							// Move cursor left
							prompt_selectcursor = max(prompt_selectcursor - 1, 0);
						) : (
							// Move to left of selection
							prompt_selectcursor = prompt_selectlow;
						);
						prompt_selecttrail = prompt_selectcursor;
					);
				) : char == 1752132965 ? ( // Home
					prompt_selectcursor = 0;
					(!(mouse_cap&8)) ? (
						prompt_selecttrail = prompt_selectcursor;
					);
				) : char == 6647396 ? ( // End
					prompt_selectcursor = text_length;
					(!(mouse_cap&8)) ? (
						prompt_selecttrail = prompt_selectcursor;
					);
				) : char == 1 ? ( // Ctrl+A
					prompt_selectcursor = 0;
					prompt_selecttrail = text_length;
				) : (
					keyinterested = 0;
				);
				keyinterested ? (
					ui_key_next();
					uix_control_cursortimeoffset = time_precise();
				);
			);
		);
	ui_pop();

	uix_control_textinput_pack(prompt_focused, prompt_selectcursor, prompt_selecttrail);
);

uix_control_hidden_text_active_x =uix_control_hidden_text_active_y = -1;
uix_control_hidden_text_state;
function control_hidden_text(text) local(i) (
	uix_control_hidden_text_active_x == ui_left() && uix_control_hidden_text_active_y == ui_top() ? (
		ui_key() == 27 || ui_key() == 13 || ui_mouse_down_outside(1) || ui_mouse_down_outside(2) || ui_mouse_down_outside(64) ? (
			uix_control_hidden_text_active_x = uix_control_hidden_text_active_y = -1;
		);
		uix_control_hidden_text_state = control_textinput(text, uix_control_hidden_text_state);
	) : (
		ui_text(text);
		ui_click(2) || (ui_click() && ui_clickcount() == 3) ? ( // Right-click
			uix_control_hidden_text_active_x = ui_left();
			uix_control_hidden_text_active_y = ui_top();
			// TODO: select-all here, when it's implemented
			uix_control_hidden_text_state = control_textinput_focus(0);
			uix_control_hidden_text_state = control_textinput_select(uix_control_hidden_text_state, 0, strlen(text));
		);
	);
);
function control_hidden_textnumber(actualnumber, number, format) local(i) (
	uix_control_hidden_text_active_x == ui_left() && uix_control_hidden_text_active_y == ui_top() ? (
		ui_key() == 27 || ui_key() == 13 || ui_mouse_down_outside(1) || ui_mouse_down_outside(2) || ui_mouse_down_outside(64) ? (
			uix_control_hidden_text_active_x = uix_control_hidden_text_active_y = -1;
			ui_key() != 27 ? (
				actualnumber = ui_parsenumber(#uix_control_hidden_textnumber, actualnumber);
				uix_undo_point();
			);
		);
		uix_control_hidden_text_state = control_textinput(#uix_control_hidden_textnumber, uix_control_hidden_text_state);
	) : (
		ui_textnumber(number, format);
		ui_click(2) || (ui_click() && ui_clickcount() == 3) ? ( // Right-click
			sprintf(#uix_control_hidden_textnumber, format ? format : "%f", number);
			uix_control_hidden_text_active_x = ui_left();
			uix_control_hidden_text_active_y = ui_top();
			// TODO: select-all here, when it's implemented
			uix_control_hidden_text_state = control_textinput_focus(0);
			uix_control_hidden_text_state = control_textinput_select(uix_control_hidden_text_state, 0, strlen(#uix_control_hidden_textnumber));
		);
	);
	actualnumber;
);
function control_hidden_textnumber(number, format) (
	control_hidden_textnumber(number, number*1.00000006 /* sprintf() bug */, format);
);
function control_hidden_textnumber(number) (
	control_hidden_textnumber(number, "%f");
);

function control_system() local(prompt_title, prompt_text, prompt_init, prompt_selectlow, prompt_selecthigh, textx, texty, selectw, t, char, OK) (
	ui_screen() == "control.prompt" ? (
		prompt_text = ui_screen_arg(0);
		prompt_title = ui_screen_arg(1);
		prompt_init = ui_screen_arg(2);
		prompt_selectpacked = ui_screen_arg(3);

		!prompt_init ? (
			while (gfx_getchar()) (
				0; // Drop keys from queue
			);
			prompt_init = 1;
			strcpy(#control_prompt_text, prompt_text);
			prompt_selectpacked = control_textinput_focus(prompt_selectpacked);
		);

		OK = control_dialog(prompt_title, 0, (ui_texth() + ui_padding_y()*2)*3, "done", "cancel");

		ui_push_heighttext(-1);
			prompt_selectpacked = control_textinput(#control_prompt_text, prompt_selectpacked);
		ui_pop();

		// Confirm/exit
		ui_key() == 13 ? (
			OK = 1;
		) : ui_key() == 27 ? (
			OK = -1;
		);

		ui_screen_arg(2, prompt_init);
		ui_screen_arg(3, prompt_selectpacked);

		OK ? (
			(OK == 1) ? strcpy(prompt_text, #control_prompt_text);
			ui_screen() == "control.prompt" ? ui_screen_close();
		);
	) : ui_system();
);
