Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_PooledListComponent.c
Go to the documentation of this file.
1/*
2Pooled scrollable list that can endless simulate scrolling with only small amount of widgets.
3The component assumes two pages to be filled with entries, were Page 0 is by default on top of Page 1
4These pages are shuffled every time the scrolling is about to reach the top/bottom of a page, thus resulting in continuous scrolling.
5Size widgets above and below the pages are used to fill space and simulate the presence of other entries.
6Used with layout {611B71C627F5C61C}UI/layouts/WidgetLibraryExtended/ListView/WLib_PooledList.layout
7*/
8
9//------------------------------------------------------------------------------------------------
11{
12 // Entries
13 [Attribute("", UIWidgets.ResourceNamePicker, desc: "Entry widget that list is filled with.")]
15
16 // Animation effects attributes
17 [Attribute("1", UIWidgets.EditBox, desc: "Time for apearing animation")]
18 protected float m_fAnimationAppearTime;
19
20 [Attribute("20", UIWidgets.EditBox, desc: "How many entries should be created for single page")]
21 protected int m_iPageEntriesCount;
22
23 [Attribute("15", UIWidgets.EditBox, desc: "On which entry from border page should be changed")]
24 protected int m_iPageChangeOffset;
25
26 // Count of all entries in list
27 protected int m_iAllEntriesCount;
28
29 // Constant sizing
30 const float SIZE_UNMEASURED = -1;
31 const int CHECK_ENTRY_SIZE_DELAY = 100;
32
33 // Move offset when moving up in scroll layout
34 const float ENTRY_OFFSET_UP = 0.1;
35
36 // Constant content z orders
38 const int ZORDER_OFFSET_BOTTOM = 3;
39
40 // Constant idget names
41 const string WIDGET_PAGES = "VPages";
42 const string WIDGET_PAGE0 = "VPage0";
43 const string WIDGET_PAGE1 = "VPage1";
44
45 const string WIDGET_SCROLL_LAYOUT = "ScrollLayout";
46 const string WIDGET_SIZE_OFFSET_TOP = "SizeOffsetTop";
47 const string WIDGET_SIZE_OFFSET_BOTTOM = "SizeOffsetBottom";
48
49 const string WIDGET_FOCUS_REST = "FocusRest";
50
51 // Sizes
56
57 // Content widgets
59
61 protected Widget m_wPage0;
62 protected Widget m_wPage1;
63
68
70
71 protected ref array<Widget> m_aEntryWidgets = {};
72
75
76 // Pages switching
77 protected bool m_bPagesInverted;
78 protected int m_iCurrentPage;
79
80 // Scroll vars
81 protected float m_ScrollLastY;
82
83 // Focus
85
86 // Invokers
88
89 //-------------------------------------
90 // ScriptedWidgetComponent override
91 //-------------------------------------
92
93 //------------------------------------------------------------------------------------------------
94 override void HandlerAttached(Widget w)
95 {
96 super.HandlerAttached(w);
97
98 // Accessing handlers and widgets
100
102
103 SetupOffsets(0);
104 }
105
106 //-------------------------------------
107 // Input actions
108 //-------------------------------------
109 //------------------------------------------------------------------------------------------------
111 protected void OnActionUp()
112 {
113 if (!m_bIsListFocused)
114 return;
115
116 WorkspaceWidget workspace = GetGame().GetWorkspace();
117
118 if (m_wLastFocused)
119 workspace.SetFocusedWidget(m_wLastFocused);
120
121 if (m_fPagePxHeight == 0)
122 return;
123
124 float invisibleEntries = EntriesOutOfView();
125 if (invisibleEntries == 0)
126 return;
127
128 // Check current page
129 float scrollPageRatio = (m_iPageEntriesCount + ENTRY_OFFSET_UP) / invisibleEntries;
130 int currentPage = Math.Floor(m_ScrollLastY / scrollPageRatio);
131
132 if (m_iCurrentPage == currentPage)
133 return;
134
135 // Is focus on first entry of one of page
136 Widget focus = workspace.GetFocusedWidget();
137
138 if (focus != m_wPage0FirstEntry && focus != m_wPage1FirstEntry)
139 return;
140
141 // Switch pages
143
144 if (focus == m_wPage0FirstEntry)
145 workspace.SetFocusedWidget(m_wPage1LastEntry);
146 else if (focus == m_wPage1FirstEntry)
147 workspace.SetFocusedWidget(m_wPage0LastEntry);
148 }
149
150 //------------------------------------------------------------------------------------------------
152 protected void OnActionDown()
153 {
154 if (!m_bIsListFocused)
155 return;
156
157 WorkspaceWidget workspace = GetGame().GetWorkspace();
158
159 if (m_wLastFocused)
160 workspace.SetFocusedWidget(m_wLastFocused);
161 }
162
163 //------------------------------------------------------------------------------------------------
165 protected void OnScroll(float scrollY)
166 {
167 if (m_fPagePxHeight == 0)
168 return;
169
170 // Check if page is changed
171 int currentPage = CurrentPageFromScrollPos(scrollY);
172
173 if (m_iCurrentPage != currentPage)
174 SetCurrentPage(currentPage);
175 }
176
177 //------------------------------------------------------------------------------------------------
179 protected int CurrentPageFromScrollPos(float scrollY)
180 {
181 // Zero checks
182 if (m_iPageEntriesCount == 0)
183 return 0;
184
185 int entriesOutOfView = EntriesOutOfView();
186 if (entriesOutOfView == 0)
187 return 0;
188
189 // Ratio between entries in single page and entries out of view
190 float scrollPageRatio = m_iPageEntriesCount / entriesOutOfView;
191
192 // Check if page is changed
193 float pos = scrollY / scrollPageRatio;
194
195 // Moving up
197
198 //TODO: find out why moving down gets stuck
199
200 int currentPage = Math.Floor(pos);
201 if (currentPage < 0)
202 return 0;
203
204 return currentPage;
205 }
206
207 //------------------------------------------------------------------------------------------------
209 protected float EntriesOutOfView()
210 {
211 if (m_fPagePxHeight == 0)
212 return 0;
213
214 // What percent of whole list can bee seen
215 float pageViewRatio = m_fViewPxHeight / m_fPagePxHeight;
216 float outOfView = m_iAllEntriesCount - m_iPageEntriesCount * pageViewRatio;
217
218 if (outOfView < 0)
219 return 0;
220
221 return outOfView;
222 }
223
224 //-------------------------------------
225 // public functions
226 //-------------------------------------
227
228 //------------------------------------------------------------------------------------------------
230 void UpdateEntries(bool animated = false)
231 {
232 // Fill list with data
233 foreach (Widget w : m_aEntryWidgets)
234 {
235 if (w)
236 FillEntry(w);
237 }
238
240 }
241
242 //------------------------------------------------------------------------------------------------
245 {
246 WorkspaceWidget workspace = GetGame().GetWorkspace();
247 // Get scroll positions
248 float scrollX, scrollY = 0;
249 m_wScroll.GetSliderPos(scrollX, scrollY);
250
251 // Check if current focus is in list
253
254 if (focused)
255 m_wLastFocused = focused;
256
257 // Is list foucused - is current focus on list fallback widget or list entry?
258 Widget workspaceFocused = workspace.GetFocusedWidget();
259 m_bIsListFocused = (workspaceFocused == m_wLastFocused);
260 // Check scroll change
261 if (m_ScrollLastY == scrollY)
262 return;
263
264 OnScroll(scrollY);
265 m_ScrollLastY = scrollY;
266
267 // Check sizes
269 {
271 MoveToTop();
272 }
273 }
274
275 //------------------------------------------------------------------------------------------------
277 protected void SetCurrentPage(int page)
278 {
279 SetCurrentPageBase(page);
281 }
282
283 //------------------------------------------------------------------------------------------------
285 protected void SetCurrentPageBase(int page)
286 {
287 m_iCurrentPage = page;
288
289 // Check if pages are inverted to simulate scrolling
290 bool pagesInverted = (m_iCurrentPage % 2 != 0);
291
292 // Don't switch on last page
293 int lastPage = Math.Floor(m_iAllEntriesCount / m_iPageEntriesCount);
294
295 if (m_iCurrentPage >= lastPage - 1)
296 pagesInverted = false;
297
299 m_OnSetPage.Invoke(page);
300 }
301
302 //------------------------------------------------------------------------------------------------
304 protected void SwitchPages(bool invert, float size, int page)
305 {
306 // Check entries count
307 if (m_iAllEntriesCount == 0)
308 return;
309
310 // Check vertical list widgets
311 if (!m_wPage0 || !m_wPage1)
312 return;
313
314 // Save invert
315 m_bPagesInverted = invert;
316
317 // Check end of scrolling
318 int maxPages = Math.Floor(m_iAllEntriesCount / m_iPageEntriesCount);
319 if (page > maxPages - 1)
320 return;
321
322 SetupOffsets(page);
323
324 // Inverted order
325 m_wPage0.SetZOrder(invert);
326 m_wPage1.SetZOrder(!invert);
327 }
328
329 //------------------------------------------------------------------------------------------------
331 protected void SetupOffsets(int page)
332 {
333 int overflowEntryCount = m_iAllEntriesCount - m_iPageEntriesCount*2;
334 float offset = m_fEntryPxHeight * overflowEntryCount - m_fPagePxHeight * page;
335
336 // testing calculations
337 float pageSizeBaseOnEntry = m_fEntryPxHeight * m_iPageEntriesCount;
338
339 m_wSizeOffsetTop.SetHeightOverride(m_fPagePxHeight * page);
340 m_wSizeOffsetBottom.SetHeightOverride(offset);
341
344 }
345
346 //------------------------------------------------------------------------------------------------
349 {
350 // Get and check widget
351 Widget availableEntry = FirstAvailableEntry();
352 if (!availableEntry)
353 return;
354
355 // Focus
356 GetGame().GetWorkspace().SetFocusedWidget(null);
357 GetGame().GetWorkspace().SetFocusedWidget(availableEntry);
358 }
359
360 //------------------------------------------------------------------------------------------------
363 {
365 OnScroll(0);
366
367 m_bPagesInverted = false;
369
370 m_ScrollLastY = 0;
371 m_wScroll.SetSliderPos(0, 0);
372 }
373
374 //------------------------------------------------------------------------------------------------
376 void ShowScrollbar(bool show)
377 {
378 if (show)
379 {
380 m_wRoot.ClearFlags(WidgetFlags.CLIPCHILDREN);
381 m_wRoot.SetFlags(WidgetFlags.INHERIT_CLIPPING);
382 }
383 else
384 {
385 m_wRoot.SetFlags(WidgetFlags.CLIPCHILDREN);
386 m_wRoot.ClearFlags(WidgetFlags.INHERIT_CLIPPING);
387 }
388 }
389
390 //-------------------------------------
391 // protected functions
392 //-------------------------------------
393
394 //------------------------------------------------------------------------------------------------
396 protected void AccessingHandlers()
397 {
398 // Base scroll layout
400
401 // Find pages
402 m_wPagesWrap = m_wRoot.FindAnyWidget(WIDGET_PAGES);
403 m_wPage0 = m_wRoot.FindAnyWidget(WIDGET_PAGE0);
404 m_wPage1 = m_wRoot.FindAnyWidget(WIDGET_PAGE1);
405
406 // Find size offsets
409 }
410
411 //------------------------------------------------------------------------------------------------
421
422 //------------------------------------------------------------------------------------------------
424 protected void CreateEntriesWidgetsInPage(Widget parent, int count, out Widget firstEntry, out Widget lastEntry)
425 {
426 for (int i = 0; i < count; i++)
427 {
428 Widget entry = CreateEntry(parent);
429
430 // Assing first entry of page
431 if (i == 0)
432 firstEntry = entry;
433
434 // Assing last entry of page
435 if (i == count - 1)
436 lastEntry = entry;
437 }
438 }
439
440 //------------------------------------------------------------------------------------------------
442 protected Widget CreateEntry(Widget parent)
443 {
444 WorkspaceWidget workspace = GetGame().GetWorkspace();
445
446 if (!m_sEntry || !parent || !workspace)
447 return null;
448
449 Widget widget = workspace.CreateWidgets(m_sEntry, parent);
450 if (!widget)
451 return null;
452
453 // Setup widget entry behavior
454 SetupEntryBehavior(widget);
455
456 // Save in widget list
457 m_aEntryWidgets.Insert(widget);
458
459 return widget;
460 }
461
462 protected bool m_bIsMeasured = false;
463
464 //------------------------------------------------------------------------------------------------
466 protected void CheckEntrySize()
467 {
468 if (m_aEntryWidgets.IsEmpty())
469 return;
470
471 // Check widgets
472 if (!m_bIsMeasured)
473 {
474 ShowScrollbar(false);
475
476 // Entry height in px - with bottom padding
477 float x;
478 m_aEntryWidgets[0].GetScreenSize(x, m_fEntryPxHeight);
479
480 // Page height in px
481 m_wPage0.GetScreenSize(x, m_fPagePxHeight);
482
483 // Height of view int px - how much can user see in px
484 m_wRoot.GetScreenSize(x, m_fViewPxHeight);
485
486 // Check measures
487 if (m_fEntryPxHeight != 0)
488 {
489 m_bIsMeasured = true;
490 ShowScrollbar(true);
491
493 }
494 }
495
496 // Whole height size in px - cut last bottom padding
498 }
499
500 //------------------------------------------------------------------------------------------------
505 protected void SetupEntryBehavior(Widget entry) { }
506
507 //------------------------------------------------------------------------------------------------
512 protected void FillEntry(Widget w) {}
513
514 //------------------------------------------------------------------------------------------------
516 protected void AnimateEntryOpacity(Widget w, int delay, float animTime, float opacityEnd, float opacityStart = -1)
517 {
518 if (opacityStart != -1)
519 w.SetOpacity(opacityStart);
520
521 GetGame().GetCallqueue().CallLater(OpacityAnimation, delay, false, w, animTime, opacityEnd);
522 }
523
524 //------------------------------------------------------------------------------------------------
525 protected void OpacityAnimation(Widget w, int time, float opacityEnd)
526 {
527 AnimateWidget.Opacity(w, opacityEnd, time);
528 }
529
530 //------------------------------------------------------------------------------------------------
532 protected void ShowEntries(int dataCount)
533 {
534 // Show entries
535 for (int i = 0; i < m_aEntryWidgets.Count(); i++)
536 {
537 bool show = i < dataCount;
538 m_aEntryWidgets[i].SetVisible(show);
539 }
540
541 // Check if offsets needed
542 int overflow = dataCount - m_iPageEntriesCount*2;
543 bool addOffsets = overflow > 0;
544
545 // Set offstes visible if needed
546 m_wSizeOffsetTop.SetVisible(addOffsets);
547 m_wSizeOffsetBottom.SetVisible(addOffsets);
548
549 if (!addOffsets)
550 return;
551 }
552
553 //------------------------------------------------------------------------------------------------
556 {
557 Widget focused = GetGame().GetWorkspace().GetFocusedWidget();
558
559 int focusedEntryId = m_aEntryWidgets.Find(focused);
560
561 if (focusedEntryId == -1)
562 return null;
563
564 return focused;
565 }
566
567 //-------------------------------------
568 // Get & Set
569 //-------------------------------------
570 //------------------------------------------------------------------------------------------------
572 {
573 return m_iPageEntriesCount;
574 }
575
576 //------------------------------------------------------------------------------------------------
577 array<Widget> GetEntryWidgets()
578 {
579 return m_aEntryWidgets;
580 }
581
582 //------------------------------------------------------------------------------------------------
583 // Setup entries defaults and total count
584 void SetDataEntries(int entriesCount)
585 {
586 // Set data
587 m_iAllEntriesCount = entriesCount;
588
589 // Show entries
590 ShowEntries(entriesCount);
591
592 // Check sizes
593 GetGame().GetCallqueue().CallLater(CheckEntrySize, CHECK_ENTRY_SIZE_DELAY);
594 }
595
596 //------------------------------------------------------------------------------------------------
599 {
600 foreach (Widget entry : m_aEntryWidgets)
601 {
602 if (entry.IsVisible() && entry.IsEnabled())
603 return entry;
604 }
605
606 return null;
607 }
608
609 //------------------------------------------------------------------------------------------------
610 void SetIsListFocused(bool focused)
611 {
612 m_bIsListFocused = focused;
613 }
614
615 //------------------------------------------------------------------------------------------------
617 {
618 return m_bIsListFocused;
619 }
620
621 //------------------------------------------------------------------------------------------------
623 {
624 return m_wScroll;
625 }
626
627 //------------------------------------------------------------------------------------------------
629 {
630 if (!m_OnSetPage)
632
633 return m_OnSetPage;
634 }
635}
ArmaReforgerScripted GetGame()
Definition game.c:1398
int size
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
ScriptInvokerBase< ScriptInvokerIntMethod > ScriptInvokerInt
static WidgetAnimationOpacity Opacity(Widget widget, float targetValue, float speed, bool toggleVisibility=false)
Definition Math.c:13
void ShowEntries(int dataCount)
Display right entries with right position by scroll.
void MoveToTop()
Move list scroll to top.
void SetDataEntries(int entriesCount)
override void HandlerAttached(Widget w)
void SetCurrentPageBase(int page)
Base function for updating current page.
void ShowScrollbar(bool show)
Clip scroll bar to hide.
void SetupOffsets(int page)
Set sizes of top and bottom offsets.
void SwitchPages(bool invert, float size, int page)
Change order of list to fake endless scrolling.
void UpdateEntries(bool animated=false)
Fill entries with data.
void CreateEntriesWidgetsInPage(Widget parent, int count, out Widget firstEntry, out Widget lastEntry)
Create entries to selected page and assing first and last entries.
float EntriesOutOfView()
How many entries are of view - how many entries can be scrolled.
Widget FocusedWidgetFromEntryList()
Return if and which entry widget is actually focus.
void OnActionDown()
Call this when down action is activated.
void OpacityAnimation(Widget w, int time, float opacityEnd)
void UpdateScroll()
Update positions of pages and offsets.
int CurrentPageFromScrollPos(float scrollY)
Return current page from scroll position.
Widget FirstAvailableEntry()
Return first that is visible and enabled.
ref array< Widget > m_aEntryWidgets
void AnimateEntryOpacity(Widget w, int delay, float animTime, float opacityEnd, float opacityStart=-1)
Setup opacity animation.
void CreateEntriesWidgets()
Create server entries widget.
void SetCurrentPage(int page)
Set which page should be currently displayed.
void OnScroll(float scrollY)
Call this position of scroll is changed.
void OnActionUp()
Call this when up action is activated.
Widget CreateEntry(Widget parent)
Create entry to given page and setup it's behavior.
void SetupEntryBehavior(Widget entry)
void FocusFirstAvailableEntry()
Find first available entry and focus it.
void CheckEntrySize()
Get size of widget entry used in list.
void AccessingHandlers()
Get reference to all needed component for handling.
ref ScriptInvokerInt m_OnSetPage
SCR_FieldOfViewSettings Attribute
WidgetFlags
Widget flags. See enf::Widget::SetFlags().
Definition WidgetFlags.c:14