Exemplo n.º 1
0
static uiNode_t* UI_OptionListNodeGetOptionAtPosition (uiNode_t* node, int x, int y)
{
	uiNode_t* option;
	vec2_t pos;
	int lineHeight;
	int currentY;
	int count = 0;

	UI_GetNodeAbsPos(node, pos);
	currentY = pos[1] + node->padding;

	lineHeight =  EXTRADATA(node).lineHeight;
	if (lineHeight == 0) {
		const char* font = UI_GetFontFromNode(node);
		lineHeight = UI_FontGetHeight(font);
	}

	option = UI_AbstractOptionGetFirstOption(node);
	while (option && count < EXTRADATA(node).scrollY.viewPos) {
		option = option->next;
		count++;
	}

	/* now draw all available options for this selectbox */
	for (; option; option = option->next) {
		if (y < currentY + lineHeight)
			return option;
		if (currentY + lineHeight > pos[1] + node->box.size[1] - node->padding)
			break;
		currentY += lineHeight;
	}
	return nullptr;
}
Exemplo n.º 2
0
/**
 * @brief Return size of the cell, which is the size (in virtual "pixel") which represent 1 in the scroll values.
 * Here we guess the widget can scroll pixel per pixel.
 * @return Size in pixel.
 */
int uiOptionListNode::getCellHeight (uiNode_t* node)
{
	int lineHeight = EXTRADATA(node).lineHeight;
	if (lineHeight == 0)
		lineHeight = UI_FontGetHeight(UI_GetFontFromNode(node));
	return lineHeight;
}
Exemplo n.º 3
0
int UI_DrawString (const char* fontID, align_t align, int x, int y, int absX, int maxWidth,
		int lineHeight, const char* c, int boxHeight, int scrollPos, int* curLine, bool increaseLine, longlines_t method)
{
	const uiFont_t* font = UI_GetFontByID(fontID);
	const align_t verticalAlign = (align_t)(align / 3);  /* top, center, bottom */
	int lines;

	if (!font)
		Com_Error(ERR_FATAL, "Could not find font with id: '%s'", fontID);

	if (lineHeight <= 0)
		lineHeight = UI_FontGetHeight(font->name);

	/* vertical alignment makes only a single-line adjustment in this
	 * function. That means that ALIGN_Lx values will not show more than
	 * one line in any case. */
	if (verticalAlign == 1)
		y += -(lineHeight / 2);
	else if (verticalAlign == 2)
		y += -lineHeight;

	lines = R_FontDrawString(fontID, align, x, y, absX, maxWidth, lineHeight,
			c, boxHeight, scrollPos, curLine, method);

	if (curLine && increaseLine)
		*curLine += lines;

	return lines * lineHeight;
}
Exemplo n.º 4
0
/**
 * @brief Get the line number under an absolute position
 * @param[in] node a text node
 * @param[in] x,y position on the screen
 * @return The line number under the position (0 = first line)
 */
static int UI_TextNodeGetLine (const uiNode_t* node, int x, int y)
{
	int lineHeight;
	int line;
	assert(UI_NodeInstanceOf(node, "text"));

	lineHeight = EXTRADATACONST(node).lineHeight;
	if (lineHeight == 0) {
		const char* font = UI_GetFontFromNode(node);
		lineHeight = UI_FontGetHeight(font);
	}

	UI_NodeAbsoluteToRelativePos(node, &x, &y);
	y -= node->padding;

	/* skip position over the first line */
	if (y < 0)
		 return -1;
	line = (int) (y / lineHeight) + EXTRADATACONST(node).super.scrollY.viewPos;

	/* skip position under the last line */
	if (line >= EXTRADATACONST(node).super.scrollY.fullSize)
		return -1;

	return line;
}
Exemplo n.º 5
0
/**
 * @brief Get the line number under an absolute position
 * @param[in] node a text node
 * @param[in] x position x on the screen
 * @param[in] y position y on the screen
 * @return The line number under the position (0 = first line)
 */
static int UI_TextListNodeGetLine (const uiNode_t *node, int x, int y)
{
	int lineHeight = EXTRADATACONST(node).lineHeight;
	if (lineHeight == 0) {
		const char *font = UI_GetFontFromNode(node);
		lineHeight = UI_FontGetHeight(font);
	}

	UI_NodeAbsoluteToRelativePos(node, &x, &y);
	y -= node->padding;
	return (int) (y / lineHeight) + EXTRADATACONST(node).super.scrollY.viewPos;
}
Exemplo n.º 6
0
/**
 * @brief Handled after the end of the load of the node from script (all data and/or child are set)
 */
