#define MF_DS_VALUE		(1i << 0i)

typedef struct
{
	float *currentf;
	int *currenti;
	float key;
	vector *mousepos;
	vector mousediff;
	int flags;
} menu_t;

int (vector topleft, vector bottomright, vector cursor) cursor_in_widget
{
	if (cursor_x <= bottomright_x && cursor_x >= topleft_x)
		if (cursor_y <= bottomright_y && cursor_y >= topleft_y)
			return 1;
	return 0;
}

void(menu_t *menu, string fieldname, vector pos, float *value, float minv, float maxv) sliderf_widgit =
{
	local vector rpos, spos, col;
	local float f;
	local int render_only;
	local vector mousepos = *menu->mousepos;
	local vector mp = *menu->mousepos;
	local vector mousediff = menu->mousediff;
	local float key = menu->key;

	render_only = 0;

	rpos = pos;
	spos = rpos;
	spos_x = pos_x + strlen(fieldname) * 8 + 4;
	/*if they're dragging us, update*/
	if (menu->currentf == value)
	{
		if (mousedown == 1)
		{
			*value = *value + mousediff_x/10;
			*value = bound(minv, *value, maxv);
			f = *value;
			mp_y = spos_y + 4;
			mp_x = spos_x + 9 * 8 * (f - minv) / (maxv - minv) + 4;
			*menu->mousepos = mp;
		}
		else
		{
			menu->currentf = (float*)__NULL__;
		}
	}
	else
		if (mousedown == 1)
			render_only = 1;

	if (key == -1 || render_only == 1 )
	{
		if (mousepos_y >= pos_y && mousepos_y < pos_y + 8 && render_only == 0)
		{
			col_x = (sin(cltime*3.14)+1) / 2;
			col_y = col_x;
			col_z = 1;
		}
		else
			col = '1 1 1';

		f = *value;
		if (f < minv)
			f = minv;
		if (f > maxv)
			f = maxv;
		drawstring(pos, fieldname, '8 8 0', col, 1, 0);
		drawstring(spos, "^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082", '8 8 0', '1 1 1', 1, 0);
		if (!(menu->flags & MF_DS_VALUE))
			drawstring(spos + '88 0', ftos(f), '8 8 0', col, 1, 0);
		spos_x += 4 + 9*8*(f - minv) / (maxv - minv);
		drawstring(spos, "^Ue083", '8 8 0', '1 1 1', 1, 0);
	}
	else 	if (mousepos_y >= pos_y && mousepos_y < pos_y + 8)
	{
		if (key == 512)
		{
			f = *value;
			menu->currentf = value;
			mp_x = spos_x + 9 * 8 * (f - minv) / (maxv - minv) + 4;
			*menu->mousepos = mp;
		}
		else if (key == 515)
			*value = bound(minv, *value + (maxv - minv) / 10, maxv);
		else if (key == 516)
			*value = bound(minv, *value - (maxv - minv) / 10, maxv);
	}
};

void(menu_t *menu, string fieldname, vector pos, float *value) sliderf_fixed_widgit =
{
	local vector rpos, spos, epos, col;
	local float f;
	local int render_only = 0;
	local vector mousepos = *menu->mousepos;
	local vector mp = *menu->mousepos;
	local vector mousediff = menu->mousediff;
	local vector *mpp = menu->mousepos;
	local float key = menu->key;

	rpos = pos;
	spos = rpos;
	spos_x = pos_x + strlen(fieldname) * 8 + 4;
	epos = spos + '20 8';
	if (!(menu->flags & MF_DS_VALUE))
		epos_x += strlen(sprintf("%f", *value)) * 8;
	/*if they're dragging us, update*/
	if (menu->currentf == value)
	{
		if (mousedown == 1)
		{
			*value = *value + mousediff_x/10;
			f = *value;
			mp_y = spos_y + 4;
			mp_x = spos_x + 4;
			*menu->mousepos = mp;
		}
		else
		{
			menu->currentf = (float*)__NULL__;
		}
	}
	else
		if (mousedown == 1)
			render_only = 1;

	if (key == -1 || render_only == 1 )
	{
		if (cursor_in_widget(pos, epos, mousepos) && render_only == 0)
		{
			col_x = (sin(cltime*3.14)+1) / 2;
			col_y = col_x;
			col_z = 1;
		}
		else
			col = '1 1 1';

		f = *value;
		drawstring(pos, fieldname, '8 8 0', col, 1, 0);
		
		drawstring(spos, "^Ue080^Ue082", '8 8 0', '1 1 1', 1, 0);
		if (!(menu->flags & MF_DS_VALUE))
			drawstring(spos + '20 0', ftos(f), '8 8 0', col, 1, 0);
		drawstring(spos + '4 0', "^Ue083", '8 8 0', '1 1 1', 1, 0);
	}
	else 	if (cursor_in_widget(pos, epos, mousepos))
	{
		if (key == 512)
		{
			f = *value;
			menu->currentf = value;
			mp_x = spos_x + 4;
			*mpp = mp;
		}
		else if (key == 515)
			*value = *value + 0.1;
		else if (key == 516)
			*value = *value - 0.1;
	}
};

