Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_GamepadScroll.c
Go to the documentation of this file.
1
7
8//#define GAMEPAD_SCROLL_DEBUG
9
11{
12 [Attribute("1", UIWidgets.CheckBox, "When true and scroll input is detected, the component will try to find a new focused widget, or will reset focused widget to null if no suitable widget found")]
13 protected bool m_bTryFindNewFocus;
14
15 [Attribute("1", UIWidgets.CheckBox, "Set scroll's initial state")]
16 protected bool m_bScrollEnabled;
17
18 [Attribute("1", UIWidgets.CheckBox, "Is the scroll vertical or horizontal")]
19 protected bool m_bIsVerticalScroll;
20
21 [Attribute("0", UIWidgets.CheckBox, "Should mouse wheel inputs be allowed")]
22 protected bool m_bAllowScrollWheel;
23
24 // Constants
25 static const float SCROLL_SPEED_PX_PER_SECOND_MAX = 1500;
26 static const float WIDGET_DETECTION_MARGIN_PX = 3;
27
28 static const float MOUSE_SCROLL_SPEED = 5;
29 static const float MOUSE_RAW_SCROLL_SPEED = 1000;
30
32
33#ifdef GAMEPAD_SCROLL_DEBUG
34 // Handling of debug markers
35 protected ref array<Widget> m_aDebugMarksPool;
36 protected ref array<Widget> m_aDebugMarksBusy;
37#endif
38
39 protected bool m_bMouseScrolled;
40 protected bool m_bShouldBeEnabled = true;
41 protected bool m_bForceDisabled;
42
43 //------------------------------------------------------------------------------------------------
44 override void HandlerAttached(Widget w)
45 {
46 super.HandlerAttached(w);
47
49
51 GetGame().GetCallqueue().CallLater(OnEachFrame, 1, true);
52
53 #ifdef GAMEPAD_SCROLL_DEBUG
54 m_aDebugMarksPool = {};
55 m_aDebugMarksBusy = {};
56 #endif
57
60 }
61
62 //------------------------------------------------------------------------------------------------
63 override void HandlerDeattached(Widget w)
64 {
66 {
67 ArmaReforgerScripted game = GetGame();
68 if (game && game.GetCallqueue())
69 game.GetCallqueue().Remove(OnEachFrame);
70 }
71
74 }
75
76 //------------------------------------------------------------------------------------------------
78 {
80 SetForceDisabled(false);
81 }
82
83 //------------------------------------------------------------------------------------------------
84 protected void OnMenuFocusLost(ChimeraMenuBase menu)
85 {
87 SetForceDisabled(true);
88 }
89
90 //------------------------------------------------------------------------------------------------
92 {
93 if (!m_wScroll)
94 return;
95
96 float tDelta = ftime / 1000.0; // ftime is milliseconds!
97 Update(tDelta, m_wScroll);
98 }
99
100 //------------------------------------------------------------------------------------------------
102 void Update(float tDelta, ScrollLayoutWidget wScroll)
103 {
104#ifdef GAMEPAD_SCROLL_DEBUG
105 DebugMarks_StartUpdate();
106
107 vector refPoint;
109 refPoint = GetVReferencePoint(wScroll);
110 else
111 refPoint = GetHReferencePoint(wScroll);
112
113 PlaceDebugMark(refPoint, "-");
114#endif
115
116 // Bail if scroll content is smaller than scroll
117 SCR_Rect2D scrollRect = GetWidgetRect(m_wScroll);
118 Widget scrollContent = m_wScroll.GetChildren();
119 if (!scrollContent)
120 return;
121
122 SCR_Rect2D scrollContentRect = GetWidgetRect(scrollContent);
124 {
125 if (scrollContentRect.GetHeight() <= scrollRect.GetHeight())
126 return;
127
128 // Handle scrolling, try find a new focus
129 float vScrollInput = GetVScrollInput();
131 vScrollInput += GetMouseScrollInput();
132
133 if (vScrollInput != 0)
134 {
135 HandleGamepadVScrolling(tDelta, wScroll);
137 TryFindNewFocus(wScroll);
138 }
139
140#ifdef GAMEPAD_SCROLL_DEBUG
141 PlaceDebugMark("200 40 0", string.Format("V Scroll Input: notNull: %1, value: %2", vScrollInput != 0, vScrollInput));
142 PlaceDebugMark("800 40 0", string.Format("Current focus: %1", GetGame().GetWorkspace().GetFocusedWidget()));
143 DebugMarks_EndUpdate();
144#endif
145 }
146 else
147 {
148 if (scrollContentRect.GetWidth() <= scrollRect.GetWidth())
149 return;
150
151 // Handle scrolling, try find a new focus
152 float hScrollInput = GetHScrollInput();
154 hScrollInput += GetMouseScrollInput();
155
156 if (hScrollInput != 0)
157 {
158 HandleGamepadHScrolling(tDelta, wScroll);
160 TryFindNewFocus(wScroll);
161 }
162
163#ifdef GAMEPAD_SCROLL_DEBUG
164 PlaceDebugMark("200 40 0", string.Format("H Scroll Input: notNull: %1, value: %2", hScrollInput != 0, hScrollInput));
165 PlaceDebugMark("800 40 0", string.Format("Current focus: %1", GetGame().GetWorkspace().GetFocusedWidget()));
166 DebugMarks_EndUpdate();
167#endif
168 }
169 }
170
171 //------------------------------------------------------------------------------------------------
172 protected void HandleGamepadVScrolling(float tDelta, ScrollLayoutWidget wScroll)
173 {
174 Widget scrollContent = wScroll.GetChildren();
175
176 if (!scrollContent)
177 return;
178
179 float xScrollSize, yScrollSize;
180 wScroll.GetScreenSize(xScrollSize, yScrollSize);
181
182 float xContentSize, yContentSize;
183 scrollContent.GetScreenSize(xContentSize, yContentSize);
184
185 if (yContentSize <= yScrollSize || yContentSize == 0)
186 return;
187
188 float scrollInputValue = GetVScrollInput();
190 scrollInputValue += GetMouseScrollInput();
191
192 float xPosAbsCurrent, yPosAbsCurrent;
193 wScroll.GetSliderPosPixels(xPosAbsCurrent, yPosAbsCurrent);
194
195 float yPosAbsNew = yPosAbsCurrent - scrollInputValue * tDelta * SCROLL_SPEED_PX_PER_SECOND_MAX;
196
197 wScroll.SetSliderPosPixels(0, yPosAbsNew);
198 }
199
200 //------------------------------------------------------------------------------------------------
201 protected void HandleGamepadHScrolling(float tDelta, ScrollLayoutWidget wScroll)
202 {
203 Widget scrollContent = wScroll.GetChildren();
204
205 if (!scrollContent)
206 return;
207
208 float xScrollSize, yScrollSize;
209 wScroll.GetScreenSize(xScrollSize, yScrollSize);
210
211 float xContentSize, yContentSize;
212 scrollContent.GetScreenSize(xContentSize, yContentSize);
213
214 if (xContentSize <= xScrollSize || xContentSize == 0)
215 return;
216
217 float scrollInputValue = GetHScrollInput();
219 scrollInputValue -= GetMouseScrollInput();
220
221 float xPosAbsCurrent, yPosAbsCurrent;
222 wScroll.GetSliderPosPixels(xPosAbsCurrent, yPosAbsCurrent);
223
224 float xPosAbsNew = xPosAbsCurrent + scrollInputValue * tDelta * SCROLL_SPEED_PX_PER_SECOND_MAX;
225
226 wScroll.SetSliderPosPixels(xPosAbsNew, 0);
227 }
228
229 //------------------------------------------------------------------------------------------------
230 protected static float GetHScrollInput()
231 {
232 return GetGame().GetInputManager().GetActionValue("MenuScrollHorizontal");
233 }
234
235 //------------------------------------------------------------------------------------------------
236 protected static float GetVScrollInput()
237 {
238 return GetGame().GetInputManager().GetActionValue("MenuScrollVertical");
239 }
240
241 //------------------------------------------------------------------------------------------------
242 protected float GetMouseScrollInput()
243 {
244 float value = GetGame().GetInputManager().GetActionValue("MouseWheel");
245 if (value != 0)
246 {
247 m_bMouseScrolled = true;
249 return value;
250 }
251
252 m_bMouseScrolled = false;
253
254 return 0;
255 }
256
257 //------------------------------------------------------------------------------------------------
258 // Try to unfocus current focused widget if it's out of scroll bounds
259 protected static void TryUnfocusWidget(Widget scroll)
260 {
261 Widget currentFocus = GetGame().GetWorkspace().GetFocusedWidget();
262
263 if (!currentFocus)
264 return;
265
266 SCR_Rect2D scrollRect = GetWidgetRect(scroll);
267 SCR_Rect2D focusedWidgetRect = GetWidgetRect(scroll);
268
269 if (!scrollRect.HasInside(focusedWidgetRect))
270 GetGame().GetWorkspace().SetFocusedWidget(null);
271 }
272
273 //------------------------------------------------------------------------------------------------
275 protected void TryFindNewFocus(ScrollLayoutWidget wScroll)
276 {
278 return;
279
280 SCR_Rect2D scrollRect = GetWidgetRect(wScroll);
281 scrollRect.ExpandAllDirections(WIDGET_DETECTION_MARGIN_PX); // Otherwise the strict conditions omit some widgets at the edge sometimes
282
283 // Find all potential focus widgets in base
284 array<Widget> allButtons = {};
285 FindAllButtons(wScroll, allButtons);
286
287 // Find widgets within view area of Base
288 array<Widget> widgetsInFrame = {};
289 foreach (Widget w : allButtons)
290 {
291 SCR_Rect2D wRect = GetWidgetRect(w);
292 if (scrollRect.HasInside(wRect))
293 widgetsInFrame.Insert(w);
294 }
295
296 if (widgetsInFrame.IsEmpty())
297 return;
298
299 vector refPos;
301 refPos = GetVReferencePoint(wScroll);
302 else
303 refPos = GetHReferencePoint(wScroll);
304
305 // Sort widgets by their proximity to prev focus, or just select any widget
306 Widget newFocus = null;
307
308 float metricMin;
309 metricMin = GetFocusMetric(refPos, widgetsInFrame[0]);
310 newFocus = widgetsInFrame[0];
311
312 foreach (Widget w : widgetsInFrame)
313 {
314 float m = GetFocusMetric(refPos, w);
315
316#ifdef GAMEPAD_SCROLL_DEBUG
317 SCR_Rect2D wRect = GetWidgetRect(w);
318 vector wRectCenter = wRect.GetCenter(); // !! The actual GetFocusMetric is not calculated between widget center!
319 PlaceDebugMark(wRectCenter, string.Format("%1", m));
320#endif
321
322 if (m < metricMin)
323 {
324 newFocus = w;
325 metricMin = m;
326 }
327 }
328
329 GetGame().GetWorkspace().SetFocusedWidget(newFocus);
330 }
331 //------------------------------------------------------------------------------------------------
334 {
335 SCR_Rect2D scrollRect = GetWidgetRect(wScroll);
336 float sliderX, sliderY;
337 wScroll.GetSliderPos(sliderX, sliderY);
338 vector refPoint;
339
340 refPoint[0] = scrollRect.p0[0];
341 refPoint[1] = scrollRect.p0[1] + sliderY * scrollRect.GetHeight();
342
343 if (!SCR_WidgetTools.InHierarchy(GetGame().GetWorkspace().GetFocusedWidget(), wScroll))
344 return refPoint;
345
346 Widget focusedWidget = GetGame().GetWorkspace().GetFocusedWidget();
347 float xPos, yPos, width, height;
348 focusedWidget.GetScreenPos(xPos, yPos);
349 focusedWidget.GetScreenSize(width, height);
350 SCR_Rect2D focusedRect = GetWidgetRect(focusedWidget);
351
352 refPoint[0] = width * 0.5 + xPos - 1;
353
354 return refPoint;
355 }
356
357 //------------------------------------------------------------------------------------------------
360 {
361 SCR_Rect2D scrollRect = GetWidgetRect(wScroll);
362 float sliderX, sliderY;
363 wScroll.GetSliderPos(sliderX, sliderY);
364 vector refPoint;
365
366 refPoint[0] = scrollRect.p0[0] + sliderX * scrollRect.GetWidth();
367 refPoint[1] = scrollRect.p0[1];
368
369 if (!SCR_WidgetTools.InHierarchy(GetGame().GetWorkspace().GetFocusedWidget(), wScroll))
370 return refPoint;
371
372 Widget focusedWidget = GetGame().GetWorkspace().GetFocusedWidget();
373 float xPos, yPos, width, height;
374 focusedWidget.GetScreenPos(xPos, yPos);
375 focusedWidget.GetScreenSize(width, height);
376 SCR_Rect2D focusedRect = GetWidgetRect(focusedWidget);
377
378 refPoint[1] = height * 0.5 + yPos - 1;
379
380 return refPoint;
381 }
382
383 //------------------------------------------------------------------------------------------------
384 // Returns metric between a point and a widget
385 protected static float GetFocusMetric(vector v0, Widget w)
386 {
387 // Find left midpoint of widget
388 SCR_Rect2D wRect = GetWidgetRect(w);
389 vector wRectPoint = wRect.p0;
390 wRectPoint[1] = 0.5 * (wRect.p0[1] + wRect.p1[1]);
391
392 vector v1 = wRectPoint;
393
394 float dx = v0[0] - v1[0];
395 float dy = v0[1] - v1[1];
396
397 return 100 *Math.AbsFloat(dy) + Math.AbsFloat(dx);
398 }
399
400 //------------------------------------------------------------------------------------------------
403 {
404 vector pos;
405 vector size;
406
407 float posX, posY;
408 float sizeX, sizeY;
409
410 w.GetScreenPos(posX, posY);
411 w.GetScreenSize(sizeX, sizeY);
412
413 pos[0] = posX;
414 pos[1] = posY;
415 size[0] = sizeX;
416 size[1] = sizeY;
417
418 return SCR_Rect2D.FromPosAndSize(pos, size);
419 }
420
421 //------------------------------------------------------------------------------------------------
423 static void FindAllButtons(Widget w, array<Widget> arrayOut)
424 {
425 // Add yourself to button list
426 ButtonWidget wb = ButtonWidget.Cast(w);
427 if (wb)
428 {
429 if (wb.IsFocusable())
430 arrayOut.Insert(wb);
431 }
432
433 Widget child = w.GetChildren();
434 while (child)
435 {
436 FindAllButtons(child, arrayOut);
437 child = child.GetSibling();
438 }
439 }
440
441 //------------------------------------------------------------------------------------------------
442 void SetTryFindNewFocus(bool tryFindNewFocus)
443 {
444 m_bTryFindNewFocus = tryFindNewFocus;
445 }
446
447 //------------------------------------------------------------------------------------------------
448 void SetEnabled(bool enabled)
449 {
450 m_bShouldBeEnabled = enabled;
451 SetEnabled_Internal(enabled);
452 }
453
454 //------------------------------------------------------------------------------------------------
455 protected void SetEnabled_Internal(bool enabled)
456 {
457 GetGame().GetCallqueue().Remove(OnEachFrame);
458
461 GetGame().GetCallqueue().CallLater(OnEachFrame, 1, true);
462 }
463
464 //------------------------------------------------------------------------------------------------
465 protected void SetForceDisabled(bool forceDisabled)
466 {
467 m_bForceDisabled = forceDisabled;
468
469 if (forceDisabled)
470 SetEnabled_Internal(false);
471 else
473 }
474
475//------------------------------------------------------------------------------------------------
476// Handling of debug markers
477//------------------------------------------------------------------------------------------------
478
479#ifdef GAMEPAD_SCROLL_DEBUG
480
481 //------------------------------------------------------------------------------------------------
482 protected void DebugMarks_StartUpdate()
483 {
484 // Return debug marks back to pool
485 foreach (Widget w : m_aDebugMarksBusy)
486 {
487 m_aDebugMarksPool.Insert(w);
488 }
489
490 m_aDebugMarksBusy.Clear();
491 }
492
493 //------------------------------------------------------------------------------------------------
494 // Puts a debug mark on this position. Must be called each frame!!
495 // This must be used only between DebugMarks_StartUpdate and DebugMarks_EndUpdate
496 protected void PlaceDebugMark(vector pos, string text)
497 {
498 WorkspaceWidget workspace = GetGame().GetWorkspace();
499
500 Widget w;
501 if (!m_aDebugMarksPool.IsEmpty())
502 {
503 w = m_aDebugMarksPool[0];
504 m_aDebugMarksPool.Remove(0);
505 }
506 else
507 {
508 Widget workspaceRoot = GetGame().GetWorkspace();
509 w = workspace.CreateWidgets("{79FC19F28E381C1E}UI/layouts/Menus/DebugTextMark.layout", workspaceRoot);
510 }
511
512 m_aDebugMarksBusy.Insert(w);
513
514 TextWidget wtext = TextWidget.Cast(w.FindWidget("Text"));
515 wtext.SetText(text);
516 w.SetVisible(true);
517 FrameSlot.SetPos(w, workspace.DPIUnscale(pos[0]), workspace.DPIUnscale(pos[1]));
518 }
519
520 //------------------------------------------------------------------------------------------------
521 protected void DebugMarks_EndUpdate()
522 {
523 // Hide all in the pool - by now they have either been used or they are not needed now
524 foreach (Widget w : m_aDebugMarksPool)
525 {
526 w.SetVisible(false);
527 }
528 }
529
530#endif
531}
ref DSGameConfig game
Definition DSConfig.c:81
ArmaReforgerScripted GetGame()
Definition game.c:1398
int size
Constant variables used in various menus.
static ChimeraMenuBase GetOwnerMenu(Widget w)
Returns parent menu of a widget.
Definition Math.c:13
static const float WIDGET_DETECTION_MARGIN_PX
static void TryUnfocusWidget(Widget scroll)
void SetTryFindNewFocus(bool tryFindNewFocus)
override void HandlerAttached(Widget w)
void Update(float tDelta, ScrollLayoutWidget wScroll)
Call this from the menu, or if used as widget component it gets called automatically.
void HandleGamepadHScrolling(float tDelta, ScrollLayoutWidget wScroll)
void SetForceDisabled(bool forceDisabled)
static vector GetHReferencePoint(ScrollLayoutWidget wScroll)
Returns reference point of the scroll widget.
static SCR_Rect2D GetWidgetRect(Widget w)
Returns a rect created from widget's GetScreenPos and GetScreenSize.
static void FindAllButtons(Widget w, array< Widget > arrayOut)
Finds all buttons recursively.
void OnMenuFocusGained(ChimeraMenuBase menu)
void HandleGamepadVScrolling(float tDelta, ScrollLayoutWidget wScroll)
static const float MOUSE_RAW_SCROLL_SPEED
override void HandlerDeattached(Widget w)
static const float SCROLL_SPEED_PX_PER_SECOND_MAX
void TryFindNewFocus(ScrollLayoutWidget wScroll)
Tries to find the new widget to focus.
void OnMenuFocusLost(ChimeraMenuBase menu)
static vector GetVReferencePoint(ScrollLayoutWidget wScroll)
Returns reference point of the scroll widget.
static const float MOUSE_SCROLL_SPEED
static float GetFocusMetric(vector v0, Widget w)
void SetEnabled_Internal(bool enabled)
static bool IsEditMode()
Definition Functions.c:1566
static ScriptInvokerMenu GetOnMenuFocusLost()
static ScriptInvokerMenu GetOnMenuFocusGained()
SCR_Rect2D ExpandAllDirections(float delta)
This rect will be expanded in all directions by given value.
Definition SCR_Rect2D.c:124
SCR_FieldOfViewSettings Attribute