static void UI_ButtonNodeLoaded (uiNode_t *node)
{
	/* auto calc the size if none was given via script files */
	if (node->size[1] == 0) {
		const char *font = UI_GetFontFromNode(node);
		node->size[1] = (UI_FontGetHeight(font) / 2) + (node->padding * 2);
	}
#ifdef DEBUG
	if (node->size[0] < CORNER_SIZE + MID_SIZE + CORNER_SIZE || node->size[1] < CORNER_SIZE + MID_SIZE + CORNER_SIZE)
		Com_DPrintf(DEBUG_CLIENT, "Node '%s' too small. It can create graphical glitches\n", UI_GetPath(node));
#endif
}
Exemplo n.º 7
0
/**
 * @brief Update the scroll according to the number
 * of items and the size of the node
 */
static void UI_OptionListNodeUpdateScroll (uiNode_t* node)
{
	int lineHeight;
	bool updated;
	int elements;

	lineHeight =  EXTRADATA(node).lineHeight;
	if (lineHeight == 0) {
		const char* font = UI_GetFontFromNode(node);
		lineHeight = UI_FontGetHeight(font);
	}

	elements = (node->box.size[1] - node->padding - node->padding) / lineHeight;
	updated = EXTRADATA(node).scrollY.set(-1, elements, EXTRADATA(node).count);
	if (updated && EXTRADATA(node).onViewChange)
		UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange);
}
Exemplo n.º 8
0
/**
 * @brief Update the scroll according to the number
 * of items and the size of the node
 */
