/trunk
COGSBARBINDINGFRAME_TITLE = "CogsBar Bindings" |
local print = CogsUtils:GetPrint("CogsBar: ") |
local cb = CogsBar |
local overlays = {} |
function CogsBar:BindingOnEvent(event, ...) |
if event == "PLAYER_REGEN_DISABLED" then |
if CogsBarBindingFrame:IsShown() then |
print("Closing binding interface for combat") |
end |
end |
end |
local function BindingKey(id) |
return (GetBindingKey("CLICK CogsBarButton"..id..":LeftButton")) |
end |
function CogsBar:BindingOnShow(frame) |
frame:SetID(0) |
CogsBarBindingFrameText:SetText("Click a CogsBar button to set its binding or right-click to unbind") |
local numOverlays = #overlays |
for i = numOverlays + 1, self.buttonOffset - numOverlays do |
overlay = CreateFrame("Button", "CogsBindingOverlay"..i, frame, "CogsBindingOverlayTemplate") |
overlay:SetAllPoints(_G["CogsBarButton"..i]) |
tinsert(overlays, overlay) |
end |
end |
function CogsBar:BindingFrameCancelClick() |
local frame = CogsBarBindingFrame |
local id = frame:GetID() |
if id > 0 then |
CogsBarBindingFrameText:SetText("Canceled binding of CogsBar button "..id) |
frame:SetID(0) |
else |
frame:Hide() |
LoadBindings(GetCurrentBindingSet()) |
end |
end |
local ignoredKeys = { |
["UNKNOWN"] = true, |
["SHIFT"] = true, |
["CTRL"] = true, |
["ALT"] = true, |
} |
function CogsBar:BindingFrameOnClick(button) |
if button == "ESCAPE" then |
self:BindingFrameCancelClick() |
return |
end |
local screenshotKey = GetBindingKey("SCREENSHOT") |
if screenshotKey and button == screenshotKey then |
TakeScreenshot() |
return |
end |
if ignoredKeys[button] then |
return |
end |
if IsShiftKeyDown() then |
button = "SHIFT-"..button |
end |
if IsControlKeyDown() then |
button = "CTRL-"..button |
end |
if IsAltKeyDown() then |
button = "ALT-"..button |
end |
local id = CogsBarBindingFrame:GetID() |
local oldKey = BindingKey(id) |
if oldKey then |
SetBinding(oldKey) |
end |
SetBindingClick(button, "CogsBarButton"..id) |
CogsBarBindingFrameText:SetText(button.." bound to CogsBar button "..id) |
CogsBarBindingFrame:SetID(0) |
end |
function CogsBar:OverlayOnClick(id, mouseButton) |
if mouseButton == "LeftButton" then |
CogsBarBindingFrame:SetID(id) |
CogsBarBindingFrameText:SetText(format("Press a key to bind CogsBar button %d", id)) |
CogsBarBindingFrameCancel:Show() |
else -- RightButton |
local key = BindingKey(id) |
if key then |
SetBinding(BindingKey(id)) |
CogsBarBindingFrameText:SetText(format("CogsBar button %d unbound", id)) |
end |
end |
end |
function CogsBar:OverlayOnEnter(frame) |
GameTooltip:SetOwner(frame) |
local bindingText = GetBindingText(BindingKey(frame:GetID()), "KEY_") |
if bindingText ~= "" then |
GameTooltip:SetText("Click to change binding") |
GameTooltip:AddLine("Right-click to remove binding", 1, 1, 1) |
local color = GREEN_FONT_COLOR |
GameTooltip:AddDoubleLine("Currently Bound:", bindingText, 1, 1, 1, color.r, color.g, color.b) |
else |
GameTooltip:SetText("Click to bind") |
end |
GameTooltip:Show() |
end |
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ |
..\UI.xsd"> |
<!-- The basic template for each button --> |
<CheckButton name="CogsActionButtonTemplate" inherits="ActionBarButtonTemplate" virtual="true"> |
<Attributes> |
<!-- Button gets its statebutton property from its parent --> |
<Attribute name="useparent-statebutton" type="boolean" value="true"/> |
</Attributes> |
</CheckButton> |
<!-- Template for a button overlay to use for bindings --> |
<Button name="CogsBindingOverlayTemplate" virtual="true" frameStrata="DIALOG"> |
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true"> |
<!--BackgroundInsets top="5" left="5" right="5" bottom="5"/--> |
<Color r="0.5" g="0.5" b="0.5"/> |
<EdgeSize val="5"/> |
<TileSize val="25"/> |
</Backdrop> |
<Scripts> |
<OnLoad> |
self:SetID(tonumber(strmatch(self:GetName(), "(%d+)$"))) |
self:SetText(self:GetID()) |
self:RegisterForClicks("LeftButtonUp", "RightButtonUp") |
</OnLoad> |
<OnClick> |
CogsBar:OverlayOnClick(self:GetID(), button) |
</OnClick> |
<OnEnter> |
CogsBar:OverlayOnEnter(self) |
</OnEnter> |
<OnLeave> |
GameTooltip:Hide() |
</OnLeave> |
</Scripts> |
<NormalFont inherits="NumberFontNormal"/> |
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD" setAllPoints="true"/> |
</Button> |
<!-- |
The main template for CogsBars. This is nothing but a little movable square. |
The real magic goes on in CogsBar.lua. |
--> |
<Frame name="CogsBarTemplate" movable="true" virtual="true"> |
<Size x="1" y="1"/> |
<Anchors> |
<Anchor point="CENTER"/> |
</Anchors> |
<Frames> |
<Frame name="$parentControlBox" enableMouse="true"> |
<Size x="10" y="10"/> |
<Anchors> |
<Anchor point="BOTTOMRIGHT" relativePoint="TOPLEFT"/> |
</Anchors> |
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true"> |
<EdgeSize val="5"/> |
<TileSize val="5"/> |
<Color a="0.7" r="0.3" g="0.3" b="0.3"/> |
</Backdrop> |
<Scripts> |
<OnMouseDown> |
self:GetParent():StartMoving() |
</OnMouseDown> |
<OnMouseUp> |
self:GetParent():StopMovingOrSizing() |
</OnMouseUp> |
</Scripts> |
</Frame> |
</Frames> |
</Frame> |
<!-- Binding frame. Shown when you click to change the binding on a button. --> |
<Frame name="CogsBarBindingFrame" movable="true" hidden="true" enableKeyboard="true" enableMouse="true" toplevel="true" inherits="" parent="UIParent"> |
<Size x="275" y="100"/> |
<Anchors> |
<Anchor point="CENTER"/> |
</Anchors> |
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true"> |
<BackgroundInsets> |
<AbsInset left="11" right="12" top="12" bottom="11"/> |
</BackgroundInsets> |
<TileSize> |
<AbsValue val="32"/> |
</TileSize> |
<EdgeSize> |
<AbsValue val="32"/> |
</EdgeSize> |
</Backdrop> |
<Layers> |
<Layer level="ARTWORK"> |
<Texture name="$parentHeader" file="Interface\DialogFrame\UI-DialogBox-Header"> |
<Size x="256" y="64"/> |
<Anchors> |
<Anchor point="TOP"> |
<Offset x="0" y="12"/> |
</Anchor> |
</Anchors> |
</Texture> |
<FontString inherits="GameFontNormal" text="COGSBARBINDINGFRAME_TITLE"> |
<Anchors> |
<Anchor point="TOP" relativeTo="$parentHeader"> |
<Offset x="0" y="-14"/> |
</Anchor> |
</Anchors> |
</FontString> |
<FontString name="$parentText" inherits="GameFontNormal" maxLines="3" justifyV="MIDDLE" justifyH="CENTER"> |
<Size x="250" y="76"/> |
<Anchors> |
<Anchor point="TOP"> |
<Offset x="0" y="-6"/> |
</Anchor> |
</Anchors> |
</FontString> |
</Layer> |
</Layers> |
<Frames> |
<Frame enableMouse="true"> |
<Size x="128" y="32"/> |
<Anchors> |
<Anchor point="TOP"> |
<Offset x="0" y="10"/> |
</Anchor> |
</Anchors> |
<Scripts> |
<OnMouseDown> |
self:GetParent():StartMoving() |
</OnMouseDown> |
<OnMouseUp> |
self:GetParent():StopMovingOrSizing() |
</OnMouseUp> |
</Scripts> |
</Frame> |
<Button name="$parentSave" inherits="UIPanelButtonTemplate2" text="SAVE"> |
<Size x="72" y="24"/> |
<Anchors> |
<Anchor point="BOTTOMRIGHT"> |
<Offset x="-12" y="12"/> |
</Anchor> |
</Anchors> |
<Scripts> |
<OnClick> |
self:GetParent():Hide() |
SaveBindings(GetCurrentBindingSet()) |
</OnClick> |
</Scripts> |
</Button> |
<Button name="$parentCancel" inherits="UIPanelButtonTemplate2" text="CANCEL"> |
<Size x="72" y="24"/> |
<Anchors> |
<Anchor point="RIGHT" relativeTo="$parentSave" relativePoint="LEFT"> |
<Offset x="-3" y="0"/> |
</Anchor> |
</Anchors> |
<Scripts> |
<OnClick> |
CogsBar:BindingFrameCancelClick() |
</OnClick> |
</Scripts> |
</Button> |
</Frames> |
<Scripts> |
<OnLoad> |
self:RegisterEvent("PLAYER_REGEN_DISABLED") |
</OnLoad> |
<OnKeyDown> |
CogsBar:BindingFrameOnClick(key) |
</OnKeyDown> |
<OnShow> |
CogsBar:BindingOnShow(self) |
</OnShow> |
<OnEvent> |
CogsBar:BindingOnEvent(event, ...) |
</OnEvent> |
</Scripts> |
</Frame> |
</Ui> |
local cb = CogsBar |
local print = CogsUtils:GetPrint("CogsBar: ") |
-- buttonOffset is determines how CogsBarButtons are numbered |
-- actionOffset determines the starting action id for the next bar created |
-- curBarNum is the number of the next bar to be created. |
cb.buttonOffset = 0 |
cb.actionOffset = 0 |
cb.curBarNum = 1 |
--[[ |
CreateBasicBar instantiates a new CogsBarTemplate and anchors to it a number of |
CogsActionButtonTemplates specified by width & height. |
]] |
local function CreateBasicBar(width, height) |
local numButtons = width * height |
-- Create the bar and set some values on it for later use |
local bar = CreateFrame("Frame", "CogsBar"..cb.curBarNum, UIParent, "CogsBarTemplate") |
bar.firstButton = cb.buttonOffset + 1 |
bar.firstAction = cb.actionOffset + 1 |
bar.numButtons = numButtons |
bar.dimensions = width.."x"..height |
for i = 1, numButtons do |
local relativeTo, relativePoint |
local xOfs, yOfs = 0, 0 |
if i == 1 then |
-- The first button in a bar is anchored to the lower right corner |
-- of the bar itself |
relativeTo = bar |
relativePoint = "TOPLEFT" |
elseif mod(i - 1, width) == 0 then |
-- The first button in a row is anchored to the button above it |
relativeTo = getglobal("CogsBarButton"..(i - width + cb.buttonOffset)) |
relativePoint = "BOTTOMLEFT" |
yOfs = -4 |
else |
-- All other buttons are anchored to the right of the previous one |
relativeTo = getglobal("CogsBarButton"..(i - 1 + cb.buttonOffset)) |
relativePoint = "TOPRIGHT" |
xOfs = 4 |
end |
-- Create the button, position it, and set its action |
local button = CreateFrame("CheckButton", "CogsBarButton"..(i + cb.buttonOffset), bar, "CogsActionButtonTemplate") |
button:SetPoint("TOPLEFT", relativeTo, relativePoint, xOfs, yOfs) |
button:SetAttribute("*action*", i + cb.actionOffset) |
end |
-- Update the control variables |
cb.buttonOffset = cb.buttonOffset + numButtons |
cb.actionOffset = cb.actionOffset + numButtons |
cb.curBarNum = cb.curBarNum + 1 |
return bar |
end |
--[[ |
CogsBar_CreateBar creates a bar and applies states to it. This function is |
exposed globally for anyone who wants to run it manually. Normally it would be |
triggerd by a slash command like: |
/cogsbar create 6x4 stance:1-3 |
]] |
function CogsBar:CreateBar(width, height, states) |
local totalActions = width * height |
if states then |
for _, v in ipairs(states) do |
totalActions = totalActions * (v.last - v.first + 1) |
end |
end |
if totalActions > (120 - cb.actionOffset) then |
error("Not enough action slots available") |
end |
local bar = CreateBasicBar(width, height) |
if states then |
self:ApplyStates(bar, states) |
end |
return bar |
end |
--[[ |
SavedVariables table |
]] |
CogsBarSV = { |
savedBars = {}, |
} |
--[[ |
Not quite sure why I made this a separate function... |
]] |
local function SaveCommand(command, parameters) |
tinsert(CogsBarSV.savedBars, {command = command, parameters = parameters}) |
end |
--[[ |
Table of functions to handle each slash command |
]] |
local commandHandlers = { |
--[[ |
The "create" command makes a CogsBar. See CogsBarCreate.lua |
]] |
create = function(parameters) return cb:CreateCommand(parameters) end, |
--[[ |
The list command prints a list of CogsBars and their configurations |
]] |
list = function() |
local message = "List of bars:" |
for i, v in ipairs(CogsBarSV.savedBars) do |
message = message.."\n "..i..": "..v.parameters |
end |
print(message) |
end, |
--[[ |
The remove command removes a CogsBar. Currently, you must reload your UI because |
all this does is remove the bar's entry from the saved variables table. |
]] |
remove = function(barNum) |
barNum = tonumber(strtrim(barNum)) |
if not barNum then |
print("Usage: /cogsbar remove <bar number>") |
return |
end |
if barNum < 1 or barNum > #CogsBarSV.savedBars then |
print("The bar you tried to remove doesn't exist. Please see /cogsbar list.") |
return |
end |
tremove(CogsBarSV.savedBars, barNum) |
print("Bar "..barNum.." removed. Please reload your UI for changes to take effect.") |
end, |
--[[ |
The clear command functions like using the remove command on all existing bars |
]] |
clear = function() |
for k in pairs(CogsBarSV.savedBars) do |
CogsBarSV.savedBars[k] = nil |
end |
print("All bars removed. Please reload your UI for changes to take effect.") |
end, |
--[[ |
status prints some overall information about the state of CogsBar |
]] |
status = function() |
print("Status:\n Number of bars: "..(cb.curBarNum - 1).. |
"\n Number of buttons: "..cb.buttonOffset.. |
"\n Available actions: "..(120 - cb.actionOffset)) |
end, |
--[[ |
bind is a very crude command to bind keys to CogsBar buttons. It is very |
inflexible at the moment. All it can do is map the left 24 keys of your keyboard |
to the first 24 CogsBar buttons. This is definitely a major TODO. |
]] |
bind = function() |
CogsBarBindingFrame:Show() |
end, |
--[[ |
lock toggles the movability of CogsBars |
]] |
lock = function() |
if CogsBarSV.lockBars then |
CogsBarSV.lockBars = nil |
else |
CogsBarSV.lockBars = true |
end |
cb:LockBars(CogsBarSV.lockBars) |
print("Bars "..(CogsBarSV.lockBars and "locked" or "unlocked")) |
end, |
} |
--[[ |
This sets up a frame that creates bars and sets the bindings depending on saved |
variables |
]] |
local cbLoader = CreateFrame("Frame") |
cbLoader:SetScript("OnEvent", function(self, event, ...) |
if event == "VARIABLES_LOADED" then |
for _, v in ipairs(CogsBarSV.savedBars) do |
commandHandlers[v.command](v.parameters) |
end |
cb:LockBars(CogsBarSV.lockBars) |
end |
end) |
cbLoader:RegisterEvent("VARIABLES_LOADED") |
--[[ |
The slash commands... The function is a stub that calls the individual command |
handlers. |
]] |
SLASH_COGSBAR1 = "/cogsbar" |
SLASH_COGSBAR2 = "/cb" |
SlashCmdList["COGSBAR"] = function(msg) |
local command, parameters = strsplit(" ", strlower(msg), 2) |
command = command and strtrim(command) |
if not commandHandlers[command] then |
print("Usage: /cogsbar <create | clear | list | remove | status | bind | lock> [<options>]") |
return |
end |
local shouldSave = commandHandlers[command](parameters) |
if shouldSave then |
SaveCommand(command, parameters) |
end |
end |
function cb:LockBars(set) |
local method = set and "Hide" or "Show" |
for i = 1, #CogsBarSV.savedBars do |
local box = getglobal("CogsBar"..i.."ControlBox") |
box[method](box) |
end |
end |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
<html xmlns="http://www.w3.org/1999/xhtml"> |
<head> |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
<title>CogsBar Readme</title> |
<style type="text/css"> |
h2,h3 { border-bottom: 1px solid; } |
a:visited:after { content: "Â â"; } |
p.notice { |
font-size: smaller; |
color: #999; |
margin-left: 0; |
} |
ol.footnotes { |
font-size: small; |
} |
.item { |
font-size: small; |
font-family: Arial, Helvetica, sans-serif; |
border: solid 1px; |
border-top-color: #FFF; |
border-left-color: #888; |
border-right-color: #888; |
border-bottom-color: #555; |
-moz-border-radius: 4px; |
background-color: #000; |
color: #FFF; |
padding: 2px; |
} |
.poor { color: gray; } |
.common { color: white; } |
.uncommon { color: #1EFF00; } |
.rare { color: #0080FF; } |
.epic { color: #B048F8; } |
.legendary { color: #F07902; } |
.artifact { color: #FFCF00; } |
@media screen { |
body { |
font-family: "Trebuchet MS", Helvetica, Verdana, Arial, sans-serif; |
color: #FFF; |
background: #333; |
width: 80%; |
min-width: 600px; |
padding-left: 60px; |
} |
h1,h2,h3,h4,h5,h6 { |
font-family: Georgia, "Times New Roman", Times, serif; |
color: #ED0; |
} |
h1,h2,h3,h5,h6 { |
font-family: Georgia, "Times New Roman", Times, serif; |
} |
h1,h2,h3 { border-bottom-color: #ED0; margin-left: -30px; } |
a:link { |
color: #FC0; |
text-decoration: none; |
} |
a:visited { |
color: #999; |
text-decoration: none; |
} |
a:hover { |
color: #0F0; |
} |
a:active { |
color: #0F0; |
} |
.gold { color: #ED0; } |
.silver { color: #BBB; } |
.copper { color: #D63; } |
} |
@media print { |
body { |
font-family: "Times New Roman", Times, serif; |
} |
h1,h2,h3,h4,h5,h6 { |
font-family: Arial, Helvetica, sans-serif; |
} |
} |
</style> |
</head> |
<body> |
<h1>CogsBar</h1> |
<p>By Cogwheel â v1.10.1</p> |
<p>CogsBar allows you to create a number of movable action bars of various configurations. Each bar can remap its actions based on certain types of states. </p> |
<p>Please visit <a href="http://cogwheel.wowinterface.com">Cogwheelâs Workshop</a> for updates, bug reports, feature requests, etc. </p> |
<ul> |
<li><a href="#guide">Guide</a> |
<ul> |
<li><a href="#creating">Creating bars</a></li> |
<li><a href="#info">Getting information </a></li> |
<li><a href="#removing">Removing bars</a></li> |
<li><a href="#mapping">State mapping</a> </li> |
<ul> |
<li><a href="#sanity">Sanity checks </a></li> |
<li><a href="#firstlast"><kbd>first</kbd> and <kbd>last</kbd> </a></li> |
<li><a href="#warnings">Warnings</a></li> |
</ul> |
</ul> |
</li> |
<ul> |
<li><a href="#binding">Key binding</a></li> |
</ul> |
<li><a href="#reference">Reference</a></li> |
<ul> |
<li><a href="#create">create</a> |
<ul> |
<li><a href="#states">States |
</a> |
<ul> |
<li><a href="#stance">stance</a></li> |
<li><a href="#stealth">stealth</a></li> |
<li><a href="#actionbar">actionbar</a></li> |
<li><a href="#modifiers">shift/ctrl/alt</a></li> |
<li><a href="#defaultui">defaultui</a></li> |
</ul> |
</li> |
</ul> |
</li> |
<li><a href="#list">list</a></li> |
<li><a href="#status">status</a></li> |
<li><a href="#remove">remove</a></li> |
<li><a href="#clear">clear</a></li> |
<li><a href="#bind">bind</a></li> |
<li><a href="#lock">lock</a></li> |
</ul> |
<li><a href="#bugs">Bugs/Improvements</a></li> |
<li><a href="#changes">Changes</a></li> |
</ul> |
<h2><a name="guide" id="guide"></a>Guide</h2> |
<p>This started out as a simple example of the use of state headers (see <a href="http://www.wowinterface.com/downloads/download.php?id=5977&aid=7227">v1.0</a>) and as a replacement for my personal FlexBar setup. After the initial version I added a few tweaks here and there to let me create different setups for my different characters. You can now create an arbitrary number of bars (even single buttons) that can respond to various state changes.</p> |
<p>Note that CogsBarâs job is only to create action buttons. It does not modify the default UI in any way. If you would like to hide, break up, or move the main menu bar, I highly recommend <a href="http://www.ctmod.net">CT BottomBar</a>. It is very customizable and intuitive to use. Other alternatives are <a href="http://wow.curse-gaming.com/en/files/details/4864/moveanything-bc/">MoveAnything</a>, <a href="http://www.wowinterface.com/downloads/info4744-Bongos.html">Bongos</a>, and various others I have not used myself. </p> |
<h3><a name="creating" id="creating"></a>Creating bars </h3> |
<p>The bars are created using the <kbd>/cogsbar</kbd> (<kbd>/cb</kbd>) slash command. Running this command with no arguments shows you a list of subcommands (create, clear, list, remove, status, bind). The simplest form for creating a bar is:</p> |
<pre>/cogsbar create 6x4</pre> |
<p>This creates a bar that is 6 buttons wide by 4 buttons high and uses action ids 1-24. Note: if you do not see any buttons, it means you donât have any abilities configured in the first 24 action slots. If you drag a spell out of your spellbook, the buttons will appear. You will also see the control box near the lower-middle of the screen which you can use to move the bar.</p> |
<p>Notice: the current implementation uses Blizzardâs layout-cache.txt to save its position. This means that if you log into the game with CogsBar disabled, you will have to reposition your frames the next time you log in. I will try to address this in a future version. </p> |
<p>CogsBar âconsumesâ action ids, so the next bar created would start with action id 25. In other words, if you now ran the command:</p> |
<pre>/cogsbar create 9x4</pre> |
<p>you would have another 9 by 4 bar using actions 25-60. </p> |
<h3><a name="info" id="info"></a>Getting information </h3> |
<p>To see your bar configuration, use the list command:</p> |
<pre>/cogsbar list |
CogsBar: List of bars: |
1: 6x4 |
2: 9x4</pre> |
<p>You can also see some generic information with the status command:</p> |
<pre>/cogsbar status |
CogsBar Status: |
Number of bars: 2 |
Number of buttons: 60 |
Available actions: 60</pre> |
<h3><a name="removing" id="removing"></a>Removing bars </h3> |
<p>If you would like to remove one of your bars, use the remove command, passing it the number shown in the output from list:</p> |
<pre>/cogsbar remove 1 |
CogsBar: Bar 1 removed. Please reload your UI for changes to take effect.</pre> |
<p>Due to some limitations in the current implementation, you must reload your UI after removing a bar (you can type <kbd>/console reloadui</kbd> or log out and back in). Note also that bar 2 will now use actions 1-36 instead of 25-60. Hereâs the output of <kbd>status</kbd> at this point:</p> |
<pre>CogsBar Status: |
Number of bars: 1 |
Number of buttons: 36 |
Available actions: 84</pre> |
<p>You can also use <kbd>clear</kbd> to remove all the bars bars as if you had manually run the <kbd>remove</kbd> command (UI reload is required).</p> |
<h3><a name="mapping" id="mapping"></a>State mapping </h3> |
<p>As mentioned, CogsBar bars can be driven by state changes. Any sort of state the SecureStateDriverTemplate supports can be used with CogsBar. The general syntax is:</p> |
<pre>/cogsbar <width>x<height> [state] [state] [...]</pre> |
<p>where each optional state has the syntax:</p> |
<pre><state-type>[:[<first>-]<last>]</pre> |
<p><kbd>state-type</kbd> can be one of <kbd>stance</kbd>, <kbd>stealth</kbd>, <kbd>actionbar</kbd>, <kbd>shift</kbd>, <kbd>ctrl</kbd>, or <kbd>alt</kbd> at the time of this writing (CogsBar is structured in such a way that future additions to SecureStateDriverTemplate will be automatically supported). Hereâs a simple example:</p> |
<pre>/cogsbar create 6x4 stance</pre> |
<p>If you run this command as a warrior, it will create a 6x4 button bar that maps to actions 1-24 in Battle Stance, 25-48 in Berserker Stance, and 49-72 in Defensive Stance.</p> |
<h4><a name="sanity" id="sanity"></a>Sanity checks</h4> |
<p>Because certain state types are only relevant under certain circumstances, CogsBar performs a few sanity checks. The stealth type can only be used with Rogues, Druids, Mages, and Night Elves. Stance can only be used with Warriors, Druids, Rogues, Shaman, and Priests. </p> |
<h4><kbd><a name="firstlast" id="firstlast"></a>first</kbd> and <kbd>last</kbd> </h4> |
<p>The <kbd>first</kbd> and <kbd>last</kbd> parameters tell CogsBar which states of the given type to âpay attention to.â Each known state type has certain default values for them (see <a href="#states">Reference</a>). These defaults allow you to omit the <kbd>first</kbd> and <kbd>last</kbd> parameters under most circumstances. For instance, the example above is equivalent to:</p> |
<pre>/cogsbar create 6x4 stance:1-3</pre> |
<p>You can also omit just the <kbd>first</kbd> parameter and the command will use the default value. E.g.:</p> |
<pre>/cogsbar create 6x4 stance:3</pre> |
<p>This is useful for conserving action slots when you know you donât care about certain states. Normally for a Druid the default values are 0-6. This gives you mappings for every possible shapeshift form. However, if you have neither Tree of Life nor Moonkin form and you donât have the Burning Crusade (hence flight form), you can use the command:</p> |
<p><kbd>/cogsbar create 12x1 stance:4</kbd></p> |
<p>which will provide you with mappings for caster, aquatic, bear, travel, & cat forms.</p> |
<p>The other key benefit to manual input of <kbd>first</kbd> and <kbd>last</kbd> is if Blizzard adds more state types to SecureStateDriverTemplate.</p> |
<h4>Warnings</h4> |
<p>With flexibility comes responsibility. As such, there are a few caveats to watch out for. First, because you are allowed to specify a state that CogsBar doesn't know about inherently, you must take care not to misspell your state types. For instance, if you issued the command:</p> |
<pre>/cogsbar create 12x2 satnce</pre> |
<p>CogsBar would still create the bar and use up 48 actions (the default <kbd>first</kbd> and <kbd>last</kbd> values for unknown state types are 0-1). It does display a warning about unknown state type in case you did make such a mistake. If you see this warning, you should <a href="#removing">remove</a> the newly created bar and try again. </p> |
<p>Also, behavior is undefined if you specify a range smaller than what might actually occur. For example, if you have a bar created like:</p> |
<pre>/cogsbar create 12x1 actionbar:1-2</pre> |
<p>and you switch to action bar page 3, Iâm not exactly sure what will happen... :o)</p> |
<p>A similar issue is the expansion of the state type. For instance, if you have a bar created with:</p> |
<pre>/cogsbar create 6x2 actionbar</pre> |
<p>while you have two available action bar pages (because the default UIâs âextraâ action bars use up pages from the main action bar), it will create two mappings. Now you get all your actions set up just how you want them and for some reason decide to disable all the built-in extra action bars. When you log into the game again, CogsBar will create the bar to take advantage of all <em>six</em> action bar pages, effectively âeating upâ the actions from any bars created after it. </p> |
<h3><a name="binding" id="binding"></a>Key binding </h3> |
<p>Finally, we have the bind command which displays the bindings UI. When you open the bindings interface, you can click any CogsBar button to set its bindings. Simply click a button and press a key to set the binding. If you click a button and decide not to bind something to it, click <kbd>Cancel</kbd>. If you click <kbd>Cancel</kbd> again, it will reload your previous bindings and close the bindings UI. Otherwise, click <kbd>Save</kbd> to save your changes and close the bindings interface. Note: only one key can be bound to a CogsBar button at a time.</p> |
<h2><a name="reference" id="reference"></a>Reference</h2> |
<p>All commands begin with /cogsbar which can be abreviated as /cb.</p> |
<h3><a name="create" id="create"></a>create</h3> |
<p>Syntax: <kbd>/cogsbar create <width>x<height> [<state>] [<state>] [...] </kbd></p> |
<p>Example: <kbd>/cogsbar create 6x4 stance </kbd></p> |
<p>Creates a CogsBar </p> |
<p>There must be enough available actions (as shown via the list command) in order to create the bar.</p> |
<h4><a name="states" id="states"></a>States</h4> |
<p>Syntax: <kbd><state type>[:[<first>-]<last>]</kbd></p> |
<p>Examples: <kbd>stance:1-3 stealth actionbar:2 </kbd></p> |
<p>States allow remapping based on certain conditions. The use of states multiplies the number of actions used by the bar by the state range. I.e. a 12-button bar will use 36 action slots if <kbd>stance:1-3</kbd> is used. </p> |
<p><kbd>first</kbd> and <kbd>last</kbd> define the range of states of that type to pay attention to. Each state type defines its own range depending on its characteristics. The default values are listed under each state type below. </p> |
<p>Possible state types at the time of this writing:</p> |
<h5><a name="stance" id="stance"></a>stance</h5> |
<p>Changes mapping based on the characterâs stance. Only applicable to classes with stances (Warriors, Druids, Rogues, Priests, and Shaman).</p> |
<p>Default ranges:</p> |
<ul> |
<li>Warriors: 1-3</li> |
<li>Druids: 0-7</li> |
<li>Rogues & Priests: 0-1 </li> |
</ul> |
<h5><a name="stealth" id="stealth"></a>stealth</h5> |
<p>Changes mapping based on stealth. Only applicable to characters with stealth (Rogues, prowling Druids, shadowmelding Night Elves, invisible Mages).</p> |
<p>Default range: 0-1 </p> |
<h5><a name="actionbar" id="actionbar"></a>actionbar</h5> |
<p>Changes mapping based on the current action bar page. </p> |
<p>Default range: 1-n</p> |
<p>where n is the number of action bar pages are available. Each âExtra action barâ you enable in the default UI reduces the number of action bar pages available.</p> |
<h5><a name="modifiers" id="modifiers"></a>shift/ctrl/alt</h5> |
<p>Changes mapping based on whether the given key is depressed. </p> |
<p>Default range: 0-1 </p> |
<h5><a name="defaultui" id="defaultui"></a>defaultui</h5> |
<p>Creates a mapping similar to the default UI that combines action bar pages with stances.</p> |
<p>Default ranges:</p> |
<ul> |
<li>Rogues & Priests: 0-6</li> |
<li>Warriors: 0-7</li> |
<li>Druids: 0-8</li> |
<li>Others: 0-5</li> |
</ul> |
<p>Notes: The last 5 mappings in the range are used for action bar pages 2-6. If you want fewer than 6 total pages, subtract however many you want to remove from the end of the range. For instance, if you have a warrior and want one page for your stances and only one extra page, the command would look like:</p> |
<p><kbd>/cogsbar create 12x1 defaultui:0-3</kbd></p> |
<p>or more simply:</p> |
<p><kbd>/cogsbar create 12x1 defaultui:3 </kbd></p> |
<p>Mapping 0 would correspond to page 1, battle stance; mapping 1 would be page 1, defensive stance; mapping 2 would be page 1, berserker stance; and mapping 3 would be page 2, any stance.</p> |
<h3><a name="list" id="list"></a>list</h3> |
<p>Syntax: <kbd>/cogsbar list</kbd></p> |
<p>Prints a list of existing CogsBars and their configurations. Example output:</p> |
<pre>CogsBar: List of Bars: |
1: 6x4 stance |
2: 9x4</pre> |
<h3><a name="status" id="status"></a>status</h3> |
<p>Syntax: <kbd>/cogsbar status</kbd></p> |
<p>Prints general information about the state of CogsBar. Example output:</p> |
<pre>CogsBar Status: |
Number of bars: 2 |
Number of buttons: 60 |
Available actions: 24</pre> |
<h3><a name="remove" id="remove"></a>remove</h3> |
<p>Syntax: <kbd>/cogsbar remove <index></kbd></p> |
<p>Removes the bar specified by <index>. The <index> can be determined by the list command. </p> |
<p>Note: you must perform a UI reload in order for this change to take effect.</p> |
<h3><a name="clear" id="clear"></a>clear</h3> |
<p>Syntax: <kbd>/cogsbar clear</kbd></p> |
<p>Removes all existing bars.</p> |
<p>Note: you must perform a UI reload in order for this change to take effect. </p> |
<h3><a name="bind" id="bind"></a>bind</h3> |
<p>Syntax: <kbd>/cogsbar bind</kbd></p> |
<p>Displays the binding interface.</p> |
<h3><a name="lock" id="lock"></a>lock</h3> |
<p>Syntax: /cogsbar lock</p> |
<p>Locks your bars in place. The control boxes will be hidden. </p> |
<h2><a name="bugs" id="bugs"></a>Bugs/Improvements</h2> |
<p>There is a bug in Blizzardâs templates that may cause a binding to show on a button even after it has been removed. Hopefully this will be fixed in patch 2.1. If not, I will try to find a workaround. </p> |
<p>As always, please visit <a href="http://cogwheel.wowinterface.com">Cogwheelâs Workshop</a> for bug reports, feature requests, etc.</p> |
<h2><a name="changes" id="changes"></a>Changes</h2> |
<h4>v1.10.1</h4> |
<ul> |
<li>No longer reports locked status on login.</li> |
<li>Updated for 2.3.2.</li> |
</ul> |
<h4>v1.10</h4> |
<ul> |
<li>Added defaultui state mapping.</li> |
<li>Reloading the UI will now load the correct action bar page instead of defaulting to page 1.</li> |
</ul> |
<h4>v1.9.2</h4> |
<ul> |
<li>Fixed button updating for 2.2. </li> |
</ul> |
<h4>v1.9.1</h4> |
<ul> |
<li>Fixed a bug that was preventing use of specified ranges (e.g. stance:1-5).</li> |
</ul> |
<h4>v1.9</h4> |
<ul> |
<li>ZOMG REAL BINDINGS!!!1 </li> |
</ul> |
<h4>v1.8.3</h4> |
<ul> |
<li>No longer attempts to apply bindings when zoning.</li> |
<li>No longer wipes out existing bindings when logging in and zoning if you are not using CogsBarâs bindings.</li> |
</ul> |
<h4>v1.8.2</h4> |
<ul> |
<li>Bars will now remain locked across reloads.</li> |
</ul> |
<h4>v1.8.1</h4> |
<ul> |
<li>Fixed a bug where /cogsbar lock would hide bars driven by states.</li> |
</ul> |
<h4>v1.8</h4> |
<ul> |
<li>Added /cogsbar lock. </li> |
</ul> |
<h4>v1.7</h4> |
<ul> |
<li>Updated for 2.0.3.</li> |
<li>Fixed international treatment of sanity checks for race/class.</li> |
</ul> |
<h4>v1.6.1</h4> |
<ul> |
<li>Made QWERTY the default binding layout (I really need to start remembering this when I update :P).</li> |
</ul> |
<h4>v1.6</h4> |
<ul> |
<li>Added support for multiple states on the same bar.</li> |
<li>States can now be supplied without ranges which will apply default values. </li> |
<li>Added sanity checks for state types (e.g. Warriors cannot use the stealth state). </li> |
</ul> |
<h4>v1.5</h4> |
<ul> |
<li>First generally usable release. Added all the slash commands and configuration options. </li> |
</ul> |
<h4>v1.1</h4> |
<ul> |
<li>Finished one of the comments I had forgotten about.</li> |
<li>Made QWERTY the default binding layout.</li> |
</ul> |
<h4>v1.0</h4> |
<ul> |
<li>Initial release. This version only created one 6x4 bar that responded to stance changes and was meant as a simple (and well-commented) example of the use of state headers. </li> |
</ul> |
</body> |
</html> |
## Interface: 20300 |
## Title: CogsBar |
## Notes: A simple, but flexible action bar mod |
## SavedVariablesPerCharacter: CogsBarSV |
CogsUtils\CogsUtils.lua |
CogsBarStates.lua |
CogsBarCreate.lua |
CogsBarBindings.lua |
CogsBar.lua |
CogsBar.xml |
local cb = CogsBar |
local print = CogsUtils:GetPrint("CogsBar: ") |
--[[ |
These functions provide the default ranges for the various known state types. |
They also perform various sanity checks to make sure you don't do things like: |
/cogsbar create 12x1 stance |
when you're playing a warlock. |
]] |
local defaultRanges = { |
["stance"] = function() |
local class = select(2, UnitClass("player")) |
if class == "WARRIOR" then |
return 1, 3 |
elseif class == "DRUID" then |
return 0, 6 |
elseif class == "ROGUE" or |
class == "SHAMAN" or |
class == "PRIEST" then |
return 0, 1 |
end |
end, |
["stealth"] = function() |
local class, race = select(2, UnitClass("player")), select(2, UnitRace("player")) |
local valid = false |
if class == "ROGUE" or |
class == "DRUID" or |
race == "NightElf" or |
class == "MAGE" then |
return 0, 1 |
end |
end, |
["actionbar"] = function() |
local viewable = 0 |
for i = 1, NUM_ACTIONBAR_PAGES do |
if VIEWABLE_ACTION_BAR_PAGES[i] then |
viewable = viewable + 1 |
end |
end |
return 1, viewable |
end, |
["modifier"] = function() |
return 0, 1 |
end, |
["defaultui"] = function() |
local class = select(2, UnitClass("player")) |
if class == "ROGUE" or class == "PRIEST" then |
return 0, 6 |
elseif class == "WARRIOR" then |
return 0, 7 |
elseif class == "DRUID" then |
return 0, 8 |
else |
return 0, 5 |
end |
end |
} |
defaultRanges["shift"] = defaultRanges["modifier"] |
defaultRanges["ctrl"] = defaultRanges["modifier"] |
defaultRanges["alt"] = defaultRanges["modifier"] |
--[[ |
MakeStatesTables generates the state type table necessary for |
CogsBar:ApplyStates (see CogsBarStates.lua) |
]] |
local function MakeStatesTable(...) |
local stateTable = {} |
for i = 1, select("#", ...) do |
-- <name>:<range> |
local name, range = strsplit(":", strtrim((select(i, ...)))) |
local defaultFirst, defaultLast |
-- Make sure the state type (name) passes sanity check |
if defaultRanges[name] then |
defaultFirst, defaultLast = defaultRanges[name]() |
if not defaultFirst then |
print("State type "..name.." failed sanity check") |
return nil |
end |
else |
print("Warning - Unknown state type: "..name) |
defaultFirst, defaultLast = 0, 1 |
end |
local first, last = defaultFirst, defaultLast |
if range then |
-- <last> or <first>-<last> |
first, last = strsplit("-", range) |
if not last then |
last = first |
first = defaultFirst |
end |
first = tonumber(first) |
last = tonumber(last) |
if not first or not last then |
print("Invalid range provided for state type: "..name) |
return nil |
end |
end |
tinsert(stateTable, {name = name, first = first, last = last}) |
end |
return stateTable |
end |
--[[ |
... yeah... I'm really going to document this function... |
]] |
local function PrintUsage() |
print("Usage:\n /cogsbar create <width>x<height> [state] [state] [...]".. |
"\n state: <state type>[:[<first>-]<last>]") |
end |
--[[ |
handler for the /cogsbar create command |
]] |
function cb:CreateCommand(parameters) |
if not parameters then |
PrintUsage() |
return false |
end |
-- <dimensions> <states> |
local dimensions, states = strsplit(" ", parameters, 2) |
-- <width>x<height> |
local width, height = strmatch(dimensions, "(%d+)x(%d+)") |
if not width then |
print("No dimensions specified") |
PrintUsage() |
return false |
end |
-- Create the table of states if specified |
local statesTable |
if states then |
local valid |
statesTable = MakeStatesTable(strsplit(" ", states)) |
if not statesTable then |
PrintUsage() |
return false |
end |
end |
self:CreateBar(width, height, statesTable) |
return true |
end |
--[[ |
This is a hack to add a new state type to the state driver template so CogsBar |
can emulate the default UI |
]] |
local oldOnLoad = SecureStateDriver_OnLoad |
local function SecureStateDriver_OnLoad(self, ...) |
local class = select(2, UnitClass("player")) |
local pageOffset = -1 |
local stances = "" |
if class == "WARRIOR" then |
stances = "[actionbar:1, stance:2] 1; [actionbar:1, stance:3] 2; " |
pageOffset = 1 |
elseif class == "ROGUE" or class == "PRIEST" then |
stances = "[actionbar:1, stance:1] 1; " |
pageOffset = 0 |
elseif class == "DRUID" then |
stances = "[actionbar:1, stance:1] 1; [actionbar:1,stance:3] 2; [actionbar:1, stance:5, nomounted, noflying] 3; " |
pageOffset = 2 |
end |
local pages = "" |
for page = 2, NUM_ACTIONBAR_PAGES do |
pages = pages.."[actionbar:"..page.."] "..(page + pageOffset).."; " |
end |
pages = pages.."0" |
RegisterStateDriver(self, "defaultui", stances..pages) |
oldOnLoad(self, ...) |
end |
--[[ |
This is a simple helper function for MakeStateTable which inserts strings into |
tbl. For example: |
tbl = {} |
StateTableInsert(tbl, {name = "stance", first = 1, last = 3}, "-ctrl1") |
tbl now looks like |
{ |
"stance1-ctrl1", |
"stance2-ctrl1", |
"stance3-ctrl1" |
} |
]] |
local function StateTableInsert(tbl, state, suffix) |
for i = state.first, state.last do |
local str = state.name..i |
if suffix then |
str = str..suffix |
end |
tinsert(tbl, str) |
end |
end |
--[[ |
MakeStateTable creates a flat list of all possible states given the state types |
provided. For example: |
MakeStateTable({ |
{ |
name = "stance", |
first = 1, |
last = 3 |
}, |
{ |
name = "ctrl", |
first = 0, |
last = 1 |
}, |
{ |
name = "shift", |
first = 0, |
last = 1 |
} |
}) |
results in a table like: |
{ |
"stance1-ctrl0-shift0", |
"stance2-ctrl0-shift0", |
"stance3-ctrl0-shift0", |
"stance1-ctrl1-shift0", |
"stance2-ctrl1-shift0", |
"stance3-ctrl1-shift0", |
"stance1-ctrl0-shift1", |
"stance2-ctrl0-shift1", |
"stance3-ctrl0-shift1", |
"stance1-ctrl1-shift1", |
"stance2-ctrl1-shift1", |
"stance3-ctrl1-shift1" |
} |
]] |
local function MakeStateTable(states, index) |
index = index or 1 |
local tbl = {} |
local state = states[index] |
if index < #states then |
-- Recurse into MakeStateTable for the remaining states |
for _, v in ipairs(MakeStateTable(states, index + 1, tbl)) do |
StateTableInsert(tbl, state, "-"..v) |
end |
else |
StateTableInsert(tbl, state) |
end |
return tbl |
end |
--[[ |
CreateStateMaps applies a series of "statemap-<state>-<n>" attributes to header |
given a set of states. For example: |
CreateStateMap( |
{ |
{ |
name = "shift", |
first = 0, |
last = 1 |
}, |
{ |
name = "ctrl", |
first = 0, |
last = 1 |
} |
}, |
{ |
"shift0-ctrl0", |
"shift1-ctrl0", |
"shift0-ctrl1", |
"shift1-ctrl1" |
}, |
header |
) |
does the equivalent of: |
header:SetAttribute("statemap-shift-0", "shift1-ctrl0:shift0-ctrl0;shift1-ctrl1:shift0-ctrl1") |
header:SetAttribute("statemap-shift-1", "shift0-ctrl0:shift1-ctrl0;shift0-ctrl1:shift1-ctrl1") |
header:SetAttribute("statemap-ctrl-0", "shift0-ctrl1:shift0-ctrl0;shift1-ctrl1:shift1-ctrl0") |
header:SetAttribute("statemap-ctrl-1", "shift0-ctrl0:shift0-ctrl1;shift1-ctrl0:shift1-ctrl1") |
]] |
local function CreateStateMaps(states, stateTable, header) |
-- Iterate through different state types |
for _, state in ipairs(states) do |
-- Iterate through state values (stance-1, stance-2, stance-3, etc.) |
for i = state.first, state.last do |
local statemap = "" |
-- Create the statemap for the current state type-state value pair |
for j, v in ipairs(stateTable) do |
local newState = gsub(v, "("..state.name..")(%d+)", state.name..i)..";" |
if i ~= tonumber(strmatch(v, state.name.."(%d+)")) then |
statemap = statemap..v..":"..newState |
end |
if j == #stateTable then |
statemap = statemap.."*:"..newState |
end |
end |
-- Apply the statemap to the header |
header:SetAttribute("statemap-"..state.name.."-"..i, statemap) |
end |
end |
end |
--[[ |
CreateStateButton applies a statebutton attribute to header given a set of |
states. Example: |
CreateStateButton( |
{ |
"stance1-ctrl0", |
"stance2-ctrl0", |
"stance3-ctrl0", |
"stance1-ctrl1", |
"stance2-ctrl1", |
"stance3-ctrl1" |
}, |
header |
) |
is equivalent to: |
header:SetAttribute("statebutton", "stance1-ctrl0:S1;stance2-ctrl0:S2;stance3-ctrl0:S3;stance1-ctrl1:S4;stance2-ctrl1:S5;stance3-ctrl1:S6;" |
]] |
local function CreateStateButton(stateTable, header) |
local statebutton = "" |
for i, v in ipairs(stateTable) do |
statebutton = statebutton..v..":S"..i..";" |
end |
header:SetAttribute("statebutton", statebutton) |
end |
--[[ |
ApplyStateButtons sets the various action attributes on bar's buttons and |
registers them with the state header. |
]] |
local function ApplyStateButtons(stateTable, bar, header) |
-- For each button in the bar... |
for buttonNum = bar.firstButton, bar.firstButton + bar.numButtons - 1 do |
local button = getglobal("CogsBarButton"..buttonNum) |
-- Register with state header |
header:SetAttribute("addchild", button) |
-- For each statebutton (S1, S2, S3, etc) set the action-S# attribute on |
-- the button. For example, for the first button on a 12-button bar with |
-- 3 states: |
-- button:SetAttribute("*action-S1", 1) |
-- button:SetAttribute("*action-S2", 13) |
-- button:SetAttribute("*action-S3", 25) |
for state = 1, #stateTable do |
button:SetAttribute("*action-".."S"..state, button:GetAttribute("*action*") + (bar.numButtons * (state - 1))) |
end |
end |
end |
--[[ |
ApplyStates sets up bar so that it responds to changes in the specified states. |
The states parameter should be a table structured thus: |
{ |
{ |
name = string, |
first = num, |
last = num |
}, |
{ |
name = string, |
first = num, |
last = num |
} |
--etc. |
} |
Each name must be one of the state types defined in SecureStateDriver_OnLoad (at |
the time of this writing: shift, ctrl, alt, actionbar, stance, stealth). first |
is the first state to "pay attention to" and last is the last. For example: |
{ |
{ |
name = "stance", |
first = 1, |
last = 3 |
}, |
{ |
name = "ctrl", |
first = 0, |
last = 1 |
} |
} |
This will cause the bar to exist in one of 6 different states depending on |
whether you're in stances 1 to 3 or if you have the ctrl key depressed. Note: |
you must cover all possible values with first and last or you'll run into |
problems. In other words, keeping track of stances 1-3 will only work for a |
warrior because they are always in one of those three stances. A druid will |
have to use stances 0-7 to cover all their shapeshift forms. |
TBQH, I'm not sure what would happen if you were to be in a state that you |
didn't account for |
]] |
CogsBar = CogsBar or {} |
function CogsBar:ApplyStates(bar, states) |
local stateTable = MakeStateTable(states) |
local header = CreateFrame("Frame", bar:GetName().."StateDriver", bar, "SecureStateHeaderTemplate") |
CreateStateMaps(states, stateTable, header) |
CreateStateButton(stateTable, header) |
ApplyStateButtons(stateTable, bar, header) |
SecureStateDriver_OnLoad(header) |
-- Update control variable |
self.actionOffset = self.actionOffset + bar.numButtons * (#stateTable - 1) |
end |