annotate classes/ReBar.lua @ 12:2735edcf9ab7

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