3 protected TextWidget m_wMenuTitle;
4 protected VerticalLayoutWidget m_wMenuCategoryList;
8 protected Widget m_wReadingWidget;
10 protected TextWidget m_wPageEntryTitle;
11 protected Widget m_wPageFrame;
12 protected ScrollLayoutWidget m_wGridScrollLayoutWidget;
13 protected GridLayoutWidget m_wMenuGridLayout;
15 protected string m_sLastSearch;
18 protected ref array<ref SCR_FieldManualConfigEntry> m_aAllEntries;
19 protected ref map<Widget, ref SCR_FieldManualConfigEntry> m_mWidgetEntryMap;
20 protected ref map<Widget, ref SCR_FieldManualConfigCategory> m_mWidgetSubCategoryMap;
23 protected Widget m_wLastClickedSubCategory;
27 protected ButtonWidget m_wFirstSubCategoryButton;
29 protected bool m_bIsInEntryViewMode;
30 protected bool m_bIsInSearchMode;
31 protected bool m_bOpenedFromOutside;
33 protected bool m_bArmaWarning;
35 protected static const int TILES_GRID_WIDTH = 5;
36 protected static const string SEARCH_RESULT_KEY =
"#AR-FieldManual_SearchResult";
37 protected static const string SEARCH_NO_RESULT_KEY =
"#AR-FieldManual_SearchResult_None";
38 protected static const string SCROLL_NAME =
"mainScroll";
39 protected static const int ENTRY_INPUT_REFRESH_DELAY = 500;
40 protected static const int ENTRY_SCROLL_INPUT_REFRESH_DELAY = 1000 / 60;
43 protected override void OnMenuOpen()
51 Print(
"No config component found | " + __FILE__ +
": " + __LINE__, LogLevel.WARNING);
59 Print(
"Could not load provided config | " + __FILE__ +
": " + __LINE__, LogLevel.WARNING);
64 m_ConfigRoot = configRoot;
65 SetAllEntriesAndParents();
68 bool isMainMenu =
GetGame().m_bIsMainMenuOpen;
70 Widget backgroundImage =
GetRootWidget().FindAnyWidget(
"MenuBackground");
71 if (blur && isMainMenu)
72 blur.RemoveFromHierarchy();
74 if (backgroundImage && !isMainMenu)
75 backgroundImage.RemoveFromHierarchy();
77 Widget menuFrame = rootWidget.FindAnyWidget(
"MenuFrame");
78 TextWidget menuTitle = TextWidget.Cast(menuFrame.FindAnyWidget(
"Title"));
79 VerticalLayoutWidget menuCategoryList = VerticalLayoutWidget.Cast(rootWidget.FindAnyWidget(
"CategoryList"));
80 GridLayoutWidget menuGridLayout = GridLayoutWidget.Cast(rootWidget.FindAnyWidget(
"GridLayout"));
81 if (!menuFrame || !menuTitle || !menuCategoryList || !menuGridLayout)
83 Print(
"Important elements (menu frame & title, category list, grid layout) are missing | " + __FILE__ +
": " + __LINE__, LogLevel.WARNING);
88 Widget readingWidget = rootWidget.FindAnyWidget(
"ReadingWidget");
90 TextWidget entryTitle = TextWidget.Cast(readingWidget.FindAnyWidget(
"EntryTitle"));
91 Widget entryFrame = readingWidget.FindAnyWidget(
"EntryFrame");
92 if (!readingWidget || !entryTitle || !entryFrame)
94 Print(
string.Format(
"missing one: reading widget (%1), entryTitle (%2), entryFrame (%3) | " + FilePath.StripPath(__FILE__) +
":" + __LINE__, readingWidget !=
null, entryTitle !=
null, entryFrame !=
null), LogLevel.WARNING);
100 if (!backButtonMenuFrame || !backButtonMenuFrame.m_OnClicked)
102 Print(
string.Format(
"missing menu frame's back button menu (%1) or m_OnClicked (%2) | " + FilePath.StripPath(__FILE__) +
":" + __LINE__, backButtonMenuFrame !=
null, backButtonMenuFrame.m_OnClicked !=
null), LogLevel.WARNING);
107 m_MenuBtnBack = backButtonMenuFrame;
109 m_wMenuTitle = menuTitle;
110 m_wMenuCategoryList = menuCategoryList;
111 m_wMenuGridLayout = menuGridLayout;
113 m_wReadingWidget = readingWidget;
114 m_wPageEntryTitle = entryTitle;
115 m_wPageFrame = entryFrame;
121 m_wGridScrollLayoutWidget = ScrollLayoutWidget.Cast(rootWidget.FindAnyWidget(
"GridScrollLayout"));
125 if (m_MenuSearchbar && m_MenuSearchbar.m_OnConfirm)
126 m_MenuSearchbar.m_OnConfirm.Insert(ProcessSearch);
128 m_MenuBtnBack.m_OnActivated.Insert(CloseMenuOrReadingPanel);
131 InputManager inputManager =
GetGame().GetInputManager();
134 inputManager.AddActionListener(
"MenuOpenWB", EActionTrigger.DOWN, CloseMenuOrReadingPanel);
135 inputManager.AddActionListener(
"MenuBackWB", EActionTrigger.DOWN, CloseMenuOrReadingPanel);
144 protected override void OnMenuShow()
148 CreateCategoryMenuWidgets();
150 OpenFirstSubCategory();
159 InputManager inputManager =
GetGame().GetInputManager();
162 inputManager.RemoveActionListener(
"MenuOpenWB", EActionTrigger.DOWN, CloseMenuOrReadingPanel);
163 inputManager.RemoveActionListener(
"MenuBackWB", EActionTrigger.DOWN, CloseMenuOrReadingPanel);
170 void OnSubCategoryClicked(Widget w)
172 bool resetTiles = m_bIsInSearchMode || m_bIsInEntryViewMode || w != m_wLastClickedSubCategory;
173 m_bIsInSearchMode =
false;
174 m_wLastClickedSubCategory = w;
183 void OnTileClicked(Widget w)
185 m_bIsInSearchMode =
false;
186 SetCurrentEntryByWidget(w);
188 if (m_wLastClickedSubCategory)
189 GetGame().GetWorkspace().SetFocusedWidget(m_wLastClickedSubCategory);
196 Widget createdWidget =
GetGame().GetWorkspace().CreateWidgets(m_ConfigRoot.m_MenuEntryTileLayout, parent);
199 Print(
"could not create tile widget for entry | " + FilePath.StripPath(__FILE__) +
":" + __LINE__, LogLevel.WARNING);
203 Widget assetImage = createdWidget.FindAnyWidget(
"AssetImage");
206 ImageWidget backgroundImageWidget = ImageWidget.Cast(createdWidget.FindAnyWidget(
"FullBackground"));
207 if (backgroundImageWidget && m_ConfigRoot.m_aTileBackgrounds && !m_ConfigRoot.m_aTileBackgrounds.IsEmpty())
208 backgroundImageWidget.LoadImageTexture(0, m_ConfigRoot.m_aTileBackgrounds.GetRandomElement());
210 ImageWidget imageWidget = ImageWidget.Cast(assetImage.FindAnyWidget(
"Image"));
213 if (!entry.m_Image.IsEmpty())
214 imageWidget.LoadImageTexture(0, entry.m_Image);
216 imageWidget.SetVisible(
false);
220 Widget assetInfo = createdWidget.FindAnyWidget(
"AssetInfo");
223 TextWidget textWidget = TextWidget.Cast(assetInfo.FindAnyWidget(
"EntityName"));
225 textWidget.SetText(entry.m_sTitle);
228 return createdWidget;
234 protected void SetTilesByWidget(Widget widget)
241 if (m_BreadCrumbsComponent && subCategory.m_Parent)
242 m_BreadCrumbsComponent.Set(subCategory.m_Parent.m_sTitle, subCategory.m_sTitle);
244 SetTiles(subCategory.m_aEntries);
249 protected void SetTiles(array<ref SCR_FieldManualConfigEntry> entries)
251 if (!m_wMenuGridLayout)
256 if (!entries || entries.IsEmpty())
259 m_mWidgetEntryMap.Clear();
266 assetCard = CreateTileWidget(entry, m_wMenuGridLayout);
270 GridSlot.SetColumn(assetCard, column);
271 GridSlot.SetRow(assetCard, line);
274 if (column >= TILES_GRID_WIDTH)
280 button = ButtonWidget.Cast(
SCR_WidgetHelper.GetWidgetOrChild(assetCard,
"AssetCard0"));
283 button.AddHandler(m_EntryButtonEventHandler);
284 m_mWidgetEntryMap.Insert(button, entry);
288 if (m_wGridScrollLayoutWidget)
289 m_wGridScrollLayoutWidget.SetSliderPos(0, 0);
296 if (!m_wPageFrame || !m_wPageEntryTitle)
301 m_bIsInEntryViewMode = entry !=
null;
303 m_wGridScrollLayoutWidget.SetVisible(!m_bIsInEntryViewMode);
304 m_wReadingWidget.SetVisible(m_bIsInEntryViewMode);
306 if (!m_bIsInEntryViewMode)
308 if (m_BreadCrumbsComponent && m_CurrentEntry && m_CurrentEntry.m_Parent && m_CurrentEntry.m_Parent.m_Parent)
309 m_BreadCrumbsComponent.Set(m_CurrentEntry.m_Parent.m_Parent.m_sTitle, m_CurrentEntry.m_Parent.m_sTitle);
311 m_CurrentEntry =
null;
315 if (m_BreadCrumbsComponent && entry.m_Parent && entry.m_Parent.m_Parent)
316 m_BreadCrumbsComponent.Set(entry.m_Parent.m_Parent.m_sTitle, entry.m_Parent.m_sTitle, entry.m_sTitle);
318 m_CurrentEntry = entry;
320 m_wPageEntryTitle.SetText(entry.m_sTitle);
333 Widget readingWidget = entry.CreateWidget(m_wPageFrame);
336 FillEntry_Weapon(readingWidget, weaponEntry);
341 protected void QueueRefreshCurrentEntry()
343 if (!m_CurrentEntry || !m_CurrentEntry.CanRefresh())
347 GetGame().GetCallqueue().Remove(RefreshCurrentEntry);
348 GetGame().GetCallqueue().CallLater(RefreshCurrentEntry, ENTRY_INPUT_REFRESH_DELAY,
false);
353 protected void RefreshCurrentEntry()
355 if (!m_CurrentEntry.CanRefresh())
359 ScrollLayoutWidget scroll = ScrollLayoutWidget.Cast(m_wPageFrame.FindWidget(SCROLL_NAME));
361 scroll.GetSliderPos(x, y);
363 SetCurrentEntry(m_CurrentEntry);
368 scroll = ScrollLayoutWidget.Cast(m_wPageFrame.FindWidget(SCROLL_NAME));
370 SetScrollAfterRefresh(scroll, x, y);
374 protected void SetScrollAfterRefresh(notnull ScrollLayoutWidget scroll,
float x,
float y)
377 scroll.GetScreenSize(w, h);
380 GetGame().GetCallqueue().CallLater(SetScrollAfterRefresh, ENTRY_SCROLL_INPUT_REFRESH_DELAY,
false, scroll, x, y);
384 GetGame().GetCallqueue().Remove(SetScrollAfterRefresh);
385 scroll.SetSliderPos(x, y);
396 SetCurrentEntry(
null);
402 if (entry.m_eId == entryId)
404 m_bOpenedFromOutside =
true;
405 SetCurrentEntry(entry);
410 SetCurrentEntry(
null);
415 protected void SetCurrentEntryByWidget(Widget widget)
421 SetCurrentEntry(entry);
427 Widget weaponRender = widget.FindAnyWidget(
"weaponRender");
428 if (
true || !FillEntry_Weapon_Render(RenderTargetWidget.Cast(weaponRender), entry.m_sWeaponEntityPath))
430 weaponRender.RemoveFromHierarchy();
432 FillEntry_Weapon_Statistics(widget.FindAnyWidget(
"statsLayout"), entry);
436 protected bool FillEntry_Weapon_Render(RenderTargetWidget renderTarget, ResourceName weaponResourceName)
438 if (!renderTarget || !weaponResourceName)
441 Resource resource = Resource.Load(weaponResourceName);
442 IEntity entity =
GetGame().SpawnEntityPrefabLocal(resource,
null,
null);
450 ItemPreviewManagerEntity manager = world.GetItemPreviewManager();
458 manager.SetPreviewItem(renderPreview, entity);
469 if (!weaponStatsHelper)
475 FillEntry_Weapon_Statistics_Mass(statsLayout, weaponStatsHelper);
476 FillEntry_Weapon_Statistics_SightAdjustments(statsLayout, weaponStatsHelper);
477 FillEntry_Weapon_Statistics_DefaultSightAdjustment(statsLayout, weaponStatsHelper);
478 FillEntry_Weapon_Statistics_RateOfFire(statsLayout, weaponStatsHelper);
479 FillEntry_Weapon_Statistics_MuzzleVelocity(statsLayout, weaponStatsHelper);
480 FillEntry_Weapon_Statistics_FireModes(statsLayout, weaponStatsHelper);
490 float mass = weaponStatsHelper.GetMass();
492 statsMass.RemoveWidgetFromHierarchy();
494 statsMass.SetTranslatedValue(
"#AR-ValueUnit_Short_Kilograms", mass.ToString(-1, 2));
501 if (!statsSightAdjustments)
504 array<int> sightDistanceSettings = weaponStatsHelper.GetSightDistanceSettings();
505 if (!sightDistanceSettings || sightDistanceSettings.IsEmpty())
507 statsSightAdjustments.RemoveWidgetFromHierarchy();
511 array<string> settingsStr = {};
512 foreach (
int sightDistanceSetting : sightDistanceSettings)
514 settingsStr.Insert(WidgetManager.Translate(
"#AR-ValueUnit_Short_Meters", sightDistanceSetting));
517 statsSightAdjustments.SetValue(ArrayJoin(settingsStr));
524 if (!statsDefaultSightAdjustment)
527 int defaultSightDistanceSetting = weaponStatsHelper.GetDefaultSightDistanceSetting();
528 if (defaultSightDistanceSetting < 0)
529 statsDefaultSightAdjustment.RemoveWidgetFromHierarchy();
531 statsDefaultSightAdjustment.SetTranslatedValue(
"#AR-ValueUnit_Short_Meters", defaultSightDistanceSetting.ToString());
538 if (!statsRateOfFire)
541 if (weaponStatsHelper.GetRateOfFire() < 1)
542 statsRateOfFire.RemoveWidgetFromHierarchy();
544 statsRateOfFire.SetTranslatedValue(
"#AR-ValueUnit_Short_RoundsPerMinute", weaponStatsHelper.GetRateOfFire().ToString());
551 if (!statsMuzzleVelocity)
554 if (weaponStatsHelper.m_iMuzzleVelocity < 1)
555 statsMuzzleVelocity.RemoveWidgetFromHierarchy();
557 statsMuzzleVelocity.SetTranslatedValue(
"#AR-ValueUnit_Short_MetersPerSeconds", weaponStatsHelper.m_iMuzzleVelocity.ToString());
567 array<string> fireModes = weaponStatsHelper.GetFireModes();
568 if (!fireModes || fireModes.IsEmpty())
569 statsFireModes.RemoveWidgetFromHierarchy();
571 statsFireModes.SetValue(ArrayJoin(fireModes));
577 protected void SetAllEntriesAndParents()
579 m_aAllEntries.Clear();
580 array<SCR_FieldManualConfigCategory> categoriesToRemove = {};
581 array<SCR_FieldManualConfigCategory> subCategoriesToRemove = {};
582 array<SCR_FieldManualConfigEntry> entriesToRemove = {};
587 categoriesToRemove.Insert(
category);
591 subCategoriesToRemove.Clear();
594 if (!subCategory.m_bEnabled)
596 subCategoriesToRemove.Insert(subCategory);
600 entriesToRemove.Clear();
603 if (!entry.m_bEnabled || entry.m_aContent.IsEmpty())
605 entriesToRemove.Insert(entry);
609 entry.m_Parent = subCategory;
610 m_aAllEntries.Insert(entry);
615 subCategory.m_aEntries.RemoveItemOrdered(entry);
618 if (subCategory.m_aEntries.IsEmpty() && subCategory.m_aCategories.IsEmpty())
620 subCategoriesToRemove.Insert(subCategory);
629 category.m_aCategories.RemoveItemOrdered(subCategory);
633 categoriesToRemove.Insert(
category);
638 m_ConfigRoot.m_aCategories.RemoveItemOrdered(
category);
644 protected void CreateCategoryMenuWidgets()
646 if (!m_ConfigRoot || !m_ConfigRoot.m_aCategories || !m_wMenuCategoryList)
649 m_wFirstSubCategoryButton =
null;
650 m_mWidgetSubCategoryMap.Clear();
654 m_wMenuTitle.SetText(m_ConfigRoot.m_sTitle);
656 Widget subCategoryWidget;
660 category.CreateWidget(m_wMenuCategoryList);
664 subCategoryWidget = subCategory.CreateWidget(m_wMenuCategoryList);
665 button = ButtonWidget.Cast(subCategoryWidget);
668 button.AddHandler(m_SubCategoryButtonEventHandler);
669 m_mWidgetSubCategoryMap.Insert(button, subCategory);
671 if (!m_wFirstSubCategoryButton)
672 m_wFirstSubCategoryButton = button;
680 protected void OpenFirstSubCategory()
682 OnSubCategoryClicked(m_wFirstSubCategoryButton);
683 GetGame().GetCallqueue().CallLater(
GetGame().GetWorkspace().SetFocusedWidget, 0,
false, m_wFirstSubCategoryButton,
false);
689 protected void ResetLastSearch()
691 m_sLastSearch =
string.Empty;
698 search = search.Trim();
700 if (search.IsEmpty())
711 if (!m_bArmaWarning && search.Contains(
"ArmA"))
713 m_bArmaWarning =
true;
715 if (m_BreadCrumbsComponent)
716 m_BreadCrumbsComponent.Set(
"#AR-FieldManual_Page_EasterEgg_ArmA_BreadCrumbs");
719 ArmaEntry.m_sTitle =
"#AR-FieldManual_Page_EasterEgg_ArmA_Title";
721 ArmaPiece.m_sText =
"#AR-FieldManual_Page_EasterEgg_ArmA_Text";
722 ArmaEntry.m_aContent.Insert(ArmaPiece);
723 SetCurrentEntry(ArmaEntry);
725 EditBoxWidget searchEditBox = EditBoxWidget.Cast(
GetRootWidget().FindAnyWidget(
"Searchbar").FindAnyWidget(
"EditBox"));
726 string searchText = searchEditBox.GetText();
727 searchText.Replace(
"ArmA",
"Arma");
728 searchEditBox.SetText(searchText);
735 m_bIsInSearchMode =
true;
737 string originalSearch = search;
739 if (search == m_sLastSearch)
742 m_sLastSearch = search;
744 array<ref SCR_FieldManualConfigEntry> entries = {};
746 if (!m_sLastSearch.IsEmpty())
748 array<int> indexList = {};
750 array<string> allEntriesKeys = {};
753 allEntriesKeys.Insert(entry.m_sTitle);
756 WidgetManager.SearchLocalized(m_sLastSearch, allEntriesKeys, indexList);
758 foreach (
int index : indexList)
760 entries.Insert(m_aAllEntries.Get(
index));
764 if (m_BreadCrumbsComponent)
766 if (entries.IsEmpty())
767 m_BreadCrumbsComponent.SetRichFormat(SEARCH_NO_RESULT_KEY, originalSearch);
769 m_BreadCrumbsComponent.SetRichFormat(SEARCH_RESULT_KEY, originalSearch, entries.Count().ToString());
777 protected void CloseReadingPanel()
779 SetCurrentEntry(
null);
786 protected void CloseMenuOrReadingPanel()
788 if (m_bIsInEntryViewMode && !m_bOpenedFromOutside)
803 ui.OpenEntry(entryId);
811 protected static string ArrayJoin(notnull array<string> entries)
813 int count = entries.Count();
817 case 1:
return entries[0];
818 case 2:
return WidgetManager.Translate(
"#AR-General_List_Short_2", entries[0], entries[1]);
819 case 3:
return WidgetManager.Translate(
"#AR-General_List_Short_3", entries[0], entries[1], entries[2]);
820 case 4:
return WidgetManager.Translate(
"#AR-General_List_Short_4", entries[0], entries[1], entries[2], entries[3]);
821 case 5:
return WidgetManager.Translate(
"#AR-General_List_Short_5", entries[0], entries[1], entries[2], entries[3], entries[4]);
823 Print(
string.Format(
"Too many list entries to join as a string - missing #AR-General_List_Short_%1 translation?", count), LogLevel.WARNING);
824 return WidgetManager.Translate(
"#AR-General_List_Short_5", entries[0], entries[1], entries[2], entries[3], entries[4]);
836 m_mWidgetEntryMap =
new map<Widget, ref SCR_FieldManualConfigEntry>();
837 m_mWidgetSubCategoryMap =
new map<Widget, ref SCR_FieldManualConfigCategory>();
839 ScriptInvoker inputDeviceIsGamepadInvoker =
GetGame().OnInputDeviceIsGamepadInvoker();
840 if (inputDeviceIsGamepadInvoker)
841 inputDeviceIsGamepadInvoker.Insert(QueueRefreshCurrentEntry);
848 ScriptInvoker inputDeviceIsGamepadInvoker =
GetGame().OnInputDeviceIsGamepadInvoker();
849 if (inputDeviceIsGamepadInvoker)
850 inputDeviceIsGamepadInvoker.Remove(QueueRefreshCurrentEntry);