local SUBCATEGORY_PAD = 10 local CREATE_BUCKET_WINDOW_DATA = { [CREATE_BUCKET_RACE] = { windowName = "RaceBucket", title = GetString(SI_CREATE_CHARACTER_BUCKET_TITLE_RACE), tabNormal = "EsoUI/Art/CharacterCreate/CharacterCreate_raceIcon_up.dds", tabPressed = "EsoUI/Art/CharacterCreate/CharacterCreate_raceIcon_down.dds", tabMouseOver = "EsoUI/Art/CharacterCreate/CharacterCreate_raceIcon_over.dds", nextTab = CREATE_BUCKET_CLASS, previousTab = CREATE_BUCKET_FACE, onExpandFn = function() if not ZO_CHARACTERCREATE_MANAGER:GetPlayingTransitionAnimations() then CharacterCreateSetIdlePosture() end SetCharacterCameraZoomAmount(-1) end, }, [CREATE_BUCKET_CLASS] = { windowName = "ClassBucket", title = GetString(SI_CREATE_CHARACTER_BUCKET_TITLE_CLASS), tabNormal = "EsoUI/Art/CharacterCreate/CharacterCreate_classIcon_up.dds", tabPressed = "EsoUI/Art/CharacterCreate/CharacterCreate_classIcon_down.dds", tabMouseOver = "EsoUI/Art/CharacterCreate/CharacterCreate_classIcon_over.dds", nextTab = CREATE_BUCKET_BODY, previousTab = CREATE_BUCKET_RACE, onExpandFn = function() SetCharacterCameraZoomAmount(-1) end, }, [CREATE_BUCKET_BODY] = { windowName = "BodyBucket", title = GetString(SI_CREATE_CHARACTER_BUCKET_TITLE_BODY), tabNormal = "EsoUI/Art/CharacterCreate/CharacterCreate_bodyIcon_up.dds", tabPressed = "EsoUI/Art/CharacterCreate/CharacterCreate_bodyIcon_down.dds", tabMouseOver = "EsoUI/Art/CharacterCreate/CharacterCreate_bodyIcon_over.dds", nextTab = CREATE_BUCKET_FACE, previousTab = CREATE_BUCKET_CLASS, onExpandFn = function() SetCharacterCameraZoomAmount(-1) end, subCategoryData = { { id = SLIDER_SUBCAT_BODY_TYPE, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_BODY_FEATURES, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_BODY_UPPER, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_BODY_LOWER, anchorYOffsetOverride = SUBCATEGORY_PAD, }, }, }, [CREATE_BUCKET_FACE] = { windowName = "FaceBucket", title = GetString(SI_CREATE_CHARACTER_BUCKET_TITLE_FACE), tabNormal = "EsoUI/Art/CharacterCreate/CharacterCreate_faceIcon_up.dds", tabPressed = "EsoUI/Art/CharacterCreate/CharacterCreate_faceIcon_down.dds", tabMouseOver = "EsoUI/Art/CharacterCreate/CharacterCreate_faceIcon_over.dds", nextTab = CREATE_BUCKET_RACE, previousTab = CREATE_BUCKET_BODY, onExpandFn = function() SetCharacterCameraZoomAmount(1) end, subCategoryData = { { id = SLIDER_SUBCAT_FACE_TYPE, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_VOICE, anchorYOffsetOverride = -42, }, { id = SLIDER_SUBCAT_FACE_HAIR, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_FACE_FEATURES, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_FACE_FACE, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_FACE_EYES, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_FACE_BROW, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_FACE_NOSE, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_FACE_MOUTH, anchorYOffsetOverride = SUBCATEGORY_PAD, }, { id = SLIDER_SUBCAT_FACE_EARS, anchorYOffsetOverride = SUBCATEGORY_PAD, }, }, }, } --[[ Character Create Bucket ]]-- ZO_CharacterCreateBucket_Keyboard = ZO_CharacterCreateBucket_Base:Subclass() function ZO_CharacterCreateBucket_Keyboard:New(...) return ZO_CharacterCreateBucket_Base.New(self, ...) end function ZO_CharacterCreateBucket_Keyboard:Initialize(...) ZO_CharacterCreateBucket_Base.Initialize(self, ...) local windowData = CREATE_BUCKET_WINDOW_DATA[self.category] local container = CreateControlFromVirtual(windowData.windowName, self.parent, "ZO_CharacterCreateCategoryBucket_Keyboard") local tabControl = self:CreateTabControl(windowData) tabControl.bucket = self container.bucket = self self.windowData = windowData self.container = container self.tab = tabControl self.scrollChild = GetControl(container, "PaneScrollChild") self.subcategoryContainers = {} -- Create a spacer control to keep the contents of the scroll panel centered -- since scrolling operates by setting the topleft anchor of the scrollChild -- window. local widthSpacer = self.scrollChild:CreateControl("$(parent)WidthSpacer", CT_CONTROL) widthSpacer:SetWidth(360) widthSpacer:SetAnchor(TOP) -- Create another spacer to pad out the bottom so that the full contents of the pane -- can be scrolled into view. This will need to be reanchored to each control that gets -- added to the bucket. self.viewSpacer = self.scrollChild:CreateControl("$(parent)ViewSpacer", CT_CONTROL) self.viewSpacer:SetDimensions(360, 10) end function ZO_CharacterCreateBucket_Keyboard:CreateTabControl(windowData) local tabControl = CreateControlFromVirtual(windowData.windowName .. "Tab", self.parent, "ZO_CharacterCreateCategoryTab_Keyboard") tabControl:SetNormalTexture(windowData.tabNormal) tabControl:SetMouseOverTexture(windowData.tabMouseOver) tabControl:SetPressedTexture(windowData.tabPressed) tabControl.windowData = windowData tabControl:SetHandler("OnClicked", function(control, button) self.manager:SwitchBuckets(control) end) tabControl:SetHandler("OnMouseEnter", function(control) self:MouseEnter() end) tabControl:SetHandler("OnMouseExit", function(control) self:MouseExit() end) return tabControl end function ZO_CharacterCreateBucket_Keyboard:GetTab() return self.tab end function ZO_CharacterCreateBucket_Keyboard:AddSubCategories() local windowData = self.windowData if windowData.subCategoryData then if not self.subCategories then self.subCategories = {} end for subCatIndex, subCatData in ipairs(windowData.subCategoryData) do local subCategoryObj = self.subCategories[subCatData.id] if not subCategoryObj then subCategoryObj = ZO_CharacterCreateBucketSubcategory_Keyboard:New(windowData, subCatData, self:GetScrollChild()) self.subCategories[subCatData.id] = subCategoryObj end local subCategoryContainer = subCategoryObj:GetControl() subCategoryContainer:SetHidden(false) table.insert(self.subcategoryContainers, subCategoryContainer) local NO_UPDATE_FUNCTION = nil local NO_RANDOMIZE_FUNCTION = nil local NO_SUBCATEGORY_ID = nil local NO_NARRATION_TEXT = nil local NO_DIRECTION_INPUT_NARRATION_FUNCTION = nil self:AddControl(subCategoryContainer, NO_UPDATE_FUNCTION, NO_RANDOMIZE_FUNCTION, NO_SUBCATEGORY_ID, NO_NARRATION_TEXT, NO_DIRECTION_INPUT_NARRATION_FUNCTION, subCatData.anchorYOffsetOverride) end end end function ZO_CharacterCreateBucket_Keyboard:RemoveUnusedSubCategories() local windowData = self.windowData if windowData.subCategoryData and self.subCategories then for subCatIndex, subCatData in ipairs(windowData.subCategoryData) do local subCategoryObj = self.subCategories[subCatData.id] if subCategoryObj and subCategoryObj:IsEmpty() then local subCategoryContainer = subCategoryObj:GetControl() -- Grab the subcategory after this one and anchor it to the current local nextSubCatControl = self.subcategoryContainers[subCatIndex + 1] if nextSubCatControl then local valid, point, relTo, relPoint, offsX, offsY = subCategoryContainer:GetAnchor(0) if valid then nextSubCatControl:ClearAnchors() nextSubCatControl:SetAnchor(point, relTo, relPoint, offsX, offsY) end end subCategoryContainer:SetHidden(true) subCategoryContainer:ClearAnchors() subCategoryContainer:SetAnchor(TOP, self:GetScrollChild(), TOP, 0, 0) end end end end function ZO_CharacterCreateBucket_Keyboard:AddControl(control, updateFn, randomizeFn, subCategoryId, narrationText, directionalInputNarrationFunction, anchorYOffsetOverride) control.bucket = self control:ClearAnchors() control:SetHidden(false) if subCategoryId and self.subCategories and self.subCategories[subCategoryId] then self.subCategories[subCategoryId]:AddControl(control) else control:SetParent(self:GetScrollChild()) anchorYOffsetOverride = anchorYOffsetOverride or 0 if self.lastAnchored then control:SetAnchor(TOP, self.lastAnchored, BOTTOM, 0, 20 + anchorYOffsetOverride) else -- using a little vertical padding so controls with backdrops don't overlap at the top -- NOTE: Do not use override here, if it were negative it could easily push this control out of the window control:SetAnchor(TOP, self:GetScrollChild(), TOP, 0, 5) end self.lastAnchored = control self.viewSpacer:ClearAnchors() self.viewSpacer:SetAnchor(TOP, self.lastAnchored, BOTTOM, 0, 0) end self.controlData[control] = { updateFn = updateFn, randomizeFn = randomizeFn } end function ZO_CharacterCreateBucket_Keyboard:RemoveControl(control) -- Once a control is removed from a bucket it's no longer safe to add controls -- unless the bucket is totally reset (this is because of how lastAnchored works) -- This just cleans up the control and removes any lingering update handlers -- All the controls will be re-added to the bucket at some point. self.lastAnchored = nil control.bucket = nil self.controlData[control] = nil end function ZO_CharacterCreateBucket_Keyboard:Reset() self.expanded = false self.controlData = {} self.lastAnchored = nil self.subcategoryContainers = {} local tabControl = self:GetTab() tabControl:SetEnabled(true) tabControl:SetDesaturation(0) if self.subCategories then for _, subCategoryObj in pairs(self.subCategories) do subCategoryObj:Reset() end end end function ZO_CharacterCreateBucket_Keyboard:Expand() local container = self:GetContainer() container:SetHidden(false) self:GetTab():SetState(BSTATE_PRESSED, true) self.expanded = true local expandFn = self.windowData.onExpandFn if expandFn then expandFn() end end function ZO_CharacterCreateBucket_Keyboard:Collapse() self:GetContainer():SetHidden(true) self:GetTab():SetState(BSTATE_NORMAL, false) self.expanded = false local collapseFn = self.windowData.onCollapseFn if collapseFn then collapseFn() end end function ZO_CharacterCreateBucket_Keyboard:IsExpanded() return self.expanded end function ZO_CharacterCreateBucket_Keyboard:MouseEnter() InitializeTooltip(InformationTooltip, self:GetTab(), TOPRIGHT, 0, 0, TOPLEFT) SetTooltipText(InformationTooltip, self.windowData.title) end function ZO_CharacterCreateBucket_Keyboard:MouseExit() ClearTooltip(InformationTooltip) end --[[ Character Create Bucket Subcategory ]]-- ZO_CharacterCreateBucketSubcategory_Keyboard = ZO_Object:Subclass() function ZO_CharacterCreateBucketSubcategory_Keyboard:New(bucketWindowData, subCategoryData, parent) local subCategory = ZO_Object.New(self) local subCategoryWindowName = string.format("%sSub%d", bucketWindowData.windowName, subCategoryData.id) local subCategoryControl = CreateControlFromVirtual(subCategoryWindowName, parent, "ZO_CharacterCreateSubCategoryBucket_Keyboard") subCategory.control = subCategoryControl GetControl(subCategoryControl, "Name"):SetText(GetString("SI_CHARACTERSLIDERSUBCATEGORY", subCategoryData.id)) return subCategory end function ZO_CharacterCreateBucketSubcategory_Keyboard:GetControl() return self.control end function ZO_CharacterCreateBucketSubcategory_Keyboard:AddControl(control) control:SetParent(self:GetControl()) if self.lastAnchored then control:SetAnchor(TOP, self.lastAnchored, BOTTOM, 0, 20) else control:SetAnchor(TOP, GetControl(self.control, "TopSpacer"), BOTTOM) end self.lastAnchored = control end function ZO_CharacterCreateBucketSubcategory_Keyboard:Reset() self.lastAnchored = nil end function ZO_CharacterCreateBucketSubcategory_Keyboard:IsEmpty() return self.lastAnchored == nil end --[[ Character Creation Bucket Manager ]]-- local CHARACTER_CREATE_BUCKETS = { CREATE_BUCKET_RACE, CREATE_BUCKET_CLASS, CREATE_BUCKET_BODY, CREATE_BUCKET_FACE, } ZO_CharacterCreateBucketManager_Keyboard = ZO_CharacterCreateBucketManager_Base:Subclass() function ZO_CharacterCreateBucketManager_Keyboard:New(container) return ZO_CharacterCreateBucketManager_Base.New(self, container, CHARACTER_CREATE_BUCKETS) end function ZO_CharacterCreateBucketManager_Keyboard:AddBucket(bucketCategory) local bucket = ZO_CharacterCreateBucket_Keyboard:New(self.container, bucketCategory, self) local bucketContainer = bucket:GetContainer() bucketContainer:SetAnchor(TOPLEFT, self.container, TOPLEFT, 13, 138) bucketContainer:SetAnchor(BOTTOMRIGHT, self.container, BOTTOMRIGHT, -14, -73) self.buckets[bucketCategory] = bucket local tabControl = bucket:GetTab() if self.lastAnchoredTab then tabControl:SetAnchor(TOPLEFT, self.lastAnchoredTab, TOPRIGHT, 12, 0) else tabControl:SetAnchor(TOPLEFT, self.container, TOPLEFT, 62, 20) end self.lastAnchoredTab = tabControl end function ZO_CharacterCreateBucketManager_Keyboard:SwitchBuckets(tabButtonOrCategory) -- collapse current bucket if self.currentBucket then self.currentBucket:Collapse() end -- expand desired bucket local bucket if type(tabButtonOrCategory) == "number" then bucket = self:BucketForCategory(tabButtonOrCategory) else bucket = self:BucketForChildControl(tabButtonOrCategory) end if bucket then bucket:Expand() self.currentBucket = bucket end end function ZO_CharacterCreateBucketManager_Keyboard:GetCurrentTab() if self.currentBucket then return self.currentBucket:GetTab() end end function ZO_CharacterCreateBucketManager_Keyboard:EnableBucketTab(bucketCategory, enabled) local bucket = self.buckets[bucketCategory] local tabControl = bucket:GetTab() local saturation = 1 if enabled then saturation = 0 end tabControl:SetEnabled(enabled) tabControl:SetDesaturation(saturation) end function ZO_CharacterCreateBucketManager_Keyboard:AddSubCategories() for _, bucket in pairs(self.buckets) do bucket:AddSubCategories() end end function ZO_CharacterCreateBucketManager_Keyboard:RemoveUnusedSubCategories() for _, bucket in pairs(self.buckets) do bucket:RemoveUnusedSubCategories() end end