Nenue@54
|
1 -- Veneer
|
Nenue@71
|
2 -- Base framework for making things draggable.
|
Nenue@0
|
3
|
Nenue@84
|
4
|
Nenue@84
|
5
|
Nenue@84
|
6
|
Nenue@84
|
7 SLASH_VENEER1 = "/veneer"
|
Nenue@84
|
8 SLASH_VENEER2 = "/vn"
|
Nenue@84
|
9
|
Nenue@84
|
10 SlashCmdList.VENEER = function(cmd)
|
Nenue@84
|
11 end
|
Nenue@84
|
12 VeneerCore = {
|
Nenue@84
|
13 Frames = {},
|
Nenue@84
|
14 ConfigLayers = {},
|
Nenue@84
|
15 FrameClusters = {},
|
Nenue@84
|
16 parserDepth = 0,
|
Nenue@84
|
17 pendingCalls = {},
|
Nenue@84
|
18 }
|
Nenue@84
|
19 VeneerHandlerMixin = {
|
Nenue@87
|
20 Reanchor = nop,
|
Nenue@87
|
21 anchorPoint = 'CENTER', -- indicates the initial cluster group point
|
Nenue@87
|
22 --anchorPath = 'BOTTOM', -- indicates the point from which the frame is anchored in a cluster arrangement
|
Nenue@84
|
23 }
|
Nenue@84
|
24 local print = DEVIAN_WORKSPACE and function(...) print('Veneer', ...) end or nop
|
Nenue@80
|
25 local wipe = table.wipe
|
Nenue@0
|
26
|
Nenue@59
|
27 local defaults = {
|
Nenue@59
|
28 enableAll = true,
|
Nenue@59
|
29 enableModule = {
|
Nenue@59
|
30 BuffFrame = true,
|
Nenue@59
|
31 },
|
Nenue@59
|
32 BuffFrame = {
|
Nenue@59
|
33 width = 48,
|
Nenue@59
|
34 height = 48,
|
Nenue@59
|
35 }
|
Nenue@59
|
36 }
|
Nenue@84
|
37
|
Nenue@71
|
38 local configMode
|
Nenue@79
|
39 local anonID = 0
|
Nenue@79
|
40 local tostring = tostring
|
Nenue@79
|
41 local IsFrameHandle = IsFrameHandle
|
Nenue@79
|
42 local GetAnonymousName = function(key)
|
Nenue@79
|
43 if not key then
|
Nenue@71
|
44 anonID = anonID + 1
|
Nenue@79
|
45 key = anonID
|
Nenue@71
|
46 end
|
Nenue@79
|
47 return 'VN' .. key
|
Nenue@71
|
48 end
|
Nenue@79
|
49 local GetTableName = function(table)
|
Nenue@79
|
50 return (IsFrameHandle(table) and table:GetName()) or tostring(table)
|
Nenue@79
|
51 end
|
Nenue@79
|
52
|
Nenue@87
|
53 local OFFSET_PARALLELS = {
|
Nenue@87
|
54 TOP = {'LEFT', 'RIGHT', 'SetHeight'},
|
Nenue@87
|
55 BOTTOM = {'LEFT', 'RIGHT', 'SetHeight'},
|
Nenue@87
|
56 LEFT = {'TOP', 'BOTTOM', 'SetWidth'},
|
Nenue@87
|
57 RIGHT = {'TOP', 'BOTTOM', 'SetWidth'},
|
Nenue@87
|
58 }
|
Nenue@87
|
59 local ANCHOR_OFFSET_POINT = {
|
Nenue@87
|
60 TOP = 'BOTTOM',
|
Nenue@87
|
61 TOPLEFT = 'BOTTOMRIGHT',
|
Nenue@87
|
62 TOPRIGHT = 'BOTTOMLEFT',
|
Nenue@87
|
63 LEFT = 'RIGHT',
|
Nenue@87
|
64 RIGHT = 'LEFT',
|
Nenue@87
|
65 CENTER = 'CENTER',
|
Nenue@87
|
66 BOTTOM = 'TOP',
|
Nenue@87
|
67 BOTTOMRIGHT = 'TOPLEFT',
|
Nenue@87
|
68 BOTTOMLEFT = 'TOPRIGHT',
|
Nenue@87
|
69 }
|
Nenue@87
|
70 local ANCHOR_INSET_DELTA = {
|
Nenue@87
|
71 TOP = {0, -1},
|
Nenue@87
|
72 TOPLEFT = {1, -1},
|
Nenue@87
|
73 TOPRIGHT = {-1,-1},
|
Nenue@87
|
74 LEFT = {1, 0},
|
Nenue@87
|
75 BOTTOMLEFT = {1, 1},
|
Nenue@87
|
76 BOTTOM = {0, 1},
|
Nenue@87
|
77 BOTTOMRIGHT = {-1, 1},
|
Nenue@87
|
78 RIGHT = {-1, 0},
|
Nenue@87
|
79 CENTER = {0, 0},
|
Nenue@72
|
80 }
|
Nenue@72
|
81
|
Nenue@84
|
82 function VeneerCore:print(...)
|
Nenue@84
|
83 local txt = '|cFFFFFF00Veneer|r:'
|
Nenue@84
|
84 for i = 1, select('#', ...) do
|
Nenue@84
|
85 txt = txt .. ' '.. tostring(select(i, ...))
|
Nenue@84
|
86 end
|
Nenue@84
|
87
|
Nenue@84
|
88 DEFAULT_CHAT_FRAME:AddMessage(txt)
|
Nenue@84
|
89 end
|
Nenue@84
|
90
|
Nenue@84
|
91 function VeneerCore:OnLoad()
|
Nenue@84
|
92 print('|cFFFFFF00Veneer!|r')
|
Nenue@84
|
93 self:RegisterEvent('ADDON_LOADED')
|
Nenue@84
|
94 self:RegisterEvent('PLAYER_LOGIN')
|
Nenue@84
|
95
|
Nenue@84
|
96 self.DEVIAN_PNAME = 'Veneer'
|
Nenue@84
|
97 self:RegisterForDrag('LeftButton')
|
Nenue@84
|
98 end
|
Nenue@84
|
99
|
Nenue@84
|
100 function VeneerCore:OnEvent(event, ...)
|
Nenue@84
|
101 if event == 'ADDON_LOADED' or event == 'PLAYER_LOGIN' then
|
Nenue@84
|
102 if IsLoggedIn() and not self.intialized then
|
Nenue@84
|
103 self:Setup()
|
Nenue@87
|
104 self:UnregisterEvent('ADDON_LOADED')
|
Nenue@87
|
105 self:UnregisterEvent('PLAYER_LOGIN')
|
Nenue@87
|
106 self:Reanchor()
|
Nenue@87
|
107 self:Update()
|
Nenue@84
|
108 end
|
Nenue@84
|
109 end
|
Nenue@84
|
110 end
|
Nenue@84
|
111
|
Nenue@84
|
112 function VeneerCore:OnDragStart()
|
Nenue@84
|
113 self:StartMoving()
|
Nenue@84
|
114 end
|
Nenue@84
|
115
|
Nenue@84
|
116
|
Nenue@84
|
117 function VeneerCore:OnDragStop()
|
Nenue@84
|
118 self:StopMovingOrSizing()
|
Nenue@84
|
119 end
|
Nenue@84
|
120
|
Nenue@84
|
121 function VeneerCore:Setup ()
|
Nenue@87
|
122 self.initialized = true
|
Nenue@84
|
123 if (not VeneerData) or (not VeneerData.version) then
|
Nenue@84
|
124 VeneerData = defaults
|
Nenue@84
|
125 end
|
Nenue@84
|
126 self.data = VeneerData
|
Nenue@87
|
127 self:ExecuteOnClusters(nil, 'Setup')
|
Nenue@87
|
128 end
|
Nenue@84
|
129
|
Nenue@84
|
130
|
Nenue@87
|
131 function VeneerCore:GetClusterFromArgs (...)
|
Nenue@87
|
132 local primaryAnchor
|
Nenue@87
|
133 local insertPosition
|
Nenue@87
|
134 local clusterTable = self.FrameClusters
|
Nenue@87
|
135 for i = 1, select('#', ...) do
|
Nenue@87
|
136 local arg = select(i, ...)
|
Nenue@87
|
137 local argType = type(arg)
|
Nenue@87
|
138 if argType == 'string' then
|
Nenue@87
|
139 if not primaryAnchor then
|
Nenue@87
|
140 primaryAnchor = arg
|
Nenue@87
|
141 end
|
Nenue@87
|
142 clusterTable[arg] = clusterTable[arg] or {}
|
Nenue@87
|
143 clusterTable = clusterTable[arg]
|
Nenue@87
|
144 print(string.rep(' ', i)..'anchor cluster', i, arg)
|
Nenue@87
|
145 elseif argType == 'boolean' then
|
Nenue@87
|
146 insertPosition = 1
|
Nenue@87
|
147 end
|
Nenue@87
|
148 end
|
Nenue@87
|
149 if not primaryAnchor then
|
Nenue@87
|
150 primaryAnchor = 'TOPLEFT'
|
Nenue@87
|
151 end
|
Nenue@87
|
152 if not insertPosition then
|
Nenue@87
|
153 insertPosition = #clusterTable + 1
|
Nenue@87
|
154 end
|
Nenue@87
|
155
|
Nenue@87
|
156
|
Nenue@87
|
157 return primaryAnchor, clusterTable, insertPosition
|
Nenue@84
|
158 end
|
Nenue@84
|
159
|
Nenue@84
|
160 function VeneerCore:AddHandler(handler, ...)
|
Nenue@84
|
161 print('*** Adding handler:', handler.moduleName or handler:GetName())
|
Nenue@87
|
162
|
Nenue@87
|
163 local anchorGroup, clusterTable, clusterIndex = self:GetClusterFromArgs(...)
|
Nenue@87
|
164 if clusterIndex == 1 then
|
Nenue@87
|
165 for i, frame in ipairs(clusterTable) do
|
Nenue@87
|
166 frame.clusterIndex = i + 1
|
Nenue@87
|
167 end
|
Nenue@84
|
168 end
|
Nenue@87
|
169 tinsert(clusterTable, clusterIndex, handler)
|
Nenue@87
|
170 print('cluster', anchorGroup, 'table', clusterTable, 'position', clusterIndex)
|
Nenue@87
|
171
|
Nenue@87
|
172
|
Nenue@87
|
173 handler.anchorCluster = clusterTable
|
Nenue@87
|
174 handler.anchorIndex = clusterIndex
|
Nenue@84
|
175 for k,v in pairs(VeneerHandlerMixin) do
|
Nenue@84
|
176 if not handler[k] then
|
Nenue@87
|
177 print(' * from mixin:', k)
|
Nenue@84
|
178 handler[k] = v
|
Nenue@84
|
179 end
|
Nenue@84
|
180 end
|
Nenue@87
|
181 if self.initialized then
|
Nenue@87
|
182 print(' -- doing initialization')
|
Nenue@87
|
183 if handler.Setup and not handler.initialized then
|
Nenue@87
|
184 handler:Setup()
|
Nenue@87
|
185 handler.initialized = true
|
Nenue@87
|
186 end
|
Nenue@87
|
187 if handler.Update then
|
Nenue@87
|
188 handler:Update()
|
Nenue@87
|
189 end
|
Nenue@87
|
190 self:InternalReanchor(handler)
|
Nenue@87
|
191
|
Nenue@87
|
192 end
|
Nenue@87
|
193 end
|
Nenue@87
|
194
|
Nenue@87
|
195 function VeneerCore:Reanchor()
|
Nenue@87
|
196 self:ExecuteOnClusters(nil, 'Reanchor')
|
Nenue@87
|
197 end
|
Nenue@87
|
198
|
Nenue@87
|
199 function VeneerCore:Update()
|
Nenue@87
|
200 self:ExecuteOnClusters(nil, 'Update')
|
Nenue@87
|
201 end
|
Nenue@87
|
202
|
Nenue@87
|
203 -- updates anchor relations to and from the target handler
|
Nenue@87
|
204 function VeneerCore:GetAnchor(...)
|
Nenue@87
|
205
|
Nenue@87
|
206 end
|
Nenue@87
|
207
|
Nenue@87
|
208 function VeneerCore:InternalReanchor(handler, printFunc)
|
Nenue@87
|
209 print('|cFF00FFFFVeneer:InternalReanchor('..handler:GetName()..')')
|
Nenue@87
|
210 local anchorPoint = handler.anchorPath or handler.anchorPoint
|
Nenue@87
|
211 local anchorParent, anchorTo = UIParent, anchorPoint
|
Nenue@87
|
212 for i, frame in ipairs(handler.anchorCluster) do
|
Nenue@87
|
213 if frame ~= handler then
|
Nenue@87
|
214 anchorParent = frame
|
Nenue@87
|
215 anchorTo = ANCHOR_OFFSET_POINT[anchorPoint]
|
Nenue@87
|
216
|
Nenue@87
|
217 else
|
Nenue@87
|
218 local nextFrame = handler.anchorCluster[i+1]
|
Nenue@87
|
219 if nextFrame then
|
Nenue@87
|
220
|
Nenue@87
|
221 local subPoint = nextFrame.anchorPath or nextFrame.anchorPoint
|
Nenue@87
|
222 local subTo = ANCHOR_OFFSET_POINT[subPoint]
|
Nenue@87
|
223 nextFrame:ClearAllPoints()
|
Nenue@87
|
224 nextFrame:SetPoint(subPoint, handler, subTo, 0, 0)
|
Nenue@87
|
225 print(' -- pushing '..nextFrame:GetName()..' down the anchor chain', subPoint, subTo)
|
Nenue@87
|
226 end
|
Nenue@87
|
227 break
|
Nenue@87
|
228 end
|
Nenue@87
|
229 end
|
Nenue@87
|
230
|
Nenue@87
|
231 handler:ClearAllPoints()
|
Nenue@87
|
232 handler:SetPoint(anchorPoint, anchorParent, anchorTo, 0, 0)
|
Nenue@87
|
233
|
Nenue@87
|
234 print(handler.anchorPoint, anchorParent, anchorTo)
|
Nenue@87
|
235 if printFunc then
|
Nenue@87
|
236 printFunc('|cFF88FF00'..handler:GetName()..':SetPoint(', handler.anchorPoint, anchorParent, anchorTo)
|
Nenue@87
|
237 end
|
Nenue@87
|
238
|
Nenue@84
|
239 end
|
Nenue@84
|
240
|
Nenue@84
|
241 function VeneerCore:ExecuteOnClusters(layer, method)
|
Nenue@84
|
242 self.parserDepth = self.parserDepth + 1
|
Nenue@84
|
243 if not layer then
|
Nenue@87
|
244 if self.parserDepth > 1 then
|
Nenue@84
|
245 tinsert(self.pendingCalls, method)
|
Nenue@84
|
246 print('delaying walk for', method)
|
Nenue@84
|
247 return
|
Nenue@84
|
248 end
|
Nenue@87
|
249 print('|cFF00FF00Veneer:ExecuteOnClusters|r('..tostring(layer)..', '..method..')')
|
Nenue@84
|
250 else
|
Nenue@87
|
251 print(' Level '..self.parserDepth)
|
Nenue@84
|
252 end
|
Nenue@87
|
253
|
Nenue@87
|
254 layer = layer or self.FrameClusters
|
Nenue@84
|
255 for anchor, cluster in pairs(layer) do
|
Nenue@84
|
256 for index, frame in ipairs(cluster) do
|
Nenue@87
|
257 print(' '..anchor..'.'..index..' = '..frame:GetName())
|
Nenue@84
|
258 if frame[method] then
|
Nenue@87
|
259 print(' |cFF00FF00'..frame:GetName())
|
Nenue@87
|
260 frame[method](frame, true)
|
Nenue@84
|
261 end
|
Nenue@84
|
262 end
|
Nenue@84
|
263 if cluster.FrameClusters then
|
Nenue@84
|
264 self:ExecuteOnClusters(cluster.FrameClusters, method)
|
Nenue@84
|
265 end
|
Nenue@84
|
266 end
|
Nenue@84
|
267 self.parserDepth = self.parserDepth - 1
|
Nenue@84
|
268
|
Nenue@84
|
269 if (self.parserDepth == 0) and (#self.pendingCalls >= 1) then
|
Nenue@84
|
270 local delayedMethod = tremove(self.pendingCalls, 1)
|
Nenue@84
|
271 print('starting delayed walk for', delayedMethod)
|
Nenue@84
|
272 self:ExecuteOnClusters(nil, delayedMethod)
|
Nenue@84
|
273 end
|
Nenue@84
|
274 end
|
Nenue@84
|
275
|
Nenue@72
|
276 local VeneerButton_OnDragStart = function(self)
|
Nenue@72
|
277 self.startingLeft = self:GetLeft()
|
Nenue@72
|
278 self.startingBottom = self:GetBottom()
|
Nenue@72
|
279 self.anchors = self.anchors or {}
|
Nenue@72
|
280 table.wipe(self.anchors)
|
Nenue@72
|
281
|
Nenue@72
|
282 local frame = self:GetParent()
|
Nenue@72
|
283 local n = frame:GetNumPoints()
|
Nenue@72
|
284 for i = 1, n do
|
Nenue@72
|
285 local anchor, parent, relative, x, y = frame:GetPoint(i)
|
Nenue@72
|
286 self.anchors[i] = {
|
Nenue@72
|
287 anchor = anchor,
|
Nenue@72
|
288 parent = parent,
|
Nenue@72
|
289 relative = relative,
|
Nenue@72
|
290 x = x,
|
Nenue@72
|
291 y = y
|
Nenue@72
|
292 }
|
Nenue@72
|
293 end
|
Nenue@72
|
294
|
Nenue@72
|
295 print(self:GetName(), 'start moving', self.startingLeft, self.startingBottom)
|
Nenue@72
|
296 self:StartMoving()
|
Nenue@72
|
297 end
|
Nenue@72
|
298
|
Nenue@72
|
299 local VeneerButton_OnDragStop = function(self)
|
Nenue@72
|
300 self:StopMovingOrSizing()
|
Nenue@72
|
301 if self.OnDragStop then
|
Nenue@72
|
302 self.OnDragStop(self)
|
Nenue@72
|
303 else
|
Nenue@72
|
304 local frame = self:GetParent()
|
Nenue@72
|
305 local dx = self:GetLeft() - self.startingLeft
|
Nenue@72
|
306 local dy = self:GetBottom() - self.startingBottom
|
Nenue@72
|
307
|
Nenue@72
|
308 frame:ClearAllPoints()
|
Nenue@72
|
309 for i, point in ipairs(self.anchors) do
|
Nenue@72
|
310 frame:SetPoint(point.anchor, point.parent, point.relative, point.x + dx, point.y + dy)
|
Nenue@72
|
311 print('adjusting anchor', point.anchor, point.parent, point.relative, point.x + dx, point.y + dy)
|
Nenue@72
|
312 end
|
Nenue@72
|
313 end
|
Nenue@72
|
314 end
|
Nenue@72
|
315
|
Nenue@72
|
316 local Veneer_FixMovers = function()
|
Nenue@72
|
317 for frame, veneer in pairs(veneers) do
|
Nenue@72
|
318 if veneer:IsMoving() then
|
Nenue@72
|
319 VeneerButton_OnDragStop(veneer)
|
Nenue@72
|
320 end
|
Nenue@72
|
321 end
|
Nenue@72
|
322 end
|
Nenue@71
|
323
|
Nenue@71
|
324 local VeneerButton_Update = function(self)
|
Nenue@71
|
325 if configMode then
|
Nenue@72
|
326 self:SetScript('OnDragStart', VeneerButton_OnDragStart)
|
Nenue@72
|
327 self:SetScript('OnDragStop', VeneerButton_OnDragStop)
|
Nenue@72
|
328 self:SetMovable(true)
|
Nenue@72
|
329 self:EnableMouse(true)
|
Nenue@71
|
330 self:RegisterForDrag('LeftButton')
|
Nenue@71
|
331
|
Nenue@71
|
332 self.bg:SetColorTexture(0,1,0,0.5)
|
Nenue@72
|
333 for i, region in ipairs(self.configLayers) do
|
Nenue@72
|
334 region:Show()
|
Nenue@72
|
335 end
|
Nenue@72
|
336 self:Show()
|
Nenue@71
|
337 else
|
Nenue@71
|
338
|
Nenue@71
|
339 self:SetScript('OnDragStart', self.StartMoving)
|
Nenue@71
|
340 self:SetScript('OnDragStop', self.StopMovingOrSizing)
|
Nenue@71
|
341 self:SetMovable(false)
|
Nenue@71
|
342 self:EnableMouse(false)
|
Nenue@71
|
343
|
Nenue@71
|
344 self.bg:SetColorTexture(0,1,0,0)
|
Nenue@72
|
345 for i, region in ipairs(self.configLayers) do
|
Nenue@72
|
346 region:Hide()
|
Nenue@72
|
347 end
|
Nenue@72
|
348 if self.isHidden then
|
Nenue@72
|
349 self:Hide()
|
Nenue@72
|
350 end
|
Nenue@72
|
351
|
Nenue@71
|
352 end
|
Nenue@71
|
353 end
|
Nenue@71
|
354
|
Nenue@71
|
355 local ToggleVeneerConfig = function()
|
Nenue@71
|
356 if configMode then
|
Nenue@71
|
357 configMode = false
|
Nenue@84
|
358 Veneer:print('Config mode off.')
|
Nenue@71
|
359 else
|
Nenue@71
|
360 configMode = true
|
Nenue@84
|
361 Veneer:print('Config mode on.')
|
Nenue@71
|
362 end
|
Nenue@71
|
363
|
Nenue@71
|
364 for frame, veneer in pairs(veneers) do
|
Nenue@71
|
365 VeneerButton_Update(veneer)
|
Nenue@71
|
366 end
|
Nenue@71
|
367 end
|
Nenue@71
|
368
|
Nenue@71
|
369 local VeneerButton_OnShow = function(self)
|
Nenue@71
|
370 VeneerButton_Update(self)
|
Nenue@71
|
371 end
|
Nenue@71
|
372
|
Nenue@84
|
373 function VeneerCore:Acquire (frame, template)
|
Nenue@71
|
374 if not frame then
|
Nenue@71
|
375 print('|cFFFF4400Unable to acquire frame...|r')
|
Nenue@71
|
376 return
|
Nenue@71
|
377 end
|
Nenue@84
|
378 local veneer = self.Frames[frame]
|
Nenue@84
|
379 if not veneer then
|
Nenue@84
|
380 local name = type(frame) == 'table' and GetTableName(frame) or GetAnonymousName()
|
Nenue@84
|
381 veneer = CreateFrame('Frame', name, frame, template or 'VeneerTemplate')
|
Nenue@84
|
382 print('+veneer', name)
|
Nenue@71
|
383
|
Nenue@84
|
384 veneer:SetAllPoints(frame)
|
Nenue@84
|
385 veneer:SetParent(frame)
|
Nenue@84
|
386 veneer.label:SetText(name)
|
Nenue@84
|
387 veneer.bg:SetColorTexture(0,0,0,0)
|
Nenue@84
|
388 veneer:Hide()
|
Nenue@84
|
389 veneer:EnableMouse(false)
|
Nenue@84
|
390
|
Nenue@84
|
391 veneer:SetScript('OnShow', VeneerButton_OnShow)
|
Nenue@84
|
392
|
Nenue@84
|
393 -- find current X/Y
|
Nenue@84
|
394 veneer.currentLeft = frame:GetLeft()
|
Nenue@84
|
395 veneer.currentTop = frame:GetTop()
|
Nenue@84
|
396 self.Frames[frame] = veneer
|
Nenue@71
|
397 end
|
Nenue@71
|
398
|
Nenue@84
|
399 return veneer
|
Nenue@71
|
400 end
|
Nenue@0
|
401
|
Nenue@80
|
402 local mixin_probe = {
|
Nenue@80
|
403 'ArtifactFrame',
|
Nenue@80
|
404 'ArtifactFrameUnderlay',
|
Nenue@80
|
405 }
|
Nenue@80
|
406
|
Nenue@80
|
407
|