vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | --[[--------------------------------------------------------------------------------- |
2 | General Library providing an alternate StartMoving() that allows you to |
||
3 | specify a number of frames to snap-to when moving the frame around |
||
4 | |||
5 | Example Usage: |
||
6 | |||
7 | <OnLoad> |
||
8 | this:RegisterForDrag("LeftButton") |
||
9 | </OnLoad> |
||
10 | <OnDragStart> |
||
11 | StickyFrames:StartMoving(this, {WatchDogFrame_player, WatchDogFrame_target, WatchDogFrame_party1, WatchDogFrame_party2, WatchDogFrame_party3, WatchDogFrame_party4},3,3,3,3) |
||
12 | </OnDragStart> |
||
13 | <OnDragStop> |
||
14 | StickyFrames:StopMoving(this) |
||
15 | StickyFrames:AnchorFrame(this) |
||
16 | </OnDragStop> |
||
17 | ------------------------------------------------------------------------------------]] |
||
18 | |||
19 | --[[--------------------------------------------------------------------------------- |
||
20 | Class declaration, along with a temporary table to hold any existing OnUpdate |
||
21 | scripts. |
||
22 | ------------------------------------------------------------------------------------]] |
||
23 | |||
24 | StickyFrames = {} |
||
25 | StickyFrames.scripts = {} |
||
26 | |||
27 | --[[--------------------------------------------------------------------------------- |
||
28 | StickyFrames:StartMoving() - Sets a custom OnUpdate for the frame so it follows |
||
29 | the mouse and snaps to the frames you specify |
||
30 | |||
31 | frame: The frame we want to move. Is typically "this" |
||
32 | |||
33 | frameList: A integer indexed list of frames that the given frame should try to |
||
34 | stick to. These don't have to have anything special done to them, |
||
35 | and they don't really even need to exist. You can inclue the |
||
36 | moving frame in this list, it will be ignored. This helps you |
||
37 | if you have a number of frames, just make ONE list to pass. |
||
38 | |||
39 | {WatchDogFrame_player, WatchDogFrame_party1, .. WatchDogFrame_party4} |
||
40 | |||
41 | left: If your frame has a tranparent border around the entire frame |
||
42 | (think backdrops with borders). This can be used to fine tune the |
||
43 | edges when you're stickying groups. Refers to any offset on the |
||
44 | LEFT edge of the frame being moved. |
||
45 | |||
46 | top: same |
||
47 | right: same |
||
48 | bottom: same |
||
49 | ------------------------------------------------------------------------------------]] |
||
50 | |||
51 | function StickyFrames:StartMoving(frame, frameList, left, top, right, bottom) |
||
52 | local x,y = GetCursorPosition() |
||
53 | local aX,aY = frame:GetCenter() |
||
54 | local aS = frame:GetEffectiveScale() |
||
55 | |||
56 | aX,aY = aX*aS,aY*aS |
||
57 | local xoffset,yoffset = (aX - x),(aY - y) |
||
58 | self.scripts[frame] = frame:GetScript("OnUpdate") |
||
59 | frame:SetScript("OnUpdate", self:GetUpdateFunc(frame, frameList, xoffset, yoffset, left, top, right, bottom)) |
||
60 | end |
||
61 | |||
62 | --[[--------------------------------------------------------------------------------- |
||
63 | This stops the OnUpdate, leaving the frame at its last position. This will |
||
64 | leave it anchored to UIParent. You can call StickyFrames:AnchorFrame() to |
||
65 | anchor it back "TOPLEFT" , "TOPLEFT" to the parent. |
||
66 | ------------------------------------------------------------------------------------]] |
||
67 | |||
68 | function StickyFrames:StopMoving(frame) |
||
69 | frame:SetScript("OnUpdate", self.scripts[frame]) |
||
70 | self.scripts[frame] = nil |
||
71 | end |
||
72 | |||
73 | --[[--------------------------------------------------------------------------------- |
||
74 | This can be called in conjunction with StickyFrames:StopMoving() to anchor the |
||
75 | frame right back to the parent, so you can manipulate its children as a group |
||
76 | (This is useful in WatchDog) |
||
77 | ------------------------------------------------------------------------------------]] |
||
78 | |||
79 | function StickyFrames:AnchorFrame(frame) |
||
80 | local xA,yA = frame:GetCenter() |
||
81 | local parent = frame:GetParent() or UIParent |
||
82 | local xP,yP = parent:GetCenter() |
||
83 | local sA,sP = frame:GetEffectiveScale(), parent:GetEffectiveScale() |
||
84 | |||
85 | xP,yP = (xP*sP) / sA, (yP*sP) / sA |
||
86 | |||
87 | local xo,yo = (xP - xA)*-1, (yP - yA)*-1 |
||
88 | |||
89 | frame:ClearAllPoints() |
||
90 | frame:SetPoint("CENTER", parent, "CENTER", xo, yo) |
||
91 | end |
||
92 | |||
93 | |||
94 | --[[--------------------------------------------------------------------------------- |
||
95 | Internal Functions -- Do not call these. |
||
96 | ------------------------------------------------------------------------------------]] |
||
97 | |||
98 | |||
99 | |||
100 | --[[--------------------------------------------------------------------------------- |
||
101 | Returns an anonymous OnUpdate function for the frame in question. Need |
||
102 | to provide the frame, frameList along with the x and y offset (difference between |
||
103 | where the mouse picked up the frame, and the insets (left,top,right,bottom) in the |
||
104 | case of borders, etc.w |
||
105 | ------------------------------------------------------------------------------------]] |
||
106 | |||
107 | function StickyFrames:GetUpdateFunc(frame, frameList, xoffset, yoffset, left, top, right, bottom) |
||
108 | return function() |
||
109 | local x,y = GetCursorPosition() |
||
110 | local s = frame:GetEffectiveScale() |
||
111 | local sticky = nil |
||
112 | |||
113 | x,y = x/s,y/s |
||
114 | |||
115 | frame:ClearAllPoints() |
||
116 | frame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x+xoffset, y+yoffset) |
||
117 | |||
118 | for k,v in ipairs(frameList) do |
||
119 | if frame ~= v then |
||
120 | if self:Overlap(frame, v) then |
||
121 | if self:SnapFrame(frame, v, left, top, right, bottom) then break end |
||
122 | end |
||
123 | end |
||
124 | end |
||
125 | end |
||
126 | end |
||
127 | |||
128 | |||
129 | --[[--------------------------------------------------------------------------------- |
||
130 | Internal debug function. |
||
131 | ------------------------------------------------------------------------------------]] |
||
132 | |||
133 | function StickyFrames:debug(msg) |
||
134 | DEFAULT_CHAT_FRAME:AddMessage("|cffffff00StickyFrames: |r"..tostring(msg)) |
||
135 | end |
||
136 | |||
137 | --[[--------------------------------------------------------------------------------- |
||
138 | Determines the overlap between two frames. Returns true if the frames |
||
139 | overlap anywhere, or false if they don't. Does not consider alpha on the edges of |
||
140 | textures. |
||
141 | ------------------------------------------------------------------------------------]] |
||
142 | function StickyFrames:Overlap(frameA, frameB) |
||
143 | local sA, sB = frameA:GetEffectiveScale(), frameB:GetEffectiveScale() |
||
144 | return ((frameA:GetLeft()*sA) < (frameB:GetRight()*sB)) |
||
145 | and ((frameB:GetLeft()*sB) < (frameA:GetRight()*sA)) |
||
146 | and ((frameA:GetBottom()*sA) < (frameB:GetTop()*sB)) |
||
147 | and ((frameB:GetBottom()*sB) < (frameA:GetTop()*sA)) |
||
148 | end |
||
149 | |||
150 | --[[--------------------------------------------------------------------------------- |
||
151 | This is called when finding an overlap between two sticky frame. If frameA is near |
||
152 | a sticky edge of frameB, then it will snap to that edge and return true. If there |
||
153 | is no sticky edge collision, will return false so we can test other frames for |
||
154 | stickyness. |
||
155 | ------------------------------------------------------------------------------------]] |
||
156 | function StickyFrames:SnapFrame(frameA, frameB, left, top, right, bottom) |
||
157 | local sA, sB = frameA:GetEffectiveScale(), frameB:GetEffectiveScale() |
||
158 | local xA, yA = frameA:GetCenter() |
||
159 | local xB, yB = frameB:GetCenter() |
||
160 | local hA, hB = frameA:GetHeight() / 2, ((frameB:GetHeight() * sB) / sA) / 2 |
||
161 | local wA, wB = frameA:GetWidth() / 2, ((frameB:GetWidth() * sB) / sA) / 2 |
||
162 | |||
163 | if not left then left = 0 end |
||
164 | if not top then top = 0 end |
||
165 | if not right then right = 0 end |
||
166 | if not bottom then bottom = 0 end |
||
167 | |||
168 | -- Lets translate B's coords into A's scale |
||
169 | xB, yB = (xB*sB) / sA, (yB*sB) / sA |
||
170 | |||
171 | local stickyAx, stickyAy = wA * 0.75, hA * 0.75 |
||
172 | local stickyBx, stickyBy = wB * 0.75, hB * 0.75 |
||
173 | |||
174 | -- Grab the edges of each frame, for easier comparison |
||
175 | |||
176 | local lA, tA, rA, bA = frameA:GetLeft(), frameA:GetTop(), frameA:GetRight(), frameA:GetBottom() |
||
177 | local lB, tB, rB, bB = frameB:GetLeft(), frameB:GetTop(), frameB:GetRight(), frameB:GetBottom() |
||
178 | local snap = nil |
||
179 | |||
180 | -- Translate into A's scale |
||
181 | lB, tB, rB, bB = (lB * sB) / sA, (tB * sB) / sA, (rB * sB) / sA, (bB * sB) / sA |
||
182 | |||
183 | -- Lets check for Left stickyness |
||
184 | if lA > (rB - stickyAx) then |
||
185 | -- If we are 5 pixels above or below the top of the sticky frame |
||
186 | -- Snap to the top edge of it. |
||
187 | if tA <= (tB + 5) and tA >= (tB - 5) then |
||
188 | yA = (tB - hA) |
||
189 | elseif bA <= (bB + 5) and bA >= (bB - 5) then |
||
190 | yA = (bB + hA) |
||
191 | end |
||
192 | |||
193 | -- Set the x sticky position |
||
194 | xA = rB + (wA - left) |
||
195 | |||
196 | -- Delay the snap until later |
||
197 | snap = true |
||
198 | |||
199 | -- Check for Right stickyness |
||
200 | elseif rA < (lB + stickyAx) then |
||
201 | -- If we are 5 pixels above or below the top of the sticky frame |
||
202 | -- Snap to the top edge of it. |
||
203 | if tA <= (tB + 5) and tA >= (tB - 5) then |
||
204 | yA = (tB - hA) |
||
205 | elseif bA <= (bB + 5) and bA >= (bB - 5) then |
||
206 | yA = (bB + hA) |
||
207 | end |
||
208 | |||
209 | -- Set the x sticky position |
||
210 | xA = lB - (wA - right) |
||
211 | |||
212 | -- Delay the snap until later |
||
213 | snap = true |
||
214 | |||
215 | -- Bottom stickyness |
||
216 | elseif bA > (tB - stickyAy) then |
||
217 | |||
218 | -- If we are 5 pixels to the left or right of the sticky frame |
||
219 | -- Snap to the edge of it. |
||
220 | |||
221 | if lA <= (lB + 5) and lA >= (lB - 5) then |
||
222 | xA = (lB + wA) |
||
223 | elseif rA >= (rB - 5) and rA <= (rB + 5) then |
||
224 | xA = (rB - wA) |
||
225 | end |
||
226 | |||
227 | -- Set the y sticky position |
||
228 | yA = tB + (hA - bottom) |
||
229 | |||
230 | -- Delay the snap |
||
231 | snap = true |
||
232 | |||
233 | elseif tA < (bB + stickyAy) then |
||
234 | -- If we are 5 pixels to the left or right of the sticky frame |
||
235 | -- Snap to the edge of it. |
||
236 | if lA <= (lB + 5) and lA >= (lB - 5) then |
||
237 | xA = (lB + wA) |
||
238 | elseif rA >= (rB - 5) and rA <= (rB + 5) then |
||
239 | xA = (rB - wA) |
||
240 | end |
||
241 | |||
242 | -- Set the y sticky position |
||
243 | yA = bB - (hA - bottom) |
||
244 | |||
245 | -- Delay the snap |
||
246 | snap = true |
||
247 | end |
||
248 | |||
249 | if snap then |
||
250 | frameA:ClearAllPoints() |
||
251 | frameA:SetPoint("CENTER", UIParent, "BOTTOMLEFT", xA, yA) |
||
252 | return true |
||
253 | end |
||
254 | end |