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