17 [
Attribute(
desc:
"Class must be SCR_ScriptedWidgetTooltipPresets",
params:
"conf class=SCR_ScriptedWidgetTooltipPresets")]
18 protected ResourceName m_sPresetsConfig;
21 protected string m_sPresetTag;
23 protected ref SCR_ScriptedWidgetTooltipPreset m_Preset;
24 protected WorkspaceWidget m_wWorkspace;
25 protected Widget m_wTooltipProxy;
26 protected Widget m_wHoverWidget;
28 protected float m_fTargetPosition[2];
31 protected RichTextWidget m_wMessage;
34 protected const string WIDGET_MESSAGE =
"Message";
36 private const float DISTANCE_THRESHOLD = 0.001;
39 protected static Widget m_wTooltipContent;
40 protected static WidgetAnimationPosition m_PositionAnimation;
53 override static Widget CreateTooltipWidget()
55 return GetGame().GetWorkspace().CreateWidgets(
"{39445BE1E35BEA33}UI/layouts/Menus/Tooltips/TooltipBaseProxy.layout");
59 override void Show(WorkspaceWidget pWorkspace, Widget pToolTipWidget,
float desiredPosX,
float desiredPosY)
61 ForceHideCurrentTooltip();
63 m_CurrentTooltip =
this;
67 BaseContainer container = rsc.GetResource().ToBaseContainer();
87 if(m_OnTooltipShowInit)
91 FrameSlot.SetAnchorMin(pToolTipWidget, 0, 0);
92 FrameSlot.SetAnchorMax(pToolTipWidget, 0, 0);
95 FrameSlot.SetSizeToContent(pToolTipWidget,
m_Preset.m_bSizeToContent);
97 Widget debugBorder = pToolTipWidget.FindAnyWidget(
"DebugBorder");
101 showDebug =
m_Preset.m_bShowDebugBorder;
105 debugBorder.SetVisible(showDebug);
112 InitContentPosition();
115 UpdatePosition(
true,
false,
true);
134 m_OnTooltipShow.Invoke(
this, m_wTooltipContent, m_wHoverWidget, m_Preset,
m_Preset.m_sTag);
137 GetGame().GetCallqueue().CallLater(Update,
m_Preset.m_fUpdateFrequency,
true);
140 super.Show(pWorkspace, pToolTipWidget, desiredPosX, desiredPosY);
144 override void Hide(WorkspaceWidget pWorkspace, Widget pToolTipWidget)
148 super.Hide(pWorkspace, pToolTipWidget);
153 protected void Update()
168 protected void OnHide()
173 m_OnTooltipHide.Invoke(
this, m_wTooltipProxy, m_wHoverWidget, m_Preset,
m_Preset.m_sTag);
189 protected void Clear()
191 GetGame().GetCallqueue().Remove(Update);
197 if (m_PositionAnimation)
198 m_PositionAnimation.Stop();
200 if (m_wTooltipContent)
206 protected void InitContentPosition()
208 SCR_TooltipPositionPreset positionPreset =
m_Preset.GetInputPositionSettings();
212 float targetX = positionPreset.GetContentAlignmentHorizontal();
213 float targetY = positionPreset.GetContentAlignmentVertical();
217 FrameSlot.SetAnchorMax(m_wTooltipContent, targetX, targetY);
221 protected void InitContents()
224 SetMessage(
m_Preset.m_sMessageText);
229 void UpdatePosition(
bool followTarget =
true,
bool animate =
true,
bool force =
false)
232 bool rendered = tooltipSize[0] != 0 && tooltipSize[1] != 0;
234 vector goalPosition, goalAlignment, goalAlpha;
242 if (followTarget || !rendered)
247 vector tooltipPos = FrameSlot.GetPos(m_wTooltipProxy);
250 FrameSlot.SetAlignment(m_wTooltipProxy, goalAlignment[0], goalAlignment[1]);
254 FrameSlot.SetPos(m_wTooltipProxy, goalPosition[0], goalPosition[1]);
256 else if (vector.DistanceSq(Vector(tooltipPos[0], tooltipPos[1], 0), Vector(m_fTargetPosition[0], m_fTargetPosition[1], 0)) >= DISTANCE_THRESHOLD)
257 m_PositionAnimation = AnimateWidget.Position(m_wTooltipProxy, m_fTargetPosition,
m_Preset.m_fInterpolationSpeed);
261 if (!m_wTooltipContent)
264 FrameSlot.SetAlignment(m_wTooltipContent, goalAlignment[0], goalAlignment[1]);
265 FrameSlot.SetAnchorMin(m_wTooltipContent, goalAlignment[0], goalAlignment[1]);
266 FrameSlot.SetAnchorMax(m_wTooltipContent, goalAlignment[0], goalAlignment[1]);
270 bool SetMessage(
string message)
282 return SetMessage(GetDefaultMessage());
286 bool SetMessageColor(Color color)
288 if (!m_wMessage || !color)
305 string GetDefaultMessage()
333 Widget GetContentWidget()
339 Widget GetTooltipWidget()
345 Widget GetHoverWidget()
352 Widget GetContentWrapper()
358 static bool ForceHideCurrentTooltip()
360 if (!m_CurrentTooltip)
363 m_CurrentTooltip.ForceHidden();
370 return m_CurrentTooltip;
376 if (!m_OnTooltipShowInit)
379 return m_OnTooltipShowInit;
385 if (!m_OnTooltipShow)
388 return m_OnTooltipShow;
394 if (!m_OnTooltipHide)
397 return m_OnTooltipHide;
406 class SCR_ScriptedWidgetTooltipPreset
408 [
Attribute(
"", UIWidgets.Auto,
"Custom tag, used for finding this preset at run time.")]
411 [
Attribute(
"{197FC671D07413E9}UI/layouts/Menus/Tooltips/Tooltip_SimpleMessage.layout", UIWidgets.ResourceNamePicker,
".layout for the content of the Tooltip",
params:
"layout")]
412 ResourceName m_sContentLayout;
415 ref SCR_TooltipPositionPreset m_MousePositionSettings;
418 ref SCR_TooltipPositionPreset m_GamepadPositionSettings;
420 [
Attribute(
"1", UIWidgets.CheckBox,
"Defines if the tooltip should animate to follow mouse cursor or remain at initial position")]
424 vector m_vFixedPosition;
426 [
Attribute(
"0", UIWidgets.CheckBox,
desc:
"Should the proxy adapt to the content: the proxy is used to check for overflowing and contains the actual Content layout. Giving it a fixed size will prevent slide in effect for overflowing tooltips. This will NOT influence the look of the comntent layout, as long as it fits inside the proxy and it's not set to stretch")]
427 bool m_bSizeToContent;
429 [
Attribute(
desc:
"Fixed proxy layout size. The proxy is used to check for overflowing and contains the actual Content layout. This will NOT influence the look of the comntent layout, as long as it fits inside the proxy and it's not set to stretch")]
433 string m_sMessageText;
439 float m_fInterpolationSpeed;
442 float m_fUpdateFrequency;
445 bool m_bShowDebugBorder;
447 string m_sDefaultMessage;
452 m_sDefaultMessage = m_sMessageText;
458 bool GetGoalPosition(Widget tooltipContent, Widget hoverWidget, out vector goalPosition, out vector goalAlignment, out vector goalAlpha,
bool force =
false)
460 vector tooltipSize = GetTooltipSize(tooltipContent);
461 SCR_TooltipPositionPreset positionSettings = GetInputPositionSettings();
463 if (positionSettings.m_eAnchor != SCR_ETooltipAnchor.CURSOR && !force)
466 positionSettings.GetGoalPosition(tooltipSize, hoverWidget, m_vFixedPosition, goalPosition, goalAlignment, goalAlpha);
471 vector GetTooltipSize(Widget tooltip)
474 WorkspaceWidget workspace =
GetGame().GetWorkspace();
477 float xTooltipSize = workspace.DPIScale(m_vSize[0]);
478 float yTooltipSize = workspace.DPIScale(m_vSize[1]);
479 if (m_bSizeToContent && tooltip)
480 tooltip.GetScreenSize(xTooltipSize, yTooltipSize);
482 size[0] = xTooltipSize;
483 size[1] = yTooltipSize;
488 SCR_TooltipPositionPreset GetInputPositionSettings()
490 bool isUsingMouse =
GetGame().GetInputManager().GetLastUsedInputDevice() == EInputDeviceType.MOUSE;
492 return m_MousePositionSettings;
494 return m_GamepadPositionSettings;
505 ref array<ref SCR_ScriptedWidgetTooltipPreset> m_aPresets;
509 SCR_ScriptedWidgetTooltipPreset FindPreset(
string tag)
511 foreach (SCR_ScriptedWidgetTooltipPreset preset :
m_aPresets)
513 if (preset.m_sTag == tag)
525 class SCR_TooltipPositionPreset
527 [
Attribute(
"0", UIWidgets.ComboBox,
"Where to position the Tooltip",
"", ParamEnumArray.FromEnum(SCR_ETooltipAnchor))]
528 SCR_ETooltipAnchor m_eAnchor;
533 [
Attribute(
"0", UIWidgets.ComboBox,
"Vertical Alignment",
"", ParamEnumArray.FromEnum(SCR_ETooltipAlignmentVertical))]
536 [
Attribute(
"8 20 0",
desc:
"Tooltip offset from cursor or desired position")]
539 [
Attribute(
"0", UIWidgets.ComboBox,
"How to deal with overflow",
"", ParamEnumArray.FromEnum(SCR_ETooltipOverflowHandling))]
540 SCR_ETooltipOverflowHandling m_eOverflowHandling;
542 const float ALIGNMENT_CENTER = 0.5;
543 const float ALIGNMENT_LEFT_TOP = 0;
544 const float ALIGNMENT_RIGHT_DOWN = 1;
548 void GetGoalPosition(vector tooltipSize, Widget hoverWidget, vector absolutePosition, out vector goalPosition, out vector goalAlignment, out vector goalAlpha)
550 float xHover, yHover;
551 float xHoverSize, yHoverSize;
556 hoverWidget.GetScreenPos(xHover, yHover);
559 hoverWidget.GetScreenSize(xHoverSize, yHoverSize);
563 int xCursor, yCursor;
564 WidgetManager.GetMousePos(xCursor, yCursor);
567 WorkspaceWidget workspace =
GetGame().GetWorkspace();
568 float xWorkspaceSize, yWorkspaceSize;
569 workspace.GetScreenSize(xWorkspaceSize, yWorkspaceSize);
576 float xAlignment, yAlignment;
577 float xTargetSize, yTargetSize;
581 case SCR_ETooltipAnchor.CURSOR:
586 case SCR_ETooltipAnchor.HOVERED_WIDGET:
589 xTargetSize = xHoverSize;
590 yTargetSize = yHoverSize;
593 case SCR_ETooltipAnchor.ABSOLUTE:
594 xGoal = absolutePosition[0];
595 yGoal = absolutePosition[1];
599 CalculateGoalPosition(
m_eHorizontalAlignment, xTargetSize, tooltipSize[0], xWorkspaceSize, xGoal, xOffset, xAlignment);
600 CalculateGoalPosition(
m_eVerticalAlignment, yTargetSize, tooltipSize[1], yWorkspaceSize, yGoal, yOffset, yAlignment);
603 if (xWorkspaceSize == 0)
606 if (yWorkspaceSize == 0)
609 goalAlpha[0] = (xGoal + workspace.DPIScale(xOffset)) / xWorkspaceSize;
610 goalAlpha[1] = (yGoal + workspace.DPIScale(yOffset)) / yWorkspaceSize;
613 goalPosition[0] = workspace.DPIUnscale(xGoal + workspace.DPIScale(xOffset));
614 goalPosition[1] = workspace.DPIUnscale(yGoal + workspace.DPIScale(yOffset));
617 goalAlignment[0] = xAlignment;
618 goalAlignment[1] = yAlignment;
622 protected void CalculateGoalPosition(
int alignmentCase,
float targetSize,
float tooltipSize,
float maxAreaSize, inout
float desiredPos, inout
float offset, inout
float alignment)
624 switch (alignmentCase)
630 desiredPos = desiredPos + (targetSize * ALIGNMENT_CENTER);
631 alignment = ALIGNMENT_CENTER;
635 desiredPos = desiredPos + targetSize;
636 alignment = ALIGNMENT_RIGHT_DOWN;
640 alignment = ALIGNMENT_RIGHT_DOWN;
644 desiredPos = desiredPos + targetSize;
648 CheckOverflow(tooltipSize, maxAreaSize, desiredPos, offset, alignment);
654 bool CheckOverflow(
float tooltipSize,
float maxAreaSize, inout
float desiredPos, inout
float offset, inout
float alignment)
656 SCR_ETooltipOverflowType overflowType;
659 if (alignment < ALIGNMENT_CENTER && desiredPos + offset + tooltipSize > maxAreaSize)
661 overflowType = SCR_ETooltipOverflowType.RIGHT;
665 else if (alignment > ALIGNMENT_CENTER && desiredPos + offset - tooltipSize < 0)
667 overflowType = SCR_ETooltipOverflowType.LEFT;
673 if (desiredPos + offset + (tooltipSize * ALIGNMENT_CENTER) > maxAreaSize)
674 overflowType = SCR_ETooltipOverflowType.CENTER_RIGHT;
677 else if (desiredPos + offset - (tooltipSize * ALIGNMENT_CENTER) < 0)
678 overflowType = SCR_ETooltipOverflowType.CENTER_LEFT;
681 if (overflowType == SCR_ETooltipOverflowType.NONE)
686 if (m_eOverflowHandling == SCR_ETooltipOverflowHandling.INVERT)
688 if (alignment == ALIGNMENT_CENTER)
689 desiredPos = Math.Clamp(desiredPos, offset + (tooltipSize * ALIGNMENT_CENTER), maxAreaSize - (offset + (tooltipSize * ALIGNMENT_CENTER)));
691 alignment = 1 - alignment;
697 switch (overflowType)
699 case SCR_ETooltipOverflowType.LEFT: desiredPos = tooltipSize + offset;
break;
700 case SCR_ETooltipOverflowType.RIGHT: desiredPos = maxAreaSize - tooltipSize - offset;
break;
701 case SCR_ETooltipOverflowType.CENTER_LEFT: desiredPos = (tooltipSize * ALIGNMENT_CENTER) + offset;
break;
702 case SCR_ETooltipOverflowType.CENTER_RIGHT: desiredPos = maxAreaSize - (tooltipSize * ALIGNMENT_CENTER) - offset;
break;
710 float GetContentAlignmentHorizontal()
721 return ALIGNMENT_LEFT_TOP;
725 float GetContentAlignmentVertical()
729 case SCR_ETooltipAlignmentVertical.TOP:
return ALIGNMENT_LEFT_TOP;
730 case SCR_ETooltipAlignmentVertical.ABOVE:
return ALIGNMENT_RIGHT_DOWN;
731 case SCR_ETooltipAlignmentVertical.BELOW:
return ALIGNMENT_LEFT_TOP;
732 case SCR_ETooltipAlignmentVertical.BOTTOM:
return ALIGNMENT_RIGHT_DOWN;
733 case SCR_ETooltipAlignmentVertical.CENTER:
return ALIGNMENT_CENTER;
736 return ALIGNMENT_LEFT_TOP;
817 enum SCR_ETooltipAlignmentVertical
827 enum SCR_ETooltipAnchor
835 enum SCR_ETooltipOverflowHandling
842 enum SCR_ETooltipOverflowType