--Pixel Unit Control ----------------------- PIXEL_SOURCE_PIXELS = 1 PIXEL_SOURCE_UI_UNITS = 2 PIXEL_SOURCE_UNSCALED_UI_UNITS = 3 ZO_PixelUnitControl = ZO_Object:Subclass() function ZO_PixelUnitControl:New(control, pixelSource, baseObject) local obj = baseObject.New(self) obj:Initialize(control, pixelSource, baseObject) return obj end function ZO_PixelUnitControl:Initialize(control, pixelSource) self.control = control self.pixelSource = pixelSource self.dirty = false self.applyLocked = false self.anchors = { } self.scale = 1 end ZO_PixelUnitControl.PIXEL_CONVERTERS = { [PIXEL_SOURCE_PIXELS] = function(measurement) return measurement end, [PIXEL_SOURCE_UI_UNITS] = function(measurement) local globalScale = GetUIGlobalScale() local pixels = measurement * globalScale return pixels end, [PIXEL_SOURCE_UNSCALED_UI_UNITS] = function(measurement) local unscaledUIUnits = measurement / GetUICustomScale() local globalScale = GetUIGlobalScale() local pixels = unscaledUIUnits * globalScale return pixels end, } function ZO_PixelUnitControl:ConvertToUIUnits(measurement) local pixels = ZO_PixelUnitControl.PIXEL_CONVERTERS[self.pixelSource](measurement) --If the measurement wasn't zero, return at least one pixel's worth. We don't want it to decay to no spacing. if pixels == 0 then if measurement > 0 then pixels = 1 elseif measurement < 0 then pixels = -1 end end local globalScale = GetUIGlobalScale() return pixels / globalScale end function ZO_PixelUnitControl:OnScreenResized() if self.width then self.widthUIUnits = self:ConvertToUIUnits(self.width) end if self.height then self.heightUIUnits = self:ConvertToUIUnits(self.height) end if self.minWidth then self.minWidthUIUnits = self:ConvertToUIUnits(self.minWidth) end if self.minHeight then self.minHeightUIUnits = self:ConvertToUIUnits(self.minHeight) end if self.maxWidth then self.maxWidthUIUnits = self:ConvertToUIUnits(self.maxWidth) end if self.maxHeight then self.maxHeightUIUnits = self:ConvertToUIUnits(self.maxHeight) end for _, anchor in ipairs(self.anchors) do anchor.offsetXUIUnits = self:ConvertToUIUnits(anchor.offsetX) anchor.offsetYUIUnits = self:ConvertToUIUnits(anchor.offsetY) end self:ApplyToControl() end function ZO_PixelUnitControl:ClearAnchors() ZO_ClearNumericallyIndexedTable(self.anchors) self:ApplyToControl() end function ZO_PixelUnitControl:AddAnchor(point, anchorTo, relativePoint, offsetX, offsetY, anchorConstrains) local anchor = { point = point, anchorTo = anchorTo, relativePoint = relativePoint, offsetX = offsetX, offsetXUIUnits = self:ConvertToUIUnits(offsetX), offsetY = offsetY, offsetYUIUnits = self:ConvertToUIUnits(offsetY), anchorConstrains = anchorConstrains, } table.insert(self.anchors, anchor) self:ApplyToControl() end function ZO_PixelUnitControl:SetWidth(width) self.width = width self.widthUIUnits = self:ConvertToUIUnits(self.width) self:ApplyToControl() end function ZO_PixelUnitControl:SetHeight(height) self.height = height self.heightUIUnits = self:ConvertToUIUnits(self.height) self:ApplyToControl() end function ZO_PixelUnitControl:SetDimensions(width, height) self.width = width self.widthUIUnits = self:ConvertToUIUnits(self.width) self.height = height self.heightUIUnits = self:ConvertToUIUnits(self.height) self:ApplyToControl() end function ZO_PixelUnitControl:SetDimensionConstraints(minWidth, minHeight, maxWidth, maxHeight) if minWidth then self.minWidth = minWidth self.minWidthUIUnits = self:ConvertToUIUnits(minWidth) else self.minWidth = nil self.maxWidthUIUnits = nil end if minHeight then self.minHeight = minHeight self.minHeightUIUnits = self:ConvertToUIUnits(minHeight) else self.minHeight = nil self.minHeightUIUnits = nil end if maxWidth then self.maxWidth = maxWidth self.maxWidthUIUnits = self:ConvertToUIUnits(maxWidth) else self.maxWidth = nil self.maxWidthUIUnits = nil end if maxHeight then self.maxHeight = maxHeight self.maxHeightUIUnits = self:ConvertToUIUnits(maxHeight) else self.maxHeight = nil self.maxHeightUIUnits = nil end self:ApplyToControl() end function ZO_PixelUnitControl:SetScale(scale) if zo_abs(self.scale - scale) > 0.01 then self.scale = scale self:ApplyToControl() end end function ZO_PixelUnitControl:IsDimensionConstrainedByAnchors(side1, side2, checkDirection1, checkDirection2) if #self.anchors == MAX_ANCHORS and not self.control:GetResizeToFitDescendents() then for i = 1, MAX_ANCHORS do local anchorPoint1 = self.anchors[i].point local anchorPoint2 = self.anchors[(i % MAX_ANCHORS) + 1].point if side1 == anchorPoint1 or (side1 + checkDirection1) == anchorPoint1 or (side1 + checkDirection2) == anchorPoint1 then if side2 == anchorPoint2 or (side2 + checkDirection2) == anchorPoint2 or (side2 + checkDirection2) == anchorPoint2 then return true end end end end return false end function ZO_PixelUnitControl:ScrapeFromXML() self:LockApply() for i = 0, MAX_ANCHORS - 1 do local isValid, point, anchorTo, relPoint, offsetX, offsetY = self.control:GetAnchor(i) if isValid then self:AddAnchor(point, anchorTo, relPoint, offsetX, offsetY) end end if not self:IsDimensionConstrainedByAnchors(LEFT, RIGHT, TOP, BOTTOM) then self:SetWidth(self.control:GetWidth()) end if not self:IsDimensionConstrainedByAnchors(TOP, BOTTOM, LEFT, RIGHT) then self:SetHeight(self.control:GetHeight()) end self:UnlockApply() end function ZO_PixelUnitControl:LockApply() self.applyLocked = true end function ZO_PixelUnitControl:UnlockApply() self.applyLocked = false self:ApplyToControl() end function ZO_PixelUnitControl:ApplyToControl() if self.applyLocked then self.dirty = true else self.dirty = false local scale = self.scale if #self.anchors > 0 then self.control:ClearAnchors() for i = 1, #self.anchors do local anchor = self.anchors[i] self.control:SetAnchor(anchor.point, anchor.anchorTo, anchor.relativePoint, anchor.offsetXUIUnits * scale, anchor.offsetYUIUnits * scale, anchor.anchorConstrains) end end local minWidthUIUnits = self.minWidthUIUnits local minHeightUIUnits = self.minHeightUIUnits local maxWidthUIUnits = self.maxWidthUIUnits local maxHeightUIUnits = self.maxHeightUIUnits if minWidthUIUnits or minHeightUIUnits or maxWidthUIUnits or maxHeightUIUnits then minWidthUIUnits = minWidthUIUnits and minWidthUIUnits * scale or -1 minHeightUIUnits = minHeightUIUnits and minHeightUIUnits * scale or -1 maxWidthUIUnits = maxWidthUIUnits and maxWidthUIUnits * scale or -1 maxHeightUIUnits = maxHeightUIUnits and maxHeightUIUnits * scale or -1 self.control:SetDimensionConstraints(minWidthUIUnits, minHeightUIUnits, maxWidthUIUnits, maxHeightUIUnits) end if self.widthUIUnits then self.control:SetWidth(self.widthUIUnits * scale) end if self.heightUIUnits then self.control:SetHeight(self.heightUIUnits * scale) end end end --Pixel Units ------------------- ZO_PixelUnits = ZO_Object:Subclass() function ZO_PixelUnits:New(namespace, baseObject) local obj = baseObject.New(self) obj:Initialize(namespace, baseObject) return obj end function ZO_PixelUnits:Initialize(namespace, baseObject) self.baseObject = baseObject self.pixelUnitControls = { } EVENT_MANAGER:RegisterForEvent(namespace, EVENT_SCREEN_RESIZED, function() self:OnScreenResized() end) end function ZO_PixelUnits:OnScreenResized() for _, pixelUnitControl in pairs(self.pixelUnitControls) do pixelUnitControl:OnScreenResized() end end function ZO_PixelUnits:Get(control) return self.pixelUnitControls[control] end function ZO_PixelUnits:Add(control, pixelSource) local pixelUnitControl = ZO_PixelUnitControl:New(control, pixelSource, self.baseObject) self.pixelUnitControls[control] = pixelUnitControl return pixelUnitControl end function ZO_PixelUnits:Remove(...) for i = 1, select("#", ...) do self.pixelUnitControls[select(i, ...)] = nil end end function ZO_PixelUnits:AddControlAndAllChildren(control) self:Add(control, PIXEL_SOURCE_PIXELS) for i = 1, control:GetNumChildren() do self:AddControlAndAllChildren(control:GetChild(i)) end end function ZO_PixelUnits:AddAnchor(control, point, relativeTo, relativePoint, offsetX, offsetY, anchorConstrains) local pixelUnitControl = self:Get(control) if pixelUnitControl then pixelUnitControl:AddAnchor(point, relativeTo, relativePoint, offsetX, offsetY, anchorConstrains) end end function ZO_PixelUnits:SetDimensionConstraints(control, minWidth, minHeight, maxWidth, maxHeight) local pixelUnitControl = self:Get(control) if pixelUnitControl then pixelUnitControl:SetDimensionConstraints(minWidth, minHeight, maxWidth, maxHeight) end end function ZO_PixelUnits:SetDimensions(control, width, height) local pixelUnitControl = self:Get(control) if pixelUnitControl then pixelUnitControl:SetDimensions(width, height) end end function ZO_PixelUnits:SetWidth(control, width) local pixelUnitControl = self:Get(control) if pixelUnitControl then pixelUnitControl:SetWidth(width) end end function ZO_PixelUnits:SetHeight(control, height) local pixelUnitControl = self:Get(control) if pixelUnitControl then pixelUnitControl:SetHeight(height) end end function ZO_PixelUnits:SetScale(control, scale) local pixelUnitControl = self:Get(control) if pixelUnitControl then pixelUnitControl:SetScale(scale) end end PIXEL_UNITS = ZO_PixelUnits:New("ZO_PixelUnits", ZO_Object) --Global XML function ZO_PixelUnitsControl_OnInitialized(self) local pixelControl = PIXEL_UNITS:Add(self, PIXEL_SOURCE_PIXELS) pixelControl:ScrapeFromXML() end