annotate Bar.lua @ 75:06cd74bdc7da

- Cleaned up Bar interface - Move all attribute setting from Bar into State - Separated Moonkin and Tree of Life - Removed PossessBar module - Added some infrastructure for paged/mind control support to Action
author Flick <flickerstreak@gmail.com>
date Mon, 16 Jun 2008 18:46:08 +0000
parents dd01feae0d89
children da8ba8783924
rev   line source
flickerstreak@25 1 local ReAction = ReAction
flickerstreak@25 2 local L = ReAction.L
flickerstreak@25 3 local _G = _G
flickerstreak@25 4 local CreateFrame = CreateFrame
flickerstreak@33 5 local floor = math.floor
flickerstreak@75 6 local fmod = math.fmod
flickerstreak@75 7 local format = string.format
flickerstreak@71 8 local SecureStateHeader_Refresh = SecureStateHeader_Refresh
flickerstreak@33 9
flickerstreak@33 10
flickerstreak@25 11 -- update ReAction revision if this file is newer
flickerstreak@33 12 local revision = tonumber(("$Revision$"):match("%d+"))
flickerstreak@25 13 if revision > ReAction.revision then
flickerstreak@52 14 ReAction.revision = revision
flickerstreak@25 15 end
flickerstreak@25 16
flickerstreak@75 17
flickerstreak@28 18 ------ BAR CLASS ------
flickerstreak@28 19 local Bar = { _classID = {} }
flickerstreak@25 20
flickerstreak@28 21 local function Constructor( self, name, config )
flickerstreak@25 22 if type(config) ~= "table" then
flickerstreak@28 23 error("ReAction.Bar: config table required")
flickerstreak@25 24 end
flickerstreak@75 25 config.width = config.width or 480
flickerstreak@75 26 config.height = config.height or 40
flickerstreak@75 27
flickerstreak@75 28 self.name, self.config = name, config
flickerstreak@75 29 self.buttons = setmetatable({},{__mode="k"})
flickerstreak@75 30 self.statedrivers = { }
flickerstreak@75 31 self.keybinds = { }
flickerstreak@25 32
flickerstreak@54 33 local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent
flickerstreak@75 34 local f = CreateFrame("Button",name and format("ReAction-%s",name),parent,"SecureStateHeaderTemplate, SecureActionButtonTemplate")
flickerstreak@75 35
flickerstreak@75 36 -- The frame itself is read-only
flickerstreak@75 37 function self:GetFrame()
flickerstreak@75 38 return f
flickerstreak@75 39 end
flickerstreak@75 40
flickerstreak@75 41 -- The bar itself is also a Button derived from SecureActionButtonTemplate, so it has an OnClick handler
flickerstreak@75 42 -- which we can use as a virtual button for keybinds, which will send attribute-value changes to itself.
flickerstreak@75 43 -- However, we don't ever want the user to be able to click it directly.
flickerstreak@75 44 f:EnableMouse(false)
flickerstreak@75 45 f:SetAttribute("type","attribute")
flickerstreak@25 46 f:SetFrameStrata("MEDIUM")
flickerstreak@25 47 f:SetWidth(config.width)
flickerstreak@25 48 f:SetWidth(config.height)
flickerstreak@75 49 f:Show()
flickerstreak@25 50
flickerstreak@75 51 self:ApplyAnchor()
flickerstreak@63 52 ReAction.RegisterCallback(self, "OnConfigModeChanged")
flickerstreak@25 53 end
flickerstreak@25 54
flickerstreak@25 55 function Bar:Destroy()
flickerstreak@75 56 local f = self:GetFrame()
flickerstreak@25 57 f:UnregisterAllEvents()
flickerstreak@25 58 f:Hide()
flickerstreak@25 59 f:SetParent(UIParent)
flickerstreak@25 60 f:ClearAllPoints()
flickerstreak@63 61 ReAction.UnregisterAllCallbacks(self)
flickerstreak@75 62 for driver in pairs(self.statedrivers) do
flickerstreak@75 63 UnregisterStateDriver(f, driver)
flickerstreak@72 64 end
flickerstreak@25 65 self.labelString = nil
flickerstreak@25 66 self.controlFrame = nil
flickerstreak@25 67 self.config = nil
flickerstreak@25 68 end
flickerstreak@25 69
flickerstreak@63 70 function Bar:OnConfigModeChanged(event, mode)
flickerstreak@75 71 self:ShowControls(mode) -- Bar:ShowControls() defined in Overlay.lua
flickerstreak@25 72 end
flickerstreak@25 73
flickerstreak@25 74 function Bar:ApplyAnchor()
flickerstreak@75 75 local f, config = self:GetFrame(), self.config
flickerstreak@25 76 f:SetWidth(config.width)
flickerstreak@25 77 f:SetHeight(config.height)
flickerstreak@75 78 local point = config.point
flickerstreak@51 79 f:ClearAllPoints()
flickerstreak@75 80 if point then
flickerstreak@75 81 local anchor = f:GetParent()
flickerstreak@75 82 if config.anchor then
flickerstreak@75 83 local bar = ReAction:GetBar(config.anchor)
flickerstreak@52 84 if bar then
flickerstreak@75 85 anchor = bar:GetFrame()
flickerstreak@52 86 else
flickerstreak@75 87 anchor = _G[config.anchor]
flickerstreak@52 88 end
flickerstreak@25 89 end
flickerstreak@75 90 f:SetPoint(point, anchor or f:GetParent(), config.relpoint, config.x or 0, config.y or 0)
flickerstreak@25 91 else
flickerstreak@25 92 f:SetPoint("CENTER")
flickerstreak@25 93 end
flickerstreak@25 94 end
flickerstreak@25 95
flickerstreak@51 96 function Bar:SetAnchor(point, frame, relativePoint, x, y)
flickerstreak@51 97 local c = self.config
flickerstreak@75 98 c.point = point or c.point
flickerstreak@75 99 c.anchor = frame and frame:GetName() or c.anchor
flickerstreak@75 100 c.relpoint = relativePoint or c.relpoint
flickerstreak@51 101 c.x = x or c.x
flickerstreak@51 102 c.y = y or c.y
flickerstreak@51 103 self:ApplyAnchor()
flickerstreak@51 104 end
flickerstreak@51 105
flickerstreak@51 106 function Bar:GetAnchor()
flickerstreak@51 107 local c = self.config
flickerstreak@75 108 return (c.point or "CENTER"), (c.anchor or self:GetFrame():GetParent():GetName()), (c.relpoint or c.point or "CENTER"), (c.x or 0), (c.y or 0)
flickerstreak@25 109 end
flickerstreak@25 110
flickerstreak@25 111 function Bar:GetSize()
flickerstreak@75 112 local f = self:GetFrame()
flickerstreak@75 113 return f:GetWidth(), f:GetHeight()
flickerstreak@25 114 end
flickerstreak@25 115
flickerstreak@25 116 function Bar:SetSize(w,h)
flickerstreak@25 117 self.config.width = w
flickerstreak@25 118 self.config.height = h
flickerstreak@75 119 local f = self:GetFrame()
flickerstreak@75 120 f:SetWidth(w)
flickerstreak@75 121 f:SetHeight(h)
flickerstreak@25 122 end
flickerstreak@25 123
flickerstreak@25 124 function Bar:GetButtonSize()
flickerstreak@25 125 local w = self.config.btnWidth or 32
flickerstreak@25 126 local h = self.config.btnHeight or 32
flickerstreak@25 127 -- TODO: get from modules?
flickerstreak@25 128 return w,h
flickerstreak@25 129 end
flickerstreak@25 130
flickerstreak@25 131 function Bar:SetButtonSize(w,h)
flickerstreak@25 132 if w > 0 and h > 0 then
flickerstreak@25 133 self.config.btnWidth = w
flickerstreak@25 134 self.config.btnHeight = h
flickerstreak@25 135 end
flickerstreak@75 136 ReAction:RefreshBar(self)
flickerstreak@25 137 end
flickerstreak@25 138
flickerstreak@25 139 function Bar:GetButtonGrid()
flickerstreak@25 140 local cfg = self.config
flickerstreak@25 141 local r = cfg.btnRows or 1
flickerstreak@25 142 local c = cfg.btnColumns or 1
flickerstreak@25 143 local s = cfg.spacing or 4
flickerstreak@25 144 return r,c,s
flickerstreak@25 145 end
flickerstreak@25 146
flickerstreak@25 147 function Bar:SetButtonGrid(r,c,s)
flickerstreak@25 148 if r > 0 and c > 0 and s > 0 then
flickerstreak@25 149 local cfg = self.config
flickerstreak@25 150 cfg.btnRows = r
flickerstreak@25 151 cfg.btnColumns = c
flickerstreak@25 152 cfg.spacing = s
flickerstreak@25 153 end
flickerstreak@75 154 ReAction:RefreshBar(self)
flickerstreak@25 155 end
flickerstreak@25 156
flickerstreak@25 157 function Bar:GetName()
flickerstreak@25 158 return self.name
flickerstreak@25 159 end
flickerstreak@25 160
flickerstreak@75 161 -- only ReAction:RenameBar() should call this function
flickerstreak@33 162 function Bar:SetName(name)
flickerstreak@33 163 self.name = name
flickerstreak@75 164 -- controlLabelString is defined in Overlay.lua
flickerstreak@33 165 if self.controlLabelString then
flickerstreak@33 166 self.controlLabelString:SetText(self.name)
flickerstreak@33 167 end
flickerstreak@33 168 end
flickerstreak@33 169
flickerstreak@75 170 function Bar:AddButton(idx, button)
flickerstreak@75 171 self.buttons[button] = idx
flickerstreak@75 172 SecureStateHeader_Refresh(self:GetFrame())
flickerstreak@75 173 end
flickerstreak@75 174
flickerstreak@75 175 function Bar:RemoveButton(button)
flickerstreak@75 176 self.buttons[button] = nil
flickerstreak@75 177 end
flickerstreak@75 178
flickerstreak@75 179 function Bar:IterateButtons() -- iterator returns button, idx
flickerstreak@75 180 return pairs(self.buttons)
flickerstreak@75 181 end
flickerstreak@75 182
flickerstreak@75 183 function Bar:PlaceButton(button, baseW, baseH)
flickerstreak@75 184 local idx = self.buttons[button]
flickerstreak@75 185 if not idx then return end
flickerstreak@25 186 local r, c, s = self:GetButtonGrid()
flickerstreak@25 187 local bh, bw = self:GetButtonSize()
flickerstreak@75 188 local row, col = floor((idx-1)/c), fmod((idx-1),c) -- zero-based
flickerstreak@25 189 local x, y = col*bw + (col+0.5)*s, row*bh + (row+0.5)*s
flickerstreak@25 190 local scale = bw/baseW
flickerstreak@75 191 local f = button:GetFrame()
flickerstreak@25 192
flickerstreak@25 193 f:ClearAllPoints()
flickerstreak@25 194 f:SetPoint("TOPLEFT",x/scale,-y/scale)
flickerstreak@25 195 f:SetScale(scale)
flickerstreak@25 196 end
flickerstreak@25 197
flickerstreak@75 198 -- Creates (or updates) a named binding which binds a key press to a call to SetAttribute()
flickerstreak@75 199 -- pass a nil key to unbind
flickerstreak@75 200 function Bar:SetAttributeBinding( name, key, attribute, value )
flickerstreak@75 201 if not name then
flickerstreak@75 202 error("usage - Bar:SetAttributeBinding(name [, key, attribute, value]")
flickerstreak@75 203 end
flickerstreak@75 204 local f = self:GetFrame()
flickerstreak@71 205
flickerstreak@75 206 -- clear the old binding, if any
flickerstreak@75 207 if self.keybinds[name] then
flickerstreak@75 208 SetOverrideBinding(f, false, self.keybinds[name], nil)
flickerstreak@75 209 end
flickerstreak@75 210 if key then
flickerstreak@75 211 f:SetAttribute(format("attribute-name-%s",name), attribute)
flickerstreak@75 212 f:SetAttribute(format("attribute-value-%s",name), value)
flickerstreak@75 213 SetOverrideBindingClick(f, false, key, f:GetName(), name) -- binding name is the virtual mouse button
flickerstreak@75 214 end
flickerstreak@75 215 self.keybinds[name] = key
flickerstreak@68 216 end
flickerstreak@28 217
flickerstreak@75 218 -- Sets up a state driver 'name' for the bar, using the provided 'rule'
flickerstreak@75 219 -- Also sets attributes 'statemap-<name>-<key>'=<value> for each entry in the passed map
flickerstreak@75 220 -- if 'rule' is nil or an empty string, the driver is unregistered.
flickerstreak@75 221 function Bar:SetStateDriver( name, rule, map )
flickerstreak@75 222 local f = self:GetFrame()
flickerstreak@75 223 if rule and #rule > 0 then
flickerstreak@75 224 if map then
flickerstreak@75 225 for key, value in pairs(map) do
flickerstreak@75 226 f:SetAttribute( format("statemap-%s-%s",name,key), value )
flickerstreak@72 227 end
flickerstreak@72 228 end
flickerstreak@75 229 RegisterStateDriver(f, name, rule)
flickerstreak@75 230 self.statedrivers[name] = true
flickerstreak@75 231 elseif self.statedrivers[name] then
flickerstreak@75 232 UnregisterStateDriver(f, name)
flickerstreak@75 233 self.statedrivers[name] = nil
flickerstreak@72 234 end
flickerstreak@72 235 end
flickerstreak@72 236
flickerstreak@75 237 -- Set an attribute on the frame (or its buttons if 'doButtons' = true)
flickerstreak@75 238 -- Either or both 'map' and 'default' can be passed:
flickerstreak@75 239 -- - If 'map' is omitted, then 'default' is set to the attribute.
flickerstreak@75 240 -- - If 'map' is provided, then it is interpreted as an unordered
flickerstreak@75 241 -- table of the form { ["statename"] = ["value"] }, and will be
flickerstreak@75 242 -- converted into a SecureStateHeaderTemplate style state-parsed
flickerstreak@75 243 -- string, e.g. "<state1>:<value1>;<state2>:<value2>". If 'default'
flickerstreak@75 244 -- is also provided, then its value will be converted to a string
flickerstreak@75 245 -- and appended.
flickerstreak@75 246 function Bar:SetStateAttribute( attribute, map, default, doButtons )
flickerstreak@75 247 local value = default
flickerstreak@75 248 if map then
flickerstreak@75 249 local tmp = { }
flickerstreak@75 250 for state, value in pairs(map) do
flickerstreak@75 251 table.insert(tmp, format("%s:%s",tostring(state),tostring(value)))
flickerstreak@68 252 end
flickerstreak@75 253 if default then
flickerstreak@75 254 table.insert(tmp, tostring(default))
flickerstreak@75 255 end
flickerstreak@75 256 value = table.concat(tmp,";")
flickerstreak@68 257 end
flickerstreak@75 258 if doButtons then
flickerstreak@75 259 for b in pairs(self.buttons) do
flickerstreak@75 260 local f = b.GetFrame and b:GetFrame()
flickerstreak@75 261 if f then
flickerstreak@75 262 f:SetAttribute(attribute, value)
flickerstreak@71 263 end
flickerstreak@71 264 end
flickerstreak@75 265 else
flickerstreak@75 266 self:GetFrame():SetAttribute(attribute, value)
flickerstreak@71 267 end
flickerstreak@75 268 SecureStateHeader_Refresh(self:GetFrame())
flickerstreak@71 269 end
flickerstreak@71 270
flickerstreak@33 271
flickerstreak@28 272 ------ Export as a class-factory ------
flickerstreak@28 273 ReAction.Bar = {
flickerstreak@73 274 prototype = Bar,
flickerstreak@75 275 New = function(self, ...)
flickerstreak@28 276 local x = { }
flickerstreak@28 277 for k,v in pairs(Bar) do
flickerstreak@28 278 x[k] = v
flickerstreak@28 279 end
flickerstreak@28 280 Constructor(x, ...)
flickerstreak@28 281 return x
flickerstreak@28 282 end
flickerstreak@28 283 }