Back to Home

ESO Lua File v101044

libraries/utility/zo_anchor.lua

[◄ back to folders ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
local POINT = 1
local TARGET = 2
local REL_POINT = 3
local OFFS_X = 4
local OFFS_Y = 5
local CONSTRAINTS = 6
ZO_OPPOSING_ANCHOR_POINTS =
{
    [BOTTOM] = TOP,
    [BOTTOMLEFT] = TOPRIGHT,
    [BOTTOMRIGHT] = TOPLEFT,
    [CENTER] = CENTER,
    [LEFT] = RIGHT,
    [RIGHT] = LEFT,
    [TOP] = BOTTOM,
    [TOPLEFT] = BOTTOMRIGHT,
    [TOPRIGHT] = BOTTOMLEFT,
}
function ZO_GetOpposingAnchorPoint(anchorPoint)
    return ZO_OPPOSING_ANCHOR_POINTS[anchorPoint] or NONE
end
function ZO_GetAnchorPointNearestScreenCenter(controlCenterX, controlCenterY)
    local screenCenterX, screenCenterY = GuiRoot:GetCenter()
    local screenOffsetX = controlCenterX / screenCenterX
    local screenOffsetY = controlCenterY / screenCenterY
    local strongHorizontalAnchor, weakHorizontalAnchor
    if screenOffsetX < 0.5 then
        weakHorizontalAnchor = RIGHT
        strongHorizontalAnchor = screenOffsetX < 0.45 and RIGHT or NONE
    else
        weakHorizontalAnchor = LEFT
        strongHorizontalAnchor = screenOffsetX > 0.55 and LEFT or NONE
    end
    local strongVerticalAnchor, weakVerticalAnchor
    if screenOffsetY < 0.5 then
        weakVerticalAnchor = BOTTOM
        strongVerticalAnchor = screenOffsetY < 0.45 and BOTTOM or NONE
    else
        weakVerticalAnchor = TOP
        strongVerticalAnchor = screenOffsetY > 0.55 and TOP or NONE
    end
    local strongAnchor = strongHorizontalAnchor + strongVerticalAnchor
    if strongAnchor ~= NONE then
        return strongAnchor
    end
    local weakAnchor = weakHorizontalAnchor + weakVerticalAnchor
    return weakAnchor
end
ZO_Anchor = ZO_Object:Subclass ()
function ZO_Anchor:New(pointOnMe, target, pointOnTarget, offsetX, offsetY, constraints)
    local a = ZO_Object.New(self)
    
    if type(pointOnMe) == "table" then
        local copy = pointOnMe.data
        a.data = { copy[POINT], copy[TARGET], copy[REL_POINT], copy[OFFS_X], copy[OFFS_Y], copy[CONSTRAINTS] }
    else
        a.data = { pointOnMe or TOPLEFT, target, pointOnTarget or a[POINT], offsetX or 0, offsetY or 0, constraints or ANCHOR_CONSTRAINS_XY }
    end
    
    return a
end
function ZO_Anchor:ResetToAnchor(anchorObj)
    self.data[POINT]     = anchorObj.data[POINT] or TOPLEFT
    self.data[TARGET]    = anchorObj.data[TARGET]
    self.data[REL_POINT] = anchorObj.data[REL_POINT] or self.data[POINT]
    self.data[OFFS_X]    = anchorObj.data[OFFS_X] or 0
    self.data[OFFS_Y]    = anchorObj.data[OFFS_Y] or 0
    self.data[CONSTRAINTS] = anchorObj.data[CONSTRAINTS] or ANCHOR_CONSTRAINS_XY
end
function ZO_Anchor:SetFromControlAnchor(control, anchorIndex)
    local isValid, point, relTo, relPoint, offsX, offsY, constraints = control:GetAnchor(anchorIndex)
    
    if isValid then
        local data = self.data
        data[POINT] = point
        data[TARGET] = relTo
        data[REL_POINT] = relPoint
        data[OFFS_X] = offsX
        data[OFFS_Y] = offsY
        data[CONSTRAINTS] = constraints
    end
end
function ZO_Anchor:GetTarget()
    return self.data[TARGET]
end
function ZO_Anchor:SetTarget(control)
    self.data[TARGET] = control
end
function ZO_Anchor:GetMyPoint()
    return self.data[POINT]
end
function ZO_Anchor:SetMyPoint(myPoint)
    self.data[POINT] = myPoint
end
function ZO_Anchor:GetRelativePoint()
    return self.data[REL_POINT]
end
function ZO_Anchor:SetRelativePoint(relPoint)
    self.data[REL_POINT] = relPoint
end
function ZO_Anchor:GetOffsets()
    return self.data[OFFS_X], self.data[OFFS_Y]
end
function ZO_Anchor:GetOffsetX()
    return self.data[OFFS_X]
end
function ZO_Anchor:GetOffsetY()
    return self.data[OFFS_Y]
end
function ZO_Anchor:SetOffsets(offsetX, offsetY)
    self.data[OFFS_X] = offsetX or self.data[OFFS_X]
    self.data[OFFS_Y] = offsetY or self.data[OFFS_Y]
end
function ZO_Anchor:AddOffsets(offsetX, offsetY)
    if(offsetX)
    then
        self.data[OFFS_X] = offsetX + self.data[OFFS_X]
    end
    if(offsetY)
    then
        self.data[OFFS_Y] = offsetY + self.data[OFFS_Y]
    end
end
function ZO_Anchor:GetConstraints()
    return self.data[CONSTRAINTS]
end
function ZO_Anchor:SetConstraints(constraints)
    self.data[CONSTRAINTS] = constraints
end
function ZO_Anchor:Set(control)
    if(control)
    then
        control:ClearAnchors()
        local data = self.data
        control:SetAnchor(data[POINT], data[TARGET], data[REL_POINT], data[OFFS_X], data[OFFS_Y], data[CONSTRAINTS])
    end
end
function ZO_Anchor:AddToControl(control)
    if(control)
    then
        local data = self.data
        control:SetAnchor(data[POINT], data[TARGET], data[REL_POINT], data[OFFS_X], data[OFFS_Y], data[CONSTRAINTS])
    end
end
GROW_DIRECTION_UP_LEFT = 1
GROW_DIRECTION_UP_RIGHT = 2
GROW_DIRECTION_DOWN_LEFT = 3
GROW_DIRECTION_DOWN_RIGHT = 4
local verticalGrowthProduct =
{
    [GROW_DIRECTION_UP_LEFT] = -1,
    [GROW_DIRECTION_UP_RIGHT] = -1,
    [GROW_DIRECTION_DOWN_LEFT] = 1,
    [GROW_DIRECTION_DOWN_RIGHT] = 1,
}
local horizontalGrowthProduct =
{
    [GROW_DIRECTION_UP_LEFT] = -1,
    [GROW_DIRECTION_UP_RIGHT] = 1,
    [GROW_DIRECTION_DOWN_LEFT] = -1,
    [GROW_DIRECTION_DOWN_RIGHT] = 1,
}
function ZO_Anchor_BoxLayout(currentAnchor, control, controlIndex, containerStride, padX, padY, controlWidth, controlHeight, initialX, initialY, growDirection)
    growDirection = growDirection or GROW_DIRECTION_DOWN_RIGHT
    local row = zo_floor(controlIndex / containerStride)
    local col = controlIndex - (row * containerStride)
    
    padX = col * padX
    padY = row * padY
    if(padX < 0) then padX = 0 end
    if(padY < 0) then padY = 0 end
    local offsetX = horizontalGrowthProduct[growDirection] * ((col * controlWidth) + padX + initialX)
    local offsetY = verticalGrowthProduct[growDirection] * ((row * controlHeight) + padY + initialY)
    currentAnchor:SetOffsets(offsetX, offsetY)
    currentAnchor:Set(control)
    return row, col, offsetX, offsetY
end
--[[
You would like to anchor "control" to "anchorTo".
anchorTo will not move.
This function determines the best fit for control so that anchorTo
is not obscured and so that control fits in the window.
NOTE: anchorTo can't be nil...it MUST be a valid control.
The most common use of this function is to anchor a really big window, like a tooltip,
to a really small window, like an actionbutton or inventory slot.
--]]
function ZO_Anchor_DynamicAnchorTo(control, anchorTo, offsetX, offsetY)
    offsetX = offsetX or 0
    offsetY = offsetY or 0
    local anchorToLeft, anchorToTop = anchorTo:GetLeft(), anchorTo:GetTop()
    local anchorToWidth, anchorToHeight = anchorTo:GetDimensions()
    local anchorToCenterX, anchorToCenterY = anchorToLeft + anchorToWidth * 0.5, anchorToTop + anchorToHeight * 0.5
    local UIWidth, UIHeight = GuiRoot:GetDimensions()
    local UICenterX, UICenterY = UIWidth * 0.5, UIHeight * 0.5
    if(anchorToCenterX < UICenterX) then
        if(anchorToCenterY < UICenterY) then
            --TOPLEFT
            control:SetAnchor(TOPLEFT, anchorTo, BOTTOMRIGHT, offsetX, offsetY)
        else
            --BOTTOMLEFT
            control:SetAnchor(BOTTOMLEFT, anchorTo, TOPRIGHT, offsetX, -offsetY)
        end
    else
        if(anchorToCenterY < UICenterY) then
            --TOPRIGHT
            control:SetAnchor(TOPRIGHT, anchorTo, BOTTOMLEFT, -offsetX, offsetY)
        else
            --BOTTOMRIGHT
            control:SetAnchor(BOTTOMRIGHT, anchorTo, TOPLEFT, -offsetX, -offsetY)
        end
    end
end
--anchors a control to the centered text in a larger label
function ZO_Anchor_ToCenteredLabel(control, anchor, labelWidth)
     local label = anchor:GetTarget()
     local textWidth, _ = label:GetTextDimensions()
     local labelWidth = labelWidth or label:GetWidth()
     local offX, offY = anchor:GetOffsets()
     
    control:SetAnchor(anchor:GetMyPoint(), label, anchor:GetRelativePoint(), labelWidth*0.5 - textWidth*0.5 + offX, offY)
end
function ZO_Anchor_OnRing(control, anchorToControl, x, y, radiusArg)
     local radius = radiusArg or anchorToControl:GetWidth() * 0.5
     local anchorCenterX = anchorToControl:GetLeft() + anchorToControl:GetWidth() * 0.5
     local anchorCenterY = anchorToControl:GetTop() + anchorToControl:GetHeight() * 0.5
     
     local vx = x - anchorCenterX
     local vy = y - anchorCenterY
     
     local vMagSq = vx*vx + vy*vy
     local rx, ry
     
     if(vMagSq > 0.001) then
          --scale the vector toward the origin of rotation
          local radiusSq = radius * radius
          local factor = math.sqrt(radiusSq / vMagSq)
          
          rx = vx * factor
          ry = vy * factor
     else
          --just put it at the top, we're so close to the center that it doesn't really matter what side we're on
          rx = 0
          ry = -radius
     end
     
     control:ClearAnchors()
     control:SetAnchor(CENTER, anchorToControl, CENTER, rx, ry)
end
function ZO_Anchor_ByAngle(control, anchorToControl, theta, radiusArg)
     local radius = radiusArg or anchorToControl:GetWidth() * 0.5     
     control:SetAnchor(CENTER, anchorToControl, CENTER, math.cos(theta) * radius, (-math.sin(theta)) * radius)
end
function ZO_Anchor_LineInContainer(line, container, startX, startY, endX, endY)
    line:ClearAnchors()
    line:SetAnchor(TOPLEFT, container, TOPLEFT, startX, startY)
    line:SetAnchor(BOTTOMRIGHT, container, TOPLEFT, endX, endY)
end