annotate classes/ReBar.lua @ 7:f920db5fc6b1

version 0.3
author Flick <flickerstreak@gmail.com>
date Tue, 20 Mar 2007 21:25:29 +0000
parents dfd829db3ad0
children c05fd3e18b4f
rev   line source
flickerstreak@7 1 -- private constants
flickerstreak@7 2 local anchoredLabelColor = { r = 1.0, g = 0.82, b = 0.0 }
flickerstreak@7 3 local nonAnchoredLabelColor = { r = 1.0, g = 1.0, b = 1.0 }
flickerstreak@1 4
flickerstreak@7 5 local DRAG_UPDATE_RATE = 0.125 -- cap at 8 Hz
flickerstreak@1 6
flickerstreak@7 7 local nStancePages = {
flickerstreak@7 8 WARRIOR = 3,
flickerstreak@7 9 ROGUE = 0,
flickerstreak@7 10 HUNTER = 0,
flickerstreak@7 11 DRUID = 3, -- updated to 4 if talented
flickerstreak@7 12 PALADIN = 0,
flickerstreak@7 13 SHAMAN = 0, -- As far as I know, ghost wolf is not a proper shapeshift form, it's just a buff
flickerstreak@7 14 MAGE = 0,
flickerstreak@7 15 PRIEST = 0, -- updated to 1 if talented
flickerstreak@7 16 WARLOCK = 0,
flickerstreak@1 17 }
flickerstreak@1 18
flickerstreak@7 19 local stanceMaps = {
flickerstreak@7 20 WARRIOR = {
flickerstreak@7 21 -- note: warriors are never in shapeshift form 0.
flickerstreak@7 22 [1] = "*:1", -- battle stance. All states go to state (page) 1.
flickerstreak@7 23 [2] = "*:2", -- defensive stance. All states go to state (page) 2.
flickerstreak@7 24 [3] = "*:3", -- berserker stance. All states go to state (page) 3.
flickerstreak@7 25 },
flickerstreak@7 26 ROGUE = {},
flickerstreak@7 27 HUNTER = {},
flickerstreak@7 28 DRUID = {
flickerstreak@7 29 [0] = "*:1", -- humanoid form. All states go to state (page) 1.
flickerstreak@7 30 [1] = "*:2", -- bear/dire bear form. All states go to state (page) 2.
flickerstreak@7 31 [2] = "*:1", -- aquatic form. All states to go state (page) 1 (same as humanoid)
flickerstreak@7 32 [3] = "*:3", -- cat form. All states go to state (page) 3
flickerstreak@7 33 [4] = "*:1", -- travel form. All states go to state (page) 1 (same as humanoid)
flickerstreak@7 34 [5] = "*:4", -- oomkin/tree form [talent only]. All states go to state (page) 4
flickerstreak@7 35 [6] = "*:1", -- flight form. All states go to state (page) 1 (same as humanoid) (??? How does this work with oomkin/tree?)
flickerstreak@7 36 },
flickerstreak@7 37 PALADIN = {},
flickerstreak@7 38 SHAMAN = {},
flickerstreak@7 39 MAGE = {},
flickerstreak@7 40 PRIEST = {
flickerstreak@7 41 [0] = "*:1", -- normal form. All states go to page 1.
flickerstreak@7 42 [1] = "*:2", -- shadowform (talent only). All states go to page 2.
flickerstreak@7 43 },
flickerstreak@7 44 WARLOCK = {},
flickerstreak@1 45 }
flickerstreak@1 46
flickerstreak@7 47 local stealthMaps = {
flickerstreak@7 48 WARRIOR = "",
flickerstreak@7 49 ROGUE = "1:2", -- go to page 2 for rogues
flickerstreak@7 50 HUNTER = "",
flickerstreak@7 51 DRUID = "3:5", -- we'll replace with 1:2 if stance mapping is not enabled, and page 5 with 6 if oomkin/tree
flickerstreak@7 52 PALADIN = "",
flickerstreak@7 53 SHAMAN = "",
flickerstreak@7 54 MAGE = "",
flickerstreak@7 55 PRIEST = "",
flickerstreak@1 56 }
flickerstreak@1 57
flickerstreak@7 58 local unstealthMaps = {
flickerstreak@7 59 WARRIOR = "",
flickerstreak@7 60 ROGUE = "2:1", -- go to page 1 for rogues
flickerstreak@7 61 HUNTER = "",
flickerstreak@7 62 DRUID = "5:3", -- we'll replace with 2:1 if stance mapping is not enabled, and page 5 with 6 if oomkin/tree
flickerstreak@7 63 PALADIN = "",
flickerstreak@7 64 SHAMAN = "",
flickerstreak@7 65 MAGE = "",
flickerstreak@7 66 PRIEST = "",
flickerstreak@7 67 }
flickerstreak@7 68
flickerstreak@7 69 -- Immediately fix if a druid with oomkin or tree (note: can't have both)
flickerstreak@7 70 local _, playerClass = UnitClass("player")
flickerstreak@7 71 if playerClass == "DRUID" and GetNumShapeshiftForms() > 4 then
flickerstreak@7 72 nStancePages.DRUID = 4
flickerstreak@7 73 stanceMaps.DRUID[5] = "*:4"
flickerstreak@7 74 stealthMaps.DRUID = "3:6"
flickerstreak@7 75 unstealthMaps.DRUID ="6:3"
flickerstreak@7 76 end
flickerstreak@7 77
flickerstreak@7 78 -- Immediately fix if a priest with shadowform
flickerstreak@7 79 if playerClass == "PRIEST" and GetNumShapeshiftForms() > 1 then
flickerstreak@7 80 nStancePages.PRIEST = 2
flickerstreak@7 81 end
flickerstreak@7 82
flickerstreak@7 83 local AceOO = AceLibrary("AceOO-2.0")
flickerstreak@7 84
flickerstreak@1 85 -- ReBar is an Ace 2 class prototype object.
flickerstreak@7 86 ReBar = AceOO.Class("AceEvent-2.0", ReAnchor, ReAnchor.IAnchorable)
flickerstreak@1 87
flickerstreak@1 88
flickerstreak@7 89 ----------------------
flickerstreak@7 90 -- Static members
flickerstreak@7 91 ----------------------
flickerstreak@7 92 -- IButtonClass is an interface required of any button class type (not the class objects themselves) to be used with the bar
flickerstreak@7 93 ReBar.IButtonClass = AceOO.Interface {
flickerstreak@7 94 Acquire = "function", -- btn = Acquire(config, barIdx, pages, buttonsPerPage)
flickerstreak@7 95 -- analogous to new(), this should re-use recycled frames for memory efficiency
flickerstreak@7 96 Release = "function", -- Release(btn) should hide and dispose of the button (and recycle it)
flickerstreak@7 97 }
flickerstreak@7 98
flickerstreak@7 99 -- IButton is an interface required of any button objects to be used with the bar
flickerstreak@7 100 ReBar.IButton = AceOO.Interface {
flickerstreak@7 101 GetActionFrame = "function", -- obtains the action frame, presumably inherited from SecureActionButtonTemplate or similar.
flickerstreak@7 102 BarLocked = "function", -- BarLocked() called when the bar is locked.
flickerstreak@7 103 BarUnlocked = "function", -- BarUnlocked() called when the bar is unlocked.
flickerstreak@7 104 PlaceButton = "function", -- PlaceButton(parent, anchorPoint, offsetX, offsetY, squareSz), one-stop position and size setting
flickerstreak@7 105 SetPages = "function", -- SetPages(n): sets number of pages for multi-paging. Can error if paging not supported.
flickerstreak@7 106 }
flickerstreak@7 107
flickerstreak@7 108 -- wrap UIParent and WorldFrame in objects which implement the ReAnchor.IAnchorable interface
flickerstreak@7 109 local UIParentPlaceable = {
flickerstreak@7 110 GetFrame = function() return UIParent end,
flickerstreak@7 111 GetAnchorage = function() return ReAnchor.anchorInside end,
flickerstreak@7 112 }
flickerstreak@7 113
flickerstreak@7 114 local WorldFramePlaceable = {
flickerstreak@7 115 GetFrame = function() return WorldFrame end,
flickerstreak@7 116 GetAnchorage = function() return ReAnchor.anchorInside end,
flickerstreak@7 117 }
flickerstreak@7 118
flickerstreak@7 119 ReBar.anchorTargets = {
flickerstreak@7 120 UIParentPlaceable,
flickerstreak@7 121 WorldFramePlaceable
flickerstreak@7 122 }
flickerstreak@7 123
flickerstreak@7 124 ReBar.UIParentAnchorTarget = {
flickerstreak@7 125 UIParentPlaceable
flickerstreak@7 126 }
flickerstreak@7 127
flickerstreak@7 128
flickerstreak@7 129
flickerstreak@7 130
flickerstreak@7 131
flickerstreak@7 132
flickerstreak@7 133 --------------------
flickerstreak@7 134 -- instance methods
flickerstreak@7 135 --------------------
flickerstreak@7 136 -- construction and destruction
flickerstreak@1 137 function ReBar.prototype:init( config, id )
flickerstreak@1 138 ReBar.super.prototype.init(self)
flickerstreak@1 139
flickerstreak@1 140 self.config = config
flickerstreak@1 141 self.barID = id
flickerstreak@1 142 self.buttons = { }
flickerstreak@7 143 self.locked = true
flickerstreak@7 144
flickerstreak@7 145 self.buttonClass = config.btnConfig and config.btnConfig.type and getglobal(config.btnConfig.type)
flickerstreak@7 146 if not AceOO.inherits(self.buttonClass, ReBar.IButton) then
flickerstreak@7 147 error("ReBar: Supplied Button type does not meet required interface.")
flickerstreak@7 148 end
flickerstreak@7 149
flickerstreak@1 150
flickerstreak@1 151 -- create the bar and control widgets
flickerstreak@7 152 self.barFrame = CreateFrame("Frame", "ReBar"..id, config.parent and getglobal(config.parent) or UIParent, "ReBarTemplate")
flickerstreak@2 153 self.controlFrame = getglobal(self.barFrame:GetName().."Controls")
flickerstreak@1 154 self.controlFrame.reBar = self
flickerstreak@2 155 self.barFrame:SetClampedToScreen(true)
flickerstreak@1 156
flickerstreak@1 157 -- set the text label on the control widget
flickerstreak@2 158 self.labelString = getglobal(self.controlFrame:GetName().."LabelString")
flickerstreak@2 159 self.labelString:SetText(id)
flickerstreak@1 160
flickerstreak@7 161 -- initial stateheader state
flickerstreak@7 162 self.barFrame.StateChanged = function() self:StateChanged() end
flickerstreak@7 163 self.barFrame:SetAttribute("state",config.pages and config.pages.currentPage or 1) -- initial state
flickerstreak@7 164
flickerstreak@1 165 -- initialize the bar layout
flickerstreak@1 166 self:ApplySize()
flickerstreak@1 167 self:ApplyAnchor()
flickerstreak@7 168 self:AcquireButtons()
flickerstreak@1 169 self:LayoutButtons()
flickerstreak@1 170 self:ApplyVisibility()
flickerstreak@1 171
flickerstreak@7 172 if self.config.pages then
flickerstreak@7 173 self:SetPages(self.config.pages.n)
flickerstreak@7 174 self:ApplyAutoStanceSwitch()
flickerstreak@7 175 self:ApplyAutoStealthSwitch()
flickerstreak@7 176 self:RefreshPageControls()
flickerstreak@7 177 end
flickerstreak@7 178
flickerstreak@7 179 -- register page up/down buttons with ReBound for keybinding
flickerstreak@7 180 if ReBound then
flickerstreak@7 181 ReBound:AddKeybindTarget(getglobal(self.barFrame:GetName().."PageUp"))
flickerstreak@7 182 ReBound:AddKeybindTarget(getglobal(self.barFrame:GetName().."PageDown"))
flickerstreak@7 183 end
flickerstreak@7 184
flickerstreak@7 185 -- add bar to anchorTargets list
flickerstreak@7 186 table.insert(ReBar.anchorTargets, self)
flickerstreak@1 187 end
flickerstreak@1 188
flickerstreak@7 189 function ReBar.prototype:Destroy()
flickerstreak@7 190 local f = self.barFrame
flickerstreak@1 191
flickerstreak@7 192 self:HideControls()
flickerstreak@7 193 f:Hide()
flickerstreak@7 194 f:ClearAllPoints()
flickerstreak@7 195 f:SetParent(nil)
flickerstreak@7 196 f:SetPoint("BOTTOMRIGHT", UIParent, "TOPLEFT", 0, 0)
flickerstreak@7 197
flickerstreak@7 198 while #self.buttons > 0 do
flickerstreak@7 199 self.buttonClass:Release(table.remove(self.buttons))
flickerstreak@1 200 end
flickerstreak@1 201
flickerstreak@7 202 -- remove from anchorTargets table
flickerstreak@7 203 for idx, b in ipairs(ReBar.anchorTargets) do
flickerstreak@7 204 if b == self then
flickerstreak@7 205 table.remove(ReBar.anchorTargets, idx)
flickerstreak@7 206 break
flickerstreak@7 207 end
flickerstreak@7 208 end
flickerstreak@1 209
flickerstreak@7 210 -- remove from globals
flickerstreak@7 211 local n = f:GetName()
flickerstreak@7 212 setglobal(n, nil)
flickerstreak@7 213 setglobal(n.."Control", nil)
flickerstreak@7 214 setglobal(n.."Controls", nil)
flickerstreak@7 215 setglobal(n.."ControlsLabelString", nil)
flickerstreak@7 216 setglobal(n.."PageUp", nil)
flickerstreak@7 217 setglobal(n.."PageDown", nil)
flickerstreak@7 218 setglobal(n.."Page", nil)
flickerstreak@7 219 setglobal(n.."PageNumber", nil)
flickerstreak@7 220 setglobal(n.."PageNumberLabel", nil)
flickerstreak@7 221 setglobal(n.."PageNumberLabelText", nil)
flickerstreak@7 222 end
flickerstreak@1 223
flickerstreak@1 224
flickerstreak@7 225
flickerstreak@7 226
flickerstreak@7 227 -- ReAnchor.IAnchorable interface implementation
flickerstreak@7 228 function ReBar.prototype:GetFrame()
flickerstreak@7 229 return self.barFrame
flickerstreak@1 230 end
flickerstreak@1 231
flickerstreak@7 232 function ReBar.prototype:GetAnchorage()
flickerstreak@7 233 return ReAnchor.anchorOutside
flickerstreak@7 234 end
flickerstreak@7 235
flickerstreak@7 236
flickerstreak@7 237
flickerstreak@1 238
flickerstreak@1 239 -- show/hide the control frame
flickerstreak@1 240 function ReBar.prototype:ShowControls()
flickerstreak@7 241 self.locked = false
flickerstreak@1 242 self.controlFrame:Show()
flickerstreak@2 243 for _, b in ipairs(self.buttons) do
flickerstreak@2 244 b:BarUnlocked()
flickerstreak@7 245 b:DisplayVisibility()
flickerstreak@2 246 end
flickerstreak@7 247 self:ApplyVisibility()
flickerstreak@1 248 end
flickerstreak@1 249
flickerstreak@1 250 function ReBar.prototype:HideControls()
flickerstreak@7 251 self.locked = true
flickerstreak@1 252 local b = self.barFrame
flickerstreak@1 253 if b.isMoving or b.resizing then
flickerstreak@1 254 b:StopMovingOrSizing()
flickerstreak@1 255 b:SetScript("OnUpdate",nil)
flickerstreak@1 256 end
flickerstreak@2 257 for _, b in ipairs(self.buttons) do
flickerstreak@2 258 b:BarLocked()
flickerstreak@7 259 b:DisplayVisibility()
flickerstreak@2 260 end
flickerstreak@1 261 self.controlFrame:Hide()
flickerstreak@7 262 self:ApplyVisibility()
flickerstreak@1 263 end
flickerstreak@1 264
flickerstreak@7 265 function ReBar.prototype:GetControlFrame()
flickerstreak@7 266 return self.controlFrame
flickerstreak@7 267 end
flickerstreak@1 268
flickerstreak@1 269
flickerstreak@1 270 -- accessors
flickerstreak@1 271 function ReBar.prototype:GetVisibility()
flickerstreak@1 272 return self.config.visible
flickerstreak@1 273 end
flickerstreak@1 274
flickerstreak@1 275 function ReBar.prototype:ToggleVisibility()
flickerstreak@7 276 self:SetVisibility( not self:GetVisibility() )
flickerstreak@7 277 end
flickerstreak@7 278
flickerstreak@7 279 function ReBar.prototype:SetVisibility(v)
flickerstreak@7 280 self.config.visible = v and true or false -- force data integrity
flickerstreak@1 281 self:ApplyVisibility()
flickerstreak@1 282 end
flickerstreak@1 283
flickerstreak@1 284 function ReBar.prototype:GetOpacity()
flickerstreak@7 285 return tonumber(self.config.opacity) or 100
flickerstreak@1 286 end
flickerstreak@1 287
flickerstreak@1 288 function ReBar.prototype:SetOpacity( o )
flickerstreak@7 289 o = tonumber(o)
flickerstreak@7 290 if o then
flickerstreak@7 291 self.config.opacity = o
flickerstreak@7 292 self:ApplyVisibility()
flickerstreak@7 293 return self.config.opacity
flickerstreak@7 294 end
flickerstreak@1 295 end
flickerstreak@1 296
flickerstreak@7 297 function ReBar.prototype:GetButtonList()
flickerstreak@7 298 return self.buttons
flickerstreak@7 299 end
flickerstreak@7 300
flickerstreak@7 301 function ReBar.prototype:GetGrowLeft()
flickerstreak@7 302 return self.config.growLeft
flickerstreak@7 303 end
flickerstreak@7 304
flickerstreak@7 305 function ReBar.prototype:SetGrowLeft(g)
flickerstreak@7 306 self.config.growLeft = g and true or false
flickerstreak@7 307 self:LayoutButtons()
flickerstreak@7 308 end
flickerstreak@7 309
flickerstreak@7 310 function ReBar.prototype:GetGrowUp()
flickerstreak@7 311 return self.config.growUp
flickerstreak@7 312 end
flickerstreak@7 313
flickerstreak@7 314 function ReBar.prototype:SetGrowUp(g)
flickerstreak@7 315 self.config.growUp = g and true or false
flickerstreak@7 316 self:LayoutButtons()
flickerstreak@7 317 end
flickerstreak@7 318
flickerstreak@7 319 function ReBar.prototype:GetColumnMajor()
flickerstreak@7 320 return self.config.columnMajor
flickerstreak@7 321 end
flickerstreak@7 322
flickerstreak@7 323 function ReBar.prototype:SetColumnMajor(m)
flickerstreak@7 324 self.config.columnMajor = m and true or false
flickerstreak@7 325 self:LayoutButtons()
flickerstreak@7 326 end
flickerstreak@7 327
flickerstreak@7 328
flickerstreak@7 329 -- paging methods
flickerstreak@7 330 function ReBar.prototype:IsPagingDisabled()
flickerstreak@7 331 return not (self.config.pages and self.config.pages.n > 1)
flickerstreak@7 332 end
flickerstreak@7 333
flickerstreak@7 334 function ReBar.prototype:GetPages()
flickerstreak@7 335 return self.config.pages and self.config.pages.n or 1
flickerstreak@7 336 end
flickerstreak@7 337
flickerstreak@7 338 function ReBar.prototype:SetPages(n)
flickerstreak@7 339 n = tonumber(n)
flickerstreak@7 340 if n and n >= 1 then
flickerstreak@7 341 self.config.pages = self.config.pages or { }
flickerstreak@7 342 self.config.pages.n = n
flickerstreak@7 343 for _, btn in pairs(self.buttons) do
flickerstreak@7 344 btn:SetPages(n)
flickerstreak@7 345 end
flickerstreak@7 346 if n > 1 then
flickerstreak@7 347 local statebutton = "0:page1;"
flickerstreak@7 348 -- map states 1-n to 'page1'-'pagen'
flickerstreak@7 349 -- page 0 is the same as page 1.
flickerstreak@7 350 for i = 1, n do
flickerstreak@7 351 statebutton = statebutton..i..":page"..i..";"
flickerstreak@7 352 end
flickerstreak@7 353 self.barFrame:SetAttribute("statebutton",statebutton)
flickerstreak@7 354 else
flickerstreak@7 355 self.barFrame:SetAttribute("statebutton",ATTRIBUTE_NOOP)
flickerstreak@7 356 end
flickerstreak@7 357 self.barFrame:SetAttribute("statemap-anchor-next","1-"..n)
flickerstreak@7 358 self.barFrame:SetAttribute("statemap-anchor-prev",tostring(n).."-1")
flickerstreak@7 359 self:RefreshPageControls()
flickerstreak@7 360 end
flickerstreak@7 361 end
flickerstreak@7 362
flickerstreak@7 363 function ReBar.prototype:GetAutoStanceSwitch()
flickerstreak@7 364 return self.config.pages and self.config.pages.autoStanceSwitch
flickerstreak@7 365 end
flickerstreak@7 366
flickerstreak@7 367 function ReBar.prototype:SetAutoStanceSwitch( s )
flickerstreak@7 368 if not self.config.pages then
flickerstreak@7 369 self.config.pages = { n = 1 }
flickerstreak@7 370 end
flickerstreak@7 371 self.config.pages.autoStanceSwitch = s and true or false
flickerstreak@7 372 self:ApplyAutoStanceSwitch()
flickerstreak@7 373 end
flickerstreak@7 374
flickerstreak@7 375 function ReBar.prototype:ToggleAutoStanceSwitch()
flickerstreak@7 376 self:SetAutoStanceSwitch( not self:GetAutoStanceSwitch() )
flickerstreak@7 377 end
flickerstreak@7 378
flickerstreak@7 379 function ReBar.prototype:ApplyAutoStanceSwitch()
flickerstreak@7 380 local switch = self:GetAutoStanceSwitch()
flickerstreak@7 381 local _, class = UnitClass("player")
flickerstreak@7 382 if switch then
flickerstreak@7 383 -- check that the number of pages available is sufficient
flickerstreak@7 384 local totalPages = nStancePages[class] + (self:GetAutoStealthSwitch() and 1 or 0)
flickerstreak@7 385 if self:GetPages() < totalPages then
flickerstreak@7 386 self:SetPages(totalPages)
flickerstreak@7 387 end
flickerstreak@7 388 for form, spec in pairs(stanceMaps[class]) do
flickerstreak@7 389 self.barFrame:SetAttribute("statemap-stance-"..form,spec)
flickerstreak@7 390 end
flickerstreak@7 391 -- set initial value
flickerstreak@7 392 self.barFrame:SetAttribute("state-stance",GetShapeshiftForm(true))
flickerstreak@7 393 else
flickerstreak@7 394 for form, _ in pairs(stanceMaps[class]) do
flickerstreak@7 395 self.barFrame:SetAttribute("statemap-stance-"..form, ATTRIBUTE_NOOP)
flickerstreak@7 396 end
flickerstreak@7 397 end
flickerstreak@7 398 end
flickerstreak@7 399
flickerstreak@7 400 function ReBar.prototype:GetAutoStealthSwitch()
flickerstreak@7 401 return self.config.pages and self.config.pages.autoStealthSwitch
flickerstreak@7 402 end
flickerstreak@7 403
flickerstreak@7 404 function ReBar.prototype:SetAutoStealthSwitch( s )
flickerstreak@7 405 if not self.config.pages then
flickerstreak@7 406 self.config.pages = { n = 1 }
flickerstreak@7 407 end
flickerstreak@7 408 self.config.pages.autoStealthSwitch = s and true or false
flickerstreak@7 409 self:ApplyAutoStealthSwitch()
flickerstreak@7 410 end
flickerstreak@7 411
flickerstreak@7 412 function ReBar.prototype:ToggleAutoStealthSwitch()
flickerstreak@7 413 self:SetAutoStealthSwitch( not self:GetAutoStealthSwitch() )
flickerstreak@7 414 end
flickerstreak@7 415
flickerstreak@7 416 function ReBar.prototype:ApplyAutoStealthSwitch()
flickerstreak@7 417 local switch = self:GetAutoStealthSwitch()
flickerstreak@7 418 local _, class = UnitClass("player")
flickerstreak@7 419 if switch then
flickerstreak@7 420 -- check that the number of pages available is sufficient
flickerstreak@7 421 local totalPages = (self:GetAutoStanceSwitch() and nStancePages[class] > 0 and nStancePages[class] or 1) + 1
flickerstreak@7 422 if self:GetPages() < totalPages then
flickerstreak@7 423 self:SetPages(totalPages)
flickerstreak@7 424 end
flickerstreak@7 425 local s, s2
flickerstreak@7 426 if class == "DRUID" and not self:GetAutoStanceSwitch() then
flickerstreak@7 427 -- change mapping for cat->prowl and prowl->cat to 1:2 and 2:1 since no stance mapping
flickerstreak@7 428 s = "1:2"
flickerstreak@7 429 s2 = "2:1"
flickerstreak@7 430 end
flickerstreak@7 431 self.barFrame:SetAttribute("statemap-stealth-1",s or stealthMaps[class])
flickerstreak@7 432 self.barFrame:SetAttribute("statemap-stealth-0",s2 or unstealthMaps[class])
flickerstreak@7 433 -- set initial value
flickerstreak@7 434 self.barFrame:SetAttribute("state-stealth",IsStealthed() or 0)
flickerstreak@7 435 else
flickerstreak@7 436 self.barFrame:SetAttribute("statemap-stealth-1",ATTRIBUTE_NOOP)
flickerstreak@7 437 self.barFrame:SetAttribute("statemap-stealth-0",ATTRIBUTE_NOOP)
flickerstreak@7 438 end
flickerstreak@7 439 end
flickerstreak@7 440
flickerstreak@7 441 function ReBar.prototype:ArePageControlsHidden()
flickerstreak@7 442 return not ( self.config.pages and self.config.pages.showControls )
flickerstreak@7 443 end
flickerstreak@7 444
flickerstreak@7 445 function ReBar.prototype:TogglePageControlsHidden()
flickerstreak@7 446 if self.config.pages then
flickerstreak@7 447 self.config.pages.showControls = not self.config.pages.showControls
flickerstreak@7 448 self:RefreshPageControls()
flickerstreak@7 449 end
flickerstreak@7 450 end
flickerstreak@7 451
flickerstreak@7 452 function ReBar.prototype:GetPageControlsLoc()
flickerstreak@7 453 return self.config.pages and self.config.pages.controlsLoc
flickerstreak@7 454 end
flickerstreak@7 455
flickerstreak@7 456 function ReBar.prototype:SetPageControlsLoc(loc)
flickerstreak@7 457 if self.config.pages then
flickerstreak@7 458 self.config.pages.controlsLoc = loc
flickerstreak@7 459 self:RefreshPageControls()
flickerstreak@7 460 end
flickerstreak@7 461 end
flickerstreak@7 462
flickerstreak@7 463 function ReBar.prototype:RefreshPageControls()
flickerstreak@7 464 local b = self.barFrame;
flickerstreak@7 465 local upArrow = getglobal(b:GetName().."PageUp")
flickerstreak@7 466 local downArrow = getglobal(b:GetName().."PageDown")
flickerstreak@7 467 local pageNum = getglobal(b:GetName().."PageNumber")
flickerstreak@7 468
flickerstreak@7 469 if self:GetPages() > 1 and self.config.pages.showControls then
flickerstreak@7 470 local loc = self.config.pages.controlsLoc
flickerstreak@7 471
flickerstreak@7 472 pageNum:ClearAllPoints()
flickerstreak@7 473 upArrow:ClearAllPoints()
flickerstreak@7 474 downArrow:ClearAllPoints()
flickerstreak@7 475
flickerstreak@7 476 local vertical = { 0,0,0,1,1,0,1,1 }
flickerstreak@7 477 local horizontal = { 0,1,1,1,0,0,1,0 }
flickerstreak@7 478 local textures = {
flickerstreak@7 479 upArrow:GetNormalTexture(),
flickerstreak@7 480 upArrow:GetPushedTexture(),
flickerstreak@7 481 upArrow:GetDisabledTexture(),
flickerstreak@7 482 upArrow:GetHighlightTexture(),
flickerstreak@7 483 downArrow:GetNormalTexture(),
flickerstreak@7 484 downArrow:GetPushedTexture(),
flickerstreak@7 485 downArrow:GetDisabledTexture(),
flickerstreak@7 486 downArrow:GetHighlightTexture(),
flickerstreak@7 487 }
flickerstreak@7 488
flickerstreak@7 489 local offset = 10
flickerstreak@7 490 local mult = (loc == "RIGHT" or loc == "TOP") and 1 or -1
flickerstreak@7 491 local pageNumOffset = mult * (self.config.spacing/2 - offset)
flickerstreak@7 492 local arrowOffset = mult * offset
flickerstreak@7 493
flickerstreak@7 494 if loc == "Blizzard" or loc == nil then
flickerstreak@7 495 pageNum:SetPoint("LEFT", b, "RIGHT", 28, 0)
flickerstreak@7 496 upArrow:SetPoint("LEFT", b, "RIGHT", -2, 9)
flickerstreak@7 497 downArrow:SetPoint("LEFT", b, "RIGHT", -2, -10)
flickerstreak@7 498 for _, tex in ipairs(textures) do
flickerstreak@7 499 tex:SetTexCoord(unpack(vertical))
flickerstreak@7 500 end
flickerstreak@7 501 elseif loc == "RIGHT" or loc == "LEFT" then
flickerstreak@7 502 local relPoint = loc == "RIGHT" and "LEFT" or "RIGHT"
flickerstreak@7 503 pageNum:SetPoint(relPoint, b, loc, pageNumOffset, 0)
flickerstreak@7 504 upArrow:SetPoint("BOTTOM",pageNum,"TOP",arrowOffset, -12)
flickerstreak@7 505 downArrow:SetPoint("TOP",pageNum,"BOTTOM",arrowOffset, 12)
flickerstreak@7 506 for _, tex in ipairs(textures) do
flickerstreak@7 507 tex:SetTexCoord(unpack(vertical))
flickerstreak@7 508 end
flickerstreak@7 509 else
flickerstreak@7 510 pageNum:SetPoint(loc == "BOTTOM" and "TOP" or "BOTTOM", b, loc, 0, pageNumOffset)
flickerstreak@7 511 upArrow:SetPoint("LEFT",pageNum,"RIGHT",-12,arrowOffset)
flickerstreak@7 512 downArrow:SetPoint("RIGHT",pageNum,"LEFT",12,arrowOffset)
flickerstreak@7 513 for _, tex in ipairs(textures) do
flickerstreak@7 514 tex:SetTexCoord(unpack(horizontal))
flickerstreak@7 515 end
flickerstreak@7 516 end
flickerstreak@7 517 self:StateChanged()
flickerstreak@7 518 upArrow:Show()
flickerstreak@7 519 downArrow:Show()
flickerstreak@7 520 pageNum:Show()
flickerstreak@7 521 else
flickerstreak@7 522 upArrow:Hide()
flickerstreak@7 523 downArrow:Hide()
flickerstreak@7 524 pageNum:Hide()
flickerstreak@7 525 end
flickerstreak@7 526 end
flickerstreak@7 527
flickerstreak@7 528 function ReBar.prototype:StateChanged()
flickerstreak@7 529 local page = self.barFrame:GetAttribute("state") or 1
flickerstreak@7 530 getglobal(self.barFrame:GetName().."PageNumberLabelText"):SetText(page)
flickerstreak@7 531 if self.config.pages then self.config.pages.currentPage = page end
flickerstreak@7 532 end
flickerstreak@7 533
flickerstreak@7 534
flickerstreak@1 535
flickerstreak@1 536 -- layout methods
flickerstreak@1 537 function ReBar.prototype:ApplySize()
flickerstreak@1 538 local buttonSz = self.config.size or 36
flickerstreak@1 539 local spacing = self.config.spacing or 4
flickerstreak@1 540 local rows = self.config.rows or 1
flickerstreak@1 541 local columns = self.config.columns or 12
flickerstreak@7 542 local w = buttonSz * columns + spacing * columns
flickerstreak@7 543 local h = buttonSz * rows + spacing * rows
flickerstreak@1 544 local f = self.barFrame
flickerstreak@1 545
flickerstreak@7 546 -- + 0.1: avoid issues with UI scaling
flickerstreak@7 547 f:SetMinResize(buttonSz + spacing + 0.1, buttonSz + spacing + 0.1)
flickerstreak@7 548 f:SetWidth(w + 0.1)
flickerstreak@7 549 f:SetHeight(h + 0.1)
flickerstreak@1 550 end
flickerstreak@1 551
flickerstreak@1 552 function ReBar.prototype:ApplyAnchor()
flickerstreak@1 553 local a = self.config.anchor
flickerstreak@1 554 local f = self.barFrame
flickerstreak@2 555 if a then
flickerstreak@2 556 f:ClearAllPoints()
flickerstreak@7 557 f:SetPoint(a.point,getglobal(a.frame),a.relPoint,a.x,a.y)
flickerstreak@2 558 local color = anchoredLabelColor
flickerstreak@7 559 if a.frame == "UIParent" or a.frame == "WorldFrame" then
flickerstreak@2 560 color = nonAnchoredLabelColor
flickerstreak@2 561 end
flickerstreak@2 562 self.labelString:SetTextColor(color.r, color.g, color.b)
flickerstreak@2 563 end
flickerstreak@1 564 end
flickerstreak@1 565
flickerstreak@1 566 function ReBar.prototype:ApplyVisibility()
flickerstreak@7 567 local v = self.config.visible or not self.locked
flickerstreak@1 568
flickerstreak@7 569 if tonumber(self.config.opacity) then
flickerstreak@1 570 self.barFrame:SetAlpha(self.config.opacity / 100)
flickerstreak@1 571 end
flickerstreak@1 572
flickerstreak@1 573 if v then
flickerstreak@1 574 self.barFrame:Show()
flickerstreak@1 575 else
flickerstreak@1 576 self.barFrame:Hide()
flickerstreak@1 577 end
flickerstreak@1 578 end
flickerstreak@1 579
flickerstreak@1 580 function ReBar.prototype:LayoutButtons()
flickerstreak@1 581 local r = self.config.rows
flickerstreak@1 582 local c = self.config.columns
flickerstreak@1 583 local sp = self.config.spacing
flickerstreak@1 584 local sz = self.config.size
flickerstreak@1 585 local gSize = sp + sz
flickerstreak@7 586 local point = (self.config.growUp and "BOTTOM" or "TOP")..(self.config.growLeft and "RIGHT" or "LEFT")
flickerstreak@7 587 local major = self.config.columnMajor and r or c
flickerstreak@7 588
flickerstreak@7 589 for i, b in ipairs(self.buttons) do
flickerstreak@7 590 local x = sp/2 + gSize * math.fmod(i-1,major)
flickerstreak@7 591 local y = sp/2 + gSize * math.floor((i-1)/major)
flickerstreak@7 592 if self.config.columnMajor then x,y = y,x end
flickerstreak@7 593 if self.config.growLeft then x = -x end
flickerstreak@7 594 if not self.config.growUp then y = -y end
flickerstreak@7 595 b:PlaceButton(self.barFrame, point, x, y, sz)
flickerstreak@7 596 end
flickerstreak@7 597 end
flickerstreak@7 598
flickerstreak@7 599 function ReBar.prototype:FlipRowsColumns()
flickerstreak@7 600 self.config.rows, self.config.columns = self.config.columns, self.config.rows
flickerstreak@7 601 self.config.columnMajor = not self.config.columnMajor
flickerstreak@7 602 self:ApplySize()
flickerstreak@7 603 self:LayoutButtons()
flickerstreak@7 604 end
flickerstreak@7 605
flickerstreak@7 606 function ReBar.prototype:AcquireButtons()
flickerstreak@7 607 local n = self.config.rows * self.config.columns
flickerstreak@1 608
flickerstreak@1 609 for i = 1, n do
flickerstreak@1 610 if self.buttons[i] == nil then
flickerstreak@7 611 local b = self.buttonClass:Acquire(self.config.btnConfig, i, self.config.pages and self.config.pages.n, n)
flickerstreak@7 612 if b then
flickerstreak@7 613 if not AceOO.inherits(b, ReBar.IButton) then
flickerstreak@7 614 error("ReBar: specified Button class object did not meet required interface")
flickerstreak@7 615 end
flickerstreak@7 616 if self.locked == false then
flickerstreak@7 617 b:BarUnlocked() -- buttons assume they are created in a barlocked state
flickerstreak@7 618 end
flickerstreak@7 619 self.buttons[i] = b
flickerstreak@7 620 self.barFrame:SetAttribute("addchild",b:GetActionFrame())
flickerstreak@7 621 end
flickerstreak@1 622 end
flickerstreak@1 623 end
flickerstreak@1 624
flickerstreak@7 625 local maxn = table.maxn(self.buttons)
flickerstreak@7 626 for i = n+1, table.maxn(self.buttons) do
flickerstreak@7 627 local b = self.buttons[i]
flickerstreak@7 628 self.buttons[i] = nil
flickerstreak@7 629 if b then
flickerstreak@7 630 self.buttonClass:Release(b)
flickerstreak@7 631 end
flickerstreak@1 632 end
flickerstreak@1 633
flickerstreak@1 634 end
flickerstreak@1 635
flickerstreak@1 636
flickerstreak@1 637 function ReBar.prototype:StoreAnchor(f, p, rp, x, y)
flickerstreak@1 638 local name = f:GetName()
flickerstreak@1 639 -- no point if we can't store the name or the offsets are incomplete
flickerstreak@1 640 if name and x and y then
flickerstreak@1 641 self.config.anchor = {
flickerstreak@7 642 frame = name,
flickerstreak@1 643 point = p,
flickerstreak@1 644 relPoint = rp or p,
flickerstreak@1 645 x = x,
flickerstreak@1 646 y = y
flickerstreak@1 647 }
flickerstreak@1 648 end
flickerstreak@1 649 end
flickerstreak@1 650
flickerstreak@1 651
flickerstreak@1 652
flickerstreak@7 653 function ReBar.prototype:StickyIndicatorUpdate()
flickerstreak@7 654 if IsShiftKeyDown() then
flickerstreak@7 655 local snapRange = self.config.size + self.config.spacing
flickerstreak@7 656 self:DisplaySnapIndicator(ReBar.anchorTargets, snapRange, 0, 0)
flickerstreak@7 657 else
flickerstreak@7 658 self:HideSnapIndicator()
flickerstreak@7 659 end
flickerstreak@7 660 end
flickerstreak@7 661
flickerstreak@7 662
flickerstreak@1 663 -- mouse event handlers (clicking/dragging/resizing the bar)
flickerstreak@1 664 function ReBar.prototype:BeginDrag()
flickerstreak@1 665 local f = self.barFrame
flickerstreak@1 666 f:StartMoving()
flickerstreak@1 667 f.isMoving = true
flickerstreak@7 668 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@7 669 f:SetScript("OnUpdate", function(frame, elapsed) self:StickyIndicatorUpdate(elapsed) end)
flickerstreak@1 670 end
flickerstreak@1 671
flickerstreak@1 672 function ReBar.prototype:FinishDrag()
flickerstreak@7 673 local o, p, rp, x, y
flickerstreak@1 674 local bf = self.barFrame
flickerstreak@7 675 local snapRange = self.config.size + self.config.spacing
flickerstreak@1 676
flickerstreak@1 677 bf:StopMovingOrSizing()
flickerstreak@1 678 bf.isMoving = false
flickerstreak@1 679
flickerstreak@1 680 bf:SetScript("OnUpdate",nil)
flickerstreak@1 681 if IsShiftKeyDown() then
flickerstreak@7 682 o, p, rp, x, y = self:GetClosestPointSnapped(ReBar.anchorTargets, snapRange, 0, 0)
flickerstreak@1 683 end
flickerstreak@1 684
flickerstreak@7 685 if o == nil then
flickerstreak@7 686 o, p, rp, x, y = self:GetClosestVisiblePoint(ReBar.UIParentAnchorTarget, snapRange, 0, 0)
flickerstreak@1 687 end
flickerstreak@7 688
flickerstreak@7 689 self:HideSnapIndicator()
flickerstreak@7 690 self:StoreAnchor(o:GetFrame(), p, rp, x, y)
flickerstreak@7 691 self:ApplyAnchor()
flickerstreak@1 692 end
flickerstreak@1 693
flickerstreak@1 694 function ReBar.prototype:BeginBarResize( sizingPoint )
flickerstreak@1 695 local f = self.barFrame
flickerstreak@1 696 f:StartSizing(sizingPoint)
flickerstreak@1 697 f.resizing = true
flickerstreak@7 698 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@7 699 f:SetScript("OnUpdate",function(frame, elapsed) self:ReflowButtons(elapsed) end)
flickerstreak@1 700 end
flickerstreak@1 701
flickerstreak@1 702 function ReBar.prototype:BeginButtonResize( sizingPoint, mouseBtn )
flickerstreak@1 703 local f = self.barFrame
flickerstreak@1 704 f:StartSizing(sizingPoint)
flickerstreak@1 705 f.resizing = true
flickerstreak@1 706 local r = self.config.rows
flickerstreak@1 707 local c = self.config.columns
flickerstreak@1 708 local s = self.config.spacing
flickerstreak@1 709 local sz = self.config.size
flickerstreak@7 710 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@1 711 if mouseBtn == "LeftButton" then
flickerstreak@7 712 f:SetMinResize(c*(12 + s) +0.1, r*(12 + s) +0.1)
flickerstreak@7 713 f:SetScript("OnUpdate",function(frame, elapsed) self:DragSizeButtons(elapsed) end)
flickerstreak@1 714 elseif mouseBtn == "RightButton" then
flickerstreak@7 715 f:SetMinResize(c*sz+0.1, r*sz+0.1)
flickerstreak@7 716 f:SetScript("OnUpdate",function(frame, elapsed) self:DragSizeSpacing(elapsed) end)
flickerstreak@1 717 end
flickerstreak@1 718 end
flickerstreak@1 719
flickerstreak@1 720 function ReBar.prototype:FinishResize()
flickerstreak@1 721 local f = self.barFrame
flickerstreak@1 722 f:StopMovingOrSizing()
flickerstreak@1 723 f.resizing = false
flickerstreak@1 724 f:SetScript("OnUpdate",nil)
flickerstreak@1 725 self:ApplySize()
flickerstreak@1 726 end
flickerstreak@1 727
flickerstreak@1 728
flickerstreak@1 729
flickerstreak@1 730
flickerstreak@1 731
flickerstreak@1 732
flickerstreak@1 733
flickerstreak@1 734 -- utility function to get the height, width, and button size attributes
flickerstreak@1 735 function ReBar.prototype:GetLayout()
flickerstreak@1 736 local c = self.config
flickerstreak@1 737 local f = self.barFrame
flickerstreak@1 738 return f:GetWidth(), f:GetHeight(), c.size, c.rows, c.columns, c.spacing
flickerstreak@1 739 end
flickerstreak@1 740
flickerstreak@7 741
flickerstreak@1 742 -- add and remove buttons dynamically as the bar is resized
flickerstreak@7 743 function ReBar.prototype:ReflowButtons( elapsed )
flickerstreak@7 744 self.updateTime = self.updateTime - elapsed
flickerstreak@7 745 if self.updateTime <= 0 then
flickerstreak@7 746 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@7 747
flickerstreak@7 748 local w, h, sz, r, c, sp = self:GetLayout()
flickerstreak@1 749
flickerstreak@7 750 self.config.rows = math.floor( (h+1) / (sz + sp) )
flickerstreak@7 751 self.config.columns = math.floor( (w+1) / (sz + sp) )
flickerstreak@1 752
flickerstreak@7 753 if self.config.rows ~= r or self.config.columns ~= c then
flickerstreak@7 754 self:AcquireButtons()
flickerstreak@7 755 self:LayoutButtons()
flickerstreak@7 756 end
flickerstreak@1 757 end
flickerstreak@1 758 end
flickerstreak@1 759
flickerstreak@1 760
flickerstreak@1 761 -- change the size of buttons as the bar is resized
flickerstreak@7 762 function ReBar.prototype:DragSizeButtons( elapsed )
flickerstreak@7 763 self.updateTime = self.updateTime - elapsed
flickerstreak@7 764 if self.updateTime <= 0 then
flickerstreak@7 765 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@7 766
flickerstreak@7 767 local w, h, sz, r, c, sp = self:GetLayout()
flickerstreak@1 768
flickerstreak@7 769 local newSzW = math.floor((w - c*sp)/c)
flickerstreak@7 770 local newSzH = math.floor((h - r*sp)/r)
flickerstreak@7 771
flickerstreak@7 772 self.config.size = math.max(12, math.min(newSzW, newSzH))
flickerstreak@1 773
flickerstreak@7 774 if self.config.size ~= sz then
flickerstreak@7 775 self:LayoutButtons()
flickerstreak@7 776 self:UpdateResizeTooltip()
flickerstreak@7 777 end
flickerstreak@1 778 end
flickerstreak@1 779 end
flickerstreak@1 780
flickerstreak@1 781
flickerstreak@1 782 -- change the spacing of buttons as the bar is resized
flickerstreak@7 783 function ReBar.prototype:DragSizeSpacing( elapsed )
flickerstreak@7 784 self.updateTime = self.updateTime - elapsed
flickerstreak@7 785 if self.updateTime <= 0 then
flickerstreak@7 786 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@7 787
flickerstreak@7 788 local w, h, sz, r, c, sp = self:GetLayout()
flickerstreak@1 789
flickerstreak@7 790 local newSpW = math.floor((w - c*sz)/c)
flickerstreak@7 791 local newSpH = math.floor((h - r*sz)/r)
flickerstreak@1 792
flickerstreak@7 793 self.config.spacing = math.max(0, math.min(newSpW, newSpH))
flickerstreak@1 794
flickerstreak@7 795 if self.config.spacing ~= sp then
flickerstreak@7 796 self:LayoutButtons()
flickerstreak@7 797 self:UpdateResizeTooltip()
flickerstreak@7 798 end
flickerstreak@1 799 end
flickerstreak@1 800 end
flickerstreak@1 801
flickerstreak@1 802
flickerstreak@1 803 -- update the drag tooltip to indicate current sizes
flickerstreak@1 804 function ReBar.prototype:UpdateResizeTooltip()
flickerstreak@1 805 GameTooltipTextRight4:SetText(self.config.size)
flickerstreak@1 806 GameTooltipTextRight5:SetText(self.config.spacing)
flickerstreak@1 807 GameTooltip:Show()
flickerstreak@1 808 end
flickerstreak@1 809
flickerstreak@1 810 function ReBar.prototype:ShowTooltip()
flickerstreak@1 811 GameTooltip:SetOwner(self.barFrame, "ANCHOR_TOPRIGHT")
flickerstreak@7 812 GameTooltip:AddLine(self.config.btnConfig.subtype.." Bar "..self.barID..(self.config.visible and "" or " (Hidden)"))
flickerstreak@1 813 GameTooltip:AddLine("Drag to move")
flickerstreak@1 814 GameTooltip:AddLine("Shift-drag for sticky mode")
flickerstreak@1 815 GameTooltip:AddLine("Right-click for options")
flickerstreak@1 816 GameTooltip:Show()
flickerstreak@1 817 end
flickerstreak@1 818
flickerstreak@1 819 function ReBar.prototype:ShowButtonResizeTooltip(point)
flickerstreak@1 820 GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point)
flickerstreak@1 821 GameTooltip:AddLine("Drag to resize buttons")
flickerstreak@1 822 GameTooltip:AddLine("Right-click-drag")
flickerstreak@1 823 GameTooltip:AddLine("to change spacing")
flickerstreak@1 824 GameTooltip:AddDoubleLine("Size: ", "0")
flickerstreak@1 825 GameTooltip:AddDoubleLine("Spacing: ", "0")
flickerstreak@1 826 self:UpdateResizeTooltip()
flickerstreak@1 827 end
flickerstreak@1 828
flickerstreak@1 829 function ReBar.prototype:ShowBarResizeTooltip(point)
flickerstreak@1 830 GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point)
flickerstreak@1 831 GameTooltip:AddLine("Drag to add/remove buttons")
flickerstreak@1 832 GameTooltip:Show()
flickerstreak@1 833 end