| flickerstreak@122 | 1 local ReAction               = ReAction | 
| flickerstreak@122 | 2 local L                      = ReAction.L | 
| flickerstreak@122 | 3 local CreateFrame            = CreateFrame | 
| flickerstreak@122 | 4 local InCombatLockdown       = InCombatLockdown | 
| flickerstreak@122 | 5 local floor                  = math.floor | 
| flickerstreak@122 | 6 local min                    = math.min | 
| flickerstreak@122 | 7 local format                 = string.format | 
| flickerstreak@122 | 8 local GameTooltip            = GameTooltip | 
| flickerstreak@122 | 9 local Bar                    = ReAction.Bar | 
| flickerstreak@122 | 10 local GetSize                = Bar.GetSize | 
| flickerstreak@122 | 11 local SetSize                = Bar.SetSize | 
| flickerstreak@122 | 12 local GetButtonSize          = Bar.GetButtonSize | 
| flickerstreak@122 | 13 local GetButtonGrid          = Bar.GetButtonGrid | 
| flickerstreak@122 | 14 local SetButtonSize          = Bar.SetButtonSize | 
| flickerstreak@122 | 15 local SetButtonGrid          = Bar.SetButtonGrid | 
| flickerstreak@122 | 16 local ApplyAnchor            = Bar.ApplyAnchor | 
| flickerstreak@122 | 17 local GameTooltipTextRight1  = GameTooltipTextRight1 | 
| flickerstreak@122 | 18 local GameTooltipTextRight2  = GameTooltipTextRight2 | 
| flickerstreak@122 | 19 local GameTooltipTextRight3  = GameTooltipTextRight3 | 
| flickerstreak@122 | 20 | 
| flickerstreak@122 | 21 local KB = LibStub("LibKeyBound-1.0") | 
| flickerstreak@122 | 22 | 
| flickerstreak@122 | 23 ReAction:UpdateRevision("$Revision$") | 
| flickerstreak@122 | 24 | 
| flickerstreak@122 | 25 | 
| flickerstreak@122 | 26 -- | 
| flickerstreak@122 | 27 -- Wrap some of the bar manipulators to make them state-aware | 
| flickerstreak@122 | 28 -- | 
| flickerstreak@122 | 29 local function SetAnchor( bar, point, frame, relPoint, x, y ) | 
| flickerstreak@122 | 30   local state = bar:GetState() | 
| flickerstreak@122 | 31   if state then | 
| flickerstreak@122 | 32     local anchorstate = bar:GetStateProperty(state, "anchorEnable") | 
| flickerstreak@122 | 33     if anchorstate then | 
| flickerstreak@122 | 34       bar:SetStateProperty(state, "anchorFrame", frame) | 
| flickerstreak@122 | 35       bar:SetStateProperty(state, "anchorPoint", point) | 
| flickerstreak@122 | 36       bar:SetStateProperty(state, "anchorRelPoint", relPoint) | 
| flickerstreak@122 | 37       bar:SetStateProperty(state, "anchorX", x or 0) | 
| flickerstreak@122 | 38       bar:SetStateProperty(state, "anchorY", y or 0) | 
| flickerstreak@122 | 39       bar:SetAnchor(bar:GetAnchor()) | 
| flickerstreak@122 | 40       return | 
| flickerstreak@122 | 41     end | 
| flickerstreak@122 | 42   end | 
| flickerstreak@122 | 43   bar:SetAnchor(point, frame, relPoint, x, y) | 
| flickerstreak@122 | 44 end | 
| flickerstreak@122 | 45 | 
| flickerstreak@122 | 46 local function GetStateScale( bar ) | 
| flickerstreak@122 | 47   local state = bar:GetState() | 
| flickerstreak@122 | 48   if state and bar:GetStateProperty(state, "enableScale") then | 
| flickerstreak@122 | 49     return bar:GetStateProperty(state, "scale") | 
| flickerstreak@122 | 50   end | 
| flickerstreak@122 | 51 end | 
| flickerstreak@122 | 52 | 
| flickerstreak@122 | 53 local function SetStateScale( bar, scale ) | 
| flickerstreak@122 | 54   local state = bar:GetState() | 
| flickerstreak@122 | 55   if state and bar:GetStateProperty(state, "enableScale") then | 
| flickerstreak@122 | 56     bar:SetStateProperty(state, "scale", scale) | 
| flickerstreak@122 | 57   end | 
| flickerstreak@122 | 58 end | 
| flickerstreak@122 | 59 | 
| flickerstreak@122 | 60 | 
| flickerstreak@122 | 61 -- | 
| flickerstreak@122 | 62 -- Bar config overlay | 
| flickerstreak@122 | 63 -- | 
| flickerstreak@122 | 64 | 
| flickerstreak@122 | 65 local function GetNormalTextColor() | 
| flickerstreak@122 | 66   return 1.0, 1.0, 1.0, 1.0 | 
| flickerstreak@122 | 67 end | 
| flickerstreak@122 | 68 | 
| flickerstreak@122 | 69 local function GetAnchoredTextColor() | 
| flickerstreak@122 | 70   return 1.0, 1.0, 1.0, 1.0 | 
| flickerstreak@122 | 71 end | 
| flickerstreak@122 | 72 | 
| flickerstreak@122 | 73 local function GetNormalBgColor() | 
| flickerstreak@122 | 74   return 0.7, 0.7, 1.0, 0.3 | 
| flickerstreak@122 | 75 end | 
| flickerstreak@122 | 76 | 
| flickerstreak@122 | 77 local function GetAnchoredBgColor() | 
| flickerstreak@122 | 78   return 0.9, 0.2, 0.7, 0.3 | 
| flickerstreak@122 | 79 end | 
| flickerstreak@122 | 80 | 
| flickerstreak@122 | 81 local function StoreSize(bar) | 
| flickerstreak@122 | 82   local f = bar:GetFrame() | 
| flickerstreak@122 | 83   SetSize( bar, f:GetWidth(), f:GetHeight() ) | 
| flickerstreak@122 | 84 end | 
| flickerstreak@122 | 85 | 
| flickerstreak@122 | 86 local function StoreExtents(bar) | 
| flickerstreak@122 | 87   local f = bar:GetFrame() | 
| flickerstreak@122 | 88   local p, fr, rp, x, y = f:GetPoint(1) | 
| flickerstreak@122 | 89   fr = fr and fr:GetName() or "UIParent" | 
| flickerstreak@122 | 90   SetAnchor( bar, p, fr, rp, x, y ) | 
| flickerstreak@122 | 91   SetSize( bar, f:GetWidth(), f:GetHeight() ) | 
| flickerstreak@122 | 92 end | 
| flickerstreak@122 | 93 | 
| flickerstreak@122 | 94 local function RecomputeButtonSize(bar) | 
| flickerstreak@122 | 95   local w, h = GetSize(bar) | 
| flickerstreak@122 | 96   local bw, bh = GetButtonSize(bar) | 
| flickerstreak@122 | 97   local r, c, s = GetButtonGrid(bar) | 
| flickerstreak@122 | 98 | 
| flickerstreak@122 | 99   local scaleW = (floor(w/c) - s) / bw | 
| flickerstreak@122 | 100   local scaleH = (floor(h/r) - s) / bh | 
| flickerstreak@122 | 101   local scale = min(scaleW, scaleH) | 
| flickerstreak@122 | 102 | 
| flickerstreak@122 | 103   SetButtonSize(bar, scale * bw, scale * bh, s) | 
| flickerstreak@122 | 104 end | 
| flickerstreak@122 | 105 | 
| flickerstreak@122 | 106 local function ComputeBarScale(bar) | 
| flickerstreak@122 | 107   local w, h = bar.controlFrame:GetWidth() - 8, bar.controlFrame:GetHeight() - 8 | 
| flickerstreak@122 | 108   local bw, bh = GetButtonSize(bar) | 
| flickerstreak@122 | 109   local r, c, s = GetButtonGrid(bar) | 
| flickerstreak@122 | 110 | 
| flickerstreak@122 | 111   local scaleW = w / (c*(bw+s)) | 
| flickerstreak@122 | 112   local scaleH = h / (r*(bh+s)) | 
| flickerstreak@122 | 113   local scale = min(scaleW, scaleH) | 
| flickerstreak@122 | 114 | 
| flickerstreak@122 | 115   if scale > 2.5 then | 
| flickerstreak@122 | 116     scale = 2.5 | 
| flickerstreak@122 | 117   elseif scale < 0.25 then | 
| flickerstreak@122 | 118     scale = 0.25 | 
| flickerstreak@122 | 119   end | 
| flickerstreak@122 | 120 | 
| flickerstreak@122 | 121   return scale | 
| flickerstreak@122 | 122 end | 
| flickerstreak@122 | 123 | 
| flickerstreak@122 | 124 local function RecomputeButtonSpacing(bar) | 
| flickerstreak@122 | 125   local w, h = GetSize(bar) | 
| flickerstreak@122 | 126   local bw, bh = GetButtonSize(bar) | 
| flickerstreak@122 | 127   local r, c, s = GetButtonGrid(bar) | 
| flickerstreak@122 | 128 | 
| flickerstreak@122 | 129   SetButtonGrid(bar,r,c,min(floor(w/c) - bw, floor(h/r) - bh)) | 
| flickerstreak@122 | 130 end | 
| flickerstreak@122 | 131 | 
| flickerstreak@122 | 132 local function RecomputeGrid(bar) | 
| flickerstreak@122 | 133   local w, h = GetSize(bar) | 
| flickerstreak@122 | 134   local bw, bh = GetButtonSize(bar) | 
| flickerstreak@122 | 135   local r, c, s = GetButtonGrid(bar) | 
| flickerstreak@122 | 136 | 
| flickerstreak@122 | 137   SetButtonGrid(bar, floor(h/(bh+s)), floor(w/(bw+s)), s) | 
| flickerstreak@122 | 138 end | 
| flickerstreak@122 | 139 | 
| flickerstreak@122 | 140 local function ClampToButtons(bar) | 
| flickerstreak@122 | 141   local bw, bh = GetButtonSize(bar) | 
| flickerstreak@122 | 142   local r, c, s = GetButtonGrid(bar) | 
| flickerstreak@122 | 143   SetSize(bar, (bw+s)*c + 1, (bh+s)*r + 1) | 
| flickerstreak@122 | 144 end | 
| flickerstreak@122 | 145 | 
| flickerstreak@122 | 146 local function HideGameTooltip() | 
| flickerstreak@122 | 147   GameTooltip:Hide() | 
| flickerstreak@122 | 148 end | 
| flickerstreak@122 | 149 | 
| flickerstreak@122 | 150 local anchorInside  = { inside = true } | 
| flickerstreak@122 | 151 local anchorOutside = { outside = true } | 
| flickerstreak@122 | 152 local edges = { "BOTTOM", "TOP", "LEFT", "RIGHT" } | 
| flickerstreak@122 | 153 local oppositeEdges = { | 
| flickerstreak@122 | 154   TOP = "BOTTOM", | 
| flickerstreak@122 | 155   BOTTOM = "TOP", | 
| flickerstreak@122 | 156   LEFT = "RIGHT", | 
| flickerstreak@122 | 157   RIGHT = "LEFT" | 
| flickerstreak@122 | 158 } | 
| flickerstreak@122 | 159 local pointsOnEdge = { | 
| flickerstreak@122 | 160   BOTTOM = { "BOTTOM", "BOTTOMLEFT",  "BOTTOMRIGHT",  }, | 
| flickerstreak@122 | 161   TOP    = { "TOP",    "TOPLEFT",     "TOPRIGHT",     }, | 
| flickerstreak@122 | 162   RIGHT  = { "RIGHT",  "BOTTOMRIGHT", "TOPRIGHT",     }, | 
| flickerstreak@122 | 163   LEFT   = { "LEFT",   "BOTTOMLEFT",  "TOPLEFT",      }, | 
| flickerstreak@122 | 164 } | 
| flickerstreak@122 | 165 local edgeSelector = { | 
| flickerstreak@122 | 166   BOTTOM = 1,  -- select x of x,y | 
| flickerstreak@122 | 167   TOP    = 1,  -- select x of x,y | 
| flickerstreak@122 | 168   LEFT   = 2,  -- select y of x,y | 
| flickerstreak@122 | 169   RIGHT  = 2,  -- select y of x,y | 
| flickerstreak@122 | 170 } | 
| flickerstreak@122 | 171 local snapPoints = { | 
| flickerstreak@122 | 172   [anchorOutside] = { | 
| flickerstreak@122 | 173     BOTTOMLEFT  = {"BOTTOMRIGHT","TOPLEFT","TOPRIGHT"}, | 
| flickerstreak@122 | 174     BOTTOM      = {"TOP"}, | 
| flickerstreak@122 | 175     BOTTOMRIGHT = {"BOTTOMLEFT","TOPRIGHT","TOPLEFT"}, | 
| flickerstreak@122 | 176     RIGHT       = {"LEFT"}, | 
| flickerstreak@122 | 177     TOPRIGHT    = {"TOPLEFT","BOTTOMRIGHT","BOTTOMLEFT"}, | 
| flickerstreak@122 | 178     TOP         = {"BOTTOM"}, | 
| flickerstreak@122 | 179     TOPLEFT     = {"TOPRIGHT","BOTTOMLEFT","BOTTOMRIGHT"}, | 
| flickerstreak@122 | 180     LEFT        = {"RIGHT"}, | 
| flickerstreak@122 | 181     CENTER      = {"CENTER"} | 
| flickerstreak@122 | 182   }, | 
| flickerstreak@122 | 183   [anchorInside] = { | 
| flickerstreak@122 | 184     BOTTOMLEFT  = {"BOTTOMLEFT"}, | 
| flickerstreak@122 | 185     BOTTOM      = {"BOTTOM"}, | 
| flickerstreak@122 | 186     BOTTOMRIGHT = {"BOTTOMRIGHT"}, | 
| flickerstreak@122 | 187     RIGHT       = {"RIGHT"}, | 
| flickerstreak@122 | 188     TOPRIGHT    = {"TOPRIGHT"}, | 
| flickerstreak@122 | 189     TOP         = {"TOP"}, | 
| flickerstreak@122 | 190     TOPLEFT     = {"TOPLEFT"}, | 
| flickerstreak@122 | 191     LEFT        = {"LEFT"}, | 
| flickerstreak@122 | 192     CENTER      = {"CENTER"} | 
| flickerstreak@122 | 193   } | 
| flickerstreak@122 | 194 } | 
| flickerstreak@122 | 195 local insidePointOffsetFuncs = { | 
| flickerstreak@122 | 196   BOTTOMLEFT  = function(x, y) return x, y end, | 
| flickerstreak@122 | 197   BOTTOM      = function(x, y) return 0, y end, | 
| flickerstreak@122 | 198   BOTTOMRIGHT = function(x, y) return -x, y end, | 
| flickerstreak@122 | 199   RIGHT       = function(x, y) return -x, 0 end, | 
| flickerstreak@122 | 200   TOPRIGHT    = function(x, y) return -x, -y end, | 
| flickerstreak@122 | 201   TOP         = function(x, y) return 0, -y end, | 
| flickerstreak@122 | 202   TOPLEFT     = function(x, y) return x, -y end, | 
| flickerstreak@122 | 203   LEFT        = function(x, y) return x, 0 end, | 
| flickerstreak@122 | 204   CENTER      = function(x, y) return x, y end, | 
| flickerstreak@122 | 205 } | 
| flickerstreak@122 | 206 local pointCoordFuncs = { | 
| flickerstreak@122 | 207   BOTTOMLEFT  = function(f) return f:GetLeft(),  f:GetBottom() end, | 
| flickerstreak@122 | 208   BOTTOM      = function(f) return nil,          f:GetBottom() end, | 
| flickerstreak@122 | 209   BOTTOMRIGHT = function(f) return f:GetRight(), f:GetBottom() end, | 
| flickerstreak@122 | 210   RIGHT       = function(f) return f:GetRight(), nil end, | 
| flickerstreak@122 | 211   TOPRIGHT    = function(f) return f:GetRight(), f:GetTop() end, | 
| flickerstreak@122 | 212   TOP         = function(f) return nil,          f:GetTop() end, | 
| flickerstreak@122 | 213   TOPLEFT     = function(f) return f:GetLeft(),  f:GetTop() end, | 
| flickerstreak@122 | 214   LEFT        = function(f) return f:GetLeft(),  nil end, | 
| flickerstreak@122 | 215   CENTER      = function(f) return f:GetCenter() end, | 
| flickerstreak@122 | 216 } | 
| flickerstreak@122 | 217 local edgeBoundsFuncs = { | 
| flickerstreak@122 | 218   BOTTOM = function(f) return f:GetLeft(), f:GetRight() end, | 
| flickerstreak@122 | 219   LEFT   = function(f) return f:GetBottom(), f:GetTop() end | 
| flickerstreak@122 | 220 } | 
| flickerstreak@122 | 221 edgeBoundsFuncs.TOP   = edgeBoundsFuncs.BOTTOM | 
| flickerstreak@122 | 222 edgeBoundsFuncs.RIGHT = edgeBoundsFuncs.LEFT | 
| flickerstreak@122 | 223 local cornerTexCoords = { | 
| flickerstreak@122 | 224               -- ULx, ULy, LLx, LLy, URx, URy, LRx, LRy | 
| flickerstreak@122 | 225   TOPLEFT     = { 1,   1,   1,   0,   0,   1,   0,   0 }, | 
| flickerstreak@122 | 226   TOPRIGHT    = { 1,   0,   0,   0,   1,   1,   0,   1 }, | 
| flickerstreak@122 | 227   BOTTOMLEFT  = { 0,   1,   1,   1,   0,   0,   1,   0 }, | 
| flickerstreak@122 | 228   BOTTOMRIGHT = { 0,   0,   0,   1,   1,   0,   1,   1 }, | 
| flickerstreak@122 | 229 } | 
| flickerstreak@122 | 230 | 
| flickerstreak@122 | 231 -- Returns absolute coordinates x,y of the named point 'p' of frame 'f' | 
| flickerstreak@122 | 232 local function GetPointCoords( f, p ) | 
| flickerstreak@122 | 233   local x, y = pointCoordFuncs[p](f) | 
| flickerstreak@122 | 234   if not(x and y) then | 
| flickerstreak@122 | 235     local cx, cy = f:GetCenter() | 
| flickerstreak@122 | 236     x = x or cx | 
| flickerstreak@122 | 237     y = y or cy | 
| flickerstreak@122 | 238   end | 
| flickerstreak@122 | 239   return x, y | 
| flickerstreak@122 | 240 end | 
| flickerstreak@122 | 241 | 
| flickerstreak@122 | 242 | 
| flickerstreak@122 | 243 -- Returns true if frame 'f1' can be anchored to frame 'f2' | 
| flickerstreak@122 | 244 local function CheckAnchorable( f1, f2 ) | 
| flickerstreak@122 | 245   -- can't anchor a frame to itself or to nil | 
| flickerstreak@122 | 246   if f1 == f2 or f2 == nil then | 
| flickerstreak@122 | 247     return false | 
| flickerstreak@122 | 248   end | 
| flickerstreak@122 | 249 | 
| flickerstreak@122 | 250   -- can always anchor to UIParent | 
| flickerstreak@122 | 251   if f2 == UIParent then | 
| flickerstreak@122 | 252     return true | 
| flickerstreak@122 | 253   end | 
| flickerstreak@122 | 254 | 
| flickerstreak@122 | 255   -- also can't do circular anchoring of frames | 
| flickerstreak@122 | 256   -- walk the anchor chain, which generally shouldn't be that expensive | 
| flickerstreak@122 | 257   -- (who nests draggables that deep anyway?) | 
| flickerstreak@122 | 258   for i = 1, f2:GetNumPoints() do | 
| flickerstreak@122 | 259     local _, f = f2:GetPoint(i) | 
| flickerstreak@122 | 260     if not f then f = f2:GetParent() end | 
| flickerstreak@122 | 261     return CheckAnchorable(f1,f) | 
| flickerstreak@122 | 262   end | 
| flickerstreak@122 | 263 | 
| flickerstreak@122 | 264   return true | 
| flickerstreak@122 | 265 end | 
| flickerstreak@122 | 266 | 
| flickerstreak@122 | 267 -- Returns true if frames f1 and f2 specified edges overlap | 
| flickerstreak@122 | 268 local function CheckEdgeOverlap( f1, f2, e ) | 
| flickerstreak@122 | 269   local l1, u1 = edgeBoundsFuncs[e](f1) | 
| flickerstreak@122 | 270   local l2, u2 = edgeBoundsFuncs[e](f2) | 
| flickerstreak@122 | 271   return l1 <= l2 and l2 <= u1 or l2 <= l1 and l1 <= u2 | 
| flickerstreak@122 | 272 end | 
| flickerstreak@122 | 273 | 
| flickerstreak@122 | 274 -- Returns true if point p1 on frame f1 overlaps edge e2 on frame f2 | 
| flickerstreak@122 | 275 local function CheckPointEdgeOverlap( f1, p1, f2, e2 ) | 
| flickerstreak@122 | 276   local l, u = edgeBoundsFuncs[e2](f2) | 
| flickerstreak@122 | 277   local x, y = GetPointCoords(f1,p1) | 
| flickerstreak@122 | 278   x = select(edgeSelector[e2], x, y) | 
| flickerstreak@122 | 279   return l <= x and x <= u | 
| flickerstreak@122 | 280 end | 
| flickerstreak@122 | 281 | 
| flickerstreak@122 | 282 -- Returns the distance between corresponding edges. It is | 
| flickerstreak@122 | 283 -- assumed that the passed in edges e1 and e2 are the same or opposites | 
| flickerstreak@122 | 284 local function GetEdgeDistance( f1, f2, e1, e2 ) | 
| flickerstreak@122 | 285   local x1, y1 = pointCoordFuncs[e1](f1) | 
| flickerstreak@122 | 286   local x2, y2 = pointCoordFuncs[e2](f2) | 
| flickerstreak@122 | 287   return math.abs((x1 or y1) - (x2 or y2)) | 
| flickerstreak@122 | 288 end | 
| flickerstreak@122 | 289 | 
| flickerstreak@122 | 290 local globalSnapTargets = { [UIParent] = anchorInside } | 
| flickerstreak@122 | 291 | 
| flickerstreak@122 | 292 local function GetClosestFrameEdge(f1,f2,a) | 
| flickerstreak@122 | 293   local dist, edge, opp | 
| flickerstreak@122 | 294   if f2:IsVisible() and CheckAnchorable(f1,f2) then | 
| flickerstreak@122 | 295     for _, e in pairs(edges) do | 
| flickerstreak@122 | 296       local o = a.inside and e or oppositeEdges[e] | 
| flickerstreak@122 | 297       if CheckEdgeOverlap(f1,f2,e) then | 
| flickerstreak@122 | 298         local d = GetEdgeDistance(f1, f2, e, o) | 
| flickerstreak@122 | 299         if not dist or (d < dist) then | 
| flickerstreak@122 | 300           dist, edge, opp = d, e, o | 
| flickerstreak@122 | 301         end | 
| flickerstreak@122 | 302       end | 
| flickerstreak@122 | 303     end | 
| flickerstreak@122 | 304   end | 
| flickerstreak@122 | 305   return dist, edge, opp | 
| flickerstreak@122 | 306 end | 
| flickerstreak@122 | 307 | 
| flickerstreak@122 | 308 local function GetClosestVisibleEdge( f ) | 
| flickerstreak@122 | 309   local r, o, e1, e2 | 
| flickerstreak@122 | 310   local a = anchorOutside | 
| flickerstreak@122 | 311   for _, b in ReAction:IterateBars() do | 
| flickerstreak@122 | 312     local d, e, opp = GetClosestFrameEdge(f,b:GetFrame(),a) | 
| flickerstreak@122 | 313     if d and (not r or d < r) then | 
| flickerstreak@122 | 314       r, o, e1, e2 = d, b:GetFrame(), e, opp | 
| flickerstreak@122 | 315     end | 
| flickerstreak@122 | 316   end | 
| flickerstreak@122 | 317   for f2, a2 in pairs(globalSnapTargets) do | 
| flickerstreak@122 | 318     local d, e, opp = GetClosestFrameEdge(f,f2,a2) | 
| flickerstreak@122 | 319     if d and (not r or d < r) then | 
| flickerstreak@122 | 320       r, o, e1, e2, a = d, f2, e, opp, a2 | 
| flickerstreak@122 | 321     end | 
| flickerstreak@122 | 322   end | 
| flickerstreak@122 | 323   return o, e1, e2, a | 
| flickerstreak@122 | 324 end | 
| flickerstreak@122 | 325 | 
| flickerstreak@122 | 326 local function GetClosestVisiblePoint(f1) | 
| flickerstreak@122 | 327   local f2, e1, e2, a = GetClosestVisibleEdge(f1) | 
| flickerstreak@122 | 328   if f2 then | 
| flickerstreak@122 | 329     local rsq, p, rp, x, y | 
| flickerstreak@122 | 330     -- iterate pointsOnEdge in order and use < to prefer edge centers to corners | 
| flickerstreak@122 | 331     for _, p1 in ipairs(pointsOnEdge[e1]) do | 
| flickerstreak@122 | 332       if CheckPointEdgeOverlap(f1,p1,f2,e2) then | 
| flickerstreak@122 | 333         for _, p2 in pairs(snapPoints[a][p1]) do | 
| flickerstreak@122 | 334           local x1, y1 = GetPointCoords(f1,p1) | 
| flickerstreak@122 | 335           local x2, y2 = GetPointCoords(f2,p2) | 
| flickerstreak@122 | 336           local dx = x1 - x2 | 
| flickerstreak@122 | 337           local dy = y1 - y2 | 
| flickerstreak@122 | 338           local rsq2 = dx*dx + dy*dy | 
| flickerstreak@122 | 339           if not rsq or rsq2 < rsq then | 
| flickerstreak@122 | 340             rsq, p, rp, x, y = rsq2, p1, p2, dx, dy | 
| flickerstreak@122 | 341           end | 
| flickerstreak@122 | 342         end | 
| flickerstreak@122 | 343       end | 
| flickerstreak@122 | 344     end | 
| flickerstreak@122 | 345     return f2, p, rp, x, y | 
| flickerstreak@122 | 346   end | 
| flickerstreak@122 | 347 end | 
| flickerstreak@122 | 348 | 
| flickerstreak@122 | 349 local function GetClosestPointSnapped(f1, rx, ry, xOff, yOff) | 
| flickerstreak@122 | 350   local o, p, rp, x, y = GetClosestVisiblePoint(f1) | 
| flickerstreak@122 | 351   local s = false | 
| flickerstreak@122 | 352 | 
| flickerstreak@122 | 353   local insideOffsetFunc = p and insidePointOffsetFuncs[p] | 
| flickerstreak@122 | 354   local coordFunc = p and pointCoordFuncs[p] | 
| flickerstreak@122 | 355   if not insideOffsetFunc or not coordFunc then | 
| flickerstreak@122 | 356     return | 
| flickerstreak@122 | 357   end | 
| flickerstreak@122 | 358 | 
| flickerstreak@122 | 359   local sx, sy = insideOffsetFunc(xOff or 0, yOff or 0) | 
| flickerstreak@122 | 360   local xx, yy = coordFunc(f1) | 
| flickerstreak@122 | 361   if xx and yy then | 
| flickerstreak@122 | 362     if math.abs(x) <= rx then | 
| flickerstreak@122 | 363       if math.abs(y) <= ry then | 
| flickerstreak@122 | 364         x = sx | 
| flickerstreak@122 | 365         y = sy | 
| flickerstreak@122 | 366         s = true | 
| flickerstreak@122 | 367       elseif CheckEdgeOverlap(f1,o,"LEFT") then | 
| flickerstreak@122 | 368         x = sx | 
| flickerstreak@122 | 369         s = true | 
| flickerstreak@122 | 370       end | 
| flickerstreak@122 | 371     elseif math.abs(y) <= ry and CheckEdgeOverlap(f1,o,"TOP") then | 
| flickerstreak@122 | 372       y = sy | 
| flickerstreak@122 | 373       s = true | 
| flickerstreak@122 | 374     end | 
| flickerstreak@122 | 375   elseif xx then | 
| flickerstreak@122 | 376     if math.abs(x) <= rx then | 
| flickerstreak@122 | 377       x = sx | 
| flickerstreak@122 | 378       s = true | 
| flickerstreak@122 | 379       if math.abs(y) <= ry then | 
| flickerstreak@122 | 380         y = sy | 
| flickerstreak@122 | 381       end | 
| flickerstreak@122 | 382     end | 
| flickerstreak@122 | 383   elseif yy then | 
| flickerstreak@122 | 384     if math.abs(y) <= ry then | 
| flickerstreak@122 | 385       y = sy | 
| flickerstreak@122 | 386       s = true | 
| flickerstreak@122 | 387       if math.abs(x) <= rx then | 
| flickerstreak@122 | 388         x = sx | 
| flickerstreak@122 | 389       end | 
| flickerstreak@122 | 390     end | 
| flickerstreak@122 | 391   end | 
| flickerstreak@122 | 392 | 
| flickerstreak@122 | 393   -- correct for some Lua oddities with doubles | 
| flickerstreak@122 | 394   if x == -0 then x = 0 end | 
| flickerstreak@122 | 395   if y == -0 then y = 0 end | 
| flickerstreak@122 | 396 | 
| flickerstreak@122 | 397   if s then | 
| flickerstreak@122 | 398     return o, p, rp, math.floor(x), math.floor(y) | 
| flickerstreak@122 | 399   end | 
| flickerstreak@122 | 400 end | 
| flickerstreak@122 | 401 | 
| flickerstreak@122 | 402 local function CreateSnapIndicator() | 
| flickerstreak@122 | 403   local si = CreateFrame("Frame",nil,UIParent) | 
| flickerstreak@122 | 404   si:SetFrameStrata("HIGH") | 
| flickerstreak@122 | 405   si:SetHeight(16) | 
| flickerstreak@122 | 406   si:SetWidth(16) | 
| flickerstreak@122 | 407   local tex = si:CreateTexture() | 
| flickerstreak@122 | 408   tex:SetAllPoints() | 
| flickerstreak@122 | 409   tex:SetTexture("Interface\\AddOns\\ReAction\\img\\lock") | 
| flickerstreak@122 | 410   tex:SetBlendMode("ADD") | 
| flickerstreak@122 | 411   tex:SetDrawLayer("OVERLAY") | 
| flickerstreak@122 | 412   return si | 
| flickerstreak@122 | 413 end | 
| flickerstreak@122 | 414 | 
| flickerstreak@122 | 415 local si1 = CreateSnapIndicator() | 
| flickerstreak@122 | 416 local si2 = CreateSnapIndicator() | 
| flickerstreak@122 | 417 | 
| flickerstreak@122 | 418 local function DisplaySnapIndicator( f, rx, ry, xOff, yOff ) | 
| flickerstreak@122 | 419   local o, p, rp, x, y, snap = GetClosestPointSnapped(f, rx, ry, xOff, yOff) | 
| flickerstreak@122 | 420   if o then | 
| flickerstreak@122 | 421     si1:ClearAllPoints() | 
| flickerstreak@122 | 422     si2:ClearAllPoints() | 
| flickerstreak@122 | 423     si1:SetPoint("CENTER", f, p, 0, 0) | 
| flickerstreak@122 | 424     local xx, yy = pointCoordFuncs[rp](o) | 
| flickerstreak@122 | 425     x = math.abs(x) <=rx and xx and 0 or x | 
| flickerstreak@122 | 426     y = math.abs(y) <=ry and yy and 0 or y | 
| flickerstreak@122 | 427     si2:SetPoint("CENTER", o, rp, x, y) | 
| flickerstreak@122 | 428     si1:Show() | 
| flickerstreak@122 | 429     si2:Show() | 
| flickerstreak@122 | 430   else | 
| flickerstreak@122 | 431     if si1:IsVisible() then | 
| flickerstreak@122 | 432       si1:Hide() | 
| flickerstreak@122 | 433       si2:Hide() | 
| flickerstreak@122 | 434     end | 
| flickerstreak@122 | 435   end | 
| flickerstreak@122 | 436   return o, p | 
| flickerstreak@122 | 437 end | 
| flickerstreak@122 | 438 | 
| flickerstreak@122 | 439 local function HideSnapIndicator() | 
| flickerstreak@122 | 440   if si1:IsVisible() then | 
| flickerstreak@122 | 441     si1:Hide() | 
| flickerstreak@122 | 442     si2:Hide() | 
| flickerstreak@122 | 443   end | 
| flickerstreak@122 | 444 end | 
| flickerstreak@122 | 445 | 
| flickerstreak@122 | 446 local function UpdateLabelString(bar) | 
| flickerstreak@122 | 447   local label = bar.controlLabelString | 
| flickerstreak@122 | 448   if label then | 
| flickerstreak@122 | 449     local name = bar.labelName | 
| flickerstreak@122 | 450     if name and bar.labelSubtext then | 
| flickerstreak@122 | 451       name = format("%s (%s)", name, bar.labelSubtext) | 
| flickerstreak@122 | 452     end | 
| flickerstreak@122 | 453     label:SetText(name or "") | 
| flickerstreak@122 | 454   end | 
| flickerstreak@122 | 455 end | 
| flickerstreak@122 | 456 | 
| flickerstreak@122 | 457 local function CreateControls(bar) | 
| flickerstreak@122 | 458   local f = bar:GetFrame() | 
| flickerstreak@122 | 459 | 
| flickerstreak@122 | 460   f:SetMovable(true) | 
| flickerstreak@122 | 461   f:SetResizable(true) | 
| flickerstreak@122 | 462 | 
| flickerstreak@122 | 463   -- child of UIParent so that alpha and scale doesn't propagate to it | 
| flickerstreak@122 | 464   local overlay = CreateFrame("Button", nil, UIParent) | 
| flickerstreak@122 | 465   overlay:EnableMouse(true) | 
| flickerstreak@122 | 466   overlay:SetFrameLevel(3) -- set it above the buttons | 
| flickerstreak@122 | 467   overlay:SetPoint("TOPLEFT", f, "TOPLEFT", -4, 4) | 
| flickerstreak@122 | 468   overlay:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 4, -4) | 
| flickerstreak@122 | 469   overlay:SetBackdrop({ | 
| flickerstreak@122 | 470     edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", | 
| flickerstreak@122 | 471     tile = true, | 
| flickerstreak@122 | 472     tileSize = 16, | 
| flickerstreak@122 | 473     edgeSize = 16, | 
| flickerstreak@122 | 474     insets = { left = 0, right = 0, top = 0, bottom = 0 }, | 
| flickerstreak@122 | 475   }) | 
| flickerstreak@122 | 476 | 
| flickerstreak@122 | 477   -- textures | 
| flickerstreak@122 | 478   local bgTex = overlay:CreateTexture(nil,"BACKGROUND") | 
| flickerstreak@122 | 479   bgTex:SetTexture(0.7,0.7,1.0,0.2) | 
| flickerstreak@122 | 480   bgTex:SetPoint("TOPLEFT",4,-4) | 
| flickerstreak@122 | 481   bgTex:SetPoint("BOTTOMRIGHT",-4,4) | 
| flickerstreak@122 | 482   local hTex = overlay:CreateTexture(nil,"HIGHLIGHT") | 
| flickerstreak@122 | 483   hTex:SetTexture(0.7,0.7,1.0,0.2) | 
| flickerstreak@122 | 484   hTex:SetPoint("TOPLEFT",4,-4) | 
| flickerstreak@122 | 485   hTex:SetPoint("BOTTOMRIGHT",-4,4) | 
| flickerstreak@122 | 486   hTex:SetBlendMode("ADD") | 
| flickerstreak@122 | 487   local aTex = overlay:CreateTexture(nil,"ARTWORK") | 
| flickerstreak@122 | 488   aTex:SetTexture("Interface\\AddOns\\ReAction\\img\\lock") | 
| flickerstreak@122 | 489   aTex:SetWidth(16) | 
| flickerstreak@122 | 490   aTex:SetHeight(16) | 
| flickerstreak@122 | 491   aTex:Hide() | 
| flickerstreak@122 | 492 | 
| flickerstreak@122 | 493   -- label | 
| flickerstreak@122 | 494   local label = overlay:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") | 
| flickerstreak@122 | 495   label:SetAllPoints() | 
| flickerstreak@122 | 496   label:SetJustifyH("CENTER") | 
| flickerstreak@122 | 497   label:SetShadowColor(0,0,0,1) | 
| flickerstreak@122 | 498   label:SetShadowOffset(3,-3) | 
| flickerstreak@122 | 499   label:SetTextColor(GetNormalTextColor()) | 
| flickerstreak@122 | 500   label:SetText(bar:GetName()) | 
| flickerstreak@122 | 501   label:Show() | 
| flickerstreak@122 | 502   bar.controlLabelString = label  -- so that bar:SetLabel() can update it | 
| flickerstreak@122 | 503 | 
| flickerstreak@122 | 504   local function UpdateAnchorDecoration() | 
| flickerstreak@122 | 505     local point, anchor, relPoint, x, y = f:GetPoint(1) | 
| flickerstreak@122 | 506     if point then | 
| flickerstreak@122 | 507       local ofsx, ofsy = insidePointOffsetFuncs[point](x,y) | 
| flickerstreak@122 | 508       if (anchor and anchor ~= UIParent) or (ofsx == 0 and ofsy == 0) then | 
| flickerstreak@122 | 509         bgTex:SetTexture( GetAnchoredBgColor() ) | 
| flickerstreak@122 | 510         hTex:SetTexture( GetAnchoredBgColor() ) | 
| flickerstreak@122 | 511         label:SetTextColor( GetAnchoredTextColor() ) | 
| flickerstreak@122 | 512         aTex:ClearAllPoints() | 
| flickerstreak@122 | 513         aTex:SetPoint(point) | 
| flickerstreak@122 | 514         aTex:Show() | 
| flickerstreak@122 | 515         return | 
| flickerstreak@122 | 516       end | 
| flickerstreak@122 | 517     end | 
| flickerstreak@122 | 518     bgTex:SetTexture( GetNormalBgColor() ) | 
| flickerstreak@122 | 519     hTex:SetTexture( GetNormalBgColor() ) | 
| flickerstreak@122 | 520     label:SetTextColor( GetNormalTextColor() ) | 
| flickerstreak@122 | 521     aTex:Hide() | 
| flickerstreak@122 | 522   end | 
| flickerstreak@122 | 523 | 
| flickerstreak@122 | 524   local function StopResize() | 
| flickerstreak@122 | 525     f:StopMovingOrSizing() | 
| flickerstreak@122 | 526     f.isMoving = false | 
| flickerstreak@122 | 527     f:SetScript("OnUpdate",nil) | 
| flickerstreak@122 | 528     StoreSize(bar) | 
| flickerstreak@122 | 529     ClampToButtons(bar) | 
| flickerstreak@122 | 530     ReAction:RefreshOptions() | 
| flickerstreak@122 | 531   end | 
| flickerstreak@122 | 532 | 
| flickerstreak@122 | 533   local function CornerUpdate() | 
| flickerstreak@122 | 534     local bw, bh = GetButtonSize(bar) | 
| flickerstreak@122 | 535     local r, c, s = GetButtonGrid(bar) | 
| flickerstreak@122 | 536     local ss = GetStateScale(bar) | 
| flickerstreak@122 | 537     if IsShiftKeyDown() then | 
| flickerstreak@122 | 538       if ss then | 
| flickerstreak@122 | 539         f:SetMinResize( ((s+bw)*c*0.25)/ss, ((s+bh)*r*0.25)/ss ) | 
| flickerstreak@122 | 540         f:SetMaxResize( ((s+bw)*c*2.5 + 1)/ss, ((s+bh)*r*2.5 + 1)/ss ) | 
| flickerstreak@122 | 541         scale = ComputeBarScale(bar) | 
| flickerstreak@122 | 542       else | 
| flickerstreak@122 | 543         f:SetMinResize( (s+12)*c+1, (s+12)*r+1 ) | 
| flickerstreak@122 | 544         f:SetMaxResize( (s+128)*c+1, (s+128)*r+1 ) | 
| flickerstreak@122 | 545         RecomputeButtonSize(bar) | 
| flickerstreak@122 | 546       end | 
| flickerstreak@122 | 547     elseif not ss and IsAltKeyDown() then | 
| flickerstreak@122 | 548       f:SetMinResize( bw*c, bh*r ) | 
| flickerstreak@122 | 549       f:SetMaxResize( 2*bw*c, 2*bh*r ) | 
| flickerstreak@122 | 550       RecomputeButtonSpacing(bar) | 
| flickerstreak@122 | 551     else | 
| flickerstreak@122 | 552       f:SetMinResize( bw+s+1, bh+s+1 ) | 
| flickerstreak@122 | 553       f:SetMaxResize( 50*(bw+s)+1, 50*(bh+s)+1 ) | 
| flickerstreak@122 | 554       RecomputeGrid(bar) | 
| flickerstreak@122 | 555     end | 
| flickerstreak@122 | 556     GameTooltipTextRight2:SetText(format("%d x %d",r,c)) | 
| flickerstreak@122 | 557 | 
| flickerstreak@122 | 558     local ss = GetStateScale(bar) | 
| flickerstreak@122 | 559     local state = bar:GetState() | 
| flickerstreak@122 | 560     if ss then | 
| flickerstreak@122 | 561       GameTooltipTextRight4:SetText(format("%d%%", scale*100)) | 
| flickerstreak@122 | 562     else | 
| flickerstreak@122 | 563       local size = (bw == bh) and tostring(bw) or format("%d x %d",bw,bh) | 
| flickerstreak@122 | 564       GameTooltipTextRight3:SetText(size) | 
| flickerstreak@122 | 565       GameTooltipTextRight4:SetText(tostring(s)) | 
| flickerstreak@122 | 566     end | 
| flickerstreak@122 | 567   end | 
| flickerstreak@122 | 568 | 
| flickerstreak@122 | 569   -- corner drag handles | 
| flickerstreak@122 | 570   for _, point in pairs({"BOTTOMLEFT","TOPLEFT","BOTTOMRIGHT","TOPRIGHT"}) do | 
| flickerstreak@122 | 571     local corner = CreateFrame("Frame",nil,overlay) | 
| flickerstreak@122 | 572     corner:EnableMouse(true) | 
| flickerstreak@122 | 573     corner:SetWidth(16) | 
| flickerstreak@122 | 574     corner:SetHeight(16) | 
| flickerstreak@122 | 575     corner:SetPoint(point) | 
| flickerstreak@122 | 576 | 
| flickerstreak@122 | 577     local tex = corner:CreateTexture(nil,"HIGHLIGHT") | 
| flickerstreak@122 | 578     tex:SetTexture("Interface\\AddOns\\ReAction\\img\\corner") | 
| flickerstreak@122 | 579     tex:SetTexCoord(unpack(cornerTexCoords[point])) | 
| flickerstreak@122 | 580     tex:SetBlendMode("ADD") | 
| flickerstreak@122 | 581     tex:SetAlpha(0.6) | 
| flickerstreak@122 | 582     tex:SetAllPoints() | 
| flickerstreak@122 | 583 | 
| flickerstreak@122 | 584     corner:SetScript("OnMouseDown", | 
| flickerstreak@122 | 585       function(_,btn) | 
| flickerstreak@122 | 586         f:SetScript("OnUpdate", CornerUpdate) | 
| flickerstreak@122 | 587         f:StartSizing(point) | 
| flickerstreak@122 | 588       end | 
| flickerstreak@122 | 589     ) | 
| flickerstreak@122 | 590     corner:SetScript("OnMouseUp", | 
| flickerstreak@122 | 591       function() | 
| flickerstreak@122 | 592         local ss = GetStateScale(bar) | 
| flickerstreak@122 | 593         if ss then | 
| flickerstreak@122 | 594           local state = bar:GetState() | 
| flickerstreak@122 | 595           SetStateScale(bar, ComputeBarScale(bar)) | 
| flickerstreak@122 | 596         end | 
| flickerstreak@122 | 597         StopResize() | 
| flickerstreak@122 | 598       end) | 
| flickerstreak@122 | 599     corner:SetScript("OnEnter", | 
| flickerstreak@122 | 600       function() | 
| flickerstreak@122 | 601         local bw, bh = GetButtonSize(bar) | 
| flickerstreak@122 | 602         local r, c, s = bar:GetButtonGrid() | 
| flickerstreak@122 | 603         local size = (bw == bh) and tostring(bw) or format("%d x %d",bw,bh) | 
| flickerstreak@122 | 604         local ss = GetStateScale(bar) | 
| flickerstreak@122 | 605         local state = bar:GetState() | 
| flickerstreak@122 | 606         GameTooltip:SetOwner(f, "ANCHOR_"..point) | 
| flickerstreak@122 | 607         if ss then | 
| flickerstreak@122 | 608           GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state)) | 
| flickerstreak@122 | 609         else | 
| flickerstreak@122 | 610           GameTooltip:AddLine(bar:GetName()) | 
| flickerstreak@122 | 611         end | 
| flickerstreak@122 | 612         GameTooltip:AddDoubleLine(format("|cffcccccc%s|r %s",L["Drag"],L["to add/remove buttons:"]), format("%d x %d",r,c)) | 
| flickerstreak@122 | 613         if ss then | 
| flickerstreak@122 | 614           GameTooltip:AddLine(L["State Scale Override"]) | 
| flickerstreak@122 | 615           GameTooltip:AddDoubleLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to change scale:"]), format("%d%%", bar:GetStateProperty(state,"scale")*100)) | 
| flickerstreak@122 | 616         else | 
| flickerstreak@122 | 617           GameTooltip:AddDoubleLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to resize buttons:"]), tostring(floor(size))) | 
| flickerstreak@122 | 618           GameTooltip:AddDoubleLine(format("|cff0033cc%s|r %s",L["Hold Alt"],  L["to change spacing:"]), tostring(floor(s))) | 
| flickerstreak@122 | 619         end | 
| flickerstreak@122 | 620         GameTooltip:Show() | 
| flickerstreak@122 | 621       end | 
| flickerstreak@122 | 622     ) | 
| flickerstreak@122 | 623     corner:SetScript("OnLeave", | 
| flickerstreak@122 | 624       function() | 
| flickerstreak@122 | 625         GameTooltip:Hide() | 
| flickerstreak@122 | 626         f:SetScript("OnUpdate",nil) | 
| flickerstreak@122 | 627       end | 
| flickerstreak@122 | 628     ) | 
| flickerstreak@122 | 629   end | 
| flickerstreak@122 | 630 | 
| flickerstreak@122 | 631   overlay:RegisterForDrag("LeftButton") | 
| flickerstreak@122 | 632   overlay:RegisterForClicks("RightButtonUp") | 
| flickerstreak@122 | 633 | 
| flickerstreak@122 | 634   overlay:SetScript("OnDragStart", | 
| flickerstreak@122 | 635     function() | 
| flickerstreak@122 | 636       f:StartMoving() | 
| flickerstreak@122 | 637       f.isMoving = true | 
| flickerstreak@122 | 638       local w,h = bar:GetButtonSize() | 
| flickerstreak@122 | 639       f:ClearAllPoints() | 
| flickerstreak@122 | 640       UpdateAnchorDecoration() | 
| flickerstreak@122 | 641       f:SetScript("OnUpdate", function() | 
| flickerstreak@122 | 642           if IsShiftKeyDown() then | 
| flickerstreak@122 | 643             local f, p = DisplaySnapIndicator(f,w,h) | 
| flickerstreak@122 | 644           else | 
| flickerstreak@122 | 645             HideSnapIndicator() | 
| flickerstreak@122 | 646           end | 
| flickerstreak@122 | 647         end) | 
| flickerstreak@122 | 648     end | 
| flickerstreak@122 | 649   ) | 
| flickerstreak@122 | 650 | 
| flickerstreak@122 | 651   local function UpdateDragTooltip() | 
| flickerstreak@122 | 652     GameTooltip:SetOwner(f, "ANCHOR_TOPRIGHT") | 
| flickerstreak@122 | 653     local ss = GetStateScale(bar) | 
| flickerstreak@122 | 654     local state = bar:GetState() | 
| flickerstreak@122 | 655     if ss then | 
| flickerstreak@122 | 656       GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state)) | 
| flickerstreak@122 | 657     else | 
| flickerstreak@122 | 658       GameTooltip:AddLine(bar:GetName()) | 
| flickerstreak@122 | 659     end | 
| flickerstreak@122 | 660     GameTooltip:AddLine(format("|cffcccccc%s|r %s",L["Drag"],L["to move"])) | 
| flickerstreak@122 | 661     GameTooltip:AddLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to anchor to nearby frames"])) | 
| flickerstreak@122 | 662     GameTooltip:AddLine(format("|cff00cccc%s|r %s",L["Right-click"],L["for options..."])) | 
| flickerstreak@122 | 663     local point, frame, relpoint, x, y = bar:GetFrame():GetPoint(1) | 
| flickerstreak@122 | 664     if point then | 
| flickerstreak@122 | 665       local ofsx, ofsy = insidePointOffsetFuncs[point](x,y) | 
| flickerstreak@122 | 666       if (frame and frame ~= UIParent) or (ofsx == 0 and ofsy == 0) then | 
| flickerstreak@122 | 667         frame = frame or UIParent | 
| flickerstreak@122 | 668         GameTooltip:AddLine(format("%s <%s>",L["Currently anchored to"],frame:GetName())) | 
| flickerstreak@122 | 669       end | 
| flickerstreak@122 | 670     end | 
| flickerstreak@122 | 671     GameTooltip:Show() | 
| flickerstreak@122 | 672   end | 
| flickerstreak@122 | 673 | 
| flickerstreak@122 | 674   overlay:SetScript("OnDragStop", | 
| flickerstreak@122 | 675     function() | 
| flickerstreak@122 | 676       f:StopMovingOrSizing() | 
| flickerstreak@122 | 677       f.isMoving = false | 
| flickerstreak@122 | 678       f:SetScript("OnUpdate",nil) | 
| flickerstreak@122 | 679 | 
| flickerstreak@122 | 680       if IsShiftKeyDown() then | 
| flickerstreak@122 | 681         local w, h = bar:GetButtonSize() | 
| flickerstreak@122 | 682         local a, p, rp, x, y = GetClosestPointSnapped(f,w,h) | 
| flickerstreak@122 | 683         if a then | 
| flickerstreak@122 | 684           f:ClearAllPoints() | 
| flickerstreak@122 | 685           f:SetPoint(p,a,rp,x,y) | 
| flickerstreak@122 | 686         end | 
| flickerstreak@122 | 687         HideSnapIndicator() | 
| flickerstreak@122 | 688       end | 
| flickerstreak@122 | 689 | 
| flickerstreak@122 | 690       StoreExtents(bar) | 
| flickerstreak@122 | 691       ReAction:RefreshOptions() | 
| flickerstreak@122 | 692       UpdateDragTooltip() | 
| flickerstreak@122 | 693       UpdateAnchorDecoration() | 
| flickerstreak@122 | 694     end | 
| flickerstreak@122 | 695   ) | 
| flickerstreak@122 | 696 | 
| flickerstreak@122 | 697   overlay:SetScript("OnEnter", | 
| flickerstreak@122 | 698     function() | 
| flickerstreak@122 | 699       UpdateDragTooltip() | 
| flickerstreak@122 | 700     end | 
| flickerstreak@122 | 701   ) | 
| flickerstreak@122 | 702 | 
| flickerstreak@122 | 703   overlay:SetScript("OnLeave", HideGameTooltip) | 
| flickerstreak@122 | 704 | 
| flickerstreak@122 | 705   overlay:SetScript("OnClick", | 
| flickerstreak@122 | 706     function() | 
| flickerstreak@122 | 707       ReAction:ShowEditor(bar) | 
| flickerstreak@122 | 708     end | 
| flickerstreak@122 | 709   ) | 
| flickerstreak@122 | 710 | 
| flickerstreak@122 | 711   function overlay:LIBKEYBOUND_ENABLED(evt) | 
| flickerstreak@122 | 712     self:SetFrameLevel(1) | 
| flickerstreak@122 | 713   end | 
| flickerstreak@122 | 714 | 
| flickerstreak@122 | 715   function overlay:LIBKEYBOUND_DISABLED(evt) | 
| flickerstreak@122 | 716     self:SetFrameLevel(3) | 
| flickerstreak@122 | 717   end | 
| flickerstreak@122 | 718 | 
| flickerstreak@122 | 719   function overlay:RefreshControls() | 
| flickerstreak@122 | 720     UpdateAnchorDecoration() | 
| flickerstreak@122 | 721   end | 
| flickerstreak@122 | 722 | 
| flickerstreak@122 | 723   overlay:SetScript("OnShow", overlay.RefreshControls) | 
| flickerstreak@122 | 724 | 
| flickerstreak@122 | 725   KB.RegisterCallback(overlay,"LIBKEYBOUND_ENABLED") | 
| flickerstreak@122 | 726   KB.RegisterCallback(overlay,"LIBKEYBOUND_DISABLED") | 
| flickerstreak@122 | 727 | 
| flickerstreak@122 | 728   if ReAction:GetKeybindMode() then | 
| flickerstreak@122 | 729     overlay:SetFrameLevel(1) | 
| flickerstreak@122 | 730   end | 
| flickerstreak@122 | 731 | 
| flickerstreak@122 | 732   bar:SetLabel(bar:GetName()) | 
| flickerstreak@122 | 733   UpdateLabelString(bar) | 
| flickerstreak@122 | 734   UpdateAnchorDecoration() | 
| flickerstreak@122 | 735 | 
| flickerstreak@122 | 736   return overlay | 
| flickerstreak@122 | 737 end | 
| flickerstreak@122 | 738 | 
| flickerstreak@122 | 739 | 
| flickerstreak@122 | 740 -- export methods to the Bar prototype | 
| flickerstreak@122 | 741 | 
| flickerstreak@122 | 742 function Bar:ShowControls(show) | 
| flickerstreak@122 | 743   local f = self.controlFrame | 
| flickerstreak@122 | 744   if show then | 
| flickerstreak@122 | 745     if not f then | 
| flickerstreak@122 | 746       f = CreateControls(self) | 
| flickerstreak@122 | 747       self.controlFrame = f | 
| flickerstreak@122 | 748     end | 
| flickerstreak@122 | 749     f:Show() | 
| flickerstreak@122 | 750   elseif f then | 
| flickerstreak@122 | 751     f:Hide() | 
| flickerstreak@122 | 752   end | 
| flickerstreak@122 | 753 end | 
| flickerstreak@122 | 754 | 
| flickerstreak@122 | 755 function Bar:RefreshControls() | 
| flickerstreak@122 | 756   if self.controlFrame and self.controlFrame:IsShown() then | 
| flickerstreak@122 | 757     self.controlFrame:RefreshControls() | 
| flickerstreak@122 | 758   end | 
| flickerstreak@122 | 759 end | 
| flickerstreak@122 | 760 | 
| flickerstreak@122 | 761 function Bar:SetLabel(name) | 
| flickerstreak@122 | 762   self.labelName = name | 
| flickerstreak@122 | 763   UpdateLabelString(self) | 
| flickerstreak@122 | 764 end | 
| flickerstreak@122 | 765 | 
| flickerstreak@122 | 766 function Bar:SetLabelSubtext(text) | 
| flickerstreak@122 | 767   self.labelSubtext = text | 
| flickerstreak@122 | 768   UpdateLabelString(self) | 
| flickerstreak@122 | 769 end |