UFO: Alien Invasion
Loading...
Searching...
No Matches
ui_node_optionlist.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 "../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
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
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 */
55static int mouseScrollX;
56static 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 */
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
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
217void 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
235bool 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) {
253 updated = true;
254 }
255 if (node->onWheelDown && down) {
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
280
285void 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
295void uiOptionListNode::onMouseUp (uiNode_t* node, int x, int y, int button)
296{
297 if (UI_GetMouseCapture() == node) /* More checks can never hurt */
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}
int down
Definition cl_input.cpp:66
Header file for keyboard handler.
@ K_MOUSE1
Definition cl_keys.h:46
const char * CL_Translate(const char *t)
@ LONGLINES_PRETTYCHOP
void R_Color(const vec4_t rgba)
Change the color to given value.
Definition r_state.cpp:1011
virtual void onMouseMove(uiNode_t *node, int x, int y)
void draw(uiNode_t *node) override
void onLeftClick(uiNode_t *node, int x, int y) override
Handles selectboxes clicks.
bool onScroll(uiNode_t *node, int deltaX, int deltaY) override
Auto scroll the list.
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.
void onLoading(uiNode_t *node) override
Called before loading. Used to set default attribute values.
void onCapturedMouseMove(uiNode_t *node, int x, int y) override
void onMouseUp(uiNode_t *node, int x, int y, int button) override
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...
void onLoaded(uiNode_t *node) override
QGL_EXTERN GLuint count
Definition r_gl.h:99
@ ALIGN_UL
Definition scripts.h:90
Header for lua script functions.
#define Q_streq(a, b)
Definition shared.h:136
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
Atomic structure used to define most of the UI.
Definition ui_nodes.h:80
bool disabled
Definition ui_nodes.h:102
struct uiAction_s * onWheelDown
Definition ui_nodes.h:142
uiNode_t * next
Definition ui_nodes.h:91
vec4_t color
Definition ui_nodes.h:127
struct uiAction_s * onWheel
Definition ui_nodes.h:138
vec4_t selectedColor
Definition ui_nodes.h:128
uiBox_t box
Definition ui_nodes.h:96
int padding
Definition ui_nodes.h:109
vec4_t disabledColor
Definition ui_nodes.h:103
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)
#define UI_RegisterExtradataNodeProperty(BEHAVIOUR, NAME, TYPE, EXTRADATATYPE, ATTRIBUTE)
Initialize a property from extradata of node.
int UI_FontGetHeight(const char *fontID)
Definition ui_font.cpp:166
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
bool UI_ExecuteLuaEventScript(uiNode_t *node, LUA_EVENT event)
Executes a lua event handler.
Definition ui_lua.cpp:71
Basic lua initialization for the ui.
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_TYPE
uiNode_t * UI_AbstractOption_GetFirstOption(uiNode_t *node)
Return the first option of the node.
const char * UI_AbstractOption_GetCurrentValue(uiNode_t *node)
#define EXTRADATA(node)
void UI_AbstractOption_SetCurrentValue(uiNode_t *node, const char *value)
static int mouseScrollY
static int mouseScrollX
#define OPTIONEXTRADATA(node)
void UI_RegisterOptionListNode(uiBehaviour_t *behaviour)
#define EXTRADATA(node)
static uiNode_t * UI_OptionListNodeGetOptionAtPosition(uiNode_t *node, int x, int y)
static void UI_OptionListNodeUpdateScroll(uiNode_t *node)
Update the scroll according to the number of items and the size of the node.
#define V_UI_SPRITEREF
Definition ui_parse.h:56
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_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
void UI_DrawSpriteInBox(bool flip, const uiSprite_t *sprite, uiSpriteStatus_t status, int posX, int posY, int sizeX, int sizeY)
uiSpriteStatus_t
Definition ui_sprite.h:32
@ SPRITE_STATUS_DISABLED
Definition ui_sprite.h:35
@ SPRITE_STATUS_NORMAL
Definition ui_sprite.h:33
#define Vector4Set(v, r, g, b, a)
Definition vector.h:62