UFO: Alien Invasion
Loading...
Searching...
No Matches
ui_draw.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "ui_main.h"
26#include "ui_nodes.h"
27#include "ui_internal.h"
28#include "ui_draw.h"
29#include "ui_actions.h"
30#include "ui_input.h"
31#include "ui_node.h"
32#include "ui_timer.h" /* define UI_HandleTimers */
33#include "ui_dragndrop.h"
34#include "ui_tooltip.h"
35#include "ui_render.h"
37
38#include "../client.h"
39#include "../renderer/r_draw.h"
40#include "../renderer/r_misc.h"
41
42static const int TOOLTIP_DELAY = 500; /* delay that msecs before showing tooltip */
43
45static bool tooltipVisible = false;
47
48static int noticeTime;
49static char noticeText[256];
51
58
65{
66 drawOverNode = node;
67}
68
69#ifdef DEBUG
70
71static int debugTextPositionY = 0;
72static int debugPositionX = 0;
73#define DEBUG_PANEL_WIDTH 300
74
75static void UI_HighlightNode (const uiNode_t* node, const vec4_t color)
76{
77 vec2_t pos;
78 int width;
79 int lineDefinition[4];
80 const char* text;
81
82 if (node->parent) {
83 static const vec4_t grey = {0.7, 0.7, 0.7, 1.0};
84 UI_HighlightNode(node->parent, grey);
85 }
86
87 UI_GetNodeAbsPos(node, pos);
88
89 text = va("%s (%s)", node->name, UI_Node_GetWidgetName(node));
90 R_FontTextSize("f_small_bold", text, DEBUG_PANEL_WIDTH, LONGLINES_PRETTYCHOP, &width, nullptr, nullptr, nullptr);
91
92 R_Color(color);
93 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX + 20, debugTextPositionY, debugPositionX + 20, DEBUG_PANEL_WIDTH, 0, text, 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
94 debugTextPositionY += 15;
95
96 if (debugPositionX != 0) {
97 lineDefinition[0] = debugPositionX + 20;
98 lineDefinition[2] = pos[0] + node->box.size[0];
99 } else {
100 lineDefinition[0] = debugPositionX + 20 + width;
101 lineDefinition[2] = pos[0];
102 }
103 lineDefinition[1] = debugTextPositionY - 5;
104 lineDefinition[3] = pos[1];
105 R_DrawLine(lineDefinition, 1);
106 R_Color(nullptr);
107
108 /* exclude rect */
109 if (node->firstExcludeRect) {
110 vec4_t trans = {1, 1, 1, 1};
111 Vector4Copy(color, trans);
112 trans[3] = trans[3] / 2;
113
114 for (uiExcludeRect_t* current = node->firstExcludeRect; current != nullptr; current = current->next) {
115 const int x = pos[0] + current->pos[0];
116 const int y = pos[1] + current->pos[1];
117 UI_DrawFill(x, y, current->size[0], current->size[1], trans);
118 }
119 }
120
121 /* bounded box */
122 UI_DrawRect(pos[0] - 1, pos[1] - 1, node->box.size[0] + 2, node->box.size[1] + 2, color, 2.0, 0x3333);
123}
124
128static void UI_DrawDebugNodeNames (void)
129{
130 static const vec4_t white = {1, 1.0, 1.0, 1.0};
131 static const vec4_t background = {0.0, 0.0, 0.0, 0.5};
132
133 debugTextPositionY = 100;
134
135 /* x panel position with hysteresis */
136 if (mousePosX < viddef.virtualWidth / 3)
137 debugPositionX = viddef.virtualWidth - DEBUG_PANEL_WIDTH;
138 if (mousePosX > 2 * viddef.virtualWidth / 3)
139 debugPositionX = 0;
140
141 /* mouse position */
142 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX, debugTextPositionY, debugPositionX, 200, 0, va("Mouse X: %i Y: %i", mousePosX, mousePosY), 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
143 debugTextPositionY += 15;
144 /* global */
145 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX, debugTextPositionY, debugPositionX, 200, 0, "main active window:", 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
146 debugTextPositionY += 15;
147 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX+20, debugTextPositionY, debugPositionX + 20, 200, 0, Cvar_GetString("ui_sys_active"), 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
148 debugTextPositionY += 15;
149 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX, debugTextPositionY, debugPositionX, 200, 0, "main option window:", 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
150 debugTextPositionY += 15;
151 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX+20, debugTextPositionY, debugPositionX + 20, 200, 0, Cvar_GetString("ui_sys_main"), 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
152 debugTextPositionY += 15;
153 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX, debugTextPositionY, debugPositionX, 200, 0, "-----------------------", 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
154 debugTextPositionY += 15;
155
156 /* background */
157 UI_DrawFill(debugPositionX, debugTextPositionY, DEBUG_PANEL_WIDTH, VID_NORM_HEIGHT - debugTextPositionY - 100, background);
158
159 /* window stack */
160 R_Color(white);
161 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX, debugTextPositionY, debugPositionX, 200, 0, "window stack:", 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
162 debugTextPositionY += 15;
163 for (int stackPosition = 0; stackPosition < ui_global.windowStackPos; stackPosition++) {
164 uiNode_t* window = ui_global.windowStack[stackPosition];
165 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX+20, debugTextPositionY, debugPositionX + 20, 200, 0, window->name, 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
166 debugTextPositionY += 15;
167 }
168
169 /* hovered node */
171 if (hoveredNode) {
172 static const vec4_t red = {1.0, 0.0, 0.0, 1.0};
173 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX, debugTextPositionY, debugPositionX, 200, 0, "-----------------------", 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
174 debugTextPositionY += 15;
175
176 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX, debugTextPositionY, debugPositionX, 200, 0, "hovered node:", 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
177 debugTextPositionY += 15;
178 UI_HighlightNode(hoveredNode, red);
179 R_Color(white);
180 }
181
182 /* target node */
183 if (UI_DNDIsDragging()) {
185 if (targetNode) {
186 static const vec4_t green = {0.0, 0.5, 0.0, 1.0};
187 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX, debugTextPositionY, debugPositionX, 200, 0, "-----------------------", 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
188 debugTextPositionY += 15;
189
190 R_Color(green);
191 UI_DrawString("f_small_bold", ALIGN_UL, debugPositionX, debugTextPositionY, debugPositionX, 200, 0, "drag and drop target node:", 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
192 debugTextPositionY += 15;
193 UI_HighlightNode(targetNode, green);
194 }
195 }
196 R_Color(nullptr);
197}
198#endif
199
200
202{
203 tooltipVisible = true;
205}
206
207static void UI_DrawNode (uiNode_t* node)
208{
209 /* update the layout */
210 UI_Validate(node);
211
212 /* skip invisible, virtual, and undrawable nodes */
213 if (node->invis || UI_Node_IsVirtual(node))
214 return;
215 /* if construct */
216 if (!UI_CheckVisibility(node))
217 return;
218
219 vec2_t pos;
220 UI_GetNodeAbsPos(node, pos);
221
225 /* check node size x and y value to check whether they are zero */
226 if (Vector2NotEmpty(node->box.size)) {
227 if (node->bgcolor[3] != 0)
228 UI_DrawFill(pos[0], pos[1], node->box.size[0], node->box.size[1], node->bgcolor);
229
230 if (node->border && node->bordercolor[3] != 0) {
231 UI_DrawRect(pos[0], pos[1], node->box.size[0], node->box.size[1],
232 node->bordercolor, node->border, 0xFFFF);
233 }
234 }
235
236 /* draw the node */
237 if (UI_Node_IsDrawable(node)) {
238 UI_Node_Draw(node);
239 }
240
241 /* draw all child */
242 if (!UI_Node_IsDrawItselfChild(node) && node->firstChild) {
243 static int globalTransX = 0;
244 static int globalTransY = 0;
245 bool hasClient = false;
246 vec2_t clientPosition;
248 UI_Node_GetClientPosition(node, clientPosition);
249 hasClient = true;
250 }
251
252 UI_PushClipRect(pos[0] + globalTransX, pos[1] + globalTransY, node->box.size[0], node->box.size[1]);
253
255 if (hasClient) {
256 vec3_t trans;
257 globalTransX += clientPosition[0];
258 globalTransY += clientPosition[1];
259 trans[0] = clientPosition[0] * viddef.rx;
260 trans[1] = clientPosition[1] * viddef.ry;
261 trans[2] = 0;
262 R_Transform(trans, nullptr, nullptr);
263 }
264
266 for (uiNode_t* child = node->firstChild; child; child = child->next)
267 UI_DrawNode(child);
268
270 if (hasClient) {
271 vec3_t trans;
272 globalTransX -= clientPosition[0];
273 globalTransY -= clientPosition[1];
274 trans[0] = -clientPosition[0] * viddef.rx;
275 trans[1] = -clientPosition[1] * viddef.ry;
276 trans[2] = 0;
277 R_Transform(trans, nullptr, nullptr);
278 }
279
281 }
282
283 for (uiNode_t* iter = node->firstChild; iter; ) {
284 uiNode_t* child = iter;
285 iter = iter->next;
286 if (child->deleteTime > 0 && child->deleteTime < CL_Milliseconds()) {
287 UI_DeleteNode(child);
288 }
289 }
290}
291
296static void UI_DrawNotice (void)
297{
298 const vec4_t noticeBG = { 1.0f, 0.0f, 0.0f, 0.2f };
299 const vec4_t noticeColor = { 1.0f, 1.0f, 1.0f, 1.0f };
300 int height = 0, width = 0;
301 const int maxWidth = 500;
302 const char* font = "f_normal";
303 int lines = 5;
304 int dx;
305 int x, y;
306 vec_t* noticePosition;
307
309 if (noticePosition) {
310 x = noticePosition[0];
311 y = noticePosition[1];
312 } else {
313 x = VID_NORM_WIDTH / 2;
314 y = 110;
315 }
316
317 /* relative to the window */
318 x += noticeWindow->box.pos[0];
319 y += noticeWindow->box.pos[1];
320
321 R_FontTextSize(font, noticeText, maxWidth, LONGLINES_WRAP, &width, &height, nullptr, nullptr);
322
323 if (!width)
324 return;
325
326 if (x + width + 3 > viddef.virtualWidth)
327 dx = -(width + 10);
328 else
329 dx = 0;
330
331 UI_DrawFill((x - 2 + dx) - ((width + 2) / 2), (y - 2) - ((height + 2) / 2), width + 4, height + 4, noticeBG);
332 R_Color(noticeColor);
333 UI_DrawString(font, ALIGN_CC, x + 1 + dx, y + 1, x + 1, maxWidth, 0, noticeText, lines);
334 R_Color(nullptr);
335}
336
341void UI_Draw (void)
342{
344
345 assert(ui_global.windowStackPos >= 0);
346
347 const bool mouseMoved = UI_CheckMouseMove();
349
350 /* handle delay time for tooltips */
351 if (mouseMoved && tooltipVisible) {
353 tooltipVisible = false;
354 } else if (!tooltipVisible && !mouseMoved && !tooltipTimer->isRunning && ui_show_tooltips->integer && hoveredNode) {
356 }
357
358 /* under a fullscreen, windows should not be visible */
359 int pos = UI_GetLastFullScreenWindow();
360 if (pos < 0)
361 return;
362
363 /* draw all visible windows */
364 for (; pos < ui_global.windowStackPos; pos++) {
365 uiNode_t* window;
366 window = ui_global.windowStack[pos];
367
368 drawOverNode = nullptr;
369
370 UI_DrawNode(window);
371
372 /* draw a node over the window */
373 if (drawOverNode) {
375 }
376 }
377
378 /* draw a special notice */
379 if (noticeWindow != nullptr && CL_Milliseconds() < noticeTime)
381
382 /* unactive notice */
383 if (noticeWindow != nullptr && CL_Milliseconds() >= noticeTime)
384 noticeWindow = nullptr;
385
386 /* draw tooltip */
389 }
390
391#ifdef DEBUG
392 /* debug information */
393 if (UI_DebugMode() >= 1) {
394 UI_DrawDebugNodeNames();
395 }
396#endif
397}
398
403
411void UI_DisplayNotice (const char* text, int time, const char* windowName)
412{
413 noticeTime = CL_Milliseconds() + time;
414 Q_strncpyz(noticeText, text, sizeof(noticeText));
415
416 if (windowName == nullptr) {
418 if (noticeWindow == nullptr)
419 Com_Printf("UI_DisplayNotice: No active window\n");
420 } else {
421 noticeWindow = UI_GetWindow(windowName);
422 if (noticeWindow == nullptr)
423 Com_Printf("UI_DisplayNotice: '%s' not found\n", windowName);
424 }
425}
426
427void UI_InitDraw (void)
428{
429 ui_show_tooltips = Cvar_Get("ui_show_tooltips", "1", CVAR_ARCHIVE, "Show tooltips in the UI");
431}
int mousePosY
Definition cl_input.cpp:76
int mousePosX
Definition cl_input.cpp:76
int CL_Milliseconds(void)
Definition cl_main.cpp:1207
#define VID_NORM_WIDTH
Definition cl_renderer.h:40
void R_FontTextSize(const char *fontId, const char *text, int maxWidth, longlines_t method, int *width, int *height, int *lines, bool *isTruncated)
Supply information about the size of the text when it is linewrapped and rendered,...
Definition r_font.cpp:522
@ LONGLINES_WRAP
@ LONGLINES_PRETTYCHOP
#define VID_NORM_HEIGHT
Definition cl_renderer.h:41
void R_Color(const vec4_t rgba)
Change the color to given value.
Definition r_state.cpp:1011
viddef_t viddef
Definition cl_video.cpp:34
Primary header for client.
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
static const vec4_t red
static const vec4_t green
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition cvar.cpp:342
const char * Cvar_GetString(const char *varName)
Returns the value of cvar as string.
Definition cvar.cpp:210
#define CVAR_ARCHIVE
Definition cvar.h:40
void R_DrawLine(int *verts, float thickness)
Draws one line with only one start and one end point.
Definition r_draw.cpp:494
void R_Transform(const vec3_t transform, const vec3_t rotate, const vec3_t scale)
Perform translate, rotate and scale operations on the current matrix.
Definition r_misc.cpp:220
@ ALIGN_CC
Definition scripts.h:94
@ ALIGN_UL
Definition scripts.h:90
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition shared.cpp:410
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition cvar.h:71
vec2_t size
Definition ui_nodes.h:52
struct uiExcludeRect_s * next
Definition ui_nodes.h:47
Atomic structure used to define most of the UI.
Definition ui_nodes.h:80
int border
Definition ui_nodes.h:124
uiNode_t * firstChild
Definition ui_nodes.h:89
bool invis
Definition ui_nodes.h:101
uiNode_t * next
Definition ui_nodes.h:91
int deleteTime
Definition ui_nodes.h:113
uiExcludeRect_t * firstExcludeRect
Definition ui_nodes.h:116
uiNode_t * parent
Definition ui_nodes.h:92
uiBox_t box
Definition ui_nodes.h:96
char name[MAX_VAR]
Definition ui_nodes.h:82
vec4_t bgcolor
Definition ui_nodes.h:125
vec4_t bordercolor
Definition ui_nodes.h:126
float vec_t
Definition ufotypes.h:37
vec_t vec3_t[3]
Definition ufotypes.h:39
vec_t vec4_t[4]
Definition ufotypes.h:40
vec_t vec2_t[2]
Definition ufotypes.h:38
bool UI_DNDIsDragging(void)
Return true if we are dragging something.
static uiNode_t * targetNode
uiNode_t * UI_DNDGetTargetNode(void)
Return target of the DND.
void UI_DrawDragAndDrop(int mousePosX, int mousePosY)
Draw to dragging object and catch mouse move event.
static void UI_DrawNode(uiNode_t *node)
Definition ui_draw.cpp:207
void UI_CaptureDrawOver(uiNode_t *node)
Capture a node we will draw over all nodes (per window).
Definition ui_draw.cpp:64
static int noticeTime
Definition ui_draw.cpp:48
static char noticeText[256]
Definition ui_draw.cpp:49
void UI_DrawCursor(void)
Definition ui_draw.cpp:399
static const int TOOLTIP_DELAY
Definition ui_draw.cpp:42
static uiNode_t * drawOverNode
Node we will draw over.
Definition ui_draw.cpp:57
static bool tooltipVisible
Definition ui_draw.cpp:45
static void UI_CheckTooltipDelay(uiNode_t *node, uiTimer_t *timer)
Definition ui_draw.cpp:201
static cvar_t * ui_show_tooltips
Definition ui_draw.cpp:44
static uiTimer_t * tooltipTimer
Definition ui_draw.cpp:46
static uiNode_t * noticeWindow
Definition ui_draw.cpp:50
void UI_DisplayNotice(const char *text, int time, const char *windowName)
Displays a message over all windows.
Definition ui_draw.cpp:411
static void UI_DrawNotice(void)
Generic notice function that renders a message to the screen.
Definition ui_draw.cpp:296
void UI_InitDraw(void)
Definition ui_draw.cpp:427
void UI_Draw(void)
Draws the window stack.
Definition ui_draw.cpp:341
bool UI_CheckMouseMove(void)
Call mouse move only if the mouse position change.
Definition ui_input.cpp:569
uiNode_t * UI_GetHoveredNode(void)
Get the current hovered node.
Definition ui_input.cpp:552
static uiNode_t * hoveredNode
save the current hovered node (first node under the mouse)
Definition ui_input.cpp:56
Internal data use by the UI package.
uiGlobal_t ui_global
Definition ui_main.cpp:38
int UI_DebugMode(void)
Get the current debug mode (0 mean disabled).
Definition ui_main.cpp:52
void UI_Validate(uiNode_t *node)
Validate a node tree.
Definition ui_node.cpp:1078
bool UI_Node_IsVirtual(uiNode_t const *node)
Definition ui_node.cpp:42
void UI_Node_DrawTooltip(const uiNode_t *node, int x, int y)
Definition ui_node.cpp:115
const char * UI_Node_GetWidgetName(uiNode_t const *node)
Definition ui_node.cpp:99
void UI_Node_DrawOverWindow(uiNode_t *node)
Definition ui_node.cpp:121
void UI_Node_GetClientPosition(uiNode_t const *node, vec2_t position)
Definition ui_node.cpp:295
bool UI_Node_IsDrawItselfChild(uiNode_t const *node)
Definition ui_node.cpp:77
bool UI_Node_IsDrawable(uiNode_t const *node)
Definition ui_node.cpp:48
void UI_Node_Draw(uiNode_t *node)
Definition ui_node.cpp:109
bool UI_Node_IsScrollableContainer(uiNode_t const *node)
Definition ui_node.cpp:93
void UI_GetNodeAbsPos(const uiNode_t *node, vec2_t pos)
Returns the absolute position of a node.
Definition ui_node.cpp:526
C interface to allow to access to cpp node code.
static const vec4_t grey
vec_t * UI_WindowNodeGetNoticePosition(uiNode_t *node)
Get the noticePosition from a window node.
bool UI_CheckVisibility(uiNode_t *node)
Check the if conditions for a given node.
Definition ui_nodes.cpp:152
void UI_DeleteNode(uiNode_t *node)
Definition ui_nodes.cpp:618
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)
void UI_DrawRect(int x, int y, int w, int h, const vec4_t color, float lineWidth, int pattern)
Definition ui_render.cpp:42
void UI_PushClipRect(int x, int y, int width, int height)
Definition ui_render.cpp:47
void UI_DrawFill(int x, int y, int w, int h, const vec4_t color)
Fills a box of pixels with a single color.
Definition ui_render.cpp:37
void UI_PopClipRect(void)
Definition ui_render.cpp:52
void UI_HandleTimers(void)
Internal function to handle timers.
Definition ui_timer.cpp:98
void UI_TimerStop(uiTimer_t *timer)
Stop a timer.
Definition ui_timer.cpp:163
uiTimer_t * UI_AllocTimer(uiNode_t *node, int firstDelay, timerCallback_t callback)
Allocate a new time for a node.
Definition ui_timer.cpp:123
void UI_TimerStart(uiTimer_t *timer)
Restart a timer.
Definition ui_timer.cpp:150
uiNode_t * UI_GetWindow(const char *name)
Searches all windows for the specified one.
int UI_GetLastFullScreenWindow(void)
Returns the ID of the last fullscreen ID. Before this, window should be hidden.
uiNode_t * UI_GetActiveWindow(void)
Returns the current active window from the window stack or nullptr if there is none.
#define Vector2NotEmpty(a)
Definition vector.h:75
#define Vector4Copy(src, dest)
Definition vector.h:53