Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_BasePaginationUIComponent.c
Go to the documentation of this file.
2 {
3  [Attribute("1", desc: "Number of rows in content area.")]
4  protected int m_iRows;
5 
6  [Attribute("1", desc: "Number of columns in content area.")]
7  protected int m_iColumns;
8 
9  [Attribute("-1", desc: "Minimum mumber of rows in content area.\n When -1, value from 'Rows' will be used.")]
10  protected int m_iMinRows;
11 
12  [Attribute("-1", desc: "Minimum number of rows in content area.\n When -1, value from 'Columns' will be used.")]
13  protected int m_iMinColumns;
14 
15  [Attribute(desc: "Name of content area widget.")]
16  protected string m_sContentName;
17 
18  [Attribute(desc: "Name of a widget which, when activated, will move to the previous page. This button is shown when cursor is focused on the area.")]
19  protected string m_sButtonPrevName;
20 
21  [Attribute(desc: "Name of a widget which, when activated, will move to the next page. This button is shown when cursor is focused on the area.")]
22  protected string m_sButtonNextName;
23 
24  [Attribute("PrevButton_NoScroll", desc: "Name of a widget which, when activated, will move to the previous page. This button is shown when cursor is not focused on the area.")]
25  protected string m_sButtonPrevName_NoScrolling;
26 
27  [Attribute("NextButton_NoScroll", desc: "Name of a widget which, when activated, will move to the next page. This button is shown when cursor is not focused on the area.")]
28  protected string m_sButtonNextName_NoScrolling;
29 
30  [Attribute(desc: "Name of a widget which, when focused, will move to the previous page.\nused to auto-paging when focusing outside of content area in given direction.")]
31  protected string m_sFocusPrevName;
32 
33  [Attribute(desc: "Name of a widget which, when focused, will move to the next page.\nused to auto-paging when focusing outside of content area in given direction.")]
34  protected string m_sFocusNextName;
35 
36  [Attribute(desc: "Name of the widget which will show page numbers.")]
37  protected string m_sPageIndexVisualName;
38 
39  [Attribute("#AR-Editor_ContentBrowser_PageIndex_Text", desc: "Format of page number text.")]
40  protected string m_sPageIndexVisualText;
41 
42  [Attribute(desc: "When enabled, button shortcuts will be accepted only when cursor is over content widget.\nWhen disabled, cursor can be anywhere inside area of the widget this component is attached to.\nDoes not affect gamepad controls.")]
43  protected bool m_bMustHoverOverContent;
44 
45  [Attribute(desc: "If content widget is UniformGridSlot, empty grid tiles will be filled with these layouts.\nIf there are more items than defined here, the last layout in the list will be used.\n\nWhen undefined, no filling will be performed.", uiwidget: UIWidgets.ResourceNamePicker, params: "layout")]
46  protected ref array<ResourceName> m_aEmptyItemLayouts;
47 
48  [Attribute(desc: "When enabled, going next from the last page will cycle back to the first page, and vice versa.")]
49  protected bool m_bLoop;
50 
51  [Attribute("1", desc: "When true it will hide the arrows instead of disabling them if the button is disabled.")]
52  protected bool m_bHideArrowsIfDisabled;
53 
54  [Attribute("0", desc: "When true always ignore gamepad input. Set this true if the widget is always on the screen and there is a seperate dialog version of it for the gamepad. Setting this true will make sure the next and prev focus buttons will have 'No Focus' enabled")]
55  protected bool m_bIgnoreGamePadInput;
56 
57  [Attribute("1", desc: "If true it will play the next and prev page audio on page change")]
58  protected bool m_bPlayAudioOnPageChange;
59 
60  [Attribute(SCR_SoundEvent.TURN_PAGE, UIWidgets.EditBox)]
61  protected string m_sOnNextPageSfx;
62 
63  [Attribute(SCR_SoundEvent.TURN_PAGE, UIWidgets.EditBox)]
64  protected string m_sOnPrevPageSfx;
65 
66  protected int m_iCurrentPage;
67  protected bool m_bUnderCursor;
68  protected Widget m_ContentWidget, m_ButtonPrevWidget, m_ButtonNextWidget, m_FocusPrevWidget, m_FocusNextWidget, m_ButtonPrevNoScrollWidget, m_ButtonNextNoScrollWidget;
69  protected TextWidget m_PageNumberWidget;
70  protected ref ScriptInvoker m_OnPageChanged = new ScriptInvoker();
71  protected int m_FocusedIndex[2];
72 
73  //--- To be overridden by inherited classes
81  protected void ShowEntries(Widget contentWidget, int indexStart, int indexEnd);
87  int GetEntryCount();
88 
89  //--- Public functions
93  int GetRows()
94  {
95  return m_iRows;
96  }
100  int GetColumns()
101  {
102  return m_iColumns;
103  }
107  int GetCurrentPage()
108  {
109  return m_iCurrentPage;
110  }
115  int GetEntryIndex(Widget w)
116  {
117  int row = UniformGridSlot.GetRow(w);
118  int column = UniformGridSlot.GetColumn(w);
119  return (m_iCurrentPage * m_iRows * m_iColumns) + (row * m_iColumns + column);
120  }
124  ScriptInvoker GetOnPageChanged()
125  {
126  return m_OnPageChanged;
127  }
128 
134  sealed bool SetPage(int page, bool isRefresh = false)
135  {
136  if (!m_ContentWidget)
137  return false;
138 
139  //--- Get currently focused widget
140  int focusedRow = m_FocusedIndex[0];
141  int focusedColumn = m_FocusedIndex[1];
142 
143  //--- Set new page
144  int pageCapacity = m_iRows * m_iColumns;
145  int countEntries = GetEntryCount();
146  int totalPages = Math.Ceil(countEntries / (m_iRows * m_iColumns));
147  if (totalPages > 0 && m_bLoop)
148  page = Math.Repeat(page, totalPages);
149 
150  int indexStart = page * pageCapacity;
151  int indexEnd = Math.Min(indexStart + pageCapacity, countEntries);
152  if (indexStart < 0 || (countEntries > 0 && indexStart >= countEntries))
153  return false;
154 
155  if (m_bPlayAudioOnPageChange && !isRefresh && m_iCurrentPage != page)
156  {
157  if (page > m_iCurrentPage)
158  SCR_UISoundEntity.SoundEvent(m_sOnNextPageSfx, true);
159  else
160  SCR_UISoundEntity.SoundEvent(m_sOnPrevPageSfx, true);
161  }
162 
163  m_iCurrentPage = page;
164 
165  //--- Delete existing entries
166  while (m_ContentWidget.GetChildren())
167  {
168  m_ContentWidget.GetChildren().RemoveFromHierarchy();
169  }
170 
171  //--- Add new entries
172  ShowEntries(m_ContentWidget, indexStart, indexEnd);
173  bool hasContent = m_ContentWidget.GetChildren() != null;
174 
175  //--- Position entries in the grid
176  Widget focusedButton;
177  if (m_ContentWidget.GetTypeID() == WidgetType.UniformGridLayoutWidgetTypeID)
178  {
179  int row, column;
180  Widget child = m_ContentWidget.GetChildren();
181  while (child)
182  {
183  UniformGridSlot.SetRow(child, row);
184  UniformGridSlot.SetColumn(child, column);
185 
186  //--- Set navigation
187  if (column == 0 && m_sFocusPrevName)
188  child.SetNavigation(WidgetNavigationDirection.LEFT, WidgetNavigationRuleType.EXPLICIT, m_sFocusPrevName);
189 
190  if (column == m_iColumns - 1 && m_sFocusNextName)
191  child.SetNavigation(WidgetNavigationDirection.RIGHT, WidgetNavigationRuleType.EXPLICIT, m_sFocusNextName);
192 
193  //--- Find focused widget
194  if (row == focusedRow && column == focusedColumn)
195  focusedButton = SCR_WidgetTools.FindWidgetInChildren(child, WidgetType.ButtonWidgetTypeID);
196 
197  IterateIndex(row, column);
198  child = child.GetSibling();
199  }
200  //--- Fill the rest with empty layout
201  int minRows = m_iRows;
202  if (page == 0 && m_iMinRows >= 0)
203  minRows = Math.Max(m_iMinRows, row);
204 
205  int minColumns = m_iColumns;
206  if (page == 0 && m_iMinColumns >= 0)
207  minColumns = Math.Max(m_iMinColumns, row);
208 
209  Widget emptyWidget;
210  int emptyItemsCount = m_aEmptyItemLayouts.Count() - 1;
211  while (row < minRows && column < minColumns)
212  {
213  if (m_aEmptyItemLayouts.IsEmpty())
214  {
215  emptyWidget = GetGame().GetWorkspace().CreateWidget(WidgetType.ImageWidgetTypeID, WidgetFlags.VISIBLE | WidgetFlags.IGNORE_CURSOR | WidgetFlags.NOFOCUS, new Color(0, 0, 0, 0), 0, m_ContentWidget);
216  }
217  else
218  {
219  int index = Math.Min(row * m_iColumns + column, emptyItemsCount);
220  emptyWidget = GetGame().GetWorkspace().CreateWidgets(m_aEmptyItemLayouts[index], m_ContentWidget);
221  }
222 
223  UniformGridSlot.SetRow(emptyWidget, row);
224  UniformGridSlot.SetColumn(emptyWidget, column);
225 
226  IterateIndex(row, column);
227  }
228  }
229 
230  //--- No focus preserved, choose the first item
231  if (!focusedButton)
232  focusedButton = m_ContentWidget.GetChildren();
233 
234  //--- Set focus
235  if (focusedButton)
236  GetGame().GetWorkspace().SetFocusedWidget(focusedButton);
237 
238  /*
239  //--- Create dummy widget in bottom right cell to stretch the grid
240  WorkspaceWidget workspace = GetGame().GetWorkspace();
241  if (workspace)
242  {
243  Widget dummy = workspace.CreateWidget(WidgetType.ImageWidgetTypeID, WidgetFlags.VISIBLE | WidgetFlags.DISABLED, new Color(0, 0, 0, 0), 0, m_ContentWidget);
244  UniformGridSlot.SetRow(dummy, m_iRows - 1);
245  UniformGridSlot.SetColumn(dummy, m_iColumns - 1);
246  }*/
247 
248  //--- Update page number
249  if (m_PageNumberWidget)
250  {
251  if (countEntries == 0)
252  {
253  m_PageNumberWidget.SetVisible(false);
254  }
255  else
256  {
257  m_PageNumberWidget.SetTextFormat(m_sPageIndexVisualText, m_iCurrentPage + 1, totalPages);
258  m_PageNumberWidget.SetVisible(true);
259  }
260  }
261 
262  //--- Set prev/next button visibility
263  bool canLoop = m_bLoop && totalPages > 1;
264 
265  EnablePageButton(m_ButtonPrevWidget, canLoop || page > 0);
266  EnablePageButton(m_ButtonPrevNoScrollWidget, canLoop || page > 0);
267 
268  EnablePageButton(m_ButtonNextWidget, canLoop || page < totalPages - 1);
269  EnablePageButton(m_ButtonNextNoScrollWidget, canLoop || page < totalPages - 1);
270 
271  m_OnPageChanged.Invoke(page);
272 
273  return hasContent;
274  }
279  sealed bool RefreshPage()
280  {
281  return SetPage(m_iCurrentPage, true);
282  }
283  protected void IterateIndex(out int row, out int column)
284  {
285  column++;
286  if (column >= m_iColumns)
287  {
288  column = 0;
289  row++;
290  }
291  }
292  protected void EnablePageButton(Widget w, bool enable)
293  {
294  if (!w)
295  return;
296 
297  if (m_bHideArrowsIfDisabled)
298  {
299  w.SetOpacity(enable);
300  return;
301  }
302 
303  SCR_ButtonBaseComponent buttonComponent = SCR_ButtonBaseComponent.Cast(w.FindHandler(SCR_ButtonBaseComponent));
304 
305  if (buttonComponent)
306  buttonComponent.SetEnabled(enable);
307  else
308  w.SetEnabled(enable);
309  }
310  protected void OnButtonPrev()
311  {
312  if (m_bIgnoreGamePadInput && !GetGame().GetInputManager().IsUsingMouseAndKeyboard())
313  return;
314 
315  if (m_bUnderCursor && GetMenu().IsFocused())
316  SetPage(m_iCurrentPage - 1);
317 
318  }
319  protected void OnButtonNext()
320  {
321  if (m_bIgnoreGamePadInput && !GetGame().GetInputManager().IsUsingMouseAndKeyboard())
322  return;
323 
324  if (m_bUnderCursor && GetMenu().IsFocused())
325  SetPage(m_iCurrentPage + 1);
326  }
327 
328  protected void SetUnderCursor(bool newUnderCursor)
329  {
330  m_bUnderCursor = newUnderCursor;
331 
332  if (m_ButtonPrevNoScrollWidget && m_ButtonNextNoScrollWidget)
333  {
334  m_ButtonPrevWidget.SetVisible(m_bUnderCursor);
335  m_ButtonPrevNoScrollWidget.SetVisible(!m_bUnderCursor);
336 
337  m_ButtonNextWidget.SetVisible(m_bUnderCursor);
338  m_ButtonNextNoScrollWidget.SetVisible(!m_bUnderCursor);
339  }
340  }
341 
342  protected void OnInputDeviceIsGamepad(bool isGamepad)
343  {
344  //--- Always considered "under cursor" with gamepad
345  SetUnderCursor(isGamepad);
346  }
347 
348  override protected bool IsUnique()
349  {
350  return false;
351  }
352  override bool OnFocus(Widget w, int x, int y)
353  {
354  if (w == m_FocusPrevWidget)
355  {
356  m_FocusedIndex[1] = m_iColumns - 1; //--- Select rightmost item to preserve continuity
357  OnButtonPrev();
358  }
359  else if (w == m_FocusNextWidget)
360  {
361  m_FocusedIndex[1] = 0; //--- Select leftmost item to preserve continuity
362  OnButtonNext();
363  }
364  else
365  {
366  //--- Remember coordinates of selected item, so it can be restored when current page changes
367  while (w)
368  {
369  if (w.GetParent() == m_ContentWidget)
370  {
371  m_FocusedIndex[0] = UniformGridSlot.GetRow(w);
372  m_FocusedIndex[1] = UniformGridSlot.GetColumn(w);
373  break;
374  }
375  w = w.GetParent();
376  }
377  }
378 
379  return false;
380  }
381  override bool OnMouseEnter(Widget w, int x, int y)
382  {
383  if (m_bMustHoverOverContent)
384  {
385  //--- Hovering over prev/next buttons always counts
386  if (w == m_ButtonPrevWidget || w == m_ButtonNextWidget)// || (w == m_ButtonPrevNoScrollWidget && w != null) || (w == m_ButtonNextNoScrollWidget && w != null))
387  {
388  SetUnderCursor(true);
389  return false;
390  }
391 
392  //--- Considered under cursor only when hovering over content area
393  while (w)
394  {
395  if (w == m_ContentWidget)
396  {
397  SetUnderCursor(true);
398  break;
399  }
400  w = w.GetParent();
401  }
402  }
403  else
404  {
405  SetUnderCursor(true);
406  }
407  return false;
408  }
409  override bool OnMouseLeave(Widget w, Widget enterW, int x, int y)
410  {
411  SetUnderCursor(false);
412  return false;
413  }
414  override void HandlerAttached(Widget w)
415  {
416  super.HandlerAttached(w);
417 
418  if (SCR_Global.IsEditMode())
419  return;
420 
421  m_ContentWidget = w.FindAnyWidget(m_sContentName);
422 
423  m_PageNumberWidget = TextWidget.Cast(w.FindAnyWidget(m_sPageIndexVisualName));
424 
425  m_ButtonPrevWidget = w.FindAnyWidget(m_sButtonPrevName);
426  m_ButtonNextWidget = w.FindAnyWidget(m_sButtonNextName);
427 
428  m_ButtonPrevNoScrollWidget = w.FindAnyWidget(m_sButtonPrevName_NoScrolling);
429  m_ButtonNextNoScrollWidget = w.FindAnyWidget(m_sButtonNextName_NoScrolling);
430 
431  m_FocusPrevWidget = w.FindAnyWidget(m_sFocusPrevName);
432  m_FocusNextWidget = w.FindAnyWidget(m_sFocusNextName);
433 
434  if (m_bIgnoreGamePadInput)
435  {
436  if (m_FocusPrevWidget)
437  m_FocusPrevWidget.SetFlags(WidgetFlags.NOFOCUS);
438  if (m_FocusNextWidget)
439  m_FocusNextWidget.SetFlags(WidgetFlags.NOFOCUS);
440 
441  if (m_ButtonPrevWidget)
442  m_ButtonPrevWidget.SetFlags(WidgetFlags.NOFOCUS);
443  if (m_ButtonNextWidget)
444  m_ButtonNextWidget.SetFlags(WidgetFlags.NOFOCUS);
445 
446  if (m_ButtonPrevNoScrollWidget)
447  m_ButtonPrevNoScrollWidget.SetFlags(WidgetFlags.NOFOCUS);
448  if (m_ButtonNextNoScrollWidget)
449  m_ButtonNextNoScrollWidget.SetFlags(WidgetFlags.NOFOCUS);
450  }
451 
452  SCR_InputButtonComponent prevButtonComponent = SCR_InputButtonComponent.Cast(m_ButtonPrevWidget.FindHandler(SCR_InputButtonComponent));
453  if (prevButtonComponent)
454  prevButtonComponent.m_OnActivated.Insert(OnButtonPrev);
455  else
456  ButtonActionComponent.GetOnAction(m_ButtonPrevWidget, true).Insert(OnButtonPrev);
457 
458  SCR_InputButtonComponent nextButtonComponent = SCR_InputButtonComponent.Cast(m_ButtonNextWidget.FindHandler(SCR_InputButtonComponent));
459  if (nextButtonComponent)
460  nextButtonComponent.m_OnActivated.Insert(OnButtonNext);
461  else
462  ButtonActionComponent.GetOnAction(m_ButtonNextWidget, true).Insert(OnButtonNext);
463 
464  if (m_ButtonPrevNoScrollWidget)
465  {
466  prevButtonComponent = SCR_InputButtonComponent.Cast(m_ButtonPrevNoScrollWidget.FindHandler(SCR_InputButtonComponent));
467  if (prevButtonComponent)
468  prevButtonComponent.m_OnActivated.Insert(OnButtonPrev);
469  else
470  ButtonActionComponent.GetOnAction(m_ButtonPrevNoScrollWidget, true).Insert(OnButtonPrev);
471  }
472 
473  if (m_ButtonNextNoScrollWidget)
474  {
475  nextButtonComponent = SCR_InputButtonComponent.Cast(m_ButtonNextNoScrollWidget.FindHandler(SCR_InputButtonComponent));
476  if (nextButtonComponent)
477  nextButtonComponent.m_OnActivated.Insert(OnButtonNext);
478  else
479  ButtonActionComponent.GetOnAction(m_ButtonNextNoScrollWidget, true).Insert(OnButtonNext);
480  }
481 
482  OnInputDeviceIsGamepad(!GetGame().GetInputManager().IsUsingMouseAndKeyboard());
483  GetGame().OnInputDeviceIsGamepadInvoker().Insert(OnInputDeviceIsGamepad);
484 
485  SetPage(m_iCurrentPage, true);
486  }
487  override void HandlerDeattached(Widget w)
488  {
489  super.HandlerDeattached(w);
490 
492  GetGame().OnInputDeviceIsGamepadInvoker().Remove(OnInputDeviceIsGamepad);
493  }
494 };
SCR_BasePaginationUIComponent
Definition: SCR_BasePaginationUIComponent.c:1
SCR_WidgetTools
Definition: SCR_WidgetTools.c:1
m_iCurrentPage
protected int m_iCurrentPage
Definition: SCR_ContentBrowser_AddonsSubMenu.c:75
MenuRootSubComponent
Definition: MenuRootSubComponent.c:5
SCR_UISoundEntity
Definition: SCR_UISoundEntity.c:7
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
SCR_SoundEvent
Definition: SCR_SoundEvent.c:1
ShowEntries
override protected void ShowEntries(Widget contentWidget, int indexStart, int indexEnd)
Definition: SCR_ActionsToolbarEditorUIComponent.c:68
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
GetMenu
SCR_RadialMenu GetMenu()
Definition: SCR_RadialMenuGameModeComponent.c:41
Attribute
SCR_BasePaginationUIComponent Attribute
Post-process effect of scripted camera.
SCR_ButtonBaseComponent
Base class for any button, regardless its own content.
Definition: SCR_ButtonBaseComponent.c:3
ButtonActionComponent
Component to execute action when the button or its shortcut is pressed.
Definition: ButtonActionComponent.c:2
index
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
Definition: SCR_DestructionSynchronizationComponent.c:17
SCR_Global
Definition: Functions.c:6
GetInputManager
protected InputManager GetInputManager()
Definition: SCR_BaseManualCameraComponent.c:65
params
Configs ServerBrowser KickDialogs params
Definition: SCR_NotificationSenderComponent.c:24
OnInputDeviceIsGamepadInvoker
ScriptInvoker OnInputDeviceIsGamepadInvoker()
Definition: game.c:246
SCR_InputButtonComponent
Definition: SCR_InputButtonComponent.c:1