void(menu_t *menu, string fieldname, vector pos, int *value, int minv, int maxv) slideri_widgit =
{
	local vector rpos, spos, epos, col;
	local int f;
	local int render_only;
	local vector mousepos = *menu->mousepos;
	local vector mp = *menu->mousepos;
	local vector mousediff = menu->mousediff;
	local float key;

	key = menu->key;

	render_only = 0;

	rpos = pos;
	spos = rpos;
	spos_x = pos_x + strlen(fieldname) * 8 + 4;
	epos = spos + '88 8';
	if (!(menu->flags & MF_DS_VALUE))
		epos_x = strlen(sprintf("%i", *value)) * 8;
	/*if they're dragging us, update*/
	if (menu->currenti == value)
	{
		if (mousedown == 1)
		{
			*value = *value + mousediff_x/10;
			*value = bound(minv, *value, maxv);
			f = *value;
			mp_y = spos_y + 4;
			mp_x = spos_x + 9 * 8 * (f - minv) / (maxv - minv) + 4;
			*menu->mousepos = mp;
		}
		else
		{
			menu->currenti = (int*)__NULL__;
		}
	}
	else
		if (mousedown == 1)
			render_only = 1;

	if (key == -1 || render_only == 1 )
	{
		if (mousepos_y >= pos_y && mousepos_y < pos_y + 8 && render_only == 0)
		{
			col_x = (sin(cltime*3.14)+1) / 2;
			col_y = col_x;
			col_z = 1;
		}
		else
			col = '1 1 1';

		f = *value;
		if (f < minv)
			f = minv;
		if (f > maxv)
			f = maxv;
		drawstring(pos, fieldname, '8 8 0', col, 1, 0);
		drawstring(spos, "^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082", '8 8 0', '1 1 1', 1, 0);
		if (!(menu->flags & MF_DS_VALUE))
			drawstring(spos + '88 0', ftos(f), '8 8 0', col, 1, 0);
		spos_x += 9*8*(f - minv) / (maxv - minv);
		drawstring(spos, "^Ue083", '8 8 0', '1 1 1', 1, 0);
	}
	else 	if (mousepos_y >= pos_y && mousepos_y < pos_y + 8)
	{
		if (key == 512)
		{
			f = *value;
			menu->currenti = value;
			mp_x = spos_x + 9 * 8 * (f - minv) / (maxv - minv) + 4;
			*menu->mousepos = mp;
		}
		else if (key == 515)
			*value = bound(minv, *value + 1i, maxv);
		else if (key == 516)
			*value = bound(minv, *value - 1i, maxv);
	}
};


void(string fieldname, vector pos, vector *mousepos_in, float *value, float key) checkboxf_widgit =
{
	local vector rpos, col;
	local int render_only;
	local vector mousepos = *mousepos_in;
	rpos = pos + '132 0 0';

	render_only = 0;
	// fix this
	if (mousedown == 1)
		render_only = 1;

	if (key == -1 || render_only == 1)
	{
		if (mousepos_y >= pos_y && mousepos_y < pos_y + 8 && render_only == 0)
		{
			col_x = (sin(cltime*3.14)+1) / 2;
			col_y = col_x;
			col_z = 1;
		}
		else
			col = '1 1 1';

		drawstring(pos, fieldname, '8 8 0', col, 1, 0);
		rpos_x -= 4;
		drawstring(rpos, "^Ue080^Ue082", '8 8 0', '1 1 1', 1, 0);
		drawstring(rpos + '88 0', ((*value) ?"TRUE":"FALSE"), '8 8 0', col, 1, 0);
		rpos_x += 4;
		if (*value)
			drawstring(rpos, "^Ue083", '8 8 0', '1 1 1', 1, 0);
	}
	else 	if (mousepos_y >= pos_y && mousepos_y < pos_y + 8)
	{
		if (key == 512)
			*value = !*value;
		else if (key == 515)
			*value = !*value;
		else if (key == 516)
			*value = !*value;
	}
};