static void UI_OptionTreeNodeUpdateScroll (uiNode_t *node)
{
	const char *font;
	int fontHeight;
	qboolean updated;
	int elements;

	font = UI_GetFontFromNode(node);
	fontHeight = EXTRADATA(node).lineHeight;
	if (fontHeight == 0)
		fontHeight = UI_FontGetHeight(font);

	elements = (node->size[1] - node->padding - node->padding) / fontHeight;
	updated = UI_SetScroll(&EXTRADATA(node).scrollY, -1, elements, EXTRADATA(node).count);
	if (updated && EXTRADATA(node).onViewChange)
		UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange);
}
Exemplo n.º 9
0
static uiNode_t* UI_OptionTreeNodeGetOptionAtPosition (uiNode_t * node, int x, int y, int *depth)
{
	uiNode_t* option;
	const char *font;
	int fontHeight;
	int count;
	uiOptionIterator_t iterator;

	UI_NodeAbsoluteToRelativePos(node, &x, &y);

	font = UI_GetFontFromNode(node);
	fontHeight = EXTRADATA(node).lineHeight;
	if (fontHeight == 0)
		fontHeight = UI_FontGetHeight(font);

	option = UI_OptionTreeNodeGetFirstOption(node);
	count = EXTRADATA(node).scrollY.viewPos + (y - node->padding) / fontHeight;
	option = UI_InitOptionIteratorAtIndex(count, option, &iterator);
	*depth = iterator.depthPos;
	return option;
}
Exemplo n.º 10
0
void uiTextNode::onLoaded (uiNode_t* node)
{
	int lineheight = EXTRADATA(node).lineHeight;
	/* auto compute lineheight */
	/* we don't overwrite EXTRADATA(node).lineHeight, because "0" is dynamically replaced by font height on draw function */
	if (lineheight == 0) {
		/* the font is used */
		const char* font = UI_GetFontFromNode(node);
		lineheight = UI_FontGetHeight(font);
	}

	/* auto compute rows (super.viewSizeY) */
	if (EXTRADATA(node).super.scrollY.viewSize == 0) {
		if (node->box.size[1] != 0 && lineheight != 0) {
			EXTRADATA(node).super.scrollY.viewSize = node->box.size[1] / lineheight;
		} else {
			EXTRADATA(node).super.scrollY.viewSize = 1;
			Com_Printf("UI_TextNodeLoaded: node '%s' has no rows value\n", UI_GetPath(node));
		}
	}

	/* auto compute height */
	if (node->box.size[1] == 0) {
		node->box.size[1] = EXTRADATA(node).super.scrollY.viewSize * lineheight;
	}

	/* is text slot exists */
	if (EXTRADATA(node).dataID >= UI_MAX_DATAID)
		Com_Error(ERR_DROP, "Error in node %s - max shared data id num exceeded (num: %i, max: %i)", UI_GetPath(node), EXTRADATA(node).dataID, UI_MAX_DATAID);

#ifdef DEBUG
	if (EXTRADATA(node).super.scrollY.viewSize != (int)(node->box.size[1] / lineheight)) {
		Com_Printf("UI_TextNodeLoaded: rows value (%i) of node '%s' differs from size (%.0f) and format (%i) values\n",
			EXTRADATA(node).super.scrollY.viewSize, UI_GetPath(node), node->box.size[1], lineheight);
	}
#endif

	if (node->text == nullptr && EXTRADATA(node).dataID == TEXT_NULL)
		Com_Printf("UI_TextNodeLoaded: 'textid' property of node '%s' is not set\n", UI_GetPath(node));
}
Exemplo n.º 11
0
void uiOptionListNode::draw (uiNode_t* node)
{
	uiNode_t* option;
	const char* ref;
	const char* font;
	int lineHeight;
	vec2_t pos;
	int currentY;
	const float* textColor;
	int count = 0;

	ref = UI_AbstractOptionGetCurrentValue(node);
	if (ref == nullptr)
		return;

	UI_GetNodeAbsPos(node, pos);

	if (EXTRADATA(node).background) {
		UI_DrawSpriteInBox(false, EXTRADATA(node).background, SPRITE_STATUS_NORMAL, pos[0], pos[1], node->box.size[0], node->box.size[1]);
	}

	font = UI_GetFontFromNode(node);

	lineHeight =  EXTRADATA(node).lineHeight;
	if (lineHeight == 0)
		lineHeight = UI_FontGetHeight(font);
	currentY = pos[1] + node->padding;

	/* skip option over current position */
	option = UI_AbstractOptionGetFirstOption(node);
	while (option && count < EXTRADATA(node).scrollY.viewPos) {
		option = option->next;
		count++;
	}

	/* draw all available options for this selectbox */
	for (; option; option = option->next) {
		int decX = pos[0] + node->padding;
		/* outside the node */
		if (currentY + lineHeight > pos[1] + node->box.size[1] - node->padding) {
			count++;
			break;
		}

		/* draw the hover effect */
		if (OPTIONEXTRADATA(option).hovered)
			UI_DrawFill(pos[0] + node->padding, currentY, node->box.size[0] - node->padding - node->padding, lineHeight, node->color);

		/* text color */
		if (Q_streq(OPTIONEXTRADATA(option).value, ref)) {
			textColor = node->selectedColor;
		} else if (node->disabled || option->disabled) {
			textColor = node->disabledColor;
		} else if (option->color[3] == 0.0f) {
			textColor = node->color;
		} else {
			textColor = option->color;
		}

		if (OPTIONEXTRADATA(option).icon) {
			uiSpriteStatus_t iconStatus = SPRITE_STATUS_NORMAL;
			if (option->disabled)
				iconStatus = SPRITE_STATUS_DISABLED;
			R_Color(nullptr);
			UI_DrawSpriteInBox(OPTIONEXTRADATA(option).flipIcon, OPTIONEXTRADATA(option).icon, iconStatus, decX, currentY, OPTIONEXTRADATA(option).icon->size[0], lineHeight);
			decX += OPTIONEXTRADATA(option).icon->size[0] + lineHeight / 4;
		}

		/* print the option label */
		const char* label = CL_Translate(OPTIONEXTRADATA(option).label);

		R_Color(textColor);
		UI_DrawString(font, ALIGN_UL, decX, currentY,
			pos[0], node->box.size[0] - node->padding - node->padding,
			0, label, 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);

		/* next entries' position */
		currentY += lineHeight;
		count++;
	}
	R_Color(nullptr);

	/* count number of options (current architecture doesn't allow to know if the data change) */
	for (; option; option = option->next) {
		count++;
	}

	if (EXTRADATA(node).count != count) {
		EXTRADATA(node).count = count;
	}

	UI_OptionListNodeUpdateScroll(node);
}
Exemplo n.º 12
0
/**
 * @brief Handles line breaks and drawing for shared data id
 * @param[in] node The context node
 * @param[in] text The test to draw else nullptr
 * @param[in] list The test to draw else nullptr
 * @param[in] noDraw If true, calling of this function only update the cache (real number of lines)
 * @note text or list but be used, not both
 */
