annotate classes/ReBar.lua @ 18:a805e4464237

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