void(menu_t *menu, string fieldname, vector pos, int *value) checkboxi_widgit =
{
	local vector rpos, epos, spos, col;
	local int render_only = 0;
	local vector mousepos = *menu->mousepos;
	local vector mousediff = menu->mousediff;
	local float key = menu->key;

	spos = pos;
	spos_x += strlen(fieldname) * 8 + 4;
	epos = spos;
	epos_x += 16;
	epos_y += 8;
	if (!(menu->flags & MF_DS_VALUE))
		epos_x += strlen((*value) ? "TRUE":"FALSE") *8;

	render_only = 0;

	if (key == -1)
	{
		if (cursor_in_widget(pos, epos, mousepos) && render_only == 0)
		{
			col_x = (sin(cltime*3.14)+1) / 2;
			col_y = col_x;
			col_z = 1;
		}
		else
			col = '1 1 1';

		drawstring(pos, fieldname, '8 8 0', col, 1, 0);
		drawstring(spos, "^Ue080^Ue082", '8 8 0', '1 1 1', 1, 0);
		if (!(menu->flags & MF_DS_VALUE))
			drawstring(spos + '88 0', ((*value) ?"TRUE":"FALSE"), '8 8 0', col, 1, 0);
		if (*value)
			drawstring(spos + '4 0', "^Ue083", '8 8 0', '1 1 1', 1, 0);
	}

	if (cursor_in_widget(pos, epos, mousepos) && key != -1)
	{
		if (key == 512)
			*value = !*value;
		else if (key == 515)
			*value = !*value;
		else if (key == 516)
			*value = !*value;
	}
};

int (menu_t *menu, string fieldname, vector pos) button_widget =
{
	local vector rpos, epos, spos, col;
	local int render_only = 0;
	local vector mousepos = *menu->mousepos;
	local vector mousediff = menu->mousediff;
	local float key = menu->key;

	spos = pos;
	spos_x += strlen(fieldname) * 8;
	epos = spos;
	epos_y += 8;

	render_only = 0;

	if (key == -1)
	{
		if (cursor_in_widget(pos, epos, mousepos) && render_only == 0)
		{
			col_x = (sin(cltime*3.14)+1) / 2;
			col_y = col_x;
			col_z = 1;
		}
		else
			col = '1 1 1';

		drawstring(pos, fieldname, '8 8 0', col, 1, 0);
		return 0;
	}

	if (cursor_in_widget(pos, epos, mousepos) && key != -1)
	{
		if (key == 512)
			return 1;
	//	else if (key == 515)
	//	else if (key == 516)
	}

	return 0;
};

void(string shader, vector org, vector s, vector t, string text, vector col, float alph) drawlame3dtext =
{
	/*the shader must be a 16*16 grid of 256 chars*/
	vector st = draw_getimagesize(shader);
	vector pos = org;
	float chr;
	float idx;
	vector tc0,tc1,tc2,tc3;

	//with GL_LINEAR sampling, the sample value is interpolated from the nearby two pixels
	//this means that we must move the texture coord inwards by half of a pixel to avoid any bleed through into neighbouring chars
	//(with nearest sampling, this isn't needed)
	if (st != '0 0 0')
	{
		st_x = 0.5 / st_x;
		st_y = 0.5 / st_y;
	}

	//precompute the st offset for each vertex
	tc0_x = (0.0/16) + st_x;
	tc1_x = (1.0/16) - st_x;
	tc2_x = (1.0/16) - st_x;
	tc3_x = (0.0/16) + st_x;
	tc0_y = (0.0/16) + st_y;
	tc1_y = (0.0/16) + st_y;
	tc2_y = (1.0/16) - st_y;
	tc3_y = (1.0/16) - st_y;

	/*begin looks up the shader and is thus potentially expensive, fte requires it only once per batch of polygons.*/
	R_BeginPolygon(shader);

	while((chr = text[idx]))
	{
		idx+=1;

		/*handle new lines*/
		if (chr == '\n')
		{
			org += t;
			pos = org;
			continue;
		}

		/*skip spaces*/
		if (chr != ' ')
		{
			/*its a grid, so the top-left texturecoord should be easy to calculate*/
			/*weirdly though, qc has no (direct) modulo functionality, not even as a builtin, so this code is ugly*/
			st_x = (chr & 15) / 16;
			st_y = floor(chr/16) / 16;

			/*plot the poly's point and emit the quad*/
			R_PolygonVertex(pos    , st + tc0, col, alph);
			R_PolygonVertex(pos + s, st + tc1, col, alph);
			R_PolygonVertex(pos+s+t, st + tc2, col, alph);
			R_PolygonVertex(pos + t, st + tc3, col, alph);
			R_EndPolygon();
		}
		pos += s;
	}
};
