UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ui_node_messagelist.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24 */
25 
26 #include "../ui_main.h"
27 #include "../ui_internal.h"
28 #include "../ui_font.h"
29 #include "../ui_actions.h"
30 #include "../ui_parse.h"
31 #include "../ui_render.h"
32 #include "../ui_sprite.h"
33 #include "ui_node_text.h"
34 #include "ui_node_messagelist.h"
35 #include "ui_node_abstractnode.h"
36 
37 #include "../../client.h"
38 #include "../../../shared/parse.h"
39 
40 #include "../../../common/scripts_lua.h"
41 
42 #define EXTRADATA(node) UI_EXTRADATA(node, abstractScrollableExtraData_t)
43 #define EXTRADATACONST(node) UI_EXTRADATACONST(node, abstractScrollableExtraData_t)
44 
46 static const int LINEHEIGHT = 20;
47 
48 static const int DATETIME_COLUUI_SIZE = 200;
49 
50 /* Used for drag&drop-like scrolling */
51 static int mouseScrollX;
52 static int mouseScrollY;
53 
54 /* Russian timestamp (with UTF-8) is 23 bytes long */
55 #define TIMESTAMP_TEXT 24
56 typedef struct uiMessageListNodeMessage_s {
57  char title[MAX_VAR];
59  char* text;
60  date_t date;
61  const char* iconName;
62  int lineUsed;
65 
68 
70 {
71  return messageStack;
72 }
73 
75 {
76  messageStack = nullptr;
77 }
78 
80 {
81  message->next = messageStack;
82  messageStack = message;
83 }
84 
88 static int UI_MessageGetLines (const uiNode_t* node, uiMessageListNodeMessage_t* message, const char* fontID, int width)
89 {
90  const int column1 = DATETIME_COLUUI_SIZE;
91  const int column2 = width - DATETIME_COLUUI_SIZE - node->padding;
92  int lines1;
93  int lines2;
94  R_FontTextSize(fontID, message->timestamp, column1, LONGLINES_WRAP, nullptr, nullptr, &lines1, nullptr);
95  R_FontTextSize(fontID, message->text, column2, LONGLINES_WRAP, nullptr, nullptr, &lines2, nullptr);
96  return std::max(lines1, lines2);
97 }
98 
99 static char* lastDate;
100 
106 {
107  const char* iconName = message->iconName;
108  if (Q_strnull(iconName))
109  iconName = "icons/message_info";
110 
111  return UI_GetSpriteByName(iconName);
112 }
113 
114 static void UI_MessageDraw (const uiNode_t* node, uiMessageListNodeMessage_t* message, const char* fontID, int x, int y, int width, int* screenLines)
115 {
116  const int column1 = DATETIME_COLUUI_SIZE;
117  const int column2 = width - DATETIME_COLUUI_SIZE - node->padding;
118  int lines1 = *screenLines;
119  int lines2 = *screenLines;
120 
121  /* also display the first date on wraped message we only see the end */
122  if (lines1 < 0)
123  lines1 = 0;
124 
125  /* display the date */
126  if (lastDate == nullptr || !Q_streq(lastDate, message->timestamp)) {
127  R_Color(node->color);
128  UI_DrawString(fontID, ALIGN_UL, x, y, x, column1, LINEHEIGHT, message->timestamp, EXTRADATACONST(node).scrollY.viewSize, 0, &lines1, true, LONGLINES_WRAP);
129  R_Color(nullptr);
130  }
131 
132  x += DATETIME_COLUUI_SIZE + node->padding;
133 
134  /* identify the begin of a message with a mark */
135  if (lines2 >= 0) {
136  const uiSprite_t* icon = UI_MessageGetIcon(message);
137  R_Color(nullptr);
138  UI_DrawSpriteInBox(false, icon, SPRITE_STATUS_NORMAL, x - 25, y + LINEHEIGHT * lines2 - 1, 19, 19);
139  }
140 
141  /* draw the message */
142  R_Color(node->color);
143  UI_DrawString(fontID, ALIGN_UL, x, y, x, column2, LINEHEIGHT, message->text, EXTRADATACONST(node).scrollY.viewSize, 0, &lines2, true, LONGLINES_WRAP);
144  R_Color(nullptr);
145  *screenLines = std::max(lines1, lines2);
146  lastDate = message->timestamp;
147 }
148 
154 {
156  int screenLines;
157  const char* font = UI_GetFontFromNode(node);
158  vec2_t pos;
159  int x, y, width;
160  int defaultHeight;
161  int lineNumber = 0;
162  int posY;
163 
164 /* #define AUTOSCROLL */
165 #ifdef AUTOSCROLL
166  bool autoscroll;
167 #endif
168  UI_GetNodeAbsPos(node, pos);
169 
170  defaultHeight = LINEHEIGHT;
171 
172 #ifdef AUTOSCROLL
173  autoscroll = (EXTRADATA(node).scrollY.viewPos + EXTRADATA(node).scrollY.viewSize == EXTRADATA(node).scrollY.fullSize)
174  || (EXTRADATA(node).scrollY.fullSize < EXTRADATA(node).scrollY.viewSize);
175 #endif
176 
177  /* text box */
178  x = pos[0] + node->padding;
179  y = pos[1] + node->padding;
180  width = node->box.size[0] - node->padding - node->padding;
181 
182  /* update message cache */
183  if (isSizeChange(node)) {
184  /* recompute all line size */
185  message = messageStack;
186  while (message) {
187  message->lineUsed = UI_MessageGetLines(node, message, font, width);
188  lineNumber += message->lineUsed;
189  message = message->next;
190  }
191  } else {
192  /* only check unvalidated messages */
193  message = messageStack;
194  while (message) {
195  if (message->lineUsed == 0)
196  message->lineUsed = UI_MessageGetLines(node, message, font, width);
197  lineNumber += message->lineUsed;
198  message = message->next;
199  }
200  }
201 
202  /* update scroll status */
203 #ifdef AUTOSCROLL
204  if (autoscroll)
205  setScrollY(node, lineNumber, node->box.size[1] / defaultHeight, lineNumber);
206  else
207  setScrollY(node, -1, node->box.size[1] / defaultHeight, lineNumber);
208 #else
209  setScrollY(node, -1, node->box.size[1] / defaultHeight, lineNumber);
210 #endif
211 
212  /* found the first message we must display */
213  message = messageStack;
214  posY = EXTRADATA(node).scrollY.viewPos;
215  while (message && posY > 0) {
216  posY -= message->lineUsed;
217  if (posY < 0)
218  break;
219  message = message->next;
220  }
221 
222  /* draw */
224  lastDate = nullptr;
225  screenLines = posY;
226  while (message) {
227  UI_MessageDraw(node, message, font, x, y, width, &screenLines);
228  if (screenLines >= EXTRADATA(node).scrollY.viewSize)
229  break;
230  message = message->next;
231  }
232 }
233 
234 bool uiMessageListNode::onScroll (uiNode_t* node, int deltaX, int deltaY)
235 {
236  bool down = deltaY > 0;
237  bool updated;
238  if (deltaY == 0)
239  return false;
240  updated = scrollY(node, (down ? 1 : -1));
241  /* @todo use super behaviour */
242  if (node->onWheelUp && !down) {
243  UI_ExecuteEventActions(node, node->onWheelUp);
244  updated = true;
245  }
246  if (node->onWheelDown && down) {
247  UI_ExecuteEventActions(node, node->onWheelDown);
248  updated = true;
249  }
250  if (node->onWheel) {
251  UI_ExecuteEventActions(node, node->onWheel);
252  updated = true;
253  }
254  return updated;
255 }
256 
258 {
259  Vector4Set(node->color, 1.0, 1.0, 1.0, 1.0);
260 }
261 
266 void uiMessageListNode::onMouseDown (uiNode_t* node, int x, int y, int button)
267 {
268  if (!UI_GetMouseCapture() && button == K_MOUSE1 &&
269  EXTRADATA(node).scrollY.fullSize > EXTRADATA(node).scrollY.viewSize) {
270  UI_SetMouseCapture(node);
271  mouseScrollX = x;
272  mouseScrollY = y;
273  }
274 }
275 
276 void uiMessageListNode::onMouseUp (uiNode_t* node, int x, int y, int button)
277 {
278  if (UI_GetMouseCapture() == node) /* More checks can never hurt */
279  UI_MouseRelease();
280 }
281 
283 {
284  const int lineHeight = getCellHeight(node);
285  const int deltaY = (mouseScrollY - y) / lineHeight;
286  /* We're doing only vertical scroll, that's enough for the most instances */
287  if (abs(mouseScrollY - y) >= lineHeight) {
288  scrollY(node, deltaY);
289  /* @todo not accurate */
290  mouseScrollX = x;
291  mouseScrollY = y;
292  }
293  onMouseMove(node, x, y);
294 }
295 
302 {
303  return LINEHEIGHT;
304 }
305 
307 {
308  behaviour->name = "messagelist";
309  behaviour->extends = "abstractscrollable";
310  behaviour->manager = UINodePtr(new uiMessageListNode());
311  behaviour->lua_SWIG_typeinfo = UI_SWIG_TypeQuery("uiMessageListNode_t *");
312 }
static const int LINEHEIGHT
bool Q_strnull(const char *string)
Definition: shared.h:138
struct uiAction_s * onWheelDown
Definition: ui_nodes.h:142
vec2_t size
Definition: ui_nodes.h:52
void onCapturedMouseMove(uiNode_t *node, int x, int y) override
struct uiMessageListNodeMessage_s uiMessageListNodeMessage_t
#define TIMESTAMP_TEXT
void UI_MessageAddStack(struct uiMessageListNodeMessage_s *message)
const char * name
Definition: ui_behaviour.h:41
char timestamp[TIMESTAMP_TEXT]
Definition: cp_messages.h:58
static uiMessageListNodeMessage_t * messageStack
UINodePtr manager
Definition: ui_behaviour.h:43
bool setScrollY(uiNode_t *node, int viewPos, int viewSize, int fullSize)
Set the Y scroll to a position, and call event if need.
void UI_RegisterMessageListNode(uiBehaviour_t *behaviour)
void UI_DrawSpriteInBox(bool flip, const uiSprite_t *sprite, uiSpriteStatus_t status, int posX, int posY, int sizeX, int sizeY)
Definition: ui_sprite.cpp:187
static uiSprite_t * UI_MessageGetIcon(const uiMessageListNodeMessage_t *message)
virtual void onMouseMove(uiNode_t *node, int x, int y)
void onLoading(uiNode_t *node) override
void draw(uiNode_t *node) override
Draws the messagesystem node.
static int mouseScrollX
void UI_MouseRelease(void)
Release the captured node.
Definition: ui_input.cpp:526
void R_Color(const vec4_t rgba)
Change the color to given value.
Definition: r_state.cpp:1011
static int UI_MessageGetLines(const uiNode_t *node, uiMessageListNodeMessage_t *message, const char *fontID, int width)
int getCellHeight(uiNode_t *node) override
Return size of the cell, which is the size (in virtual "pixel") which represent 1 in the scroll value...
struct uiMessageListNodeMessage_s * UI_MessageGetStack(void)
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
bool onScroll(uiNode_t *node, int deltaX, int deltaY) override
#define MAX_VAR
Definition: shared.h:36
#define Vector4Set(v, r, g, b, a)
Definition: vector.h:62
struct uiAction_s * onWheelUp
Definition: ui_nodes.h:141
bool isSizeChange(uiNode_t *node)
return true if the node size change and update the cache
void UI_MessageResetStack(void)
void onMouseDown(uiNode_t *node, int x, int y, int button) override
Track mouse down/up events to implement drag&drop-like scrolling, for touchscreen devices...
SharedPtr< uiNode > UINodePtr
int padding
Definition: ui_nodes.h:109
bool scrollY(uiNode_t *node, int offset)
Scroll the Y scroll with a relative position, and call event if need.
void * lua_SWIG_typeinfo
Definition: ui_behaviour.h:57
void UI_SetMouseCapture(uiNode_t *node)
Captured the mouse into a node.
Definition: ui_input.cpp:516
Engine-side time information in the game.
Definition: common.h:290
static int mouseScrollY
void UI_ExecuteEventActions(uiNode_t *source, const uiAction_t *firstAction)
Definition: ui_actions.cpp:726
uiNode_t * UI_GetMouseCapture(void)
Return the captured node.
Definition: ui_input.cpp:508
Atomic structure used to define most of the UI.
Definition: ui_nodes.h:80
static void UI_MessageDraw(const uiNode_t *node, uiMessageListNodeMessage_t *message, const char *fontID, int x, int y, int width, int *screenLines)
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
const char * UI_GetFontFromNode(const uiNode_t *const node)
Return the font for a specific node or default font.
Definition: ui_font.cpp:145
#define EXTRADATACONST(node)
void onMouseUp(uiNode_t *node, int x, int y, int button) override
node behaviour, how a node work
Definition: ui_behaviour.h:39
vec4_t color
Definition: ui_nodes.h:127
struct uiAction_s * onWheel
Definition: ui_nodes.h:138
#define EXTRADATA(node)
const char * extends
Definition: ui_behaviour.h:42
vec_t vec2_t[2]
Definition: ufotypes.h:38
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
#define Q_streq(a, b)
Definition: shared.h:136
uiBox_t box
Definition: ui_nodes.h:96
static const int DATETIME_COLUUI_SIZE
uiSprite_t * UI_GetSpriteByName(const char *name)
Return an sprite by is name.
Definition: ui_sprite.cpp:115
struct uiMessageListNodeMessage_s * next
Definition: cp_messages.h:63
static char * lastDate
int down
Definition: cl_input.cpp:70