UFO: Alien Invasion
Loading...
Searching...
No Matches
ui_node_text2.cpp
Go to the documentation of this file.
1
6
7/*
8Copyright (C) 2002-2025 UFO: Alien Invasion.
9
10This program is free software; you can redistribute it and/or
11modify it under the terms of the GNU General Public License
12as published by the Free Software Foundation; either version 2
13of the License, or (at your option) any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25*/
26
27#include "../ui_main.h"
28#include "../ui_internal.h"
29#include "../ui_font.h"
30#include "../ui_actions.h"
31#include "../ui_parse.h"
32#include "../ui_render.h"
33#include "../ui_lua.h"
34
35#include "ui_node_text2.h"
37
38#include "../../client.h"
39#include "../../cl_language.h"
41
43
44#define EXTRADATA_TYPE text2ExtraData_t
45#define EXTRADATA(node) UI_EXTRADATA(node, EXTRADATA_TYPE)
46#define EXTRADATACONST(node) UI_EXTRADATACONST(node, EXTRADATA_TYPE)
47
49{
50 const char* data;
51 int bufferSize = 1024;
52 char* buffer = Mem_AllocTypeN(char, bufferSize);
53
54 LIST_Delete(&EXTRADATA(node).lineSplit);
55
56 if (node->text != nullptr)
57 data = UI_GetReferenceString(node, node->text);
58 else if (EXTRADATA(node).super.dataID != TEXT_NULL) {
59 const uiSharedData_t* shared;
60 shared = &ui_global.sharedData[EXTRADATA(node).super.dataID];
61 switch (shared->type) {
62 case UI_SHARED_TEXT:
63 data = UI_GetText(EXTRADATA(node).super.dataID);
64 break;
66 return;
67 default:
68 return;
69 }
70 } else
71 return;
72
74
75 while (data[0] != '\0') {
76 const char* next = strchr(data, '\n');
77 int lineSize;
78 if (next == nullptr)
79 lineSize = strlen(data);
80 else
81 lineSize = next - data;
82
83 if (lineSize + 1 > bufferSize) {
84 bufferSize = lineSize + 1;
85 Mem_Free(buffer);
86 buffer = Mem_AllocTypeN(char, bufferSize);
87 }
88
89 Q_strncpyz(buffer, data, lineSize + 1);
90 LIST_AddString(&EXTRADATA(node).lineSplit, buffer);
91
92 if (next == nullptr)
93 break;
94 data = next + 1;
95 }
96
97 Mem_Free(buffer);
98}
99
106static int UI_TextNodeGetLine (const uiNode_t* node, int x, int y)
107{
108 int lineHeight;
109 int line;
110 assert(UI_NodeInstanceOf(node, "text"));
111
112 lineHeight = EXTRADATACONST(node).super.lineHeight;
113 if (lineHeight == 0) {
114 const char* font = UI_GetFontFromNode(node);
115 lineHeight = UI_FontGetHeight(font);
116 }
117
118 UI_NodeAbsoluteToRelativePos(node, &x, &y);
119 y -= node->padding;
120
121 /* skip position over the first line */
122 if (y < 0)
123 return -1;
124 line = (int) (y / lineHeight) + EXTRADATACONST(node).super.super.scrollY.viewPos;
125
126 /* skip position under the last line */
127 if (line >= EXTRADATACONST(node).super.super.scrollY.fullSize)
128 return -1;
129
130 return line;
131}
132
133void uiText2Node::onMouseMove (uiNode_t* node, int x, int y)
134{
135 EXTRADATA(node).super.lineUnderMouse = UI_TextNodeGetLine(node, x, y);
136}
137
146void uiText2Node::drawText (uiNode_t* node, const linkedList_t* list, bool noDraw)
147{
148 char newFont[MAX_VAR];
149 const char* oldFont = nullptr;
150 int fullSizeY;
151 const char* font = UI_GetFontFromNode(node);
152 vec2_t pos;
153 int x, y, width;
154 int viewSizeY;
155
156 UI_GetNodeAbsPos(node, pos);
157
158 if (isSizeChange(node)) {
159 int lineHeight = EXTRADATA(node).super.lineHeight;
160 if (lineHeight == 0) {
161 const char* font = UI_GetFontFromNode(node);
162 lineHeight = UI_FontGetHeight(font);
163 }
164 viewSizeY = node->box.size[1] / lineHeight;
165 } else {
166 viewSizeY = EXTRADATA(node).super.super.scrollY.viewSize;
167 }
168
169 /* text box */
170 x = pos[0] + node->padding;
171 y = pos[1] + node->padding;
172 width = node->box.size[0] - node->padding - node->padding;
173
174 /* fix position of the start of the draw according to the align */
175 switch (node->contentAlign % 3) {
176 case 0: /* left */
177 break;
178 case 1: /* middle */
179 x += width / 2;
180 break;
181 case 2: /* right */
182 x += width;
183 break;
184 }
185
186 R_Color(node->color);
187
188 fullSizeY = 0;
189 while (list) {
190 const char* cur = (const char*)list->data;
191 int x1; /* variable x position */
192
193 /* new line starts from node x position */
194 x1 = x;
195 if (oldFont) {
196 font = oldFont;
197 oldFont = nullptr;
198 }
199
200 /* text styles and inline images */
201 if (cur[0] == '^') {
202 switch (toupper(cur[1])) {
203 case 'B':
204 Com_sprintf(newFont, sizeof(newFont), "%s_bold", font);
205 oldFont = font;
206 font = newFont;
207 cur += 2; /* don't print the format string */
208 break;
209 }
210 }
211
212 /* is it a white line? */
213 if (!cur) {
214 fullSizeY++;
215 } else {
216 if (noDraw) {
217 int lines = 0;
218 R_FontTextSize(font, cur, width, (longlines_t)EXTRADATA(node).super.longlines, nullptr, nullptr, &lines, nullptr);
219 fullSizeY += lines;
220 } else
221 UI_DrawString(font, (align_t)node->contentAlign, x1, y, x, width, EXTRADATA(node).super.lineHeight, cur, viewSizeY, EXTRADATA(node).super.super.scrollY.viewPos, &fullSizeY, true, (longlines_t)EXTRADATA(node).super.longlines);
222 }
223
224 list = list->next;
225 }
226
227 /* update scroll status */
228 setScrollY(node, -1, viewSizeY, fullSizeY);
229
230 R_Color(nullptr);
231}
232
234{
235 const uiSharedData_t* shared;
236
238
239 if (EXTRADATA(node).super.dataID == TEXT_NULL && node->text != nullptr) {
240 drawText(node, EXTRADATA(node).lineSplit, true);
241 return;
242 }
243
244 shared = &ui_global.sharedData[EXTRADATA(node).super.dataID];
245
246 if (shared->type == UI_SHARED_LINKEDLISTTEXT) {
247 drawText(node, shared->data.linkedListText, true);
248 } else {
249 drawText(node, EXTRADATA(node).lineSplit, true);
250 }
251
252 EXTRADATA(node).super.versionId = shared->versionId;
253}
254
259{
260 const uiSharedData_t* shared;
261
262 validateCache(node);
263
264 if (EXTRADATA(node).super.dataID == TEXT_NULL && node->text != nullptr) {
265 drawText(node, EXTRADATA(node).lineSplit, false);
266 return;
267 }
268
269 shared = &ui_global.sharedData[EXTRADATA(node).super.dataID];
270
271 switch (shared->type) {
272 case UI_SHARED_TEXT:
273 drawText(node, EXTRADATA(node).lineSplit, false);
274 break;
276 drawText(node, shared->data.linkedListText, false);
277 break;
278 default:
279 break;
280 }
281
282 EXTRADATA(node).super.versionId = shared->versionId;
283}
284
289void uiText2Node::onLeftClick (uiNode_t* node, int x, int y)
290{
291 int line = UI_TextNodeGetLine(node, x, y);
292
293 if (line < 0 || line >= EXTRADATA(node).super.super.scrollY.fullSize)
294 return;
295
296 UI_TextNodeSelectLine(node, line);
297
298 if (node->onClick) {
299 UI_ExecuteEventActions(node, node->onClick);
300 }
301 if (node->lua_onClick != LUA_NOREF) {
302 UI_ExecuteLuaEventScript_XY(node, node->lua_onClick, x, y);
303 }
304}
305
310void uiText2Node::onRightClick (uiNode_t* node, int x, int y)
311{
312 int line = UI_TextNodeGetLine(node, x, y);
313
314 if (line < 0 || line >= EXTRADATA(node).super.super.scrollY.fullSize)
315 return;
316
317 UI_TextNodeSelectLine(node, line);
318
319 if (node->onRightClick)
321}
322
324{
325 EXTRADATA(node).super.textLineSelected = -1;
326 EXTRADATA(node).super.textSelected = "";
327 Vector4Set(node->selectedColor, 1.0, 1.0, 1.0, 1.0);
328 Vector4Set(node->color, 1.0, 1.0, 1.0, 1.0);
329}
330
332{
333 int lineheight = EXTRADATA(node).super.lineHeight;
334 /* auto compute lineheight */
335 /* we don't overwrite EXTRADATA(node).lineHeight, because "0" is dynamically replaced by font height on draw function */
336 if (lineheight == 0) {
337 /* the font is used */
338 const char* font = UI_GetFontFromNode(node);
339 lineheight = UI_FontGetHeight(font);
340 }
341
342 /* auto compute rows (super.viewSizeY) */
343 if (EXTRADATA(node).super.super.scrollY.viewSize == 0) {
344 if (node->box.size[1] != 0 && lineheight != 0) {
345 EXTRADATA(node).super.super.scrollY.viewSize = node->box.size[1] / lineheight;
346 } else {
347 EXTRADATA(node).super.super.scrollY.viewSize = 1;
348 Com_Printf("UI_TextNodeLoaded: node '%s' has no rows value\n", UI_GetPath(node));
349 }
350 }
351
352 /* auto compute height */
353 if (node->box.size[1] == 0) {
354 node->box.size[1] = EXTRADATA(node).super.super.scrollY.viewSize * lineheight;
355 }
356
357 /* is text slot exists */
358 if (EXTRADATA(node).super.dataID >= UI_MAX_DATAID)
359 Com_Error(ERR_DROP, "Error in node %s - max shared data id exceeded (num: %i, max: %i)", UI_GetPath(node), EXTRADATA(node).super.dataID, UI_MAX_DATAID);
360
361#ifdef DEBUG
362 if (EXTRADATA(node).super.super.scrollY.viewSize != (int)(node->box.size[1] / lineheight)) {
363 Com_Printf("UI_TextNodeLoaded: rows value (%i) of node '%s' differs from size (%.0f) and format (%i) values\n",
364 EXTRADATA(node).super.super.scrollY.viewSize, UI_GetPath(node), node->box.size[1], lineheight);
365 }
366#endif
367
368 if (node->text == nullptr && EXTRADATA(node).super.dataID == TEXT_NULL)
369 Com_Printf("UI_TextNodeLoaded: 'textid' property of node '%s' is not set\n", UI_GetPath(node));
370}
371
373{
374 behaviour->name = "text2";
375 behaviour->extends = "text";
376 behaviour->manager = UINodePtr(new uiText2Node());
377 behaviour->extraDataSize = sizeof(EXTRADATA_TYPE);
378 behaviour->lua_SWIG_typeinfo = UI_SWIG_TypeQuery("uiText2Node_t *");
379}
const char * CL_Translate(const char *t)
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_t
void R_Color(const vec4_t rgba)
Change the color to given value.
Definition r_state.cpp:1011
bool setScrollY(uiNode_t *node, int viewPos, int viewSize, int fullSize)
Set the Y scroll to a position, and call event if need.
bool isSizeChange(uiNode_t *node)
return true if the node size change and update the cache
void draw(uiNode_t *node) override
Draw a text node.
void onLoading(uiNode_t *node) override
void updateCache(uiNode_t *node) override
void onMouseMove(uiNode_t *node, int x, int y) override
void onLoaded(uiNode_t *node) override
void onLeftClick(uiNode_t *node, int x, int y) override
Calls the script command for a text node that is clickable.
void onRightClick(uiNode_t *node, int x, int y) override
Calls the script command for a text node that is clickable via right mouse button.
void drawText(uiNode_t *node, const linkedList_t *list, bool noDraw)
Handles linked list of text. Each element of the list must be a line of text without line break....
void validateCache(uiNode_t *node)
Primary header for client.
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define ERR_DROP
Definition common.h:211
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void LIST_AddString(linkedList_t **listDest, const char *data)
Adds an string to a new or to an already existing linked list. The string is copied here.
Definition list.cpp:139
void LIST_Delete(linkedList_t **list)
Definition list.cpp:195
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_AllocTypeN(type, n)
Definition mem.h:38
Shared parsing functions.
QGL_EXTERN GLsizei const GLvoid * data
Definition r_gl.h:89
align_t
We need this here for checking the boundaries from script values.
Definition scripts.h:89
Header for lua script functions.
#define MAX_VAR
Definition shared.h:36
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
void * data
Definition list.h:31
linkedList_t * next
Definition list.h:32
node behaviour, how a node work
const char * name
void * lua_SWIG_typeinfo
UINodePtr manager
const char * extends
intptr_t extraDataSize
vec2_t size
Definition ui_nodes.h:52
Atomic structure used to define most of the UI.
Definition ui_nodes.h:80
char * text
Definition ui_nodes.h:121
int contentAlign
Definition ui_nodes.h:120
vec4_t color
Definition ui_nodes.h:127
vec4_t selectedColor
Definition ui_nodes.h:128
LUA_EVENT lua_onClick
Definition ui_nodes.h:148
uiBox_t box
Definition ui_nodes.h:96
int padding
Definition ui_nodes.h:109
struct uiAction_s * onClick
Definition ui_nodes.h:135
struct uiAction_s * onRightClick
Definition ui_nodes.h:136
union uiSharedData_t::@061052176262211162172023345235067125273303251247 data
uiSharedType_t type
Definition ui_data.h:45
linkedList_t * linkedListText
Holds a linked list for displaying in the UI.
Definition ui_data.h:50
vec_t vec2_t[2]
Definition ufotypes.h:38
void UI_ExecuteEventActions(uiNode_t *source, const uiAction_t *firstAction)
const char * UI_GetText(int textId)
Definition ui_data.cpp:144
@ UI_SHARED_TEXT
Definition ui_data.h:39
@ UI_SHARED_LINKEDLISTTEXT
Definition ui_data.h:40
@ UI_MAX_DATAID
Definition ui_dataids.h:87
@ TEXT_NULL
Definition ui_dataids.h:29
int UI_FontGetHeight(const char *fontID)
Definition ui_font.cpp:166
const char * UI_GetFontFromNode(const uiNode_t *const node)
Return the font for a specific node or default font.
Definition ui_font.cpp:145
Internal data use by the UI package.
uiGlobal_t ui_global
Definition ui_main.cpp:38
bool UI_ExecuteLuaEventScript_XY(uiNode_t *node, LUA_EVENT event, int x, int y)
Executes a lua event handler with (x,y) argument.
Definition ui_lua.cpp:143
Basic lua initialization for the ui.
void * UI_SWIG_TypeQuery(const char *name)
This function queries the SWIG type table for a type information structure. It is used in combination...
bool UI_NodeInstanceOf(const uiNode_t *node, const char *behaviourName)
Check the node inheritance.
Definition ui_node.cpp:453
void UI_NodeAbsoluteToRelativePos(const uiNode_t *node, int *x, int *y)
Update an absolute position to a relative one.
Definition ui_node.cpp:604
void UI_GetNodeAbsPos(const uiNode_t *node, vec2_t pos)
Returns the absolute position of a node.
Definition ui_node.cpp:526
SharedPtr< uiNode > UINodePtr
#define EXTRADATA_TYPE
#define EXTRADATA(node)
void UI_RegisterText2Node(uiBehaviour_t *behaviour)
static void UI_TextNodeGenerateLineSplit(uiNode_t *node)
#define EXTRADATA(node)
static int UI_TextNodeGetLine(const uiNode_t *node, int x, int y)
Get the line number under an absolute position.
#define EXTRADATACONST(node)
void UI_TextNodeSelectLine(uiNode_t *node, int num)
Change the selected line.
static int UI_TextNodeGetLine(const uiNode_t *node, int x, int y)
Get the line number under an absolute position.
const char * UI_GetPath(const uiNode_t *node)
Return a path from a window to a node.
Definition ui_nodes.cpp:174
const char * UI_GetReferenceString(const uiNode_t *const node, const char *ref)
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)
#define Vector4Set(v, r, g, b, a)
Definition vector.h:62