void uiTextNode::drawText (uiNode_t* node, const char* text, const linkedList_t* list, bool noDraw)
{
	static char textCopy[UI_TEXTNODE_BUFFERSIZE];
	char newFont[MAX_VAR];
	const char* oldFont = nullptr;
	vec4_t colorHover;
	vec4_t colorSelectedHover;
	char* cur, *tab, *end;
	int fullSizeY;
	const char* font = UI_GetFontFromNode(node);
	vec2_t pos;
	int x, y, width;
	int viewSizeY;

	UI_GetNodeAbsPos(node, pos);

	if (isSizeChange(node)) {
		int lineHeight = EXTRADATA(node).lineHeight;
		if (lineHeight == 0) {
			const char* font = UI_GetFontFromNode(node);
			lineHeight = UI_FontGetHeight(font);
		}
		viewSizeY = node->box.size[1] / lineHeight;
	} else {
		viewSizeY = EXTRADATA(node).super.scrollY.viewSize;
	}

	/* text box */
	x = pos[0] + node->padding;
	y = pos[1] + node->padding;
	width = node->box.size[0] - node->padding - node->padding;

	if (text) {
		Q_strncpyz(textCopy, text, sizeof(textCopy));
	} else if (list) {
		Q_strncpyz(textCopy, CL_Translate((const char*)list->data), sizeof(textCopy));
	} else
		return;	/**< Nothing to draw */

	cur = textCopy;

	/* Hover darkening effect for normal text lines. */
	VectorScale(node->color, 0.8, colorHover);
	colorHover[3] = node->color[3];

	/* Hover darkening effect for selected text lines. */
	VectorScale(node->selectedColor, 0.8, colorSelectedHover);
	colorSelectedHover[3] = node->selectedColor[3];

	/* fix position of the start of the draw according to the align */
	switch (node->contentAlign % 3) {
	case 0:	/* left */
		break;
	case 1:	/* middle */
		x += width / 2;
		break;
	case 2:	/* right */
		x += width;
		break;
	}

	R_Color(node->color);

	fullSizeY = 0;
	do {
		bool haveTab;
		int x1; /* variable x position */
		/* new line starts from node x position */
		x1 = x;
		if (oldFont) {
			font = oldFont;
			oldFont = nullptr;
		}

		/* text styles and inline images */
		if (cur[0] == '^') {
			switch (toupper(cur[1])) {
			case 'B':
				Com_sprintf(newFont, sizeof(newFont), "%s_bold", font);
				oldFont = font;
				font = newFont;
				cur += 2; /* don't print the format string */
				break;
			}
		}

		/* get the position of the next newline - otherwise end will be null */
		end = strchr(cur, '\n');
		if (end)
			/* set the \n to \0 to draw only this part (before the \n) with our font renderer */
			/* let end point to the next char after the \n (or \0 now) */
			*end++ = '\0';

		/* highlighting */
		if (fullSizeY == EXTRADATA(node).textLineSelected && EXTRADATA(node).textLineSelected >= 0) {
			/* Draw current line in "selected" color (if the linenumber is stored). */
			R_Color(node->selectedColor);
		} else {
			R_Color(node->color);
		}

		if (node->state && EXTRADATA(node).mousefx && fullSizeY == EXTRADATA(node).lineUnderMouse) {
			/* Highlight line if mousefx is true. */
			/** @todo what about multiline text that should be highlighted completely? */
			if (fullSizeY == EXTRADATA(node).textLineSelected && EXTRADATA(node).textLineSelected >= 0) {
				R_Color(colorSelectedHover);
			} else {
				R_Color(colorHover);
			}
		}

		/* tabulation, we assume all the tabs fit on a single line */
		haveTab = strchr(cur, '\t') != nullptr;
		if (haveTab) {
			while (cur && *cur) {
				int tabwidth;

				tab = strchr(cur, '\t');

				/* use tab stop as given via property definition
				 * or use 1/3 of the node size (width) */
				if (!EXTRADATA(node).tabWidth)
					tabwidth = width / 3;
				else
					tabwidth = EXTRADATA(node).tabWidth;

				if (tab) {
					int numtabs = strspn(tab, "\t");
					tabwidth *= numtabs;
					while (*tab == '\t')
						*tab++ = '\0';
				} else {
					/* maximize width for the last element */
					tabwidth = width - (x1 - x);
					if (tabwidth < 0)
						tabwidth = 0;
				}

				/* minimize width for element outside node */
				if ((x1 - x) + tabwidth > width)
					tabwidth = width - (x1 - x);

				/* make sure it is positive */
				if (tabwidth < 0)
					tabwidth = 0;

				if (tabwidth != 0)
					UI_DrawString(font, (align_t)node->contentAlign, x1, y, x1, tabwidth - 1, EXTRADATA(node).lineHeight, cur, viewSizeY, EXTRADATA(node).super.scrollY.viewPos, &fullSizeY, false, LONGLINES_PRETTYCHOP);

				/* next */
				x1 += tabwidth;
				cur = tab;
			}
			fullSizeY++;
		}

		/*Com_Printf("until newline - lines: %i\n", lines);*/
		/* the conditional expression at the end is a hack to draw "/n/n" as a blank line */
		/* prevent line from being drawn if there is nothing that should be drawn after it */
		if (cur && (cur[0] || end || list)) {
			/* is it a white line? */
			if (!cur) {
				fullSizeY++;
			} else {
				if (noDraw) {
					int lines = 0;
					R_FontTextSize(font, cur, width, (longlines_t)EXTRADATA(node).longlines, nullptr, nullptr, &lines, nullptr);
					fullSizeY += lines;
				} else
					UI_DrawString(font, (align_t)node->contentAlign, x1, y, x, width, EXTRADATA(node).lineHeight, cur, viewSizeY, EXTRADATA(node).super.scrollY.viewPos, &fullSizeY, true, (longlines_t)EXTRADATA(node).longlines);
			}
		}

		if (EXTRADATA(node).mousefx)
			R_Color(node->color); /* restore original color */

		/* now set cur to the next char after the \n (see above) */
		cur = end;
		if (!cur && list) {
			list = list->next;
			if (list) {
				Q_strncpyz(textCopy, CL_Translate((const char*)list->data), sizeof(textCopy));
				cur = textCopy;
			}
		}
	} while (cur);

	/* update scroll status */
	setScrollY(node, -1, viewSizeY, fullSizeY);

	R_Color(nullptr);
}
Exemplo n.º 13
0
/**
 * @brief Handles line breaks and drawing for shared data text
 * @param[in] node The context node
 * @param[in] list The text list to draw
 */
