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