function ZO_StatusBar_SetGradientColor(statusBar, gradientColorTable) if statusBar and gradientColorTable then local r, g, b, a = gradientColorTable[1]:UnpackRGBA() local r1, g1, b1, a1 = gradientColorTable[2]:UnpackRGBA() statusBar:SetGradientColors(r, g, b, a, r1, g1, b1, a1) end end function ZO_StatusBar_InitializeDefaultColors(statusBar) local startR, startG, startB = GetInterfaceColor(INTERFACE_COLOR_TYPE_GENERAL, INTERFACE_GENERAL_COLOR_STATUS_BAR_START) local endR, endG, endB = GetInterfaceColor(INTERFACE_COLOR_TYPE_GENERAL, INTERFACE_GENERAL_COLOR_STATUS_BAR_END) statusBar:SetGradientColors(startR, startG, startB, 1, endR, endG, endB, 1) end local function ZO_GetOrCreateArrowBarGlowAnimationTimeline(control) if not control.glowAnimation then control.glowAnimation = ANIMATION_MANAGER:CreateTimelineFromVirtual("ZO_ArrowBarGlowAnimation", control:GetNamedChild("Glow")) end return control.glowAnimation end function ZO_ResponsiveArrowBar_OnMouseEnter(control) ZO_GetOrCreateArrowBarGlowAnimationTimeline(control):PlayForward() end function ZO_ResponsiveArrowBar_OnMouseExit(control) ZO_GetOrCreateArrowBarGlowAnimationTimeline(control):PlayBackward() end FORCE_INIT_SMOOTH_STATUS_BAR = true do local g_animationPool local DEFAULT_ANIMATION_TIME_MS = 500 local function OnAnimationTransitionUpdate(animation, progress) local bar = animation.bar local initialValue = animation.initialValue local endValue = animation.endValue local newBarValue = zo_lerp(initialValue, endValue, progress) bar:SetValue(newBarValue) end local function OnStopAnimation(animation, completedPlaying) local animationKey = animation.key local bar = animation:GetFirstAnimation().bar bar.animation = nil g_animationPool:ReleaseObject(animationKey) if bar.onStopCallback then bar.onStopCallback(bar, completedPlaying) end end local function AcquireAnimation() if not g_animationPool then local function Factory(objectPool) local animation = ANIMATION_MANAGER:CreateTimelineFromVirtual("ZO_StatusBarGrowTemplate") animation:GetFirstAnimation():SetUpdateFunction(OnAnimationTransitionUpdate) animation:SetHandler("OnStop", function(...) OnStopAnimation(...) end) return animation end local function Reset(object) local customAnimation = object:GetFirstAnimation() customAnimation.bar = nil customAnimation.initialValue = nil customAnimation.endValue = nil end g_animationPool = ZO_ObjectPool:New(Factory, Reset) end local animation, key = g_animationPool:AcquireObject() animation.key = key return animation end function ZO_StatusBar_SmoothTransition(self, value, max, forceInit, onStopCallback, customApproachAmountMs) local oldValue = self:GetValue() self:SetMinMax(0, max) local oldMax = self.max or max self.max = max self.onStopCallback = onStopCallback if forceInit or max <= 0 then self:SetValue(value) if self.animation then self.animation:Stop() end if onStopCallback then onStopCallback(self) end else if oldMax > 0 and oldMax ~= max then local maxChange = max / oldMax oldValue = oldValue * maxChange self:SetValue(oldValue) end if not self.animation then local updateAnimation = AcquireAnimation() self.animation = updateAnimation end local customAnimation = self.animation:GetFirstAnimation() customAnimation:SetDuration(customApproachAmountMs or DEFAULT_ANIMATION_TIME_MS) customAnimation.bar = self customAnimation.initialValue = oldValue customAnimation.endValue = value self.animation:PlayFromStart() end end function ZO_StatusBar_GetTargetValue(statusBar) return (statusBar.animation and statusBar.animation:GetFirstAnimation().endValue) or statusBar:GetValue() end end ZO_WrappingStatusBar = ZO_Object:Subclass() function ZO_WrappingStatusBar:New(...) local wrappingStatusBar = ZO_Object.New(self) wrappingStatusBar:Initialize(...) return wrappingStatusBar end function ZO_WrappingStatusBar:Initialize(statusBar, onLevelChangedCallback) self.statusBar = statusBar self:SetOnLevelChangeCallback(onLevelChangedCallback) self.onAnimationFinishedCallback = function(timeline, completedPlaying) self:OnAnimationFinished(completedPlaying) end end function ZO_WrappingStatusBar:SetOnLevelChangeCallback(onLevelChangedCallback) self.onLevelChangedCallback = onLevelChangedCallback end function ZO_WrappingStatusBar:SetOnCompleteCallback(onCompleteCallback) self.onCompleteCallback = onCompleteCallback end function ZO_WrappingStatusBar:GetControl() return self.statusBar end function ZO_WrappingStatusBar:SetHidden(hidden) self.statusBar:SetHidden(hidden) end function ZO_WrappingStatusBar:GetValue() return ZO_StatusBar_GetTargetValue(self.statusBar) end function ZO_WrappingStatusBar:Reset() self.level = nil self.noWrap = nil end function ZO_WrappingStatusBar:SetAnimationTime(time) self.customAnimationTime = time end function ZO_WrappingStatusBar:SetValue(level, value, max, noWrap, animateInstantly) if noWrap == nil then noWrap = false end local forceInit = false if self.level ~= level or self.noWrap ~= noWrap then if self.level and level then if level > self.level and not noWrap then self.pendingLevels = (self.pendingLevels or 0) + level - self.level else self.pendingLevels = nil end else self.pendingLevels = nil forceInit = true noWrap = true end self.level = level self.noWrap = noWrap if self.pendingLevels == nil and self.onLevelChangedCallback then self.onLevelChangedCallback(self, self.level) end end forceInit = forceInit or animateInstantly if self.pendingLevels and not forceInit and not noWrap then self.pendingValue = value self.pendingMax = max ZO_StatusBar_SmoothTransition(self.statusBar, max, max, nil, self.onAnimationFinishedCallback, self.customAnimationTime) else if forceInit then ZO_StatusBar_SmoothTransition(self.statusBar, value, max, true) else ZO_StatusBar_SmoothTransition(self.statusBar, value, max, false, self.onCompleteCallback, self.customAnimationTime) end self.pendingValue = nil self.pendingMax = nil end end function ZO_WrappingStatusBar:OnAnimationFinished(completedPlaying) if completedPlaying then self.pendingLevels = self.pendingLevels - 1 if self.pendingLevels == 0 then ZO_StatusBar_SmoothTransition(self.statusBar, 0, self.pendingMax, FORCE_INIT_SMOOTH_STATUS_BAR) ZO_StatusBar_SmoothTransition(self.statusBar, self.pendingValue, self.pendingMax, nil, self.onCompleteCallback, self.customAnimationTime) self.pendingLevels = nil self.pendingValue = nil self.pendingMax = nil if self.onLevelChangedCallback then self.onLevelChangedCallback(self, self.level) end else ZO_StatusBar_SmoothTransition(self.statusBar, 0, self.pendingMax, FORCE_INIT_SMOOTH_STATUS_BAR) ZO_StatusBar_SmoothTransition(self.statusBar, self.pendingMax, self.pendingMax, nil, self.onAnimationFinishedCallback, self.customAnimationTime) if self.onLevelChangedCallback then self.onLevelChangedCallback(self, self.level - self.pendingLevels) end end end end function ZO_WrappingStatusBar:GetLevel() return self.level end function ZO_WrappingStatusBar:GetNarrationText() local narration = SCREEN_NARRATION_MANAGER:CreateNarratableObject() local barMax = self.statusBar.max if barMax then local barMin = self.statusBar.min or 0 if barMax > barMin then local barValue = self:GetValue() local range = barMax - barMin local percentage = (barValue - barMin) / range percentage = string.format("%.2f", percentage * 100) narration:AddNarrationText(zo_strformat(SI_SCREEN_NARRATION_PROGRESS_BAR_PERCENT_FORMATTER, percentage)) end end return { SCREEN_NARRATION_MANAGER:CreateNarratableObject(self:GetLevel()), narration } end --[[ Inventory Item Improvement Status Bar Mix In --]] ZO_InventoryItemImprovementStatusBar = {} function ZO_InventoryItemImprovementStatusBar:Initialize(control) zo_mixin(control, ZO_InventoryItemImprovementStatusBar) control.currentBar = control:GetNamedChild("Bar") control.improvementBar = control:GetNamedChild("Underlay") end function ZO_InventoryItemImprovementStatusBar:SetMinMax(min, max) self.currentBar:SetMinMax(min, max) self.improvementBar:SetMinMax(min, max) self.min, self.max = min, max end function ZO_InventoryItemImprovementStatusBar:SetValueAndPreviewValue(value, previewValue) ZO_StatusBar_SmoothTransition(self.improvementBar, previewValue, self.max) self.currentBar:SetValue(value) end function ZO_InventoryItemImprovementStatusBar:SetGradientColors(...) self.currentBar:SetGradientColors(...) end --[[ Stable Training Skill Status Bar Mix In --]] ZO_StableTrainingBar_Gamepad = {} function ZO_StableTrainingBar_Gamepad:Initialize(control) zo_mixin(control, ZO_StableTrainingBar_Gamepad) control.bar = control:GetNamedChild("StatusBar"):GetNamedChild("Bar") control.value = control:GetNamedChild("Value") self.min, self.max = 0, 0 self.valueFormat = nil end function ZO_StableTrainingBar_Gamepad:SetMinMax(min, max) self.min, self.max = min, max end function ZO_StableTrainingBar_Gamepad:SetValueFormatString(valueFormat) self.valueFormat = valueFormat end function ZO_StableTrainingBar_Gamepad:SetValue(value) local FORCE_VALUE = true ZO_StatusBar_SmoothTransition(self.bar, value, self.max, FORCE_VALUE) if self.valueFormat then self.value:SetText(zo_strformat(self.valueFormat, value)) end end function ZO_StableTrainingBar_Gamepad:SetGradientColors(...) self.bar:SetGradientColors(...) end --[[ Champion Skill Status Bar Mix In --]] ZO_ChampionSkillBar_Gamepad = {} function ZO_ChampionSkillBar_Gamepad:Initialize() self.mask = self:GetNamedChild("Mask") self.bar = self.mask:GetNamedChild("Bar") self.notchPool = ZO_ControlPool:New("ZO_ChampionSkillBarNotch_Gamepad", self:GetNamedChild("Overlay"), "Notch") self.minResultLabel = self:GetNamedChild("MinResult") self.maxResultLabel = self:GetNamedChild("MaxResult") self.min, self.max = 0, 0 end function ZO_ChampionSkillBar_Gamepad:Reset() self.notchPool:ReleaseAllObjects() end function ZO_ChampionSkillBar_Gamepad:SetMinMax(min, max) self.min, self.max = min, max self.bar:SetMinMax(min, max) end function ZO_ChampionSkillBar_Gamepad:SetMinMaxText(minText, maxText) self.minResultLabel:SetText(minText) self.maxResultLabel:SetText(maxText) end function ZO_ChampionSkillBar_Gamepad:SetValue(value) local FORCE_VALUE = true ZO_StatusBar_SmoothTransition(self.bar, value, self.max, FORCE_VALUE) end function ZO_ChampionSkillBar_Gamepad:AddNotch(value) local offsetX = self.bar:CalculateSizeWithoutLeadingEdgeForValue(value) local notchControl = self.notchPool:AcquireObject() local PADDING_Y = 5 notchControl:SetAnchor(TOP, self.bar, TOPLEFT, offsetX, PADDING_Y) notchControl:SetAnchor(BOTTOM, self.bar, BOTTOMLEFT, offsetX, -PADDING_Y) end function ZO_ChampionSkillBar_Gamepad:SetMaskValue(value) if value ~= self.max then local maskOffsetX = self.bar:CalculateSizeWithoutLeadingEdgeForValue(value) self.mask:SetAnchor(TOPLEFT, self.bar, TOPLEFT) self.mask:SetAnchor(BOTTOMRIGHT, self.bar, BOTTOMLEFT, maskOffsetX) else self.mask:SetAnchor(TOPLEFT, self.bar, TOPLEFT) self.mask:SetAnchor(BOTTOMRIGHT, self.bar, BOTTOMRIGHT) end end function ZO_ChampionSkillBar_Gamepad:SetGradientColors(...) self.bar:SetGradientColors(...) end --[[ Sliding Status Bar ]]-- ZO_SlidingStatusBar = ZO_InitializingObject:Subclass() local DEFAULT_MIN_VALUE = 0 local DEFAULT_MAX_VALUE = 1 local SLIDING_STATUS_BAR_INDICATOR_LAYOUTS = { keyboard = { icon = "EsoUI/Art/Miscellaneous/slidingStatusBar_indicator.dds", offsetY = 0, }, gamepad = { icon = "EsoUI/Art/Buttons/Gamepad/gp_upArrow.dds", offsetY = -15, }, } function ZO_SlidingStatusBar:Initialize(control) self.control = control self.statusBarLeft = control:GetNamedChild("BarLeft") self.statusBarRight = control:GetNamedChild("BarRight") self.backgroundContainer = control:GetNamedChild("BgContainer") self.valueIndicator = control:GetNamedChild("ValuePointer") self.valueIndicatorRelativeControl = control:GetNamedChild("FrameCenter") self.min = DEFAULT_MIN_VALUE self.max = DEFAULT_MAX_VALUE self.value = DEFAULT_MIN_VALUE self:ApplyStyle() control:RegisterForEvent(EVENT_GAMEPAD_PREFERRED_MODE_CHANGED, function() self:ApplyStyle() end) end function ZO_SlidingStatusBar:ApplyStyle() ApplyTemplateToControl(self.backgroundContainer:GetNamedChild("BgLeft"), ZO_GetPlatformTemplate("ZO_PlayerAttributeBgLeftArrow")) ApplyTemplateToControl(self.backgroundContainer:GetNamedChild("BgRight"), ZO_GetPlatformTemplate("ZO_PlayerAttributeBgRightArrow")) ApplyTemplateToControl(self.backgroundContainer:GetNamedChild("BgCenter"), ZO_GetPlatformTemplate("ZO_PlayerAttributeBgCenter")) ApplyTemplateToControl(self.control:GetNamedChild("FrameLeft"), ZO_GetPlatformTemplate("ZO_PlayerAttributeFrameLeftArrow")) ApplyTemplateToControl(self.control:GetNamedChild("FrameRight"), ZO_GetPlatformTemplate("ZO_PlayerAttributeFrameRightArrow")) ApplyTemplateToControl(self.control:GetNamedChild("FrameCenter"), ZO_GetPlatformTemplate("ZO_PlayerAttributeFrameCenter")) ApplyTemplateToControl(self.statusBarRight, ZO_GetPlatformTemplate("ZO_PlayerAttributeStatusBar")) ApplyTemplateToControl(self.statusBarRight, ZO_GetPlatformTemplate("ZO_PlayerAttributeHealthBarAnchorRight")) ApplyTemplateToControl(self.statusBarRight:GetNamedChild("Gloss"), ZO_GetPlatformTemplate("ZO_PlayerAttributeStatusBarGloss")) ApplyTemplateToControl(self.statusBarLeft, ZO_GetPlatformTemplate("ZO_PlayerAttributeStatusBar")) ApplyTemplateToControl(self.statusBarLeft, ZO_GetPlatformTemplate("ZO_PlayerAttributeHealthBarAnchorLeft")) ApplyTemplateToControl(self.statusBarLeft:GetNamedChild("Gloss"), ZO_GetPlatformTemplate("ZO_PlayerAttributeStatusBarGloss")) local indicatorLayout = IsInGamepadPreferredMode() and SLIDING_STATUS_BAR_INDICATOR_LAYOUTS.gamepad or SLIDING_STATUS_BAR_INDICATOR_LAYOUTS.keyboard self.valueIndicator:SetTexture(indicatorLayout.icon) self.indicatorOffsetY = indicatorLayout.offsetY local FORCE_REFRESH = true self:SetValue(self.value, FORCE_REFRESH) end function ZO_SlidingStatusBar:SetGradientColors(startColor, endColor, middleColor) --If a middle color has been given, we need to set the gradient up a little differently if middleColor then ZO_StatusBar_SetGradientColor(self.statusBarLeft, {middleColor, startColor}) ZO_StatusBar_SetGradientColor(self.statusBarRight, {middleColor, endColor}) else ZO_StatusBar_SetGradientColor(self.statusBarLeft, {startColor, endColor}) ZO_StatusBar_SetGradientColor(self.statusBarRight, {startColor, endColor}) end end function ZO_SlidingStatusBar:SetMinMax(minValue, maxValue) if minValue < maxValue and (minValue ~= self.min or maxValue ~= self.max) then self.min = minValue self.max = maxValue --Either the minimum or the maximum has changed, so we need to reapply the value in case it is no longer within bounds local FORCE_REFRESH = true self:SetValue(self.value, FORCE_REFRESH) end end function ZO_SlidingStatusBar:SetValue(value, forceRefresh) --First clamp the value between the minimum and maximum local clampedValue = zo_clamp(value, self.min, self.max) if clampedValue ~= self.value or forceRefresh then self.value = clampedValue --How far between the min and the max is the value? local percentProgress = zo_percentBetween(self.min, self.max, clampedValue) --Determine the x offset of the value indicator based on the percent progress calculated above local sliderOffsetX = zo_lerp(0, self.valueIndicatorRelativeControl:GetWidth(), percentProgress) self.valueIndicator:ClearAnchors() self.valueIndicator:SetAnchor(TOP, self.valueIndicatorRelativeControl, BOTTOMLEFT, sliderOffsetX, self.indicatorOffsetY) end end