static void UI_TextLineNodeDrawText (uiNode_t* node, const linkedList_t* list)
{
	vec4_t colorHover;
	vec4_t colorSelectedHover;
	int count; /* variable x position */
	const char *font = UI_GetFontFromNode(node);
	vec2_t pos;
	int currentY;
	int viewSizeY;
	int lineHeight;
	int maxHeight;

	lineHeight = EXTRADATA(node).lineHeight;
	if (lineHeight == 0)
		lineHeight = UI_FontGetHeight(font);

	if (UI_AbstractScrollableNodeIsSizeChange(node))
		viewSizeY = node->size[1] / lineHeight;
	else
		viewSizeY = EXTRADATA(node).super.scrollY.viewSize;

	/* text box */
	UI_GetNodeAbsPos(node, pos);
	pos[0] += node->padding;
	pos[1] += node->padding;

	/* prepare colors */
	VectorScale(node->color, 0.8, colorHover);
	colorHover[3] = node->color[3];
	VectorScale(node->selectedColor, 0.8, colorSelectedHover);
	colorSelectedHover[3] = node->selectedColor[3];

	/* skip lines over the scroll */
	count = 0;
	while (list && count < EXTRADATA(node).super.scrollY.viewPos) {
		list = list->next;
		count++;
	}

	currentY = pos[1];
	maxHeight = currentY + node->size[1] - node->padding - node->padding - node->padding - lineHeight;
	while (list) {
		const int width = node->size[0] - node->padding - node->padding;
		const char* text = (const char*) list->data;
		if (currentY > maxHeight)
			break;

		/* highlight selected line */
		if (count == EXTRADATA(node).textLineSelected && EXTRADATA(node).textLineSelected >= 0)
			R_Color(node->selectedColor);
		else
			R_Color(node->color);

		/* highlight line under mouse */
		if (node->state && count == EXTRADATA(node).lineUnderMouse) {
			if (count == EXTRADATA(node).textLineSelected && EXTRADATA(node).textLineSelected >= 0)
				R_Color(colorSelectedHover);
			else
				R_Color(colorHover);
		}

		UI_DrawStringInBox(font, node->contentAlign, pos[0], currentY, width, lineHeight, text, LONGLINES_PRETTYCHOP);

		/* next entries' position */
		currentY += lineHeight;


		list = list->next;
		count++;
	}

	/* count all elements */
	while (list) {
		list = list->next;
		count++;
	}

	/* update scroll status */
	UI_AbstractScrollableNodeSetY(node, -1, viewSizeY, count);

	R_Color(NULL);
}
Exemplo n.º 14
0
static void UI_OptionTreeNodeDraw (uiNode_t *node)
{
	static const int panelTemplate[] = {
		CORNER_SIZE, MID_SIZE, CORNER_SIZE,
		CORNER_SIZE, MID_SIZE, CORNER_SIZE,
		MARGE
	};
	uiNode_t* option;
	const char *ref;
	const char *font;
	vec2_t pos;
	const char* image;
	int fontHeight;
	int currentY;
	int currentDecY = 0;
	const float *textColor;
	vec4_t disabledColor = {0.5, 0.5, 0.5, 1.0};
	int count = 0;
	uiOptionIterator_t iterator;

	if (!systemExpand)
		systemExpand = UI_GetSpriteByName("icons/system_expand");
	if (!systemCollapse)
		systemCollapse = UI_GetSpriteByName("icons/system_collapse");

	ref = UI_AbstractOptionGetCurrentValue(node);
	if (ref == NULL)
		return;

	UI_GetNodeAbsPos(node, pos);

	image = UI_GetReferenceString(node, node->image);
	if (image)
		UI_DrawPanel(pos, node->size, image, 0, 0, panelTemplate);

	font = UI_GetFontFromNode(node);
	fontHeight = EXTRADATA(node).lineHeight;
	currentY = pos[1] + node->padding;
	if (fontHeight == 0)
		fontHeight = UI_FontGetHeight(font);
	else {
		const int height = UI_FontGetHeight(font);
		currentDecY = (fontHeight - height) / 2;
	}

	/* skip option over current position */
	option = UI_OptionTreeNodeGetFirstOption(node);
	UI_OptionTreeNodeUpdateScroll(node);
	option = UI_InitOptionIteratorAtIndex(EXTRADATA(node).scrollY.viewPos, option, &iterator);

	/* draw all available options for this selectbox */
	for (; option; option = UI_OptionIteratorNextOption(&iterator)) {
		int decX;
		const char *label;

		/* outside the node */
		if (currentY + fontHeight > pos[1] + node->size[1] - node->padding) {
			count++;
			break;
		}

		/* draw the hover effect */
		if (OPTIONEXTRADATA(option).hovered)
			UI_DrawFill(pos[0] + node->padding, currentY, node->size[0] - node->padding - node->padding, fontHeight, node->color);

		/* text color */
		if (Q_streq(OPTIONEXTRADATA(option).value, ref)) {
			textColor = node->selectedColor;
		} else if (node->disabled || option->disabled) {
			textColor = disabledColor;
		} else if (option->color[3] == 0.0f) {
			textColor = node->color;
		} else {
			textColor = option->color;
		}

		/* print the option label */
		decX = pos[0] + node->padding + iterator.depthPos * DEPTH_WIDTH;

		R_Color(NULL);
		if (option->firstChild) {
			uiSprite_t *icon = OPTIONEXTRADATA(option).collapsed ? systemExpand : systemCollapse;
			UI_DrawSpriteInBox(OPTIONEXTRADATA(option).flipIcon, icon, SPRITE_STATUS_NORMAL, decX, currentY, icon->size[0], fontHeight);
		}

		decX += COLLAPSEBUTTON_WIDTH;

		if (OPTIONEXTRADATA(option).icon) {
			uiSpriteStatus_t iconStatus = SPRITE_STATUS_NORMAL;
			if (option->disabled)
				iconStatus = SPRITE_STATUS_DISABLED;
			UI_DrawSpriteInBox(OPTIONEXTRADATA(option).flipIcon, OPTIONEXTRADATA(option).icon, iconStatus, decX, currentY,
					OPTIONEXTRADATA(option).icon->size[0], fontHeight);
			decX += OPTIONEXTRADATA(option).icon->size[0] + fontHeight / 4;
		}

		label = OPTIONEXTRADATA(option).label;
		if (label[0] == '_')
			label = _(label + 1);

		R_Color(textColor);
		UI_DrawString(font, ALIGN_UL, decX, currentY + currentDecY,
			pos[0], node->size[0] - node->padding - node->padding,
			0, label, 0, 0, NULL, qfalse, LONGLINES_PRETTYCHOP);

		/* next entries' position */
		currentY += fontHeight;
		count++;
	}
	R_Color(NULL);
}
static void UI_OptionListNodeDraw (uiNode_t *node)
{
	static const int panelTemplate[] = {
		CORNER_SIZE, MID_SIZE, CORNER_SIZE,
		CORNER_SIZE, MID_SIZE, CORNER_SIZE,
		MARGE
	};
	uiNode_t* option;
	const char *ref;
	const char *font;
	int lineHeight;
	vec2_t pos;
	const char* image;
	int currentY;
	const float *textColor;
	static vec4_t disabledColor = {0.5, 0.5, 0.5, 1.0};
	int count = 0;

	ref = UI_AbstractOptionGetCurrentValue(node);
	if (ref == NULL)
		return;

	UI_GetNodeAbsPos(node, pos);

	image = UI_GetReferenceString(node, node->image);
	if (image)
		UI_DrawPanel(pos, node->size, image, 0, 0, panelTemplate);

	font = UI_GetFontFromNode(node);

	lineHeight =  EXTRADATA(node).lineHeight;
	if (lineHeight == 0)
		lineHeight = UI_FontGetHeight(font);
	currentY = pos[1] + node->padding;

	/* skip option over current position */
	option = UI_AbstractOptionGetFirstOption(node);
	while (option && count < EXTRADATA(node).scrollY.viewPos) {
		option = option->next;
		count++;
	}

	/* draw all available options for this selectbox */
	for (; option; option = option->next) {
		const char *label;
		int decX = pos[0] + node->padding;
		/* outside the node */
		if (currentY + lineHeight > pos[1] + node->size[1] - node->padding) {
			count++;
			break;
		}

		/* draw the hover effect */
		if (OPTIONEXTRADATA(option).hovered)
			UI_DrawFill(pos[0] + node->padding, currentY, node->size[0] - node->padding - node->padding, lineHeight, node->color);

		/* text color */
		if (Q_streq(OPTIONEXTRADATA(option).value, ref)) {
			textColor = node->selectedColor;
		} else if (node->disabled || option->disabled) {
			textColor = disabledColor;
		} else if (option->color[3] == 0.0f) {
			textColor = node->color;
		} else {
			textColor = option->color;
		}

		if (OPTIONEXTRADATA(option).icon) {
			uiSpriteStatus_t iconStatus = SPRITE_STATUS_NORMAL;
			if (option->disabled)
				iconStatus = SPRITE_STATUS_DISABLED;
			R_Color(NULL);
			UI_DrawSpriteInBox(OPTIONEXTRADATA(option).flipIcon, OPTIONEXTRADATA(option).icon, iconStatus, decX, currentY, OPTIONEXTRADATA(option).icon->size[0], lineHeight);
			decX += OPTIONEXTRADATA(option).icon->size[0] + lineHeight / 4;
		}

		/* print the option label */
		label = OPTIONEXTRADATA(option).label;
		if (label[0] == '_')
			label = _(label + 1);

		R_Color(textColor);
		UI_DrawString(font, ALIGN_UL, decX, currentY,
			pos[0], node->size[0] - node->padding - node->padding,
			0, label, 0, 0, NULL, qfalse, LONGLINES_PRETTYCHOP);

		/* next entries' position */
		currentY += lineHeight;
		count++;
	}
	R_Color(NULL);

	/* count number of options (current architecture doesn't allow to know if the data change) */
	for (; option; option = option->next) {
		count++;
	}

	if (EXTRADATA(node).count != count) {
		EXTRADATA(node).count = count;
	}

	UI_OptionListNodeUpdateScroll(node);
}