annotate classes/ReBar.lua @ 8:c05fd3e18b4f

Version 0.31
author Flick <flickerstreak@gmail.com>
date Tue, 20 Mar 2007 21:33:59 +0000
parents f920db5fc6b1
children f3a7bfebc283
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@8 152 local name = "ReBar"..id
flickerstreak@8 153 self.barFrame = CreateFrame("Frame", name, config.parent and getglobal(config.parent) or UIParent, "ReBarTemplate")
flickerstreak@2 154 self.controlFrame = getglobal(self.barFrame:GetName().."Controls")
flickerstreak@1 155 self.controlFrame.reBar = self
flickerstreak@2 156 self.barFrame:SetClampedToScreen(true)
flickerstreak@1 157
flickerstreak@8 158 -- get references to sub-frames
flickerstreak@8 159 self.labelString = getglobal(name.."ControlsLabelString")
flickerstreak@8 160 self.upArrow = getglobal(name.."PageUp")
flickerstreak@8 161 self.downArrow = getglobal(name.."PageDown")
flickerstreak@8 162 self.pageNum = getglobal(name.."PageNumber")
flickerstreak@8 163
flickerstreak@1 164 -- set the text label on the control widget
flickerstreak@2 165 self.labelString:SetText(id)
flickerstreak@1 166
flickerstreak@7 167 -- initial stateheader state
flickerstreak@7 168 self.barFrame.StateChanged = function() self:StateChanged() end
flickerstreak@7 169 self.barFrame:SetAttribute("state",config.pages and config.pages.currentPage or 1) -- initial state
flickerstreak@7 170
flickerstreak@1 171 -- initialize the bar layout
flickerstreak@1 172 self:ApplySize()
flickerstreak@1 173 self:ApplyAnchor()
flickerstreak@7 174 self:AcquireButtons()
flickerstreak@1 175 self:LayoutButtons()
flickerstreak@1 176 self:ApplyVisibility()
flickerstreak@1 177
flickerstreak@7 178 if self.config.pages then
flickerstreak@7 179 self:SetPages(self.config.pages.n)
flickerstreak@7 180 self:ApplyAutoStanceSwitch()
flickerstreak@7 181 self:ApplyAutoStealthSwitch()
flickerstreak@7 182 self:RefreshPageControls()
flickerstreak@7 183 end
flickerstreak@7 184
flickerstreak@7 185 -- register page up/down buttons with ReBound for keybinding
flickerstreak@7 186 if ReBound then
flickerstreak@8 187 ReBound:AddKeybindTarget(self.upArrow)
flickerstreak@8 188 ReBound:AddKeybindTarget(self.downArrow)
flickerstreak@7 189 end
flickerstreak@7 190
flickerstreak@7 191 -- add bar to anchorTargets list
flickerstreak@7 192 table.insert(ReBar.anchorTargets, self)
flickerstreak@1 193 end
flickerstreak@1 194
flickerstreak@7 195 function ReBar.prototype:Destroy()
flickerstreak@7 196 local f = self.barFrame
flickerstreak@1 197
flickerstreak@7 198 self:HideControls()
flickerstreak@7 199 f:Hide()
flickerstreak@7 200 f:ClearAllPoints()
flickerstreak@7 201 f:SetParent(nil)
flickerstreak@7 202 f:SetPoint("BOTTOMRIGHT", UIParent, "TOPLEFT", 0, 0)
flickerstreak@7 203
flickerstreak@7 204 while #self.buttons > 0 do
flickerstreak@7 205 self.buttonClass:Release(table.remove(self.buttons))
flickerstreak@1 206 end
flickerstreak@1 207
flickerstreak@7 208 -- remove from anchorTargets table
flickerstreak@7 209 for idx, b in ipairs(ReBar.anchorTargets) do
flickerstreak@7 210 if b == self then
flickerstreak@7 211 table.remove(ReBar.anchorTargets, idx)
flickerstreak@7 212 break
flickerstreak@7 213 end
flickerstreak@7 214 end
flickerstreak@1 215
flickerstreak@7 216 -- remove from globals
flickerstreak@7 217 local n = f:GetName()
flickerstreak@7 218 setglobal(n, nil)
flickerstreak@7 219 setglobal(n.."Control", nil)
flickerstreak@7 220 setglobal(n.."Controls", nil)
flickerstreak@7 221 setglobal(n.."ControlsLabelString", nil)
flickerstreak@7 222 setglobal(n.."PageUp", nil)
flickerstreak@7 223 setglobal(n.."PageDown", nil)
flickerstreak@7 224 setglobal(n.."Page", nil)
flickerstreak@7 225 setglobal(n.."PageNumber", nil)
flickerstreak@7 226 setglobal(n.."PageNumberLabel", nil)
flickerstreak@7 227 setglobal(n.."PageNumberLabelText", nil)
flickerstreak@7 228 end
flickerstreak@1 229
flickerstreak@1 230
flickerstreak@7 231
flickerstreak@7 232
flickerstreak@7 233 -- ReAnchor.IAnchorable interface implementation
flickerstreak@7 234 function ReBar.prototype:GetFrame()
flickerstreak@7 235 return self.barFrame
flickerstreak@1 236 end
flickerstreak@1 237
flickerstreak@7 238 function ReBar.prototype:GetAnchorage()
flickerstreak@7 239 return ReAnchor.anchorOutside
flickerstreak@7 240 end
flickerstreak@7 241
flickerstreak@7 242
flickerstreak@7 243
flickerstreak@1 244
flickerstreak@1 245 -- show/hide the control frame
flickerstreak@1 246 function ReBar.prototype:ShowControls()
flickerstreak@7 247 self.locked = false
flickerstreak@1 248 self.controlFrame:Show()
flickerstreak@2 249 for _, b in ipairs(self.buttons) do
flickerstreak@2 250 b:BarUnlocked()
flickerstreak@7 251 b:DisplayVisibility()
flickerstreak@2 252 end
flickerstreak@7 253 self:ApplyVisibility()
flickerstreak@1 254 end
flickerstreak@1 255
flickerstreak@1 256 function ReBar.prototype:HideControls()
flickerstreak@7 257 self.locked = true
flickerstreak@1 258 local b = self.barFrame
flickerstreak@1 259 if b.isMoving or b.resizing then
flickerstreak@1 260 b:StopMovingOrSizing()
flickerstreak@1 261 b:SetScript("OnUpdate",nil)
flickerstreak@1 262 end
flickerstreak@2 263 for _, b in ipairs(self.buttons) do
flickerstreak@2 264 b:BarLocked()
flickerstreak@7 265 b:DisplayVisibility()
flickerstreak@2 266 end
flickerstreak@1 267 self.controlFrame:Hide()
flickerstreak@7 268 self:ApplyVisibility()
flickerstreak@1 269 end
flickerstreak@1 270
flickerstreak@7 271 function ReBar.prototype:GetControlFrame()
flickerstreak@7 272 return self.controlFrame
flickerstreak@7 273 end
flickerstreak@1 274
flickerstreak@1 275
flickerstreak@1 276 -- accessors
flickerstreak@1 277 function ReBar.prototype:GetVisibility()
flickerstreak@1 278 return self.config.visible
flickerstreak@1 279 end
flickerstreak@1 280
flickerstreak@1 281 function ReBar.prototype:ToggleVisibility()
flickerstreak@7 282 self:SetVisibility( not self:GetVisibility() )
flickerstreak@7 283 end
flickerstreak@7 284
flickerstreak@7 285 function ReBar.prototype:SetVisibility(v)
flickerstreak@7 286 self.config.visible = v and true or false -- force data integrity
flickerstreak@1 287 self:ApplyVisibility()
flickerstreak@1 288 end
flickerstreak@1 289
flickerstreak@7 290 function ReBar.prototype:GetButtonList()
flickerstreak@7 291 return self.buttons
flickerstreak@7 292 end
flickerstreak@7 293
flickerstreak@7 294 function ReBar.prototype:GetGrowLeft()
flickerstreak@7 295 return self.config.growLeft
flickerstreak@7 296 end
flickerstreak@7 297
flickerstreak@7 298 function ReBar.prototype:SetGrowLeft(g)
flickerstreak@7 299 self.config.growLeft = g and true or false
flickerstreak@7 300 self:LayoutButtons()
flickerstreak@7 301 end
flickerstreak@7 302
flickerstreak@7 303 function ReBar.prototype:GetGrowUp()
flickerstreak@7 304 return self.config.growUp
flickerstreak@7 305 end
flickerstreak@7 306
flickerstreak@7 307 function ReBar.prototype:SetGrowUp(g)
flickerstreak@7 308 self.config.growUp = g and true or false
flickerstreak@7 309 self:LayoutButtons()
flickerstreak@7 310 end
flickerstreak@7 311
flickerstreak@7 312 function ReBar.prototype:GetColumnMajor()
flickerstreak@7 313 return self.config.columnMajor
flickerstreak@7 314 end
flickerstreak@7 315
flickerstreak@7 316 function ReBar.prototype:SetColumnMajor(m)
flickerstreak@7 317 self.config.columnMajor = m and true or false
flickerstreak@7 318 self:LayoutButtons()
flickerstreak@7 319 end
flickerstreak@7 320
flickerstreak@7 321
flickerstreak@7 322 -- paging methods
flickerstreak@7 323 function ReBar.prototype:IsPagingDisabled()
flickerstreak@7 324 return not (self.config.pages and self.config.pages.n > 1)
flickerstreak@7 325 end
flickerstreak@7 326
flickerstreak@7 327 function ReBar.prototype:GetPages()
flickerstreak@7 328 return self.config.pages and self.config.pages.n or 1
flickerstreak@7 329 end
flickerstreak@7 330
flickerstreak@7 331 function ReBar.prototype:SetPages(n)
flickerstreak@7 332 n = tonumber(n)
flickerstreak@7 333 if n and n >= 1 then
flickerstreak@7 334 self.config.pages = self.config.pages or { }
flickerstreak@7 335 self.config.pages.n = n
flickerstreak@7 336 for _, btn in pairs(self.buttons) do
flickerstreak@7 337 btn:SetPages(n)
flickerstreak@7 338 end
flickerstreak@7 339 if n > 1 then
flickerstreak@7 340 local statebutton = "0:page1;"
flickerstreak@7 341 -- map states 1-n to 'page1'-'pagen'
flickerstreak@7 342 -- page 0 is the same as page 1.
flickerstreak@7 343 for i = 1, n do
flickerstreak@7 344 statebutton = statebutton..i..":page"..i..";"
flickerstreak@7 345 end
flickerstreak@7 346 self.barFrame:SetAttribute("statebutton",statebutton)
flickerstreak@7 347 else
flickerstreak@7 348 self.barFrame:SetAttribute("statebutton",ATTRIBUTE_NOOP)
flickerstreak@7 349 end
flickerstreak@7 350 self.barFrame:SetAttribute("statemap-anchor-next","1-"..n)
flickerstreak@7 351 self.barFrame:SetAttribute("statemap-anchor-prev",tostring(n).."-1")
flickerstreak@7 352 self:RefreshPageControls()
flickerstreak@7 353 end
flickerstreak@7 354 end
flickerstreak@7 355
flickerstreak@7 356 function ReBar.prototype:GetAutoStanceSwitch()
flickerstreak@7 357 return self.config.pages and self.config.pages.autoStanceSwitch
flickerstreak@7 358 end
flickerstreak@7 359
flickerstreak@7 360 function ReBar.prototype:SetAutoStanceSwitch( s )
flickerstreak@7 361 if not self.config.pages then
flickerstreak@7 362 self.config.pages = { n = 1 }
flickerstreak@7 363 end
flickerstreak@7 364 self.config.pages.autoStanceSwitch = s and true or false
flickerstreak@7 365 self:ApplyAutoStanceSwitch()
flickerstreak@7 366 end
flickerstreak@7 367
flickerstreak@7 368 function ReBar.prototype:ToggleAutoStanceSwitch()
flickerstreak@7 369 self:SetAutoStanceSwitch( not self:GetAutoStanceSwitch() )
flickerstreak@7 370 end
flickerstreak@7 371
flickerstreak@7 372 function ReBar.prototype:ApplyAutoStanceSwitch()
flickerstreak@7 373 local switch = self:GetAutoStanceSwitch()
flickerstreak@7 374 if switch then
flickerstreak@7 375 -- check that the number of pages available is sufficient
flickerstreak@8 376 local totalPages = nStancePages[playerClass] + (self:GetAutoStealthSwitch() and 1 or 0)
flickerstreak@7 377 if self:GetPages() < totalPages then
flickerstreak@7 378 self:SetPages(totalPages)
flickerstreak@7 379 end
flickerstreak@8 380 for form, spec in pairs(stanceMaps[playerClass]) do
flickerstreak@7 381 self.barFrame:SetAttribute("statemap-stance-"..form,spec)
flickerstreak@7 382 end
flickerstreak@7 383 -- set initial value
flickerstreak@7 384 self.barFrame:SetAttribute("state-stance",GetShapeshiftForm(true))
flickerstreak@7 385 else
flickerstreak@8 386 for form, _ in pairs(stanceMaps[playerClass]) do
flickerstreak@7 387 self.barFrame:SetAttribute("statemap-stance-"..form, ATTRIBUTE_NOOP)
flickerstreak@7 388 end
flickerstreak@7 389 end
flickerstreak@7 390 end
flickerstreak@7 391
flickerstreak@7 392 function ReBar.prototype:GetAutoStealthSwitch()
flickerstreak@7 393 return self.config.pages and self.config.pages.autoStealthSwitch
flickerstreak@7 394 end
flickerstreak@7 395
flickerstreak@7 396 function ReBar.prototype:SetAutoStealthSwitch( s )
flickerstreak@7 397 if not self.config.pages then
flickerstreak@7 398 self.config.pages = { n = 1 }
flickerstreak@7 399 end
flickerstreak@7 400 self.config.pages.autoStealthSwitch = s and true or false
flickerstreak@7 401 self:ApplyAutoStealthSwitch()
flickerstreak@7 402 end
flickerstreak@7 403
flickerstreak@7 404 function ReBar.prototype:ToggleAutoStealthSwitch()
flickerstreak@7 405 self:SetAutoStealthSwitch( not self:GetAutoStealthSwitch() )
flickerstreak@7 406 end
flickerstreak@7 407
flickerstreak@7 408 function ReBar.prototype:ApplyAutoStealthSwitch()
flickerstreak@7 409 local switch = self:GetAutoStealthSwitch()
flickerstreak@7 410 if switch then
flickerstreak@7 411 -- check that the number of pages available is sufficient
flickerstreak@8 412 local totalPages = (self:GetAutoStanceSwitch() and nStancePages[playerClass] > 0 and nStancePages[playerClass] or 1) + 1
flickerstreak@7 413 if self:GetPages() < totalPages then
flickerstreak@7 414 self:SetPages(totalPages)
flickerstreak@7 415 end
flickerstreak@7 416 local s, s2
flickerstreak@8 417 if playerClass == "DRUID" and not self:GetAutoStanceSwitch() then
flickerstreak@7 418 -- change mapping for cat->prowl and prowl->cat to 1:2 and 2:1 since no stance mapping
flickerstreak@7 419 s = "1:2"
flickerstreak@7 420 s2 = "2:1"
flickerstreak@7 421 end
flickerstreak@8 422 self.barFrame:SetAttribute("statemap-stealth-1",s or stealthMaps[playerClass])
flickerstreak@8 423 self.barFrame:SetAttribute("statemap-stealth-0",s2 or unstealthMaps[playerClass])
flickerstreak@7 424 -- set initial value
flickerstreak@7 425 self.barFrame:SetAttribute("state-stealth",IsStealthed() or 0)
flickerstreak@7 426 else
flickerstreak@7 427 self.barFrame:SetAttribute("statemap-stealth-1",ATTRIBUTE_NOOP)
flickerstreak@7 428 self.barFrame:SetAttribute("statemap-stealth-0",ATTRIBUTE_NOOP)
flickerstreak@7 429 end
flickerstreak@7 430 end
flickerstreak@7 431
flickerstreak@7 432 function ReBar.prototype:ArePageControlsHidden()
flickerstreak@7 433 return not ( self.config.pages and self.config.pages.showControls )
flickerstreak@7 434 end
flickerstreak@7 435
flickerstreak@7 436 function ReBar.prototype:TogglePageControlsHidden()
flickerstreak@7 437 if self.config.pages then
flickerstreak@7 438 self.config.pages.showControls = not self.config.pages.showControls
flickerstreak@7 439 self:RefreshPageControls()
flickerstreak@7 440 end
flickerstreak@7 441 end
flickerstreak@7 442
flickerstreak@7 443 function ReBar.prototype:GetPageControlsLoc()
flickerstreak@7 444 return self.config.pages and self.config.pages.controlsLoc
flickerstreak@7 445 end
flickerstreak@7 446
flickerstreak@7 447 function ReBar.prototype:SetPageControlsLoc(loc)
flickerstreak@7 448 if self.config.pages then
flickerstreak@7 449 self.config.pages.controlsLoc = loc
flickerstreak@7 450 self:RefreshPageControls()
flickerstreak@7 451 end
flickerstreak@7 452 end
flickerstreak@7 453
flickerstreak@7 454 function ReBar.prototype:RefreshPageControls()
flickerstreak@7 455 local b = self.barFrame;
flickerstreak@8 456 local upArrow = self.upArrow
flickerstreak@8 457 local downArrow = self.downArrow
flickerstreak@8 458 local pageNum = self.pageNum
flickerstreak@7 459
flickerstreak@7 460 if self:GetPages() > 1 and self.config.pages.showControls then
flickerstreak@7 461 local loc = self.config.pages.controlsLoc
flickerstreak@7 462
flickerstreak@8 463 upArrow:SetAttribute("hidestates",nil)
flickerstreak@8 464 downArrow:SetAttribute("hidestates",nil)
flickerstreak@8 465
flickerstreak@7 466 pageNum:ClearAllPoints()
flickerstreak@7 467 upArrow:ClearAllPoints()
flickerstreak@7 468 downArrow:ClearAllPoints()
flickerstreak@7 469
flickerstreak@7 470 local vertical = { 0,0,0,1,1,0,1,1 }
flickerstreak@7 471 local horizontal = { 0,1,1,1,0,0,1,0 }
flickerstreak@7 472 local textures = {
flickerstreak@7 473 upArrow:GetNormalTexture(),
flickerstreak@7 474 upArrow:GetPushedTexture(),
flickerstreak@7 475 upArrow:GetDisabledTexture(),
flickerstreak@7 476 upArrow:GetHighlightTexture(),
flickerstreak@7 477 downArrow:GetNormalTexture(),
flickerstreak@7 478 downArrow:GetPushedTexture(),
flickerstreak@7 479 downArrow:GetDisabledTexture(),
flickerstreak@7 480 downArrow:GetHighlightTexture(),
flickerstreak@7 481 }
flickerstreak@7 482
flickerstreak@7 483 local offset = 10
flickerstreak@7 484 local mult = (loc == "RIGHT" or loc == "TOP") and 1 or -1
flickerstreak@7 485 local pageNumOffset = mult * (self.config.spacing/2 - offset)
flickerstreak@7 486 local arrowOffset = mult * offset
flickerstreak@7 487
flickerstreak@7 488 if loc == "Blizzard" or loc == nil then
flickerstreak@7 489 pageNum:SetPoint("LEFT", b, "RIGHT", 28, 0)
flickerstreak@7 490 upArrow:SetPoint("LEFT", b, "RIGHT", -2, 9)
flickerstreak@7 491 downArrow:SetPoint("LEFT", b, "RIGHT", -2, -10)
flickerstreak@7 492 for _, tex in ipairs(textures) do
flickerstreak@7 493 tex:SetTexCoord(unpack(vertical))
flickerstreak@7 494 end
flickerstreak@7 495 elseif loc == "RIGHT" or loc == "LEFT" then
flickerstreak@7 496 local relPoint = loc == "RIGHT" and "LEFT" or "RIGHT"
flickerstreak@7 497 pageNum:SetPoint(relPoint, b, loc, pageNumOffset, 0)
flickerstreak@7 498 upArrow:SetPoint("BOTTOM",pageNum,"TOP",arrowOffset, -12)
flickerstreak@7 499 downArrow:SetPoint("TOP",pageNum,"BOTTOM",arrowOffset, 12)
flickerstreak@7 500 for _, tex in ipairs(textures) do
flickerstreak@7 501 tex:SetTexCoord(unpack(vertical))
flickerstreak@7 502 end
flickerstreak@7 503 else
flickerstreak@7 504 pageNum:SetPoint(loc == "BOTTOM" and "TOP" or "BOTTOM", b, loc, 0, pageNumOffset)
flickerstreak@7 505 upArrow:SetPoint("LEFT",pageNum,"RIGHT",-12,arrowOffset)
flickerstreak@7 506 downArrow:SetPoint("RIGHT",pageNum,"LEFT",12,arrowOffset)
flickerstreak@7 507 for _, tex in ipairs(textures) do
flickerstreak@7 508 tex:SetTexCoord(unpack(horizontal))
flickerstreak@7 509 end
flickerstreak@7 510 end
flickerstreak@7 511 self:StateChanged()
flickerstreak@7 512 upArrow:Show()
flickerstreak@7 513 downArrow:Show()
flickerstreak@7 514 pageNum:Show()
flickerstreak@7 515 else
flickerstreak@8 516 upArrow:SetAttribute("hidestates","1-"..self:GetPages())
flickerstreak@8 517 downArrow:SetAttribute("hidestates","1-"..self:GetPages())
flickerstreak@8 518
flickerstreak@7 519 upArrow:Hide()
flickerstreak@7 520 downArrow:Hide()
flickerstreak@7 521 pageNum:Hide()
flickerstreak@7 522 end
flickerstreak@7 523 end
flickerstreak@7 524
flickerstreak@7 525 function ReBar.prototype:StateChanged()
flickerstreak@7 526 local page = self.barFrame:GetAttribute("state") or 1
flickerstreak@7 527 getglobal(self.barFrame:GetName().."PageNumberLabelText"):SetText(page)
flickerstreak@7 528 if self.config.pages then self.config.pages.currentPage = page end
flickerstreak@7 529 end
flickerstreak@7 530
flickerstreak@7 531
flickerstreak@1 532
flickerstreak@1 533 -- layout methods
flickerstreak@1 534 function ReBar.prototype:ApplySize()
flickerstreak@1 535 local buttonSz = self.config.size or 36
flickerstreak@1 536 local spacing = self.config.spacing or 4
flickerstreak@1 537 local rows = self.config.rows or 1
flickerstreak@1 538 local columns = self.config.columns or 12
flickerstreak@7 539 local w = buttonSz * columns + spacing * columns
flickerstreak@7 540 local h = buttonSz * rows + spacing * rows
flickerstreak@1 541 local f = self.barFrame
flickerstreak@1 542
flickerstreak@7 543 -- + 0.1: avoid issues with UI scaling
flickerstreak@7 544 f:SetMinResize(buttonSz + spacing + 0.1, buttonSz + spacing + 0.1)
flickerstreak@7 545 f:SetWidth(w + 0.1)
flickerstreak@7 546 f:SetHeight(h + 0.1)
flickerstreak@1 547 end
flickerstreak@1 548
flickerstreak@1 549 function ReBar.prototype:ApplyAnchor()
flickerstreak@1 550 local a = self.config.anchor
flickerstreak@1 551 local f = self.barFrame
flickerstreak@2 552 if a then
flickerstreak@2 553 f:ClearAllPoints()
flickerstreak@7 554 f:SetPoint(a.point,getglobal(a.frame),a.relPoint,a.x,a.y)
flickerstreak@2 555 local color = anchoredLabelColor
flickerstreak@7 556 if a.frame == "UIParent" or a.frame == "WorldFrame" then
flickerstreak@2 557 color = nonAnchoredLabelColor
flickerstreak@2 558 end
flickerstreak@2 559 self.labelString:SetTextColor(color.r, color.g, color.b)
flickerstreak@2 560 end
flickerstreak@1 561 end
flickerstreak@1 562
flickerstreak@1 563 function ReBar.prototype:ApplyVisibility()
flickerstreak@7 564 local v = self.config.visible or not self.locked
flickerstreak@1 565
flickerstreak@1 566 if v then
flickerstreak@1 567 self.barFrame:Show()
flickerstreak@1 568 else
flickerstreak@1 569 self.barFrame:Hide()
flickerstreak@1 570 end
flickerstreak@1 571 end
flickerstreak@1 572
flickerstreak@1 573 function ReBar.prototype:LayoutButtons()
flickerstreak@1 574 local r = self.config.rows
flickerstreak@1 575 local c = self.config.columns
flickerstreak@1 576 local sp = self.config.spacing
flickerstreak@1 577 local sz = self.config.size
flickerstreak@1 578 local gSize = sp + sz
flickerstreak@7 579 local point = (self.config.growUp and "BOTTOM" or "TOP")..(self.config.growLeft and "RIGHT" or "LEFT")
flickerstreak@7 580 local major = self.config.columnMajor and r or c
flickerstreak@7 581
flickerstreak@7 582 for i, b in ipairs(self.buttons) do
flickerstreak@7 583 local x = sp/2 + gSize * math.fmod(i-1,major)
flickerstreak@7 584 local y = sp/2 + gSize * math.floor((i-1)/major)
flickerstreak@7 585 if self.config.columnMajor then x,y = y,x end
flickerstreak@7 586 if self.config.growLeft then x = -x end
flickerstreak@7 587 if not self.config.growUp then y = -y end
flickerstreak@7 588 b:PlaceButton(self.barFrame, point, x, y, sz)
flickerstreak@7 589 end
flickerstreak@7 590 end
flickerstreak@7 591
flickerstreak@7 592 function ReBar.prototype:FlipRowsColumns()
flickerstreak@7 593 self.config.rows, self.config.columns = self.config.columns, self.config.rows
flickerstreak@7 594 self.config.columnMajor = not self.config.columnMajor
flickerstreak@7 595 self:ApplySize()
flickerstreak@7 596 self:LayoutButtons()
flickerstreak@7 597 end
flickerstreak@7 598
flickerstreak@7 599 function ReBar.prototype:AcquireButtons()
flickerstreak@7 600 local n = self.config.rows * self.config.columns
flickerstreak@1 601
flickerstreak@1 602 for i = 1, n do
flickerstreak@1 603 if self.buttons[i] == nil then
flickerstreak@7 604 local b = self.buttonClass:Acquire(self.config.btnConfig, i, self.config.pages and self.config.pages.n, n)
flickerstreak@7 605 if b then
flickerstreak@7 606 if not AceOO.inherits(b, ReBar.IButton) then
flickerstreak@7 607 error("ReBar: specified Button class object did not meet required interface")
flickerstreak@7 608 end
flickerstreak@7 609 if self.locked == false then
flickerstreak@7 610 b:BarUnlocked() -- buttons assume they are created in a barlocked state
flickerstreak@7 611 end
flickerstreak@7 612 self.buttons[i] = b
flickerstreak@7 613 self.barFrame:SetAttribute("addchild",b:GetActionFrame())
flickerstreak@7 614 end
flickerstreak@1 615 end
flickerstreak@1 616 end
flickerstreak@1 617
flickerstreak@7 618 local maxn = table.maxn(self.buttons)
flickerstreak@7 619 for i = n+1, table.maxn(self.buttons) do
flickerstreak@7 620 local b = self.buttons[i]
flickerstreak@7 621 self.buttons[i] = nil
flickerstreak@7 622 if b then
flickerstreak@7 623 self.buttonClass:Release(b)
flickerstreak@7 624 end
flickerstreak@1 625 end
flickerstreak@1 626
flickerstreak@1 627 end
flickerstreak@1 628
flickerstreak@1 629
flickerstreak@1 630 function ReBar.prototype:StoreAnchor(f, p, rp, x, y)
flickerstreak@1 631 local name = f:GetName()
flickerstreak@1 632 -- no point if we can't store the name or the offsets are incomplete
flickerstreak@1 633 if name and x and y then
flickerstreak@1 634 self.config.anchor = {
flickerstreak@7 635 frame = name,
flickerstreak@1 636 point = p,
flickerstreak@1 637 relPoint = rp or p,
flickerstreak@1 638 x = x,
flickerstreak@1 639 y = y
flickerstreak@1 640 }
flickerstreak@1 641 end
flickerstreak@1 642 end
flickerstreak@1 643
flickerstreak@1 644
flickerstreak@1 645
flickerstreak@7 646 function ReBar.prototype:StickyIndicatorUpdate()
flickerstreak@7 647 if IsShiftKeyDown() then
flickerstreak@7 648 local snapRange = self.config.size + self.config.spacing
flickerstreak@7 649 self:DisplaySnapIndicator(ReBar.anchorTargets, snapRange, 0, 0)
flickerstreak@7 650 else
flickerstreak@7 651 self:HideSnapIndicator()
flickerstreak@7 652 end
flickerstreak@7 653 end
flickerstreak@7 654
flickerstreak@7 655
flickerstreak@1 656 -- mouse event handlers (clicking/dragging/resizing the bar)
flickerstreak@1 657 function ReBar.prototype:BeginDrag()
flickerstreak@1 658 local f = self.barFrame
flickerstreak@1 659 f:StartMoving()
flickerstreak@1 660 f.isMoving = true
flickerstreak@7 661 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@7 662 f:SetScript("OnUpdate", function(frame, elapsed) self:StickyIndicatorUpdate(elapsed) end)
flickerstreak@1 663 end
flickerstreak@1 664
flickerstreak@1 665 function ReBar.prototype:FinishDrag()
flickerstreak@7 666 local o, p, rp, x, y
flickerstreak@1 667 local bf = self.barFrame
flickerstreak@7 668 local snapRange = self.config.size + self.config.spacing
flickerstreak@1 669
flickerstreak@1 670 bf:StopMovingOrSizing()
flickerstreak@1 671 bf.isMoving = false
flickerstreak@1 672
flickerstreak@1 673 bf:SetScript("OnUpdate",nil)
flickerstreak@1 674 if IsShiftKeyDown() then
flickerstreak@7 675 o, p, rp, x, y = self:GetClosestPointSnapped(ReBar.anchorTargets, snapRange, 0, 0)
flickerstreak@1 676 end
flickerstreak@1 677
flickerstreak@7 678 if o == nil then
flickerstreak@7 679 o, p, rp, x, y = self:GetClosestVisiblePoint(ReBar.UIParentAnchorTarget, snapRange, 0, 0)
flickerstreak@1 680 end
flickerstreak@7 681
flickerstreak@7 682 self:HideSnapIndicator()
flickerstreak@7 683 self:StoreAnchor(o:GetFrame(), p, rp, x, y)
flickerstreak@7 684 self:ApplyAnchor()
flickerstreak@1 685 end
flickerstreak@1 686
flickerstreak@1 687 function ReBar.prototype:BeginBarResize( sizingPoint )
flickerstreak@1 688 local f = self.barFrame
flickerstreak@1 689 f:StartSizing(sizingPoint)
flickerstreak@1 690 f.resizing = true
flickerstreak@7 691 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@7 692 f:SetScript("OnUpdate",function(frame, elapsed) self:ReflowButtons(elapsed) end)
flickerstreak@1 693 end
flickerstreak@1 694
flickerstreak@1 695 function ReBar.prototype:BeginButtonResize( sizingPoint, mouseBtn )
flickerstreak@1 696 local f = self.barFrame
flickerstreak@1 697 f:StartSizing(sizingPoint)
flickerstreak@1 698 f.resizing = true
flickerstreak@1 699 local r = self.config.rows
flickerstreak@1 700 local c = self.config.columns
flickerstreak@1 701 local s = self.config.spacing
flickerstreak@1 702 local sz = self.config.size
flickerstreak@7 703 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@1 704 if mouseBtn == "LeftButton" then
flickerstreak@7 705 f:SetMinResize(c*(12 + s) +0.1, r*(12 + s) +0.1)
flickerstreak@7 706 f:SetScript("OnUpdate",function(frame, elapsed) self:DragSizeButtons(elapsed) end)
flickerstreak@1 707 elseif mouseBtn == "RightButton" then
flickerstreak@7 708 f:SetMinResize(c*sz+0.1, r*sz+0.1)
flickerstreak@7 709 f:SetScript("OnUpdate",function(frame, elapsed) self:DragSizeSpacing(elapsed) end)
flickerstreak@1 710 end
flickerstreak@1 711 end
flickerstreak@1 712
flickerstreak@1 713 function ReBar.prototype:FinishResize()
flickerstreak@1 714 local f = self.barFrame
flickerstreak@1 715 f:StopMovingOrSizing()
flickerstreak@1 716 f.resizing = false
flickerstreak@1 717 f:SetScript("OnUpdate",nil)
flickerstreak@1 718 self:ApplySize()
flickerstreak@1 719 end
flickerstreak@1 720
flickerstreak@1 721
flickerstreak@1 722
flickerstreak@1 723
flickerstreak@1 724
flickerstreak@1 725
flickerstreak@1 726
flickerstreak@1 727 -- utility function to get the height, width, and button size attributes
flickerstreak@1 728 function ReBar.prototype:GetLayout()
flickerstreak@1 729 local c = self.config
flickerstreak@1 730 local f = self.barFrame
flickerstreak@1 731 return f:GetWidth(), f:GetHeight(), c.size, c.rows, c.columns, c.spacing
flickerstreak@1 732 end
flickerstreak@1 733
flickerstreak@7 734
flickerstreak@1 735 -- add and remove buttons dynamically as the bar is resized
flickerstreak@7 736 function ReBar.prototype:ReflowButtons( elapsed )
flickerstreak@7 737 self.updateTime = self.updateTime - elapsed
flickerstreak@7 738 if self.updateTime <= 0 then
flickerstreak@7 739 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@7 740
flickerstreak@7 741 local w, h, sz, r, c, sp = self:GetLayout()
flickerstreak@1 742
flickerstreak@7 743 self.config.rows = math.floor( (h+1) / (sz + sp) )
flickerstreak@7 744 self.config.columns = math.floor( (w+1) / (sz + sp) )
flickerstreak@1 745
flickerstreak@7 746 if self.config.rows ~= r or self.config.columns ~= c then
flickerstreak@7 747 self:AcquireButtons()
flickerstreak@7 748 self:LayoutButtons()
flickerstreak@7 749 end
flickerstreak@1 750 end
flickerstreak@1 751 end
flickerstreak@1 752
flickerstreak@1 753
flickerstreak@1 754 -- change the size of buttons as the bar is resized
flickerstreak@7 755 function ReBar.prototype:DragSizeButtons( elapsed )
flickerstreak@7 756 self.updateTime = self.updateTime - elapsed
flickerstreak@7 757 if self.updateTime <= 0 then
flickerstreak@7 758 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@7 759
flickerstreak@7 760 local w, h, sz, r, c, sp = self:GetLayout()
flickerstreak@1 761
flickerstreak@7 762 local newSzW = math.floor((w - c*sp)/c)
flickerstreak@7 763 local newSzH = math.floor((h - r*sp)/r)
flickerstreak@7 764
flickerstreak@7 765 self.config.size = math.max(12, math.min(newSzW, newSzH))
flickerstreak@1 766
flickerstreak@7 767 if self.config.size ~= sz then
flickerstreak@7 768 self:LayoutButtons()
flickerstreak@7 769 self:UpdateResizeTooltip()
flickerstreak@7 770 end
flickerstreak@1 771 end
flickerstreak@1 772 end
flickerstreak@1 773
flickerstreak@1 774
flickerstreak@1 775 -- change the spacing of buttons as the bar is resized
flickerstreak@7 776 function ReBar.prototype:DragSizeSpacing( elapsed )
flickerstreak@7 777 self.updateTime = self.updateTime - elapsed
flickerstreak@7 778 if self.updateTime <= 0 then
flickerstreak@7 779 self.updateTime = DRAG_UPDATE_RATE
flickerstreak@7 780
flickerstreak@7 781 local w, h, sz, r, c, sp = self:GetLayout()
flickerstreak@1 782
flickerstreak@7 783 local newSpW = math.floor((w - c*sz)/c)
flickerstreak@7 784 local newSpH = math.floor((h - r*sz)/r)
flickerstreak@1 785
flickerstreak@7 786 self.config.spacing = math.max(0, math.min(newSpW, newSpH))
flickerstreak@1 787
flickerstreak@7 788 if self.config.spacing ~= sp then
flickerstreak@7 789 self:LayoutButtons()
flickerstreak@7 790 self:UpdateResizeTooltip()
flickerstreak@7 791 end
flickerstreak@1 792 end
flickerstreak@1 793 end
flickerstreak@1 794
flickerstreak@1 795
flickerstreak@1 796 -- update the drag tooltip to indicate current sizes
flickerstreak@1 797 function ReBar.prototype:UpdateResizeTooltip()
flickerstreak@1 798 GameTooltipTextRight4:SetText(self.config.size)
flickerstreak@1 799 GameTooltipTextRight5:SetText(self.config.spacing)
flickerstreak@1 800 GameTooltip:Show()
flickerstreak@1 801 end
flickerstreak@1 802
flickerstreak@1 803 function ReBar.prototype:ShowTooltip()
flickerstreak@1 804 GameTooltip:SetOwner(self.barFrame, "ANCHOR_TOPRIGHT")
flickerstreak@7 805 GameTooltip:AddLine(self.config.btnConfig.subtype.." Bar "..self.barID..(self.config.visible and "" or " (Hidden)"))
flickerstreak@1 806 GameTooltip:AddLine("Drag to move")
flickerstreak@1 807 GameTooltip:AddLine("Shift-drag for sticky mode")
flickerstreak@1 808 GameTooltip:AddLine("Right-click for options")
flickerstreak@1 809 GameTooltip:Show()
flickerstreak@1 810 end
flickerstreak@1 811
flickerstreak@1 812 function ReBar.prototype:ShowButtonResizeTooltip(point)
flickerstreak@1 813 GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point)
flickerstreak@1 814 GameTooltip:AddLine("Drag to resize buttons")
flickerstreak@1 815 GameTooltip:AddLine("Right-click-drag")
flickerstreak@1 816 GameTooltip:AddLine("to change spacing")
flickerstreak@1 817 GameTooltip:AddDoubleLine("Size: ", "0")
flickerstreak@1 818 GameTooltip:AddDoubleLine("Spacing: ", "0")
flickerstreak@1 819 self:UpdateResizeTooltip()
flickerstreak@1 820 end
flickerstreak@1 821
flickerstreak@1 822 function ReBar.prototype:ShowBarResizeTooltip(point)
flickerstreak@1 823 GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point)
flickerstreak@1 824 GameTooltip:AddLine("Drag to add/remove buttons")
flickerstreak@1 825 GameTooltip:Show()
flickerstreak@1 826 end
flickerstreak@8 827