annotate classes/ReBar.lua @ 10:f3a7bfebc283

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