UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ui_node_text2.cpp
Go to the documentation of this file.
1 
7 /*
8 Copyright (C) 2002-2020 UFO: Alien Invasion.
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 
19 See the GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, 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"
36 #include "ui_node_abstractnode.h"
37 
38 #include "../../client.h"
39 #include "../../cl_language.h"
40 #include "../../../shared/parse.h"
41 
42 #include "../../../common/scripts_lua.h"
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 
73  data = CL_Translate(data);
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 
106 static 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 
133 void uiText2Node::onMouseMove (uiNode_t* node, int x, int y)
134 {
135  EXTRADATA(node).super.lineUnderMouse = UI_TextNodeGetLine(node, x, y);
136 }
137 
146 void 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 
289 void 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 
310 void 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 }
vec2_t size
Definition: ui_nodes.h:52
#define Mem_AllocTypeN(type, n)
Definition: mem.h:38
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 draw(uiNode_t *node) override
Draw a text node.
bool UI_NodeInstanceOf(const uiNode_t *node, const char *behaviourName)
Check the node inheritance.
Definition: ui_node.cpp:441
void onLoaded(uiNode_t *node) override
uiGlobal_t ui_global
Definition: ui_main.cpp:38
const char * name
Definition: ui_behaviour.h:41
uiSharedData_t sharedData[UI_MAX_DATAID]
Holds shared data.
Definition: ui_internal.h:59
void * data
Definition: list.h:31
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
#define EXTRADATA(node)
static void UI_TextNodeGenerateLineSplit(uiNode_t *node)
UINodePtr manager
Definition: ui_behaviour.h:43
#define EXTRADATA_TYPE
bool setScrollY(uiNode_t *node, int viewPos, int viewSize, int fullSize)
Set the Y scroll to a position, and call event if need.
void onLeftClick(uiNode_t *node, int x, int y) override
Calls the script command for a text node that is clickable.
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
void LIST_Delete(linkedList_t **list)
Definition: list.cpp:195
struct uiAction_s * onClick
Definition: ui_nodes.h:135
void R_Color(const vec4_t rgba)
Change the color to given value.
Definition: r_state.cpp:1011
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
const char * UI_GetText(int textId)
Definition: ui_data.cpp:144
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, without actually rendering it. Any of the output parameters may be nullptr.
Definition: r_font.cpp:524
align_t
We need this here for checking the boundaries from script values.
Definition: scripts.h:90
#define ERR_DROP
Definition: common.h:211
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
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
#define MAX_VAR
Definition: shared.h:36
#define Vector4Set(v, r, g, b, a)
Definition: vector.h:62
bool isSizeChange(uiNode_t *node)
return true if the node size change and update the cache
SharedPtr< uiNode > UINodePtr
void updateCache(uiNode_t *node) override
const char * UI_GetPath(const uiNode_t *node)
Return a path from a window to a node.
Definition: ui_nodes.cpp:174
int padding
Definition: ui_nodes.h:109
static int UI_TextNodeGetLine(const uiNode_t *node, int x, int y)
Get the line number under an absolute position.
void * lua_SWIG_typeinfo
Definition: ui_behaviour.h:57
void UI_ExecuteEventActions(uiNode_t *source, const uiAction_t *firstAction)
Definition: ui_actions.cpp:726
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
void validateCache(uiNode_t *node)
const char * UI_GetReferenceString(const uiNode_t *const node, const char *ref)
Definition: ui_parse.cpp:1406
Atomic structure used to define most of the UI.
Definition: ui_nodes.h:80
void * UI_SWIG_TypeQuery(const char *name)
This function queries the SWIG type table for a type information structure. It is used in combination...
void UI_GetNodeAbsPos(const uiNode_t *node, vec2_t pos)
Returns the absolute position of a node.
Definition: ui_node.cpp:514
struct uiAction_s * onRightClick
Definition: ui_nodes.h:136
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 onMouseMove(uiNode_t *node, int x, int y) override
int versionId
Definition: ui_data.h:54
vec4_t selectedColor
Definition: ui_nodes.h:128
union uiSharedData_s::@18 data
intptr_t extraDataSize
Definition: ui_behaviour.h:54
const char * CL_Translate(const char *t)
const char * UI_GetFontFromNode(const uiNode_t *const node)
Return the font for a specific node or default font.
Definition: ui_font.cpp:145
void UI_NodeAbsoluteToRelativePos(const uiNode_t *node, int *x, int *y)
Update an absolute position to a relative one.
Definition: ui_node.cpp:592
node behaviour, how a node work
Definition: ui_behaviour.h:39
void onLoading(uiNode_t *node) override
int contentAlign
Definition: ui_nodes.h:120
vec4_t color
Definition: ui_nodes.h:127
const char * extends
Definition: ui_behaviour.h:42
#define Mem_Free(ptr)
Definition: mem.h:35
int UI_FontGetHeight(const char *fontID)
Definition: ui_font.cpp:166
void UI_RegisterText2Node(uiBehaviour_t *behaviour)
vec_t vec2_t[2]
Definition: ufotypes.h:38
linkedList_t * next
Definition: list.h:32
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)
Definition: ui_render.cpp:371
GLsizei const GLvoid * data
Definition: r_gl.h:152
LUA_EVENT lua_onClick
Definition: ui_nodes.h:148
uiBox_t box
Definition: ui_nodes.h:96
#define EXTRADATACONST(node)
void UI_TextNodeSelectLine(uiNode_t *node, int num)
Change the selected line.
longlines_t
Definition: cl_renderer.h:217
char * text
Definition: ui_nodes.h:121