Bug Summary

File:client/ui/node/ui_node_textentry.cpp
Location:line 182, column 3
Description:Value stored to 'length' is never read

Annotated Source Code

1/**
2 * @file
3 * @brief This node allow to edit a cvar text with the keyboard. When we
4 * click on the node, we active the edition, we can validate it with the ''RETURN'' key,
5 * or abort it with ''ESCAPE'' key. A validation fire a scriptable callback event.
6 * We can custom the mouse behaviour when we click outside the node in edition mode.
7 * It can validate or abort the edition.
8 * @todo allow to edit text without any cvar
9 * @todo add a custom max size
10 */
11
12/*
13Copyright (C) 2002-2011 UFO: Alien Invasion.
14
15This program is free software; you can redistribute it and/or
16modify it under the terms of the GNU General Public License
17as published by the Free Software Foundation; either version 2
18of the License, or (at your option) any later version.
19
20This program is distributed in the hope that it will be useful,
21but WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23
24See the GNU General Public License for more details.
25
26You should have received a copy of the GNU General Public License
27along with this program; if not, write to the Free Software
28Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29
30*/
31
32#include "../ui_main.h"
33#include "../ui_nodes.h"
34#include "../ui_font.h"
35#include "../ui_parse.h"
36#include "../ui_behaviour.h"
37#include "../ui_input.h"
38#include "../ui_actions.h"
39#include "../ui_render.h"
40#include "../ui_sprite.h"
41#include "ui_node_textentry.h"
42#include "ui_node_abstractnode.h"
43#include "ui_node_panel.h"
44
45#include "../../client.h"
46#include "../../../shared/utf8.h"
47
48#define EXTRADATA_TYPEtextEntryExtraData_t textEntryExtraData_t
49#define EXTRADATA(node)(*((textEntryExtraData_t*)((char*)node + sizeof(uiNode_t)))) UI_EXTRADATA(node, EXTRADATA_TYPE)(*((textEntryExtraData_t*)((char*)node + sizeof(uiNode_t))))
50
51static const char CURSOR = '|'; /**< Use as the cursor when we edit the text */
52static const char HIDECHAR = '*'; /**< use as a mask for password */
53
54/* limit the input for cvar editing (base name, save slots and so on) */
55#define MAX_CVAR_EDITING_LENGTH256 256 /* MAXCMDLINE */
56
57/* global data */
58static char cvarValueBackup[MAX_CVAR_EDITING_LENGTH256];
59static cvar_t *editedCvar = NULL__null;
60static bool isAborted = false;
61
62/**
63 * @brief callback from the keyboard
64 */
65static void UI_TextEntryNodeValidateEdition (uiNode_t *node)
66{
67 /* invalidate cache */
68 editedCvar = NULL__null;
69 cvarValueBackup[0] = '\0';
70
71 /* fire change event */
72 if (node->onChange) {
73 UI_ExecuteEventActions(node, node->onChange);
74 }
75}
76
77/**
78 * @brief callback from the keyboard
79 */
80static void UI_TextEntryNodeAbortEdition (uiNode_t *node)
81{
82 assert(editedCvar)(__builtin_expect(!(editedCvar), 0) ? __assert_rtn(__func__, "src/client/ui/node/ui_node_textentry.cpp"
, 82, "editedCvar") : (void)0)
;
83
84 /* set the old cvar value */
85 Cvar_ForceSet(editedCvar->name, cvarValueBackup);
86
87 /* invalidate cache */
88 editedCvar = NULL__null;
89 cvarValueBackup[0] = '\0';
90
91 /* fire abort event */
92 if (EXTRADATA(node)(*((textEntryExtraData_t*)((char*)node + sizeof(uiNode_t)))).onAbort) {
93 UI_ExecuteEventActions(node, EXTRADATA(node)(*((textEntryExtraData_t*)((char*)node + sizeof(uiNode_t)))).onAbort);
94 }
95}
96
97/**
98 * @brief force edition of a textentry node
99 * @note the textentry must be on the active window
100 */
101static void UI_TextEntryNodeFocus (uiNode_t *node, const uiCallContext_t *context)
102{
103 /* remove the focus to show changes */
104 if (!UI_HasFocus(node)) {
105 UI_RequestFocus(node);
106 }
107}
108
109/**
110 * @brief Called when the user click with the right mouse button
111 */
112void uiTextEntryNode::onLeftClick (uiNode_t *node, int x, int y)
113{
114 if (node->disabled)
115 return;
116
117 /* no cvar */
118 if (!node->text)
119 return;
120 if (!Q_strstart(node->text, "*cvar:"))
121 return;
122
123 if (!UI_HasFocus(node)) {
124 if (node->onClick) {
125 UI_ExecuteEventActions(node, node->onClick);
126 }
127 UI_RequestFocus(node);
128 }
129}
130
131/**
132 * @brief Called when the node got the focus
133 */
134void uiTextEntryNode::onFocusGained (uiNode_t *node)
135{
136 assert(editedCvar == NULL)(__builtin_expect(!(editedCvar == __null), 0) ? __assert_rtn(
__func__, "src/client/ui/node/ui_node_textentry.cpp", 136, "editedCvar == NULL"
) : (void)0)
;
137 /* skip '*cvar ' */
138 editedCvar = Cvar_Get(&((char*)node->text)[6]);
139 assert(editedCvar)(__builtin_expect(!(editedCvar), 0) ? __assert_rtn(__func__, "src/client/ui/node/ui_node_textentry.cpp"
, 139, "editedCvar") : (void)0)
;
140 Q_strncpyz(cvarValueBackup, editedCvar->string, sizeof(cvarValueBackup))Q_strncpyzDebug( cvarValueBackup, editedCvar->string, sizeof
(cvarValueBackup), "src/client/ui/node/ui_node_textentry.cpp"
, 140 )
;
141 isAborted = false;
142}
143
144/**
145 * @brief Called when the node lost the focus
146 */
147void uiTextEntryNode::onFocusLost (uiNode_t *node)
148{
149 /* already aborted/changed with the keyboard */
150 if (editedCvar == NULL__null)
151 return;
152
153 /* release the keyboard */
154 if (isAborted || EXTRADATA(node)(*((textEntryExtraData_t*)((char*)node + sizeof(uiNode_t)))).clickOutAbort) {
155 UI_TextEntryNodeAbortEdition(node);
156 } else {
157 UI_TextEntryNodeValidateEdition(node);
158 }
159}
160
161/**
162 * @brief edit the current cvar with a char
163 */
164static void UI_TextEntryNodeEdit (uiNode_t *node, unsigned int key)
165{
166 char buffer[MAX_CVAR_EDITING_LENGTH256];
167 int length;
168
169 /* copy the cvar */
170 Q_strncpyz(buffer, editedCvar->string, sizeof(buffer))Q_strncpyzDebug( buffer, editedCvar->string, sizeof(buffer
), "src/client/ui/node/ui_node_textentry.cpp", 170 )
;
171 length = strlen(buffer);
172
173 /* compute result */
174 if (key == K_BACKSPACE) {
175 length = UTF8_delete_char(buffer, length - 1);
176 } else {
177 int charLength = UTF8_encoded_len(key);
178 /* is buffer full? */
179 if (length + charLength >= sizeof(buffer))
180 return;
181
182 length += UTF8_insert_char(buffer, sizeof(buffer), length, key);
Value stored to 'length' is never read
183 }
184
185 /* update the cvar */
186 Cvar_ForceSet(editedCvar->name, buffer);
187}
188
189/**
190 * @brief Called when we press a key when the node got the focus
191 * @return True, if we use the event
192 */
193bool uiTextEntryNode::onKeyPressed (uiNode_t *node, unsigned int key, unsigned short unicode)
194{
195 switch (key) {
196 /* remove the last char */
197 case K_BACKSPACE:
198 UI_TextEntryNodeEdit(node, K_BACKSPACE);
199 return true;
200 /* cancel the edition */
201 case K_ESCAPE:
202 isAborted = true;
203 UI_RemoveFocus();
204 return true;
205 /* validate the edition */
206 case K_ENTER:
207 case K_KP_ENTER:
208 UI_TextEntryNodeValidateEdition(node);
209 UI_RemoveFocus();
210 return true;
211 }
212
213 /* non printable */
214 if (unicode < 32 || (unicode >= 127 && unicode < 192))
215 return false;
216
217 /* add a char */
218 UI_TextEntryNodeEdit(node, unicode);
219 return true;
220}
221
222void uiTextEntryNode::draw (uiNode_t *node)
223{
224 const float *textColor;
225 vec2_t pos;
226 static vec4_t disabledColor = {0.5, 0.5, 0.5, 1.0};
227 const char *font = UI_GetFontFromNode(node);
228 uiSpriteStatus_t iconStatus = SPRITE_STATUS_NORMAL;
229
230 if (node->disabled) {
231 /** @todo need custom color when node is disabled */
232 textColor = disabledColor;
233 iconStatus = SPRITE_STATUS_DISABLED;
234 } else if (node->state) {
235 textColor = node->color;
236 iconStatus = SPRITE_STATUS_HOVER;
237 } else {
238 textColor = node->color;
239 }
240 if (UI_HasFocus(node)) {
241 textColor = node->selectedColor;
242 }
243
244 UI_GetNodeAbsPos(node, pos);
245
246 if (EXTRADATA(node)(*((textEntryExtraData_t*)((char*)node + sizeof(uiNode_t)))).background) {
247 UI_DrawSpriteInBox(false, EXTRADATA(node)(*((textEntryExtraData_t*)((char*)node + sizeof(uiNode_t)))).background, iconStatus, pos[0], pos[1], node->box.size[0], node->box.size[1]);
248 }
249
250 if (char const* const text = UI_GetReferenceString(node, node->text)) {
251 char buf[MAX_VAR64];
252 char* c = buf;
253 if (EXTRADATA(node)(*((textEntryExtraData_t*)((char*)node + sizeof(uiNode_t)))).isPassword) {
254 size_t const size = UTF8_strlen(text);
255 memset(buf, HIDECHAR, size);
256 c += size;
257 } else {
258 size_t const size = strlen(text);
259 memcpy(buf, text, size);
260 c += size;
261 }
262
263 if (UI_HasFocus(node) && CL_Milliseconds() % 1000 < 500) {
264 *c++ = CURSOR;
265 }
266
267 *c = '\0';
268
269 if (*buf != '\0') {
270 R_Color(textColor);
271 UI_DrawStringInBox(font, (align_t)node->contentAlign,
272 pos[0] + node->padding, pos[1] + node->padding,
273 node->box.size[0] - node->padding - node->padding, node->box.size[1] - node->padding - node->padding,
274 buf);
275 R_Color(NULL__null);
276 }
277 }
278
279}
280
281/**
282 * @brief Call before the script initialization of the node
283 */
284void uiTextEntryNode::onLoading (uiNode_t *node)
285{
286 node->padding = 8;
287 node->contentAlign = ALIGN_CL;
288 Vector4Set(node->color, 1, 1, 1, 1)((node->color)[0]=(1), (node->color)[1]=(1), (node->
color)[2]=(1), (node->color)[3]=(1))
;
289 Vector4Set(node->selectedColor, 1, 1, 1, 1)((node->selectedColor)[0]=(1), (node->selectedColor)[1]
=(1), (node->selectedColor)[2]=(1), (node->selectedColor
)[3]=(1))
;
290}
291
292void UI_RegisterTextEntryNode (uiBehaviour_t *behaviour)
293{
294 behaviour->name = "textentry";
295 behaviour->manager = new uiTextEntryNode();
296 behaviour->extraDataSize = sizeof(EXTRADATA_TYPEtextEntryExtraData_t);
297
298 /* Call back event called when we click on the node. If the click select the node,
299 * it called before we start the cvar edition.
300 */
301 UI_RegisterOveridedNodeProperty(behaviour, "onClick");;
302
303 /* Call back event (like click...) fired when the text is changed, after
304 * validation. An abort of the edition dont fire this event.
305 */
306 UI_RegisterOveridedNodeProperty(behaviour, "onChange");;
307
308 /* Custom the draw behaviour by hiding each character of the text with a star (''*''). */
309 UI_RegisterExtradataNodeProperty(behaviour, "isPassword", V_BOOL, textEntryExtraData_t, isPassword)UI_RegisterNodePropertyPosSize_(behaviour, "isPassword", V_BOOL
, ((size_t) &((textEntryExtraData_t *)(((textEntryExtraData_t
*)((char*)0 + sizeof(uiNode_t)))))->isPassword), sizeof(((
textEntryExtraData_t *)0)->isPassword))
;
310 /* ustom the mouse event behaviour. When we are editing the text, if we click out of the node, the edition is aborted. Changes on
311 * the text are canceled, and no change event are fired.
312 */
313 UI_RegisterExtradataNodeProperty(behaviour, "clickOutAbort", V_BOOL, textEntryExtraData_t, clickOutAbort)UI_RegisterNodePropertyPosSize_(behaviour, "clickOutAbort", V_BOOL
, ((size_t) &((textEntryExtraData_t *)(((textEntryExtraData_t
*)((char*)0 + sizeof(uiNode_t)))))->clickOutAbort), sizeof
(((textEntryExtraData_t *)0)->clickOutAbort))
;
314 /* Call it when we abort the edition */
315 UI_RegisterExtradataNodeProperty(behaviour, "onAbort", V_UI_ACTION, textEntryExtraData_t, onAbort)UI_RegisterNodePropertyPosSize_(behaviour, "onAbort", (0x8000
+ 0), ((size_t) &((textEntryExtraData_t *)(((textEntryExtraData_t
*)((char*)0 + sizeof(uiNode_t)))))->onAbort), sizeof(((textEntryExtraData_t
*)0)->onAbort))
;
316 /* Call it to force node edition */
317 UI_RegisterNodeMethod(behaviour, "edit", UI_TextEntryNodeFocus);
318 /* Sprite used to display the background */
319 UI_RegisterExtradataNodeProperty(behaviour, "background", V_UI_SPRITEREF, EXTRADATA_TYPE, background)UI_RegisterNodePropertyPosSize_(behaviour, "background", (0x8000
+ 3), ((size_t) &((textEntryExtraData_t *)(((textEntryExtraData_t
*)((char*)0 + sizeof(uiNode_t)))))->background), sizeof(((
textEntryExtraData_t *)0)->background))
;
320}