-- Alias SCENE_FRAGMENT_SHOWING = ZO_STATE.SHOWING SCENE_FRAGMENT_SHOWN = ZO_STATE.SHOWN SCENE_FRAGMENT_HIDING = ZO_STATE.HIDING SCENE_FRAGMENT_HIDDEN = ZO_STATE.HIDDEN ZO_SceneFragment = ZO_CallbackObject:Subclass() function ZO_SceneFragment:New(...) local fragment = ZO_CallbackObject.New(self) fragment:Initialize(...) return fragment end function ZO_SceneFragment:Initialize() self.state = SCENE_FRAGMENT_HIDDEN self.allowShowHideTimeUpdates = false end function ZO_SceneFragment:IsValidSceneManagerChange(newSceneManager) -- Instead of there being at most 1 scenemanager, there are now N scenemanagers with N active scenes. -- Since a fragment can be owned by only 1 scene manager at a time, we need to make sure we aren't constructing a state where two scenes are both visible and sharing the same fragment. local oldSceneManager = self.sceneManager if oldSceneManager == nil or oldSceneManager == newSceneManager then -- no change return true end local oldParentScene = oldSceneManager:GetParentScene() if oldParentScene ~= nil and oldParentScene:GetState() == SCENE_HIDDEN then -- If the old scene manager is parented to a scene, but that scene is hidden, then the subscene is effectively hidden. return true end local oldCurrentScene = oldSceneManager:GetCurrentScene() if oldCurrentScene == nil or oldCurrentScene:GetState() == SCENE_HIDDEN then -- the old scene is either hidden or nonexistent, we can safely steal this fragment from it return true end if oldCurrentScene:HasFragment(self) then local assertString = "Trying to change scene managers, but the old scene manager (%s, state:%s) still contains this fragment" internalassert(false, string.format(assertString, oldCurrentScene:GetName(), oldCurrentScene:GetState())) return false end return true end function ZO_SceneFragment:SetSceneManager(newSceneManager) if self:IsValidSceneManagerChange(newSceneManager) then self.sceneManager = newSceneManager end end function ZO_SceneFragment:GetCategory() return self.category end function ZO_SceneFragment:SetCategory(category) self.category = category end --Force Refresh causes a fragment to hide and show again even if it is part of the next scene. function ZO_SceneFragment:GetForceRefresh() return self.forceRefresh end function ZO_SceneFragment:SetForceRefresh(forceRefresh) self.forceRefresh = forceRefresh end function ZO_SceneFragment:AddDependency(fragment) if(not self.dependencies) then self.dependencies = {} end self.dependencies[fragment] = true end function ZO_SceneFragment:AddDependencies(...) for i = 1, select("#", ...) do self:AddDependency(select(i, ...)) end end function ZO_SceneFragment:IsDependentOn(fragment) if(self.dependencies) then return self.dependencies[fragment] == true end return false end function ZO_SceneFragment:HasDependencies() return self.dependencies ~= nil end function ZO_SceneFragment:GetHideOnSceneHidden() return self.hideOnSceneHidden end function ZO_SceneFragment:SetHideOnSceneHidden(hideOnSceneHidden) self.hideOnSceneHidden = hideOnSceneHidden end --Show and Hide will be called by the scene management system. They should not be called directly by code. function ZO_SceneFragment:Show() self:OnShown() end function ZO_SceneFragment:Hide() self:OnHidden() end function ZO_SceneFragment:GetState() return self.state end function ZO_SceneFragment:IsShowing() return self.state == SCENE_FRAGMENT_SHOWING or self.state == SCENE_FRAGMENT_SHOWN end function ZO_SceneFragment:IsHidden() return self.state == SCENE_FRAGMENT_HIDDEN end function ZO_SceneFragment:SetConditional(conditional) self.conditional = conditional end function ZO_SceneFragment:HasConditional() return self.conditional ~= nil end --If true, Show and Hide will be called even if the fragment is already in the Showing or Hiding state. function ZO_SceneFragment:SetAllowShowHideTimeUpdates(allow) self.allowShowHideTimeUpdates = allow end function ZO_SceneFragment:SetState(newState) if(newState ~= self.state) then local oldState = self.state self.state = newState self:FireCallbacks("StateChange", oldState, newState) local currentScene = self.sceneManager:GetCurrentScene() if(currentScene) then currentScene:OnSceneFragmentStateChange(self, oldState, newState) end end end function ZO_SceneFragment:OnShown() self:SetState(SCENE_FRAGMENT_SHOWN) end function ZO_SceneFragment:OnHidden() self:SetState(SCENE_FRAGMENT_HIDDEN) end function ZO_SceneFragment:ShouldBeShown(customShowParam) if(self.state ~= SCENE_FRAGMENT_SHOWN and (self.allowShowHideTimeUpdates == true or self.state ~= SCENE_FRAGMENT_SHOWING)) then self:SetState(SCENE_FRAGMENT_SHOWING) self:Show(customShowParam) end end function ZO_SceneFragment:ShouldBeHidden(customHideParam) if(self.state ~= SCENE_FRAGMENT_HIDDEN and (self.allowShowHideTimeUpdates == true or self.state ~= SCENE_FRAGMENT_HIDING)) then self:SetState(SCENE_FRAGMENT_HIDING) if(not self.hideOnSceneHidden) then self:Hide(customHideParam) end end end function ZO_SceneFragment:ComputeIfFragmentShouldShow() if self.sceneManager then local sceneManagerParentScene = self.sceneManager:GetParentScene() if sceneManagerParentScene and sceneManagerParentScene:IsHiding() then return false end local currentScene = self.sceneManager:GetCurrentScene() local nextScene = self.sceneManager:GetNextScene() if currentScene and currentScene:HasFragment(self) then if self.conditional == nil or self.conditional() then local currentSceneState = currentScene:GetState() if nextScene then if currentSceneState == SCENE_HIDING or currentSceneState == SCENE_HIDDEN then if nextScene:HasFragment(self) then if self.forceRefresh then -- always hide on a force refresh return false elseif self:HasDependencies() then for dependencyFragment in pairs(self.dependencies) do local currentHasDependency = currentScene:HasFragment(dependencyFragment) local nextHasDependency = nextScene:HasFragment(dependencyFragment) if currentHasDependency ~= nextHasDependency then return false end end return true else -- next scene has this fragment so we should show return true end else -- next scene does not have this fragment, so we should hide return false end end else if currentSceneState == SCENE_SHOWING or currentSceneState == SCENE_SHOWN then return true end end else -- the fragment failed its conditional, so we shouldn't show return false end else -- Either we have no current scene or the current scene doesn't have this fragment, we shouldn't be showing return false end end return false end function ZO_SceneFragment:Refresh(customShowParam, customHideParam, asAResultOfSceneStateChange, refreshedForScene) local oldState = self.state if self:ComputeIfFragmentShouldShow() then self:ShouldBeShown(customShowParam) else self:ShouldBeHidden(customHideParam) end self:FireCallbacks("Refreshed", oldState, self.state, asAResultOfSceneStateChange, refreshedForScene) end