17 const ref Color ENABLED = Color.FromSRGBA(255, 255, 255, 255);
18 const ref Color DISABLED = Color.FromSRGBA(128, 128, 128, 255);
19 const ref Color ENABLED_CONTEXT = Color.FromSRGBA(255, 182, 95, 255);
25 const static string DEFAULT =
"#AR-UserActionUnavailable";
31 static WorkspaceWidget s_wWorkspace;
32 static Widget s_wActionMenu;
35 static ResourceName s_sLayout;
36 static float s_fFadeInSpeed;
37 static int s_iSpacing = 2;
40 static float s_fHeight = 32;
41 static int s_iTextSize = 30;
42 static float s_fAlpha = 1;
45 static float s_fHeightNonSelected = 20;
46 static int s_iTextSizeNonSelected = 18;
47 static float s_fAlphaNonSelected = 0.8;
52 protected Widget m_wElement;
53 protected TextWidget m_wActionText;
54 protected TextWidget m_wContextText;
55 protected ImageWidget m_wPerformType;
56 protected ImageWidget m_wPerformTypeHold;
57 protected ImageWidget m_wProgress;
58 protected bool m_bIsSelected =
false;
59 protected int m_iIndex = 0;
61 void SetEnabled(
bool bEnabled)
88 bool Set(
BaseUserAction pAction,
int iIndex,
bool bIsSelected,
bool bIsAvailable)
96 m_bIsSelected = bIsSelected;
99 string sActionName = pAction.GetActionName();
103 if (m_bIsSelected && !bIsAvailable)
105 string failReason = pAction.GetCannotPerformReason();
106 if (failReason ==
string.Empty)
113 array<string> aActionStrings =
new array<string>();
114 sActionName.Split(
"%CTX_HACK%", aActionStrings,
true);
116 int iActionStrings = aActionStrings.Count();
118 if (iActionStrings == 0 || !aActionStrings[0])
122 m_wActionText.SetTextFormat(
124 pAction.ActionNameParams[0],
125 pAction.ActionNameParams[1],
126 pAction.ActionNameParams[2],
127 pAction.ActionNameParams[3],
128 pAction.ActionNameParams[4],
129 pAction.ActionNameParams[5],
130 pAction.ActionNameParams[6],
131 pAction.ActionNameParams[7],
132 pAction.ActionNameParams[8]
135 if (iActionStrings > 1 && aActionStrings[1])
137 m_wContextText.SetText(aActionStrings[1]);
138 m_wContextText.SetVisible(
true);
142 m_wContextText.SetText(
"");
143 m_wContextText.SetVisible(
false);
168 float fDuration = pAction.GetActionDuration();
173 m_wPerformTypeHold.SetOpacity(1);
178 m_wPerformTypeHold.SetOpacity(0);
184 void Show(
float fFadeSpeed,
float fTimeSlice = 0)
199 fAlpha = fTargetAlpha;
203 fAlpha = m_wElement.GetOpacity();
204 fAlpha = Math.Lerp(fAlpha, fTargetAlpha, fFadeSpeed * fTimeSlice);
207 m_wElement.SetOpacity(fAlpha);
208 m_wElement.SetVisible(
true);
216 m_wElement.SetOpacity(0);
217 m_wElement.SetVisible(
false);
220 void SetProgress(
float p)
225 m_wProgress.SetMaskProgress(p);
231 LayoutSlot.SetHorizontalAlign(m_wElement, LayoutHorizontalAlign.Left);
234 m_wActionText = TextWidget.Cast(m_wElement.FindAnyWidget(
"ActionText"));
235 m_wContextText = TextWidget.Cast(m_wElement.FindAnyWidget(
"ActionContext"));
236 m_wPerformType = ImageWidget.Cast(m_wElement.FindAnyWidget(
"ActionType"));
237 m_wPerformTypeHold = ImageWidget.Cast(m_wElement.FindAnyWidget(
"ActionTypeHold"));
238 m_wProgress = ImageWidget.Cast(m_wElement.FindAnyWidget(
"ActionProgress"));
244 m_wElement.RemoveFromHierarchy();
253 [
Attribute(
"{C80DEB58AA948E59}UI/layouts/HUD/InteractionSystem/ActionMenuElement.layout", UIWidgets.ResourceNamePicker,
params:
"layout")]
254 ResourceName m_sElementLayout;
256 [
Attribute(
"0", UIWidgets.CheckBox,
"Fixed placement")]
257 protected bool m_bFixedPlacement;
260 protected float m_fScrollAnimationSpeed;
263 protected float m_fAutoExpandTime;
266 protected float m_fFadeInSpeed;
268 [
Attribute(
"0.05", UIWidgets.Slider,
"Action list element fade-in expand delay (in seconds).",
params:
"0 1 0.001")]
269 protected float m_fFadeInOffset;
273 protected Widget m_wActionMenu;
274 protected Widget m_wActionButton;
275 protected Widget m_wArrowUp;
276 protected Widget m_wArrowDown;
277 protected Widget m_wHoldText;
278 protected ImageWidget m_wArrowIcon;
280 protected ref map<BaseUserAction,ActionMenuElement> m_mActionWidget =
new map<BaseUserAction,ActionMenuElement>;
281 protected ref array<ref ActionMenuElement> m_aActionMenuElements =
new array<ref ActionMenuElement>;
283 protected int m_iCurrentScroll = 0;
284 protected float m_fCurrentScrollAnimation = 0.0;
286 protected float m_fExpandTimer = 0.0;
287 protected float m_fExpandedTimer = 0.0;
295 protected const float CONTINUES_ACTION_RESET_HOLD = 0.25;
299 protected void Create()
303 Print(
"ActionsMenuDisplay is missing root layout!", LogLevel.ERROR);
307 if (!m_bFixedPlacement)
309 FrameSlot.SetAnchorMin(
m_wRoot, 0, 0);
310 FrameSlot.SetAnchorMax(
m_wRoot, 0, 0);
311 FrameSlot.SetAlignment(
m_wRoot, 0, 0);
315 FrameSlot.SetAnchorMin(
m_wRoot, 0.48, 0.94);
316 FrameSlot.SetAnchorMax(
m_wRoot, 0.48, 0.94);
317 FrameSlot.SetAlignment(
m_wRoot, 0, 0);
320 m_wActionMenu =
m_wRoot.FindAnyWidget(
"ActionMenu");
321 m_wActionButton =
m_wRoot.FindAnyWidget(
"ActionButton");
322 m_wArrowUp =
m_wRoot.FindAnyWidget(
"ArrowUp");
323 m_wArrowDown =
m_wRoot.FindAnyWidget(
"ArrowDown");
324 m_wHoldText =
m_wRoot.FindAnyWidget(
"HoldText");
325 m_wArrowIcon = ImageWidget.Cast(
m_wRoot.FindAnyWidget(
"DirectionArrow"));
344 protected void Destroy()
346 if (m_aActionMenuElements)
347 m_aActionMenuElements.Clear();
353 if (!pCurrentContext)
357 if (pCurrentContext != m_pPrevContext)
359 m_pPrevContext = pCurrentContext;
363 int iActionsCount = pActionsData.param1.Count();
365 if (!pActionsData.param1 || iActionsCount == 0)
368 if (iActionsCount > 1)
370 RunExpandTimer(fTimeSlice);
371 RunExpandedTimer(fTimeSlice);
376 int iActiveWidgetsCount = m_aActionMenuElements.Count();
377 int iActionsDelta = iActiveWidgetsCount - iActionsCount;
378 int iAbsDelta = Math.AbsInt(iActionsDelta);
381 if (iActionsDelta < 0)
384 for (
int i = 0; i < iAbsDelta; i++)
387 m_aActionMenuElements.Insert(pActionMenuElement);
390 else if (iActionsDelta > 0)
393 for (
int i = iActiveWidgetsCount-1; i >= iActiveWidgetsCount-iAbsDelta; i--)
396 pActionMenuElement.Hide();
400 int iCurrentAction = -1;
401 for (
int i = 0; i < pActionsData.param1.Count(); i++)
403 if (pActionsData.param1[i] == pSelectedAction)
410 if (iCurrentAction == -1)
414 if (iCurrentAction > 0)
418 m_mActionWidget.Clear();
421 for (
int i = 0; i < iActionsCount; i++)
427 bool succeeded = pActionMenuElement.Set(pAction, i, pAction == pSelectedAction, pActionsData.param2[i]);
431 pActionMenuElement.Hide();
436 m_mActionWidget.Insert(pAction, pActionMenuElement);
439 if ((i == 0 ||
m_eState ==
EActionMenu.EXPANDED) && (m_fExpandedTimer >= i * m_fFadeInOffset))
442 pActionMenuElement.Hide();
445 pActionMenuElement.SetEnabled(pActionsData.param2[i]);
449 if (pSelectedAction.GetActionDuration() != 0)
450 m_wHoldText.SetVisible(
true);
452 m_wHoldText.SetVisible(
false);
455 bool isInProgress = pSelectedAction && pSelectedAction.IsInProgress();
457 if (isInProgress && adjustAction && adjustAction.IsManuallyAdjusted())
462 else if (isInProgress || iActionsCount <= 1)
469 if (pSelectedAction == pActionsData.param1[0])
474 if (pSelectedAction == pActionsData.param1[iActionsCount-1])
481 SetScroll(iCurrentAction, fTimeSlice);
487 protected bool GetSafeZone(vector worldPosition, vector screenPosition, vector min01, vector max01, out vector clampedPosition)
489 WorkspaceWidget workspace = m_wActionMenu.GetWorkspace();
490 int screenw = workspace.DPIUnscale(workspace.GetWidth());
491 int screenh = workspace.DPIUnscale(workspace.GetHeight());
494 float padding = 15.0;
497 screenw * min01[0] + padding,
498 screenh * min01[1] + padding,
502 m_wActionMenu.GetScreenSize(menuw, menuh);
503 menuw = workspace.DPIUnscale(menuw);
504 menuh = workspace.DPIUnscale(menuh);
508 screenw * max01[0] - menuw - padding,
509 screenh * max01[1] - menuh + padding,
513 bool clamped =
false;
514 clampedPosition = screenPosition;
518 CameraManager cameraManager =
GetGame().GetCameraManager();
521 CameraBase currentCamera = cameraManager.CurrentCamera();
525 currentCamera.GetWorldCameraTransform(camTM);
526 vector toActionDir = (worldPosition - camTM[3]).Normalized();
527 float d = vector.Dot(toActionDir, camTM[2]);
528 const float threshold = 0.5;
529 const float invThreshold = 1.0 / 0.5;
533 float stickiness = 1.0;
536 stickiness = Math.Clamp(1.0 - (d * invThreshold), 0.0, 1.0);
538 clampedPosition[1] = Math.Lerp(clampedPosition[1], max[1], stickiness);
545 for (
int i = 0; i < 2; ++i)
547 if (clampedPosition[i] < min[i])
549 clampedPosition[i] = min[i];
552 else if (clampedPosition[i] > max[i])
554 clampedPosition[i] = max[i];
563 void SetPosition(vector vWorldPosition)
568 if (!m_bFixedPlacement)
570 vector vScreenPosition =
GetGame().GetWorkspace().ProjWorldToScreen(vWorldPosition,
GetGame().GetWorld());
571 vector vClampedPosition;
572 if (GetSafeZone(vWorldPosition, vScreenPosition,
"0.15 0.15 0",
"0.85 0.85 0", vClampedPosition))
575 vector dir = (vScreenPosition - vClampedPosition).Normalized();
578 float d = vector.Dot(dir, vector.Right);
579 if (vector.Dot(dir, vector.Up) > 0.0)
582 rads = -Math.Acos(d);
584 const float size = 25.0;
585 vector point = size * dir;
586 FrameSlot.SetPos(m_wArrowIcon, 3.0 + point[0], point[1]);
587 m_wArrowIcon.SetRotation(rads * Math.RAD2DEG);
588 m_wArrowIcon.SetVisible(
true);
592 m_wArrowIcon.SetVisible(
false);
595 FrameSlot.SetPos(
m_wRoot, vClampedPosition[0], vClampedPosition[1]);
599 SCR_2DPIPSightsComponent pipSights = ArmaReforgerScripted.GetCurrentPIPSights();
600 bool isPointInPIP = pipSights && pipSights.IsScreenPositionInSights(vClampedPosition);
606 m_wActionButton.SetOpacity(alpha);
607 m_wActionMenu.SetOpacity(alpha);
611 protected void SetScreenPosition(vector screenPosition)
616 FrameSlot.SetPos(
m_wRoot, screenPosition[0], screenPosition[1]);
620 void SetScroll(
int iCurrentScroll,
float fTimeSlice = 0)
625 float fCurrentScroll = iCurrentScroll;
630 m_fCurrentScrollAnimation = 0.0;
634 FrameSlot.SetPosY(m_wActionMenu, fVerticalPos);
637 else if (Math.AbsFloat(m_fCurrentScrollAnimation - fCurrentScroll) > 0.001)
639 m_fCurrentScrollAnimation = Math.Lerp(m_fCurrentScrollAnimation, fCurrentScroll, m_fScrollAnimationSpeed * fTimeSlice);
644 FrameSlot.SetPosY(m_wActionMenu, fVerticalPos);
670 void RunExpandTimer(
float fTimeSlice)
674 m_fExpandTimer = 0.0;
679 m_fExpandTimer += fTimeSlice;
681 if (m_fExpandTimer > m_fAutoExpandTime)
686 void RunExpandedTimer(
float fTimeSlice)
690 m_fExpandedTimer = 0.0;
695 m_fExpandedTimer += fTimeSlice;
715 #ifndef DISABLE_INTERACTIONS
718 override void OnActionStart(IEntity pUser,
BaseUserAction pPerformedAction)
722 if (!pActionMenuElement)
725 pActionMenuElement.SetProgress(0);
730 override void OnActionProgress(IEntity pUser,
BaseUserAction pPerformedAction,
float fProgress,
float fDuration)
733 if (!pActionMenuElement)
735 if (fDuration == 0.0)
736 pActionMenuElement.SetProgress(0.0);
739 pActionMenuElement.SetProgress(fProgress / fDuration);
748 if (!pActionMenuElement)
751 pActionMenuElement.SetProgress(0);
755 override void DisplayUpdate(IEntity owner,
float timeSlice)
758 if (!m_pLastData || !m_pLastData.pSelectedAction)
767 bool succeeded = Update(m_pLastData.pActionsData, m_pLastData.pSelectedAction, m_pLastData.pCurrentContext, timeSlice);
785 vector worldPosition = lastContext.GetOrigin();
786 SetPosition(worldPosition);
803 override void DisplayStartDraw(IEntity owner)
805 super.DisplayStartDraw(owner);
812 override void DisplayStopDraw(IEntity owner)
820 override void ShowDisplay()
829 override void HideDisplay()