1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 //
21 // ui_cursor.c
22 //
23
24 #include "ui_local.h"
25
26 static cVar_t *ui_cursorX;
27 static cVar_t *ui_cursorY;
28
29 /*
30 =======================================================================
31
32 MENU MOUSE CURSOR
33
34 =======================================================================
35 */
36
37 /*
38 =============
39 UI_DrawMouseCursor
40 =============
41 */
UI_DrawMouseCursor(void)42 void UI_DrawMouseCursor (void)
43 {
44 struct shader_s *cursor;
45
46 if (uiState.cursorOverItem)
47 cursor = uiMedia.cursorHoverShader;
48 else
49 cursor = uiMedia.cursorShader;
50
51 cgi.R_DrawPic (cursor, 0, uiState.cursorX + 1, uiState.cursorY + 1,
52 uiState.cursorW * clamp (UIFT_SCALE, 0.5f, 1),
53 uiState.cursorH * clamp (UIFT_SCALE, 0.5f, 1),
54 0, 0, 1, 1, Q_colorWhite);
55 }
56
57
58 /*
59 =============
60 UI_FindMouseItem
61
62 Finds the item that the mouse is over for the specified framework
63 =============
64 */
UI_FindMouseItem(uiFrameWork_t * fw)65 static void UI_FindMouseItem (uiFrameWork_t *fw)
66 {
67 int i;
68
69 // Search for the current item that the mouse is over
70 uiState.mouseItem = NULL;
71 for (i=0 ; i<fw->numItems ; i++) {
72 // Skip NOSELECT items
73 if (((uiCommon_t *) fw->items[i])->flags & UIF_NOSELECT)
74 continue;
75
76 // Check if the mouse is colliding
77 if (uiState.cursorX > ((uiCommon_t *) fw->items[i])->botRight[0]
78 || uiState.cursorY > ((uiCommon_t *) fw->items[i])->botRight[1]
79 || uiState.cursorX < ((uiCommon_t *) fw->items[i])->topLeft[0]
80 || uiState.cursorY < ((uiCommon_t *) fw->items[i])->topLeft[1])
81 continue;
82
83 uiState.cursorItem = fw->items[i];
84 uiState.mouseItem = fw->items[i];
85
86 if (fw->cursor == i)
87 break;
88 uiState.newCursorItem = qTrue;
89 fw->cursor = i;
90 break;
91 }
92
93 // Rollover cursor image
94 uiState.cursorOverItem = (uiState.mouseItem != NULL);
95 }
96
97
98 /*
99 =============
100 UI_UpdateMousePos
101 =============
102 */
UI_UpdateMousePos(void)103 void UI_UpdateMousePos (void)
104 {
105 if (!uiState.activeUI || !uiState.activeUI->numItems || uiState.cursorLock)
106 return;
107
108 uiState.newCursorItem = qFalse;
109 UI_FindMouseItem (uiState.activeUI);
110 }
111
112
113 /*
114 =============
115 UI_MoveMouse
116 =============
117 */
UI_MoveMouse(float x,float y)118 void UI_MoveMouse (float x, float y)
119 {
120 if (uiState.cursorLock)
121 return;
122
123 // Filter
124 if (ui_filtermouse->intVal) {
125 uiState.cursorX = (uiState.cursorX * 2 + (x * ui_sensitivity->floatVal)) * 0.5f;
126 uiState.cursorY = (uiState.cursorY * 2 + (y * ui_sensitivity->floatVal)) * 0.5f;
127 }
128 else {
129 uiState.cursorX += x * ui_sensitivity->floatVal;
130 uiState.cursorY += y * ui_sensitivity->floatVal;
131 }
132
133 // Clamp
134 uiState.cursorX = clamp (uiState.cursorX, 2, cg.refConfig.vidWidth - 2);
135 uiState.cursorY = clamp (uiState.cursorY, 2, cg.refConfig.vidHeight - 2);
136
137 if (x || y)
138 UI_UpdateMousePos ();
139 }
140
141
142 /*
143 =============
144 UI_SetupBounds
145 =============
146 */
Action_Setup(uiAction_t * s)147 static void Action_Setup (uiAction_t *s)
148 {
149 if (!s->generic.name)
150 return;
151
152 s->generic.topLeft[0] = s->generic.x + s->generic.parent->x;
153 s->generic.topLeft[1] = s->generic.y + s->generic.parent->y;
154
155 s->generic.botRight[1] = s->generic.topLeft[1] + UISIZE_TYPE (s->generic.flags);
156
157 if (s->generic.flags & UIF_CENTERED)
158 s->generic.topLeft[0] -= ((Q_ColorCharCount (s->generic.name, (int)strlen (s->generic.name)) * UISIZE_TYPE (s->generic.flags))*0.5);
159 else if (!(s->generic.flags & UIF_LEFT_JUSTIFY))
160 s->generic.topLeft[0] += LCOLUMN_OFFSET - ((Q_ColorCharCount (s->generic.name, (int)strlen (s->generic.name))) * UISIZE_TYPE (s->generic.flags));
161
162 s->generic.botRight[0] = s->generic.topLeft[0] + (Q_ColorCharCount (s->generic.name, (int)strlen (s->generic.name)) * UISIZE_TYPE (s->generic.flags));
163 }
164
Field_Setup(uiField_t * s)165 static void Field_Setup (uiField_t *s)
166 {
167 s->generic.topLeft[0] = s->generic.x + s->generic.parent->x;
168
169 if (s->generic.name)
170 s->generic.topLeft[0] -= (Q_ColorCharCount (s->generic.name, (int)strlen (s->generic.name)) + 1) * UISIZE_TYPE (s->generic.flags);
171
172 s->generic.topLeft[1] = s->generic.y + s->generic.parent->y - (UISIZE_TYPE (s->generic.flags) * 0.5);
173
174 s->generic.botRight[0] = s->generic.x + s->generic.parent->x + ((s->visibleLength + 2) * UISIZE_TYPE (s->generic.flags));
175 s->generic.botRight[1] = s->generic.topLeft[1] + UISIZE_TYPE (s->generic.flags)*2;
176
177 if (s->generic.flags & UIF_CENTERED) {
178 s->generic.topLeft[0] -= ((s->visibleLength + 2) * UISIZE_TYPE (s->generic.flags))*0.5;
179 s->generic.botRight[0] -= ((s->visibleLength + 2) * UISIZE_TYPE (s->generic.flags))*0.5;
180 }
181 }
182
MenuImage_Setup(uiImage_t * s)183 static void MenuImage_Setup (uiImage_t *s)
184 {
185 int width, height;
186
187 if (s->width || s->height) {
188 width = s->width;
189 height = s->height;
190 }
191 else {
192 cgi.R_GetImageSize (s->shader, &width, &height);
193 s->width = width;
194 s->height = height;
195 }
196
197 width *= UISCALE_TYPE (s->generic.flags);
198 height *= UISCALE_TYPE (s->generic.flags);
199
200 s->generic.topLeft[0] = s->generic.x + s->generic.parent->x;
201
202 if (s->generic.flags & UIF_CENTERED)
203 s->generic.topLeft[0] -= width * 0.5;
204 else if (s->generic.flags & UIF_LEFT_JUSTIFY)
205 s->generic.topLeft[0] += LCOLUMN_OFFSET;
206
207 s->generic.topLeft[1] = s->generic.y + s->generic.parent->y;
208 s->generic.botRight[0] = s->generic.topLeft[0] + width;
209 s->generic.botRight[1] = s->generic.topLeft[1] + height;
210 }
211
212 // FIXME need calculations to detect when on the left/right side of the slider
213 // so left == less and right == more
214 // if the mouse cursor position is less than the cursor position and is within the bounding box, left
215 // if the mouse cursor position is greater than the cursor position and is within the bounding box, right
Slider_Setup(uiSlider_t * s)216 static void Slider_Setup (uiSlider_t *s)
217 {
218 float xsize, ysize;
219 float offset;
220
221 if (s->generic.name)
222 offset = Q_ColorCharCount (s->generic.name, (int)strlen (s->generic.name)) * UISIZE_TYPE (s->generic.flags);
223 else
224 offset = 0;
225
226 s->generic.topLeft[0] = s->generic.x + s->generic.parent->x - offset - UISIZE_TYPE (s->generic.flags);
227 s->generic.topLeft[1] = s->generic.y + s->generic.parent->y;
228
229 xsize = (UISIZE_TYPE (s->generic.flags) * 6) + offset + ((SLIDER_RANGE-1) * UISIZE_TYPE (s->generic.flags));
230 ysize = UISIZE_TYPE (s->generic.flags);
231
232 s->generic.botRight[0] = s->generic.topLeft[0] + xsize;
233 s->generic.botRight[1] = s->generic.topLeft[1] + ysize;
234 }
235
SpinControl_Setup(uiList_t * s)236 static void SpinControl_Setup (uiList_t *s)
237 {
238 float xsize = 0, ysize = 0;
239
240 ysize = UISIZE_TYPE (s->generic.flags);
241 if (s->generic.name) {
242 s->generic.topLeft[0] = s->generic.x + s->generic.parent->x - (Q_ColorCharCount (s->generic.name, (int)strlen (s->generic.name)) * UISIZE_TYPE (s->generic.flags)) - UISIZE_TYPE (s->generic.flags);
243 s->generic.topLeft[1] = s->generic.y + s->generic.parent->y;
244
245 xsize = (Q_ColorCharCount (s->generic.name, (int)strlen (s->generic.name)) * UISIZE_TYPE (s->generic.flags)) + UISIZE_TYPE (s->generic.flags)*3;
246 }
247
248 if (s->itemNames && s->itemNames[s->curValue]) {
249 if (s->itemNames[s->curValue] && (!strchr(s->itemNames[s->curValue], '\n'))) {
250 if (!s->generic.name)
251 s->generic.topLeft[0] += UISIZE_TYPE (s->generic.flags)*20;
252 }
253 else
254 ysize += UISIZE_TYPE (s->generic.flags);
255
256 if (s->itemNames[s->curValue])
257 xsize += (Q_ColorCharCount (s->itemNames[s->curValue], (int)strlen (s->itemNames[s->curValue])) * UISIZE_TYPE (s->generic.flags));
258 }
259
260 s->generic.botRight[0] = s->generic.topLeft[0] + xsize;
261 s->generic.botRight[1] = s->generic.topLeft[1] + ysize;
262 }
263
UI_SetupBounds(uiFrameWork_t * menu)264 void UI_SetupBounds (uiFrameWork_t *menu)
265 {
266 uiCommon_t *item;
267 int i;
268
269 // Generate collision boxes for items
270 for (i=0 ; i<menu->numItems ; i++) {
271 item = (uiCommon_t *)menu->items[i];
272
273 if (item->flags & UIF_NOSELECT) {
274 item->topLeft[0] = item->topLeft[1] = 0;
275 item->botRight[0] = item->botRight[1] = 0;
276 continue;
277 }
278
279 switch (item->type) {
280 case UITYPE_ACTION:
281 Action_Setup ((uiAction_t *) menu->items[i]);
282 break;
283
284 case UITYPE_FIELD:
285 Field_Setup ((uiField_t *) menu->items[i]);
286 break;
287
288 case UITYPE_IMAGE:
289 MenuImage_Setup ((uiImage_t *) menu->items[i]);
290 break;
291
292 case UITYPE_SLIDER:
293 Slider_Setup ((uiSlider_t *) menu->items[i]);
294 break;
295
296 case UITYPE_SPINCONTROL:
297 SpinControl_Setup ((uiList_t *) menu->items[i]);
298 break;
299 }
300 }
301 }
302
303 /*
304 =======================================================================
305
306 INITIALIZATION/SHUTDOWN
307
308 =======================================================================
309 */
310
311 /*
312 =============
313 UI_CursorInit
314 =============
315 */
UI_CursorInit(void)316 void UI_CursorInit (void)
317 {
318 uiState.cursorOverItem = qFalse;
319
320 // Cursor position
321 ui_cursorX = cgi.Cvar_Register ("ui_cursorX", "-1", CVAR_READONLY);
322 ui_cursorY = cgi.Cvar_Register ("ui_cursorY", "-1", CVAR_READONLY);
323 if (ui_cursorX->floatVal == -1 && ui_cursorY->floatVal == -1) {
324 uiState.cursorX = cg.refConfig.vidWidth * 0.5f;
325 uiState.cursorY = cg.refConfig.vidHeight * 0.5f;
326 }
327 else {
328 uiState.cursorX = ui_cursorX->floatVal;
329 uiState.cursorY = ui_cursorY->floatVal;
330 }
331 }
332
333
334 /*
335 =============
336 UI_CursorShutdown
337 =============
338 */
UI_CursorShutdown(void)339 void UI_CursorShutdown (void)
340 {
341 // Store the cursor position
342 cgi.Cvar_VariableSetValue (ui_cursorX, uiState.cursorX, qTrue);
343 cgi.Cvar_VariableSetValue (ui_cursorY, uiState.cursorY, qTrue);
344 }
345