UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ui_node_optionlist.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_parse.h"
28 #include "../ui_behaviour.h"
29 #include "../ui_actions.h"
30 #include "../ui_font.h"
31 #include "../ui_sprite.h"
32 #include "../ui_render.h"
33 #include "../ui_input.h"
34 #include "../ui_lua.h"
35 
36 #include "ui_node_abstractoption.h"
37 #include "ui_node_abstractnode.h"
38 #include "ui_node_optionlist.h"
39 #include "ui_node_panel.h"
40 #include "ui_node_option.h"
41 
42 #include "../../cl_language.h"
43 #include "../../input/cl_keys.h"
44 
45 #include "../../../common/scripts_lua.h"
46 
47 #define EXTRADATA_TYPE abstractOptionExtraData_t
48 #define EXTRADATA(node) UI_EXTRADATA(node, EXTRADATA_TYPE)
49 
50 #define CORNER_SIZE 25
51 #define MID_SIZE 1
52 #define MARGE 3
53 
54 /* Used for drag&drop-like scrolling */
55 static int mouseScrollX;
56 static int mouseScrollY;
57 
63 {
64  int lineHeight;
65  bool updated;
66  int elements;
67 
68  lineHeight = EXTRADATA(node).lineHeight;
69  if (lineHeight == 0) {
70  const char* font = UI_GetFontFromNode(node);
71  lineHeight = UI_FontGetHeight(font);
72  }
73 
74  elements = (node->box.size[1] - node->padding - node->padding) / lineHeight;
75  updated = EXTRADATA(node).scrollY.set(-1, elements, EXTRADATA(node).count);
76  if (updated) {
77  if (EXTRADATA(node).onViewChange) {
78  UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange);
79  }
80  else if (EXTRADATA(node).lua_onViewChange != LUA_NOREF) {
81  UI_ExecuteLuaEventScript (node, EXTRADATA(node).lua_onViewChange);
82  }
83  }
84 }
85 
87 {
88  uiNode_t* option;
89  const char* ref;
90  const char* font;
91  int lineHeight;
92  vec2_t pos;
93  int currentY;
94  const float* textColor;
95  int count = 0;
96 
98  if (ref == nullptr)
99  return;
100 
101  UI_GetNodeAbsPos(node, pos);
102 
103  if (EXTRADATA(node).background) {
104  UI_DrawSpriteInBox(false, EXTRADATA(node).background, SPRITE_STATUS_NORMAL, pos[0], pos[1], node->box.size[0], node->box.size[1]);
105  }
106 
107  font = UI_GetFontFromNode(node);
108 
109  lineHeight = EXTRADATA(node).lineHeight;
110  if (lineHeight == 0)
111  lineHeight = UI_FontGetHeight(font);
112  currentY = pos[1] + node->padding;
113 
114  /* skip option over current position */
115  option = UI_AbstractOption_GetFirstOption(node);
116  while (option && count < EXTRADATA(node).scrollY.viewPos) {
117  option = option->next;
118  count++;
119  }
120 
121  /* draw all available options for this selectbox */
122  for (; option; option = option->next) {
123  int decX = pos[0] + node->padding;
124  /* outside the node */
125  if (currentY + lineHeight > pos[1] + node->box.size[1] - node->padding) {
126  count++;
127  break;
128  }
129 
130  /* draw the hover effect */
131  if (OPTIONEXTRADATA(option).hovered)
132  UI_DrawFill(pos[0] + node->padding, currentY, node->box.size[0] - node->padding - node->padding, lineHeight, node->color);
133 
134  /* text color */
135  if (Q_streq(OPTIONEXTRADATA(option).value, ref)) {
136  textColor = node->selectedColor;
137  } else if (node->disabled || option->disabled) {
138  textColor = node->disabledColor;
139  } else if (option->color[3] == 0.0f) {
140  textColor = node->color;
141  } else {
142  textColor = option->color;
143  }
144 
145  if (OPTIONEXTRADATA(option).icon) {
147  if (option->disabled)
148  iconStatus = SPRITE_STATUS_DISABLED;
149  R_Color(nullptr);
150  UI_DrawSpriteInBox(OPTIONEXTRADATA(option).flipIcon, OPTIONEXTRADATA(option).icon, iconStatus, decX, currentY, OPTIONEXTRADATA(option).icon->size[0], lineHeight);
151  decX += OPTIONEXTRADATA(option).icon->size[0] + lineHeight / 4;
152  }
153 
154  /* print the option label */
155  const char* label = CL_Translate(OPTIONEXTRADATA(option).label);
156 
157  R_Color(textColor);
158  UI_DrawString(font, ALIGN_UL, decX, currentY,
159  pos[0], node->box.size[0] - node->padding - node->padding,
160  0, label, 0, 0, nullptr, false, LONGLINES_PRETTYCHOP);
161 
162  /* next entries' position */
163  currentY += lineHeight;
164  count++;
165  }
166  R_Color(nullptr);
167 
168  /* count number of options (current architecture doesn't allow to know if the data change) */
169  for (; option; option = option->next) {
170  count++;
171  }
172 
173  if (EXTRADATA(node).count != count) {
174  EXTRADATA(node).count = count;
175  }
176 
178 }
179 
181 {
182  uiNode_t* option;
183  vec2_t pos;
184  int lineHeight;
185  int currentY;
186  int count = 0;
187 
188  UI_GetNodeAbsPos(node, pos);
189  currentY = pos[1] + node->padding;
190 
191  lineHeight = EXTRADATA(node).lineHeight;
192  if (lineHeight == 0) {
193  const char* font = UI_GetFontFromNode(node);
194  lineHeight = UI_FontGetHeight(font);
195  }
196 
197  option = UI_AbstractOption_GetFirstOption(node);
198  while (option && count < EXTRADATA(node).scrollY.viewPos) {
199  option = option->next;
200  count++;
201  }
202 
203  /* now draw all available options for this selectbox */
204  for (; option; option = option->next) {
205  if (y < currentY + lineHeight)
206  return option;
207  if (currentY + lineHeight > pos[1] + node->box.size[1] - node->padding)
208  break;
209  currentY += lineHeight;
210  }
211  return nullptr;
212 }
213 
217 void uiOptionListNode::onLeftClick (uiNode_t* node, int x, int y)
218 {
219  uiNode_t* option;
220 
221  if (UI_AbstractOption_GetCurrentValue(node) == nullptr)
222  return;
223 
224  /* select the right option */
225  option = UI_OptionListNodeGetOptionAtPosition(node, x, y);
226 
227  /* update the status */
228  if (option)
230 }
231 
235 bool uiOptionListNode::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 = EXTRADATA(node).scrollY.moveDelta(down ? 1 : -1);
242  if (updated) {
243  if (EXTRADATA(node).onViewChange) {
244  UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange);
245  }
246  else if (EXTRADATA(node).lua_onViewChange != LUA_NOREF) {
247  UI_ExecuteLuaEventScript (node, EXTRADATA(node).lua_onViewChange);
248  }
249  }
250  /* @todo use super behaviour */
251  if (node->onWheelUp && !down) {
252  UI_ExecuteEventActions(node, node->onWheelUp);
253  updated = true;
254  }
255  if (node->onWheelDown && down) {
256  UI_ExecuteEventActions(node, node->onWheelDown);
257  updated = true;
258  }
259  if (node->onWheel) {
260  UI_ExecuteEventActions(node, node->onWheel);
261  updated = true;
262  }
263  return updated;
264 }
265 
270 {
271  Vector4Set(node->color, 1, 1, 1, 1);
272  Vector4Set(node->disabledColor, 0.5, 0.5, 0.5, 1.0);
273  EXTRADATA(node).versionId = -1;
274  node->padding = 3;
275 }
276 
278 {
279 }
280 
285 void uiOptionListNode::onMouseDown (uiNode_t* node, int x, int y, int button)
286 {
287  if (!UI_GetMouseCapture() && button == K_MOUSE1 &&
288  EXTRADATA(node).scrollY.fullSize > EXTRADATA(node).scrollY.viewSize) {
289  UI_SetMouseCapture(node);
290  mouseScrollX = x;
291  mouseScrollY = y;
292  }
293 }
294 
295 void uiOptionListNode::onMouseUp (uiNode_t* node, int x, int y, int button)
296 {
297  if (UI_GetMouseCapture() == node) /* More checks can never hurt */
298  UI_MouseRelease();
299 }
300 
302 {
303  const int lineHeight = getCellHeight(node);
304  const int deltaY = (mouseScrollY - y) / lineHeight;
305  /* We're doing only vertical scroll, that's enough for the most instances */
306  if (deltaY != 0) {
307  bool updated;
308  updated = EXTRADATA(node).scrollY.moveDelta(deltaY);
309  if (updated) {
310  if (EXTRADATA(node).onViewChange) {
311  UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange);
312  }
313  else if (EXTRADATA(node).lua_onViewChange != LUA_NOREF) {
314  UI_ExecuteLuaEventScript (node, EXTRADATA(node).lua_onViewChange);
315  }
316  }
317  /* @todo not accurate */
318  mouseScrollX = x;
319  mouseScrollY = y;
320  }
321  onMouseMove(node, x, y);
322 }
323 
330 {
331  int lineHeight = EXTRADATA(node).lineHeight;
332  if (lineHeight == 0)
333  lineHeight = UI_FontGetHeight(UI_GetFontFromNode(node));
334  return lineHeight;
335 }
336 
338 {
339  behaviour->name = "optionlist";
340  behaviour->extends = "abstractoption";
341  behaviour->manager = UINodePtr(new uiOptionListNode());
342  behaviour->drawItselfChild = true;
343  behaviour->lua_SWIG_typeinfo = UI_SWIG_TypeQuery("uiOptionListNode_t *");
344 
345  /* Sprite used to display the background */
346  UI_RegisterExtradataNodeProperty(behaviour, "background", V_UI_SPRITEREF, EXTRADATA_TYPE, background);
347 }
struct uiAction_s * onWheelDown
Definition: ui_nodes.h:142
vec2_t size
Definition: ui_nodes.h:52
void UI_RegisterOptionListNode(uiBehaviour_t *behaviour)
static int mouseScrollX
uiNode_t * next
Definition: ui_nodes.h:91
const char * name
Definition: ui_behaviour.h:41
const char * UI_AbstractOption_GetCurrentValue(uiNode_t *node)
UINodePtr manager
Definition: ui_behaviour.h:43
bool UI_ExecuteLuaEventScript(uiNode_t *node, LUA_EVENT event)
Executes a lua event handler.
Definition: ui_lua.cpp:71
#define V_UI_SPRITEREF
Definition: ui_parse.h:56
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
virtual void onMouseMove(uiNode_t *node, int x, int y)
void onCapturedMouseMove(uiNode_t *node, int x, int y) override
void UI_MouseRelease(void)
Release the captured node.
Definition: ui_input.cpp:526
#define UI_RegisterExtradataNodeProperty(BEHAVIOUR, NAME, TYPE, EXTRADATATYPE, ATTRIBUTE)
Initialize a property from extradata of node.
Definition: ui_behaviour.h:109
void R_Color(const vec4_t rgba)
Change the color to given value.
Definition: r_state.cpp:1011
#define EXTRADATA_TYPE
static void UI_OptionListNodeUpdateScroll(uiNode_t *node)
Update the scroll according to the number of items and the size of the node.
void onMouseUp(uiNode_t *node, int x, int y, int button) override
#define OPTIONEXTRADATA(node)
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...
#define Vector4Set(v, r, g, b, a)
Definition: vector.h:62
struct uiAction_s * onWheelUp
Definition: ui_nodes.h:141
vec4_t disabledColor
Definition: ui_nodes.h:103
void onLoaded(uiNode_t *node) override
SharedPtr< uiNode > UINodePtr
int padding
Definition: ui_nodes.h:109
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
bool drawItselfChild
Definition: ui_behaviour.h:50
void UI_ExecuteEventActions(uiNode_t *source, const uiAction_t *firstAction)
Definition: ui_actions.cpp:726
void UI_AbstractOption_SetCurrentValue(uiNode_t *node, const char *value)
uiNode_t * UI_GetMouseCapture(void)
Return the captured node.
Definition: ui_input.cpp:508
bool onScroll(uiNode_t *node, int deltaX, int deltaY) override
Auto scroll the list.
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...
bool disabled
Definition: ui_nodes.h:102
void UI_GetNodeAbsPos(const uiNode_t *node, vec2_t pos)
Returns the absolute position of a node.
Definition: ui_node.cpp:514
QGL_EXTERN GLuint count
Definition: r_gl.h:99
vec4_t selectedColor
Definition: ui_nodes.h:128
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
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
const char * extends
Definition: ui_behaviour.h:42
uiSpriteStatus_t
Definition: ui_sprite.h:32
int UI_FontGetHeight(const char *fontID)
Definition: ui_font.cpp:166
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 EXTRADATA(node)
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...
#define Q_streq(a, b)
Definition: shared.h:136
uiBox_t box
Definition: ui_nodes.h:96
void UI_DrawFill(int x, int y, int w, int h, const vec4_t color)
Fills a box of pixels with a single color.
Definition: ui_render.cpp:37
static int mouseScrollY
void onLeftClick(uiNode_t *node, int x, int y) override
Handles selectboxes clicks.
int down
Definition: cl_input.cpp:70
static uiNode_t * UI_OptionListNodeGetOptionAtPosition(uiNode_t *node, int x, int y)
uiNode_t * UI_AbstractOption_GetFirstOption(uiNode_t *node)
Return the first option of the node.
void draw(uiNode_t *node) override
void onLoading(uiNode_t *node) override
Called before loading. Used to set default attribute values.