void uiTextEntryNode::draw (uiNode_t* node) { const float* textColor; vec2_t pos; const char* font = UI_GetFontFromNode(node); uiSpriteStatus_t iconStatus = SPRITE_STATUS_NORMAL; if (node->disabled) { textColor = node->disabledColor; iconStatus = SPRITE_STATUS_DISABLED; } else if (node->state) { textColor = node->color; iconStatus = SPRITE_STATUS_HOVER; } else { textColor = node->color; } if (UI_HasFocus(node)) { textColor = node->selectedColor; } UI_GetNodeAbsPos(node, pos); if (EXTRADATA(node).background) { UI_DrawSpriteInBox(false, EXTRADATA(node).background, iconStatus, pos[0], pos[1], node->box.size[0], node->box.size[1]); } if (char const* const text = UI_GetReferenceString(node, node->text)) { char buf[MAX_VAR]; if (EXTRADATA(node).isPassword) { size_t size = UTF8_strlen(text); if (size > MAX_VAR - 2) size = MAX_VAR - 2; memset(buf, HIDECHAR, size); buf[size] = '\0'; } else { /* leave one byte empty for the text-based cursor */ UTF8_strncpyz(buf, text, sizeof(buf) - 1); } /** @todo Make the cursor into a real graphical object instead of using a text character. */ if (UI_HasFocus(node)) { if (CL_Milliseconds() % 1000 < 500) { UTF8_insert_char_at(buf, sizeof(buf), EXTRADATA(node).cursorPosition, (int)CURSOR_ON); } else { UTF8_insert_char_at(buf, sizeof(buf), EXTRADATA(node).cursorPosition, (int)CURSOR_OFF); } } if (*buf != '\0') { R_Color(textColor); UI_DrawStringInBox(font, (align_t)node->contentAlign, pos[0] + node->padding, pos[1] + node->padding, node->box.size[0] - node->padding - node->padding, node->box.size[1] - node->padding - node->padding, buf); R_Color(nullptr); } } }
/** * @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; }
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; }
/** * @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; }
void uiSelectBoxNode::draw (uiNode_t* node) { uiNode_t* option; int selBoxX, selBoxY; const char* ref; const char* font; vec2_t nodepos; const char* imageName; const image_t* image; static vec4_t invisColor = {1.0, 1.0, 1.0, 0.7}; ref = UI_AbstractOptionGetCurrentValue(node); if (ref == nullptr) return; UI_GetNodeAbsPos(node, nodepos); imageName = UI_GetReferenceString(node, node->image); if (!imageName) imageName = "ui/selectbox"; image = UI_LoadImage(imageName); font = UI_GetFontFromNode(node); selBoxX = nodepos[0] + SELECTBOX_SIDE_WIDTH; selBoxY = nodepos[1] + SELECTBOX_SPACER; /* left border */ UI_DrawNormImage(false, nodepos[0], nodepos[1], SELECTBOX_SIDE_WIDTH, node->box.size[1], SELECTBOX_SIDE_WIDTH, SELECTBOX_DEFAULT_HEIGHT, 0.0f, 0.0f, image); /* stretched middle bar */ UI_DrawNormImage(false, nodepos[0] + SELECTBOX_SIDE_WIDTH, nodepos[1], node->box.size[0]-SELECTBOX_SIDE_WIDTH-SELECTBOX_RIGHT_WIDTH, node->box.size[1], 12.0f, SELECTBOX_DEFAULT_HEIGHT, 7.0f, 0.0f, image); /* right border (arrow) */ UI_DrawNormImage(false, nodepos[0] + node->box.size[0] - SELECTBOX_RIGHT_WIDTH, nodepos[1], SELECTBOX_DEFAULT_HEIGHT, node->box.size[1], 12.0f + SELECTBOX_RIGHT_WIDTH, SELECTBOX_DEFAULT_HEIGHT, 12.0f, 0.0f, image); /* draw the label for the current selected option */ for (option = UI_AbstractOptionGetFirstOption(node); option; option = option->next) { if (!Q_streq(OPTIONEXTRADATA(option).value, ref)) continue; if (option->invis) R_Color(invisColor); const char* label = CL_Translate(OPTIONEXTRADATA(option).label); UI_DrawString(font, ALIGN_UL, selBoxX, selBoxY, selBoxX, node->box.size[0] - 4, 0, label, 0, 0, nullptr, false, LONGLINES_PRETTYCHOP); R_Color(nullptr); break; } /* must we draw the drop-down list */ if (UI_GetMouseCapture() == node) { UI_CaptureDrawOver(node); } }
/** * @brief Return a tab located at a screen position * @param[in] node A tab node * @param[in] x The x position of the screen to test * @param[in] y The x position of the screen to test * @return A uiNode_t, or NULL if nothing. * @todo improve test when we are on a junction * @todo improve test when we are on a chopped tab */ static uiNode_t* UI_TabNodeTabAtPosition (const uiNode_t *node, int x, int y) { const char *font; uiNode_t* option; uiNode_t* prev = NULL; int allowedWidth; UI_NodeAbsoluteToRelativePos(node, &x, &y); /** @todo this dont work when an option is hidden */ allowedWidth = node->size[0] - TILE_WIDTH * (EXTRADATACONST(node).count + 1); /* Bounded box test (shound not need, but there are problem) */ if (x < 0 || y < 0 || x >= node->size[0] || y >= node->size[1]) return NULL; font = UI_GetFontFromNode(node); /* Text box test */ for (option = node->firstChild; option; option = option->next) { int tabWidth; const char *label; assert(option->behaviour == ui_optionBehaviour); /* skip hidden options */ if (option->invis) continue; if (x < TILE_WIDTH / 2) return prev; label = OPTIONEXTRADATA(option).label; if (label[0] == '_') label = _(label + 1); R_FontTextSize(font, label, 0, LONGLINES_PRETTYCHOP, &tabWidth, NULL, NULL, NULL); if (OPTIONEXTRADATA(option).icon && OPTIONEXTRADATA(option).icon->size[0] < allowedWidth) { tabWidth += OPTIONEXTRADATA(option).icon->size[0]; } if (tabWidth > allowedWidth) { if (allowedWidth > 0) tabWidth = allowedWidth; else tabWidth = 0; } if (x < tabWidth + TILE_WIDTH) return option; allowedWidth -= tabWidth; x -= tabWidth + TILE_WIDTH; prev = option; } if (x < TILE_WIDTH / 2) return prev; return NULL; }
/** * @brief Handles CustomButton draw */ static void UI_CustomButtonNodeDraw (uiNode_t *node) { const char *text; int texY; const float *textColor; const char *image; vec2_t pos; static vec4_t disabledColor = {0.5, 0.5, 0.5, 1.0}; uiSpriteStatus_t iconStatus = SPRITE_STATUS_NORMAL; const char *font = UI_GetFontFromNode(node); if (!node->onClick || node->disabled) { /** @todo need custom color when button is disabled */ textColor = disabledColor; texY = UI_CUSTOMBUTTON_TEX_HEIGHT * 2; iconStatus = SPRITE_STATUS_DISABLED; } else if (node->state) { textColor = node->selectedColor; texY = UI_CUSTOMBUTTON_TEX_HEIGHT; iconStatus = SPRITE_STATUS_HOVER; } else { textColor = node->color; texY = 0; } UI_GetNodeAbsPos(node, pos); image = UI_GetReferenceString(node, node->image); if (image) { const int texX = rint(EXTRADATA(node).texl[0]); texY += EXTRADATA(node).texl[1]; UI_DrawNormImageByName(qfalse, pos[0], pos[1], node->size[0], node->size[1], texX + node->size[0], texY + node->size[1], texX, texY, image); } if (EXTRADATA(node).background) { UI_DrawSpriteInBox(qfalse, EXTRADATA(node).background, iconStatus, pos[0], pos[1], node->size[0], node->size[1]); } if (EXTRADATA(node).super.icon) { UI_DrawSpriteInBox(EXTRADATA(node).super.flipIcon, EXTRADATA(node).super.icon, iconStatus, pos[0], pos[1], node->size[0], node->size[1]); } text = UI_GetReferenceString(node, node->text); if (text != NULL && *text != '\0') { R_Color(textColor); UI_DrawStringInBox(font, node->contentAlign, pos[0] + node->padding, pos[1] + node->padding, node->size[0] - node->padding - node->padding, node->size[1] - node->padding - node->padding, text, LONGLINES_PRETTYCHOP); R_Color(NULL); } }
/** * @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; }
/** * @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 }
/** * @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); }
/** * @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); }
void uiWindowNode::draw (uiNode_t* node) { const char* text; vec2_t pos; const char* font = UI_GetFontFromNode(node); UI_GetNodeAbsPos(node, pos); /* black border for anamorphic mode */ /** @todo it should be over the window */ /** @todo why not using glClear here with glClearColor set to black here? */ if (UI_WindowIsFullScreen(node)) { /* top */ if (pos[1] != 0) UI_DrawFill(0, 0, viddef.virtualWidth, pos[1], anamorphicBorder); /* left-right */ if (pos[0] != 0) UI_DrawFill(0, pos[1], pos[0], node->box.size[1], anamorphicBorder); if (pos[0] + node->box.size[0] < viddef.virtualWidth) { const int width = viddef.virtualWidth - (pos[0] + node->box.size[0]); UI_DrawFill(viddef.virtualWidth - width, pos[1], width, node->box.size[1], anamorphicBorder); } /* bottom */ if (pos[1] + node->box.size[1] < viddef.virtualHeight) { const int height = viddef.virtualHeight - (pos[1] + node->box.size[1]); UI_DrawFill(0, viddef.virtualHeight - height, viddef.virtualWidth, height, anamorphicBorder); } } /* hide background if window is modal */ if (EXTRADATA(node).modal && ui_global.windowStack[ui_global.windowStackPos - 1] == node) UI_DrawFill(0, 0, viddef.virtualWidth, viddef.virtualHeight, modalBackground); 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]); } /* draw the title */ text = UI_GetReferenceString(node, node->text); if (text) UI_DrawStringInBox(font, ALIGN_CC, pos[0] + node->padding, pos[1] + node->padding, node->box.size[0] - node->padding - node->padding, TOP_HEIGHT + 10 - node->padding - node->padding, text); }
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; }
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)); }
/** * @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); }
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); }
void uiTabNode::draw (uiNode_t *node) { ui_tabStatus_t lastStatus = UI_TAB_NOTHING; uiNode_t* option; uiNode_t* overMouseOption = NULL; const char *ref; const char *font; int currentX; int allowedWidth; vec2_t pos; const char* image = UI_GetReferenceString(node, node->image); if (!image) image = "ui/tab"; ref = UI_AbstractOptionGetCurrentValue(node); if (ref == NULL) return; font = UI_GetFontFromNode(node); if (node->state) { overMouseOption = UI_TabNodeTabAtPosition(node, mousePosX, mousePosY); } UI_GetNodeAbsPos(node, pos); currentX = pos[0]; option = node->firstChild; assert(option->behaviour == ui_optionBehaviour); /** @todo this dont work when an option is hidden */ allowedWidth = node->box.size[0] - TILE_WIDTH * (EXTRADATA(node).count + 1); while (option) { int fontHeight; int fontWidth; int tabWidth; int textPos; bool drawIcon = false; ui_tabStatus_t status = UI_TAB_NORMAL; assert(option->behaviour == ui_optionBehaviour); /* skip hidden options */ if (option->invis) { option = option->next; continue; } /* Check the status of the current tab */ if (Q_streq(OPTIONEXTRADATA(option).value, ref)) { status = UI_TAB_SELECTED; } else if (option->disabled || node->disabled) { status = UI_TAB_DISABLED; } else if (option == overMouseOption) { status = UI_TAB_HIGHLIGHTED; } /* Display */ UI_TabNodeDrawJunction(image, currentX, pos[1], lastStatus, status); currentX += TILE_WIDTH; const char *label = CL_Translate(OPTIONEXTRADATA(option).label); R_FontTextSize(font, label, 0, LONGLINES_PRETTYCHOP, &fontWidth, &fontHeight, NULL, NULL); tabWidth = fontWidth; if (OPTIONEXTRADATA(option).icon && OPTIONEXTRADATA(option).icon->size[0] < allowedWidth) { tabWidth += OPTIONEXTRADATA(option).icon->size[0]; drawIcon = true; } if (tabWidth > allowedWidth) { if (allowedWidth > 0) tabWidth = allowedWidth; else tabWidth = 0; } if (tabWidth > 0) { UI_TabNodeDrawPlain(image, currentX, pos[1], tabWidth, status); } textPos = currentX; if (drawIcon) { uiSpriteStatus_t iconStatus = SPRITE_STATUS_NORMAL; if (status == UI_TAB_DISABLED) { iconStatus = SPRITE_STATUS_DISABLED; } UI_DrawSpriteInBox(OPTIONEXTRADATA(option).flipIcon, OPTIONEXTRADATA(option).icon, iconStatus, currentX, pos[1], OPTIONEXTRADATA(option).icon->size[0], TILE_HEIGHT); textPos += OPTIONEXTRADATA(option).icon->size[0]; } /** @todo fontWidth can be =0, maybe a bug from the font cache */ OPTIONEXTRADATA(option).truncated = tabWidth < fontWidth || tabWidth == 0; UI_DrawString(font, ALIGN_UL, textPos, pos[1] + ((node->box.size[1] - fontHeight) / 2), textPos, tabWidth + 1, 0, label, 0, 0, NULL, false, LONGLINES_PRETTYCHOP); currentX += tabWidth; allowedWidth -= tabWidth; /* Next */ lastStatus = status; option = option->next; } /* Display last junction and end of header */ UI_TabNodeDrawJunction(image, currentX, pos[1], lastStatus, UI_TAB_NOTHING); currentX += TILE_WIDTH; if (currentX < pos[0] + node->box.size[0]) UI_TabNodeDrawPlain(image, currentX, pos[1], pos[0] + node->box.size[0] - currentX, UI_TAB_NOTHING); }
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_TextEntryNodeDraw (uiNode_t *node) { static const int panelTemplate[] = { CORNER_SIZE, MID_SIZE, CORNER_SIZE, CORNER_SIZE, MID_SIZE, CORNER_SIZE, MARGE }; const char *text; int texX, texY; const float *textColor; const char *image; vec2_t pos; static vec4_t disabledColor = {0.5, 0.5, 0.5, 1.0}; const char *font = UI_GetFontFromNode(node); if (node->disabled) { /** @todo need custom color when node is disabled */ textColor = disabledColor; texX = TILE_SIZE; texY = TILE_SIZE; } else if (node->state) { textColor = node->color; texX = TILE_SIZE; texY = 0; } else { textColor = node->color; texX = 0; texY = 0; } if (UI_HasFocus(node)) textColor = node->selectedColor; UI_GetNodeAbsPos(node, pos); image = UI_GetReferenceString(node, node->image); if (image) UI_DrawPanel(pos, node->size, image, texX, texY, panelTemplate); text = UI_GetReferenceString(node, node->text); if (text != NULL) { /** @todo we don't need to edit the text to draw the cursor */ if (UI_HasFocus(node)) { if (CL_Milliseconds() % 1000 < 500) { text = va("%s%c", text, CURSOR); } } if (EXTRADATA(node).isPassword) { char *c = va("%s", text); int size = UTF8_strlen(c); text = c; /* hide the text with a special char */ assert(strlen(c) >= size); /* trustable, but it can't be false */ while (size) { *c++ = HIDECHAR; size--; } /* readd the cursor */ if (UI_HasFocus(node)) { if (CL_Milliseconds() % 1000 < 500) { c--; *c++ = CURSOR; } } *c = '\0'; } if (*text != '\0') { R_Color(textColor); UI_DrawStringInBox(font, node->textalign, pos[0] + node->padding, pos[1] + node->padding, node->size[0] - node->padding - node->padding, node->size[1] - node->padding - node->padding, text, LONGLINES_PRETTYCHOP); R_Color(NULL); } } }
static void UI_KeyBindingNodeDraw (uiNode_t *node) { static const int panelTemplate[] = { CORNER_SIZE, MID_SIZE, CORNER_SIZE, CORNER_SIZE, MID_SIZE, CORNER_SIZE, MARGE }; const char *binding, *description, *command; int texX, texY; const float *textColor; const char *image; vec2_t pos; const char *font = UI_GetFontFromNode(node); const int bindingWidth = EXTRADATA(node).bindingWidth; const int descriptionWidth = node->size[0] - bindingWidth; vec2_t descriptionPos, descriptionSize; vec2_t bindingPos, bindingSize; if (node->state) { textColor = node->color; texX = TILE_SIZE; texY = 0; } else { textColor = node->color; texX = 0; texY = 0; } if (UI_HasFocus(node)) textColor = node->selectedColor; UI_GetNodeAbsPos(node, pos); Vector2Set(descriptionSize, descriptionWidth, node->size[1]); Vector2Set(bindingSize, bindingWidth, node->size[1]); Vector2Set(descriptionPos, pos[0], pos[1]); Vector2Set(bindingPos, pos[0] + descriptionWidth + node->padding, pos[1]); image = UI_GetReferenceString(node, node->image); if (image) { UI_DrawPanel(descriptionPos, descriptionSize, image, texX, texY, panelTemplate); UI_DrawPanel(bindingPos, bindingSize, image, texX, texY, panelTemplate); } binding = UI_GetReferenceString(node, node->text); if (Q_strnull(binding)) binding = _("NONE"); /** @todo check that this is a keybinding value (with macro expansion) */ command = node->text + 9; description = Cmd_GetCommandDesc(command); if (description[0] == '\0') description = command; R_Color(textColor); UI_DrawStringInBox(font, node->contentAlign, descriptionPos[0] + node->padding, descriptionPos[1] + node->padding, descriptionSize[0] - node->padding - node->padding, descriptionSize[1] - node->padding - node->padding, description, LONGLINES_PRETTYCHOP); UI_DrawStringInBox(font, node->contentAlign, bindingPos[0] + node->padding, bindingPos[1] + node->padding, bindingSize[0] - node->padding - node->padding, bindingSize[1] - node->padding - node->padding, binding, LONGLINES_PRETTYCHOP); R_Color(NULL); }
/** * @brief Handles Button draw */ static void UI_ButtonNodeDraw (uiNode_t *node) { static const int panelTemplate[] = { CORNER_SIZE, MID_SIZE, CORNER_SIZE, CORNER_SIZE, MID_SIZE, CORNER_SIZE, MARGE }; const char *text; int texX, texY; const float *textColor; const char *image; vec2_t pos; static vec4_t disabledColor = {0.5, 0.5, 0.5, 1.0}; int iconPadding = 0; uiSpriteStatus_t iconStatus = SPRITE_STATUS_NORMAL; const char *font = UI_GetFontFromNode(node); if (!node->onClick || node->disabled) { /** @todo need custom color when button is disabled */ textColor = disabledColor; texX = TILE_SIZE; texY = TILE_SIZE; iconStatus = SPRITE_STATUS_DISABLED; } else if (node->state) { textColor = node->selectedColor; texX = TILE_SIZE; texY = 0; iconStatus = SPRITE_STATUS_HOVER; } else { textColor = node->color; texX = 0; texY = 0; } UI_GetNodeAbsPos(node, pos); image = UI_GetReferenceString(node, node->image); if (image) UI_DrawPanel(pos, node->size, image, texX, texY, panelTemplate); /* display the icon at the left */ /** @todo should we move it according to the text align? */ if (EXTRADATA(node).icon) { /* use at least a box size equals to button height */ int size = node->size[1] - node->padding - node->padding; if (size < EXTRADATA(node).icon->size[0]) size = EXTRADATA(node).icon->size[0]; UI_DrawSpriteInBox(EXTRADATA(node).flipIcon, EXTRADATA(node).icon, iconStatus, pos[0] + node->padding, pos[1] + node->padding, size, node->size[1] - node->padding - node->padding); iconPadding = size + node->padding; } text = UI_GetReferenceString(node, node->text); if (text != NULL && *text != '\0') { R_Color(textColor); text = _(text); UI_DrawStringInBox(font, node->contentAlign, pos[0] + node->padding + iconPadding, pos[1] + node->padding, node->size[0] - node->padding - node->padding - iconPadding, node->size[1] - node->padding - node->padding, text, LONGLINES_PRETTYCHOP); R_Color(NULL); } }
static void UI_SelectBoxNodeDrawOverWindow (uiNode_t *node) { uiNode_t* option; int selBoxX, selBoxY; const char *ref; const char *font; vec2_t nodepos; const char* imageName; const image_t *image; ref = UI_AbstractOptionGetCurrentValue(node); if (ref == NULL) return; UI_GetNodeAbsPos(node, nodepos); imageName = UI_GetReferenceString(node, node->image); if (!imageName) imageName = "ui/selectbox"; image = UI_LoadImage(imageName); font = UI_GetFontFromNode(node); selBoxX = nodepos[0] + SELECTBOX_SIDE_WIDTH; selBoxY = nodepos[1] + SELECTBOX_SPACER; selBoxY += node->size[1]; /* drop down list */ /* left side */ UI_DrawNormImage(nodepos[0], nodepos[1] + node->size[1], SELECTBOX_SIDE_WIDTH, node->size[1] * EXTRADATA(node).count, 7.0f, 28.0f, 0.0f, 21.0f, image); /* stretched middle bar */ UI_DrawNormImage(nodepos[0] + SELECTBOX_SIDE_WIDTH, nodepos[1] + node->size[1], node->size[0] -SELECTBOX_SIDE_WIDTH-SELECTBOX_RIGHT_WIDTH, node->size[1] * EXTRADATA(node).count, 16.0f, 28.0f, 7.0f, 21.0f, image); /* right side */ UI_DrawNormImage(nodepos[0] + node->size[0] -SELECTBOX_SIDE_WIDTH-SELECTBOX_RIGHT_WIDTH, nodepos[1] + node->size[1], SELECTBOX_SIDE_WIDTH, node->size[1] * EXTRADATA(node).count, 23.0f, 28.0f, 16.0f, 21.0f, image); /* now draw all available options for this selectbox */ for (option = UI_AbstractOptionGetFirstOption(node); option; option = option->next) { const char *label; if (option->invis) continue; /* draw the hover effect */ if (OPTIONEXTRADATA(option).hovered) UI_DrawFill(selBoxX, selBoxY, node->size[0] -SELECTBOX_SIDE_WIDTH - SELECTBOX_SIDE_WIDTH - SELECTBOX_RIGHT_WIDTH, SELECTBOX_DEFAULT_HEIGHT, node->color); /* print the option label */ label = OPTIONEXTRADATA(option).label; if (label[0] == '_') label = _(label + 1); UI_DrawString(font, ALIGN_UL, selBoxX, selBoxY, selBoxX, node->size[0] - 4, 0, label, 0, 0, NULL, qfalse, LONGLINES_PRETTYCHOP); /* next entries' position */ selBoxY += node->size[1]; } /* left side */ UI_DrawNormImage(nodepos[0], selBoxY - SELECTBOX_SPACER, SELECTBOX_SIDE_WIDTH, SELECTBOX_BOTTOM_HEIGHT, 7.0f, 32.0f, 0.0f, 28.0f, image); /* stretched middle bar */ UI_DrawNormImage(nodepos[0] + SELECTBOX_SIDE_WIDTH, selBoxY - SELECTBOX_SPACER, node->size[0] - SELECTBOX_SIDE_WIDTH - SELECTBOX_RIGHT_WIDTH, SELECTBOX_BOTTOM_HEIGHT, 16.0f, 32.0f, 7.0f, 28.0f, image); /* right bottom side */ UI_DrawNormImage(nodepos[0] + node->size[0] - SELECTBOX_SIDE_WIDTH - SELECTBOX_RIGHT_WIDTH, selBoxY - SELECTBOX_SPACER, SELECTBOX_SIDE_WIDTH, SELECTBOX_BOTTOM_HEIGHT, 23.0f, 32.0f, 16.0f, 28.0f, image); }
/** * @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); }
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); }
void uiSelectBoxNode::drawOverWindow (uiNode_t* node) { const char* ref = UI_AbstractOptionGetCurrentValue(node); if (ref == nullptr) return; vec2_t nodepos; UI_GetNodeAbsPos(node, nodepos); const char* imageName = UI_GetReferenceString(node, node->image); if (!imageName) imageName = "ui/selectbox"; const image_t* image = UI_LoadImage(imageName); const char* font = UI_GetFontFromNode(node); int selBoxX = nodepos[0] + SELECTBOX_SIDE_WIDTH; int selBoxY = nodepos[1] + SELECTBOX_SPACER; selBoxY += node->box.size[1]; /* drop down list */ /* left side */ UI_DrawNormImage(false, nodepos[0], nodepos[1] + node->box.size[1], SELECTBOX_SIDE_WIDTH, node->box.size[1] * EXTRADATA(node).count, 7.0f, 28.0f, 0.0f, 21.0f, image); /* stretched middle bar */ UI_DrawNormImage(false, nodepos[0] + SELECTBOX_SIDE_WIDTH, nodepos[1] + node->box.size[1], node->box.size[0] -SELECTBOX_SIDE_WIDTH-SELECTBOX_RIGHT_WIDTH, node->box.size[1] * EXTRADATA(node).count, 16.0f, 28.0f, 7.0f, 21.0f, image); /* right side */ UI_DrawNormImage(false, nodepos[0] + node->box.size[0] -SELECTBOX_SIDE_WIDTH-SELECTBOX_RIGHT_WIDTH, nodepos[1] + node->box.size[1], SELECTBOX_SIDE_WIDTH, node->box.size[1] * EXTRADATA(node).count, 23.0f, 28.0f, 16.0f, 21.0f, image); /* now draw all available options for this selectbox */ int check = 0; for (uiNode_t* option = UI_AbstractOptionGetFirstOption(node); option; option = option->next) { if (option->invis) continue; /* draw the hover effect */ if (OPTIONEXTRADATA(option).hovered) UI_DrawFill(selBoxX, selBoxY, node->box.size[0] -SELECTBOX_SIDE_WIDTH - SELECTBOX_SIDE_WIDTH - SELECTBOX_RIGHT_WIDTH, SELECTBOX_DEFAULT_HEIGHT, node->color); /* print the option label */ const char* label = CL_Translate(OPTIONEXTRADATA(option).label); UI_DrawString(font, ALIGN_UL, selBoxX, selBoxY, selBoxX, node->box.size[0] - 4, 0, label, 0, 0, nullptr, false, LONGLINES_PRETTYCHOP); /* next entries' position */ selBoxY += node->box.size[1]; check++; } /** detect inconsistency */ if (check != EXTRADATA(node).count) { /** force clean up cache */ Com_Printf("uiSelectBoxNode::drawOverWindow: Node '%s' contains unsynchronized option list. Fixed.\n", UI_GetPath(node)); EXTRADATA(node).versionId = 0; } /* left side */ UI_DrawNormImage(false, nodepos[0], selBoxY - SELECTBOX_SPACER, SELECTBOX_SIDE_WIDTH, SELECTBOX_BOTTOM_HEIGHT, 7.0f, 32.0f, 0.0f, 28.0f, image); /* stretched middle bar */ UI_DrawNormImage(false, nodepos[0] + SELECTBOX_SIDE_WIDTH, selBoxY - SELECTBOX_SPACER, node->box.size[0] - SELECTBOX_SIDE_WIDTH - SELECTBOX_RIGHT_WIDTH, SELECTBOX_BOTTOM_HEIGHT, 16.0f, 32.0f, 7.0f, 28.0f, image); /* right bottom side */ UI_DrawNormImage(false, nodepos[0] + node->box.size[0] - SELECTBOX_SIDE_WIDTH - SELECTBOX_RIGHT_WIDTH, selBoxY - SELECTBOX_SPACER, SELECTBOX_SIDE_WIDTH, SELECTBOX_BOTTOM_HEIGHT, 23.0f, 32.0f, 16.0f, 28.0f, image); }