Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_ListViewComponent.c
Go to the documentation of this file.
1 /*
2 Scrollable list view with static count of entries.
3 */
4 
5 //------------------------------------------------------------------------------------------------
6 class SCR_ListViewComponent : ScriptedWidgetComponent
7 {
8  // Constant widget names
9  const string WIDGET_VERTICAL_LIST = "VList";
10  const string WIDGET_SIZE_SCROLL_OFFSET = "SizeScrollOffset";
11  const string WIDGET_FOCUS_REST = "BtnFocusRest";
12 
13  // Entries
14  [Attribute("", UIWidgets.ResourceNamePicker, desc: "Entry widget that list is filled with.")]
15  protected ResourceName m_sEntry;
16 
17  [Attribute("MouseWheel", UIWidgets.EditBox, desc: "Reference for scrolling action")]
18  protected string m_sScrollAction;
19 
20  // Entries properties
21  [Attribute("0", UIWidgets.CheckBox, desc: "True will automatically set entry limit value by list size and entry size")]
22  protected bool m_bAutomaticEntriesLimit;
23 
24  [Attribute("10", UIWidgets.EditBox, desc: "Number of item that should be crated to the list, that player is able to see in list")]
25  protected int m_iEntriesLimit;
26 
27  [Attribute("4", UIWidgets.EditBox, desc: "Space between each entry")]
28  protected int m_iEntriesBottomPadding;
29 
30  [Attribute("1", UIWidgets.EditBox, desc: "How many entries are move in one scroll")]
31  protected float m_fScrollMove;
32 
33  [Attribute("1", UIWidgets.EditBox, desc: "Time for apearing animation")]
34  protected float m_fAnimationAppearTime;
35 
36  // widgets
37  Widget m_wRoot;
38  protected Widget m_wVerticalList;
39  protected SizeLayoutWidget m_wSizeScrollOffset;
40  protected Widget m_wFocusRest;
41 
42  // Server entries data
43  protected ref array<Widget> m_aEntryWidgets = new array<Widget>;
44 
45  // Hadling conponents
46  protected SCR_ScrollBarComponent m_Scrollbar;
47 
48  // Scroll properties
49  protected float m_fScrollPosition = 0; // Whole number = entry id on top, decimal point = offset between whole step
50  protected float m_iLastScrollPosition = 0;
51  protected float m_iEntriesCount = 0;
52  protected float m_fEntryWidgetHeight;
53 
54  protected int m_iFocusedEntryId = 0;
55 
56  protected bool m_bIscrollActive;
57  protected bool m_bAnimateListAppearing;
58 
59  protected bool m_bCreateList = false;
60 
61  // Animations properties
62 
63  //-------------------------------------
64  // ScriptedWidgetComponent override
65  //-------------------------------------
66 
67  //------------------------------------------------------------------------------------------------
68  override void HandlerAttached(Widget w)
69  {
70  super.HandlerAttached(w);
71 
72  // Accessing handlers and widgets
73  m_wRoot = w;
74  AccessingHandlers();
75 
76  CreateEntriesWidgets();
77 
78  // Setup inputs invokers
79  GetGame().GetInputManager().AddActionListener("MenuDown", EActionTrigger.DOWN, OnMenuDown);
80  GetGame().GetInputManager().AddActionListener("MenuUp", EActionTrigger.DOWN, OnMenuUp);
81  }
82 
83  //------------------------------------------------------------------------------------------------
84  override bool OnUpdate(Widget w)
85  {
86  super.OnUpdate(w);
87 
88  if (m_bCreateList)
89  {
90  PostCheck();
91  //UpdateEntries();
92 
93  //m_bCreateList = false;
94  }
95 
96  return false;
97  }
98 
99  //-------------------------------------
100  // public functions
101  //-------------------------------------
102 
103  //------------------------------------------------------------------------------------------------
105  void UpdateEntries(bool animated = false)
106  {
107  m_bAnimateListAppearing = animated;
108 
109  // Fill list with data
110  foreach (Widget w : m_aEntryWidgets)
111  {
112  if (w)
113  FillEntry(w);
114  }
115 
116  // Hide scrollbar if list is not overfloating
117  float scrollsCount = ScrollableEntriesCount();
118  SetScrollbarVisible(scrollsCount != -1);
119  }
120 
121  //------------------------------------------------------------------------------------------------
122  void SetScrollbarVisible(bool visible)
123  {
124  if (m_Scrollbar)
125  m_Scrollbar.GetRootWidget().SetVisible(visible);
126  }
127 
128  //------------------------------------------------------------------------------------------------
130  void FocusFirstAvailableEntry()
131  {
132  // Get and check widget
133  Widget availableEntry = FirstAvailableEntry();
134  if (!availableEntry)
135  return;
136 
137  // Focus
138  GetGame().GetWorkspace().SetFocusedWidget(null);
139  GetGame().GetWorkspace().SetFocusedWidget(availableEntry);
140  }
141 
142  //-------------------------------------
143  // protected functions
144  //-------------------------------------
145 
146  //------------------------------------------------------------------------------------------------
148  protected void AccessingHandlers()
149  {
150  // Get Widgets
151  m_wVerticalList = m_wRoot.FindWidget(WIDGET_VERTICAL_LIST);
152  m_wSizeScrollOffset = SizeLayoutWidget.Cast(m_wRoot.FindAnyWidget(WIDGET_SIZE_SCROLL_OFFSET));
153  m_wFocusRest = m_wRoot.FindAnyWidget(WIDGET_FOCUS_REST);
154  }
155 
156  //------------------------------------------------------------------------------------------------
158  protected void CreateEntriesWidgets()
159  {
160  if(!m_wRoot || m_sEntry.IsEmpty())
161  return;
162 
163  // Create first entry
164  CreateEntry();
165  //m_bCreateList = true;
167 
168  // Allow create rest of entries
169 
170  //GetGame().GetCallqueue().CallLater(PostCheck, 500);
171 
172  // Auto calculate limit
173  /*if (m_bAutomaticEntriesLimit)
174  m_iEntriesLimit = CalculateLimit();*/
175 
176  // Create server entry widgets
177  for (int i = 1; i < m_iEntriesLimit; i++)
178  {
179  CreateEntry();
180  }
181 
182  // Focus on first entry
183  if(m_aEntryWidgets.Count() > 0)
184  GetGame().GetWorkspace().SetFocusedWidget(m_aEntryWidgets[0]);
185  }
186 
187  //------------------------------------------------------------------------------------------------
188  protected void PostCheck()
189  {
190  CheckEntrySize();
191 
192  // Check size
193  if (m_fEntryWidgetHeight == m_iEntriesBottomPadding)
194  return;
195 
196  int limitPrev = m_iEntriesLimit;
197 
198  // Auto calculate limit
199  if (m_bAutomaticEntriesLimit)
200  m_iEntriesLimit = CalculateLimit() + 1;
201 
202  // Remove widgets over limit
203  /*for (int i = limitPrev - 1; i > m_iEntriesLimit; i--)
204  {
205  m_aEntryWidgets[i].RemoveFromHierarchy();
206  m_aEntryWidgets.RemoveItem(m_aEntryWidgets[i]);
207  }*/
208 
209  for (int i = 0; i < m_iEntriesLimit; i++)
210  {
211  CreateEntry();
212  }
213 
214  m_bCreateList = false;
215 
216  // Focus on first entry
217  if(m_aEntryWidgets.Count() > 0)
218  GetGame().GetWorkspace().SetFocusedWidget(m_aEntryWidgets[0]);
219  }
220 
221  //------------------------------------------------------------------------------------------------
222  protected void CreateEntry()
223  {
224  WorkspaceWidget workspace = GetGame().GetWorkspace();
225 
226  if (!m_sEntry || !m_wVerticalList || !workspace)
227  return;
228 
229  Widget widget = workspace.CreateWidgets(m_sEntry, m_wVerticalList);
230  if (!widget)
231  return;
232 
233  // Setup widget entry behavior
234  SetupEntryBehavior(widget);
235 
236  // Save in widget list
237  m_aEntryWidgets.Insert(widget);
238 
239  // Set padding
240  VerticalLayoutSlot.SetPadding(widget, 0, 0, 0, m_iEntriesBottomPadding);
241 
242  // Visible in editor
243  widget.SetVisible(!GetGame().InPlayMode());
244  }
245 
246  //------------------------------------------------------------------------------------------------
248  protected int CalculateLimit()
249  {
250  float wrapHeight, x;
251  m_wVerticalList.GetScreenSize(x, wrapHeight);
252  int entryH = m_fEntryWidgetHeight + m_iEntriesBottomPadding;
253 
254  int res = Math.Ceil(wrapHeight / entryH);
255  return res;
256  }
257 
258  //------------------------------------------------------------------------------------------------
261  protected float EntryFractionFromViewPos(float viewPos, float scrollPos)
262  {
263  // Wrap
264  float wrapHeight, x;
265  m_wVerticalList.GetScreenSize(x, wrapHeight);
266 
267  // Entry
268  int entryH = m_fEntryWidgetHeight + m_iEntriesBottomPadding;
269 
270  float entriesLimit = wrapHeight / entryH;
271 
272  float entryFraction = (entriesLimit - Math.Floor(entriesLimit));
273  entriesLimit -= m_iEntriesBottomPadding*2 / m_fEntryWidgetHeight / entriesLimit;
274  //float scrollFracion = scrollPos
275 
276  return entryFraction;
277  }
278 
279  const int ENTRY_FIRST = 0;
280 
281  //------------------------------------------------------------------------------------------------
283  protected void CheckEntrySize()
284  {
285  if (m_iEntriesLimit > ENTRY_FIRST)
286  {
287  float x;
288  m_aEntryWidgets[ENTRY_FIRST].GetScreenSize(x, m_fEntryWidgetHeight);
289  m_fEntryWidgetHeight += m_iEntriesBottomPadding;
290  }
291  }
292 
293  //------------------------------------------------------------------------------------------------
296  protected void SetupEntryBehavior(Widget entry) { }
297 
298  //------------------------------------------------------------------------------------------------
301  protected void FillEntry(Widget w) {}
302 
303  //------------------------------------------------------------------------------------------------
305  protected void ScrollOffsetMove(float scrollPos)
306  {
307  // Check first entry height if = 0
308  if (m_fEntryWidgetHeight == 0)
309  CheckEntrySize();
310 
311  // Get offset from scroll position
312  float scrollsCount = ScrollableEntriesCount();
313 
314  // Prevent scroll if there are no entries to scroll
315  if (scrollsCount == -1)
316  return;
317 
318  scrollPos *= scrollsCount;
319  float offset = scrollPos - Math.Floor(scrollPos);
320  offset = offset * m_fEntryWidgetHeight;
321 
322  // Move list if offset is overflown
323  if (m_iLastScrollPosition != Math.Floor(scrollPos))
324  {
325  m_iLastScrollPosition = Math.Floor(scrollPos);
326  UpdateEntries();
327  }
328 
329  // Move list offset
330  m_wSizeScrollOffset.SetHeightOverride(-offset);
331 
332  // Save scroll position
333  m_fScrollPosition = scrollPos;
334  }
335 
336  //------------------------------------------------------------------------------------------------
338  protected void ScrollWheelMove()
339  {
340  if (!m_bIscrollActive)
341  return;
342 
343  // Check scroll input value
344  float scrollDir = GetGame().GetInputManager().GetActionValue(m_sScrollAction);
345  scrollDir = Math.Clamp(scrollDir, -1, 1);
346 
347  // Scroll if any move
348  if (scrollDir != 0)
349  {
350  ScrollList(m_fScrollMove, -scrollDir);
351 
352  StayOnLastEntry();
353  }
354 
355  // Repeat scrolling
356  GetGame().GetCallqueue().CallLater(ScrollWheelMove, 0);
357  }
358 
359  //------------------------------------------------------------------------------------------------
361  protected void StayOnLastEntry()
362  {
363  int focusedIdInList = m_iFocusedEntryId - Math.Floor(m_fScrollPosition);
364 
365  if (focusedIdInList > -1 && focusedIdInList < m_aEntryWidgets.Count())
366  ChangeFocusWithoutAnimation(m_aEntryWidgets[focusedIdInList]);
367  else
368  GetGame().GetWorkspace().SetFocusedWidget(m_wFocusRest);
369  }
370 
371  //------------------------------------------------------------------------------------------------
372  protected void ScrollList(float step, float input)
373  {
374  float scrollsCount = ScrollableEntriesCount();
375  float move = 0;
376 
377  if (m_bIscrollActive)
378  {
379  move = ScrollMove(step, input);
380  ScrollOffsetMove(move);
381 
382  // Update scroll position
383  m_fScrollPosition = move * scrollsCount;
384  }
385 
386  if (m_Scrollbar)
387  m_Scrollbar.MoveHandlerPos(move);
388  }
389 
390  //------------------------------------------------------------------------------------------------
391  protected float ScrollMove(float step, float inputMove)
392  {
393  float scrollsCount = ScrollableEntriesCount();
394 
395  float pos = step / scrollsCount * inputMove;
396 
397  // Move scrollbar
398  pos += m_fScrollPosition / scrollsCount;
399  pos = Math.Clamp(pos, 0, 1);
400 
401  return pos;
402  }
403 
404  //------------------------------------------------------------------------------------------------
405  protected void ChangeFocusWithoutAnimation(Widget w)
406  {
407  // Unfocus previous
408  Widget focused = GetGame().GetWorkspace().GetFocusedWidget();
409 
410  if (focused)
411  {
412  SCR_ButtonBaseComponent prevBtn = SCR_ButtonBaseComponent.Cast(focused.FindHandler(SCR_ButtonBaseComponent));
413  if (prevBtn)
414  prevBtn.ShowBorder(false, false);
415  }
416 
417  // Focus next
418  GetGame().GetWorkspace().SetFocusedWidget(w);
420  if (nextBtn)
421  {
422  nextBtn.ShowBorder(true, false);
423  AnimateWidget.StopAnimation(nextBtn.m_wBorder, WidgetAnimationOpacity);
424  nextBtn.m_wBorder.SetOpacity(1);
425  }
426  }
427 
428  //------------------------------------------------------------------------------------------------
430  protected void AnimateEntryOpacity(Widget w, int delay, float animTime, float opacityEnd, float opacityStart = -1)
431  {
432  if (opacityStart != -1)
433  w.SetOpacity(opacityStart);
434 
435  GetGame().GetCallqueue().CallLater(OpacityAnimation, delay, false, w, animTime, opacityEnd);
436  }
437 
438  //------------------------------------------------------------------------------------------------
439  protected void OpacityAnimation(Widget w, int time, float opacityEnd)
440  {
441  AnimateWidget.Opacity(w, opacityEnd, time);
442  }
443 
444  //------------------------------------------------------------------------------------------------
446  protected void ClearServerList()
447  {
448  // Remove widgets
449  foreach (Widget entry : m_aEntryWidgets)
450  {
451  entry.RemoveFromHierarchy();
452  }
453 
454  // Clear list
455  m_aEntryWidgets.Clear();
456  }
457 
458  //------------------------------------------------------------------------------------------------
461  /*protected void SteppingOutside(int next)
462  {
463  int nextClampped = m_iFocusedEntryId - Math.Floor(m_fScrollPosition) + next;
464 
465  // Settping down to next hidden
466  if (nextClampped > m_iEntriesLimit)
467  {
468  GetGame().GetWorkspace().SetFocusedWidget(m_aEntryWidgets[m_iEntriesLimit - 1]);
469  }
470 
471  // Stepping up to next hidden
472  if (nextClampped < 1)
473  {
474  GetGame().GetWorkspace().SetFocusedWidget(m_aEntryWidgets[0]);
475  }
476  }*/
477 
478  //------------------------------------------------------------------------------------------------
480  protected void OnMenuDown()
481  {
482  // Check room coount boundary
483  if (m_iFocusedEntryId >= m_iEntriesCount - 1)
484  return;
485 
486  // Move focus
487  m_iFocusedEntryId++;
488  int nextClampped = m_iFocusedEntryId - Math.Ceil(m_fScrollPosition);
489  int limit = m_iEntriesLimit - 1;
490 
491 
492  // Settping down to next hidden
493  if (nextClampped >= limit)
494  {
495  float scrollStep = EntryFractionFromViewPos(1, 0);
496  Print("scrollStep: " + scrollStep);
497  ScrollList(scrollStep, 1);
498  GetGame().GetWorkspace().SetFocusedWidget(m_aEntryWidgets[limit - 1]);
499  }
500  }
501 
502  //------------------------------------------------------------------------------------------------//------------------------------------------------------------------------------------------------
504  protected void OnMenuUp()
505  {
506  // Check 0
507  if (m_iFocusedEntryId < 1)
508  return;
509 
510  // Move focus
511  m_iFocusedEntryId--;
512  int nextClampped = m_iFocusedEntryId - Math.Floor(m_fScrollPosition) - 1;
513 
514  // Settping down to next hidden
515  if (nextClampped < 1)
516  {
517  ScrollList(1, -1);
518  GetGame().GetWorkspace().SetFocusedWidget(m_aEntryWidgets[0]);
519  }
520  }
521 
522  //-------------------------------------
523  // Get & Set
524  //-------------------------------------
525 
526  //------------------------------------------------------------------------------------------------
527  void SetScrollbar(SCR_ScrollBarComponent scrollbar)
528  {
529  // Check and assign
530  if (!scrollbar)
531  return;
532 
533  m_Scrollbar = scrollbar;
534 
535  UpdateScrollbar();
536 
537  // Invoker
538  m_Scrollbar.m_OnScroll.Insert(ScrollOffsetMove);
539  }
540 
541  //------------------------------------------------------------------------------------------------
543  void ActivateScrolling(bool activate)
544  {
545  m_bIscrollActive = activate;
546 
547  // Start scrolling update
548  if (m_bIscrollActive)
549  ScrollWheelMove();
550  }
551 
552  //------------------------------------------------------------------------------------------------
553  void UpdateScrollbar()
554  {
555  if (!m_Scrollbar || m_iEntriesCount < 1)
556  return;
557 
558  float fillAmount = m_iEntriesLimit / m_iEntriesCount;
559  m_Scrollbar.SetupHandlerFill(fillAmount);
560  }
561 
562  //------------------------------------------------------------------------------------------------
563  array<Widget> GetEntryWidgets() { return m_aEntryWidgets; }
564 
565  //------------------------------------------------------------------------------------------------\
566  float ScrollableEntriesCount()
568  {
569  float dif = m_iEntriesCount - m_iEntriesLimit;
570 
571  // No entries check
572  if (dif <= 0)
573  return -1;
574 
575  return dif;
576  }
577 
578  //------------------------------------------------------------------------------------------------
580  Widget FirstAvailableEntry()
581  {
582  foreach (Widget entry : m_aEntryWidgets)
583  {
584  if (entry.IsVisible() && entry.IsEnabled())
585  return entry;
586  }
587 
588  return null;
589  }
590 };
m_wRoot
protected Widget m_wRoot
Definition: SCR_ScenarioFrameworkLayerTaskDefend.c:59
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
SCR_ListViewComponent
Definition: SCR_ListViewComponent.c:6
SCR_ScrollBarComponent
Definition: SCR_ScrollBarComponent.c:5
Attribute
typedef Attribute
Post-process effect of scripted camera.
SCR_ButtonBaseComponent
Base class for any button, regardless its own content.
Definition: SCR_ButtonBaseComponent.c:3