Mercurial > wow > reaction
comparison modules/Action.lua @ 116:fb48811a8736
Convert to standard keybindings
| author | Flick <flickerstreak@gmail.com> |
|---|---|
| date | Fri, 23 Jan 2009 23:44:55 +0000 |
| parents | 77bb68eb402b |
| children | fb6c3a642ae3 |
comparison
equal
deleted
inserted
replaced
| 115:af0172ed7037 | 116:fb48811a8736 |
|---|---|
| 15 local CreateFrame = CreateFrame | 15 local CreateFrame = CreateFrame |
| 16 local format = string.format | 16 local format = string.format |
| 17 local wipe = wipe | 17 local wipe = wipe |
| 18 | 18 |
| 19 ReAction:UpdateRevision("$Revision$") | 19 ReAction:UpdateRevision("$Revision$") |
| 20 | |
| 21 local weak = { __mode="k" } | |
| 20 | 22 |
| 21 -- libraries | 23 -- libraries |
| 22 local KB = LibStub("LibKeyBound-1.0") | 24 local KB = LibStub("LibKeyBound-1.0") |
| 23 local LBF -- initialized later | 25 local LBF -- initialized later |
| 24 | 26 |
| 265 }, | 267 }, |
| 266 }, | 268 }, |
| 267 }, | 269 }, |
| 268 } | 270 } |
| 269 | 271 |
| 270 local weak = { __mode="k" } | |
| 271 local meta = { __index = Handle } | 272 local meta = { __index = Handle } |
| 272 | 273 |
| 273 function Handle:New( bar, config ) | 274 function Handle:New( bar, config ) |
| 274 local self = setmetatable( | 275 local self = setmetatable( |
| 275 { | 276 { |
| 363 ]]) | 364 ]]) |
| 364 end | 365 end |
| 365 | 366 |
| 366 function Handle:SetKeybindMode(mode) | 367 function Handle:SetKeybindMode(mode) |
| 367 for _, b in pairs(self.btns) do | 368 for _, b in pairs(self.btns) do |
| 368 if mode then | 369 b:SetKeybindMode(mode) |
| 369 -- set the border for all buttons to the keybind-enable color | |
| 370 b.border:SetVertexColor(KB:GetColorKeyBoundMode()) | |
| 371 b.border:Show() | |
| 372 elseif IsEquippedAction(b:GetActionID()) then | |
| 373 b.border:SetVertexColor(0, 1.0, 0, 0.35) -- from ActionButton.lua | |
| 374 else | |
| 375 b.border:Hide() | |
| 376 end | |
| 377 end | 370 end |
| 378 end | 371 end |
| 379 | 372 |
| 380 function Handle:GetLastButton() | 373 function Handle:GetLastButton() |
| 381 return self.btns[#self.btns] | 374 return self.btns[#self.btns] |
| 761 end | 754 end |
| 762 end | 755 end |
| 763 end | 756 end |
| 764 | 757 |
| 765 ------ Button class ------ | 758 ------ Button class ------ |
| 766 | 759 local frameRecycler = { } |
| 760 local trash = CreateFrame("Frame") | |
| 761 local OnUpdate, KBAttach, GetHotkey | |
| 767 do | 762 do |
| 768 local frameRecycler = { } | 763 local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME |
| 769 local trash = CreateFrame("Frame") | 764 local IsActionInRange = IsActionInRange |
| 770 local OnUpdate, KBAttach, GetActionName, GetHotkey, SetKey, FreeKey, ClearBindings, GetBindings | 765 |
| 771 do | 766 function OnUpdate(frame, elapsed) |
| 772 local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME | 767 -- note: This function taints frame.flashtime and frame.rangeTimer. Both of these |
| 773 local IsActionInRange = IsActionInRange | 768 -- are only read by ActionButton_OnUpdate (which this function replaces). In |
| 774 | 769 -- all other places they're just written, so it doesn't taint any secure code. |
| 775 local buttonLookup = setmetatable({},{__mode="kv"}) | 770 if frame.flashing == 1 then |
| 776 | 771 frame.flashtime = frame.flashtime - elapsed |
| 777 function OnUpdate(frame, elapsed) | 772 if frame.flashtime <= 0 then |
| 778 -- note: This function taints frame.flashtime and frame.rangeTimer. Both of these | 773 local overtime = -frame.flashtime |
| 779 -- are only read by ActionButton_OnUpdate (which this function replaces). In | 774 if overtime >= ATTACK_BUTTON_FLASH_TIME then |
| 780 -- all other places they're just written, so it doesn't taint any secure code. | 775 overtime = 0 |
| 781 if frame.flashing == 1 then | |
| 782 frame.flashtime = frame.flashtime - elapsed | |
| 783 if frame.flashtime <= 0 then | |
| 784 local overtime = -frame.flashtime | |
| 785 if overtime >= ATTACK_BUTTON_FLASH_TIME then | |
| 786 overtime = 0 | |
| 787 end | |
| 788 frame.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime | |
| 789 | |
| 790 local flashTexture = frame.flash | |
| 791 if flashTexture:IsShown() then | |
| 792 flashTexture:Hide() | |
| 793 else | |
| 794 flashTexture:Show() | |
| 795 end | |
| 796 end | 776 end |
| 797 end | 777 frame.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime |
| 798 | 778 |
| 799 if frame.rangeTimer then | 779 local flashTexture = frame.flash |
| 800 frame.rangeTimer = frame.rangeTimer - elapsed; | 780 if flashTexture:IsShown() then |
| 801 | 781 flashTexture:Hide() |
| 802 if frame.rangeTimer <= 0 then | 782 else |
| 803 if IsActionInRange(frame.action) == 0 then | 783 flashTexture:Show() |
| 804 frame.icon:SetVertexColor(1.0,0.1,0.1) | |
| 805 else | |
| 806 ActionButton_UpdateUsable(frame) | |
| 807 end | |
| 808 frame.rangeTimer = 0.1 | |
| 809 end | 784 end |
| 810 end | 785 end |
| 811 end | 786 end |
| 812 | 787 |
| 813 -- Use KeyBound-1.0 for binding, but use Override bindings instead of | 788 if frame.rangeTimer then |
| 814 -- regular bindings to support multiple profile use. This is a little | 789 frame.rangeTimer = frame.rangeTimer - elapsed; |
| 815 -- weird with the KeyBound dialog box (which has per-char selector as well | 790 |
| 816 -- as an OK/Cancel box) but it's the least amount of effort to implement. | 791 if frame.rangeTimer <= 0 then |
| 817 function GetActionName(f) | 792 if IsActionInRange(frame.action) == 0 then |
| 818 local b = buttonLookup[f] | 793 frame.icon:SetVertexColor(1.0,0.1,0.1) |
| 819 if b then | 794 else |
| 820 return format("%s:%s", b.bar:GetName(), b.idx) | 795 ActionButton_UpdateUsable(frame) |
| 821 end | |
| 822 end | |
| 823 | |
| 824 function GetHotkey(f) | |
| 825 local b = buttonLookup[f] | |
| 826 if b then | |
| 827 return KB:ToShortKey(b:GetConfig().hotkey) | |
| 828 end | |
| 829 end | |
| 830 | |
| 831 function SetKey(f, key) | |
| 832 local b = buttonLookup[f] | |
| 833 if b then | |
| 834 local c = b:GetConfig() | |
| 835 if c.hotkey then | |
| 836 SetOverrideBinding(f, false, c.hotkey, nil) | |
| 837 end | 796 end |
| 838 if key then | 797 frame.rangeTimer = 0.1 |
| 839 SetOverrideBindingClick(f, false, key, f:GetName(), nil) | 798 end |
| 840 end | 799 end |
| 841 c.hotkey = key | 800 end |
| 842 b:DisplayHotkey(GetHotkey(f)) | 801 |
| 843 end | 802 local function GetActionName(f) |
| 844 end | 803 local b = f and f._reactionButton |
| 845 | 804 if b then |
| 846 function FreeKey(f, key) | 805 return format("%s:%s", b.bar:GetName(), b.idx) |
| 847 local b = buttonLookup[f] | 806 end |
| 848 if b then | 807 end |
| 849 local c = b:GetConfig() | 808 |
| 850 if c.hotkey == key then | 809 function GetHotkey(f) |
| 851 local action = f:GetActionName() | 810 return KB:ToShortKey(GetBindingKey(format("CLICK %s:LeftButton",f:GetName()))) |
| 852 SetOverrideBinding(f, false, c.hotkey, nil) | 811 end |
| 853 c.hotkey = nil | 812 |
| 854 b:DisplayHotkey(nil) | 813 local function kb_onEnter( self ) |
| 855 return action | 814 if ReAction:GetKeybindMode() then |
| 856 end | 815 KB:Set(self) |
| 857 end | 816 end |
| 858 return ReAction:FreeOverrideHotkey(key) | 817 end |
| 859 end | 818 |
| 860 | 819 function KBAttach( button ) |
| 861 function ClearBindings(f) | 820 if not button.kbHooked then |
| 862 SetKey(f, nil) | 821 button.kbHooked = true |
| 863 end | |
| 864 | |
| 865 function GetBindings(f) | |
| 866 local b = buttonLookup[f] | |
| 867 if b then | |
| 868 return b:GetConfig().hotkey | |
| 869 end | |
| 870 end | |
| 871 | |
| 872 function KBAttach( button ) | |
| 873 local f = button:GetFrame() | 822 local f = button:GetFrame() |
| 823 f:HookScript("OnEnter", kb_onEnter) | |
| 874 f.GetActionName = GetActionName | 824 f.GetActionName = GetActionName |
| 875 f.GetHotkey = GetHotkey | 825 f.GetHotkey = GetHotkey |
| 876 f.SetKey = SetKey | 826 end |
| 877 f.FreeKey = FreeKey | 827 end |
| 878 f.ClearBindings = ClearBindings | 828 |
| 879 f.GetBindings = GetBindings | 829 -- This is a bit hokey : install a bare hook on ActionButton_UpdateHotkey because |
| 880 buttonLookup[f] = button | 830 -- even though it's secure it's never called in a way that can cause taint. This is |
| 881 f:SetKey(button:GetConfig().hotkey) | 831 -- for performance reasons to avoid having to hook frame:OnEvent securely. |
| 882 ReAction:RegisterKeybindFrame(f) | 832 local UpdateHotkey_old = ActionButton_UpdateHotkeys |
| 883 if ReAction:GetKeybindMode() then | 833 ActionButton_UpdateHotkeys = function( frame, ... ) |
| 884 button.border:SetVertexColor(KB:GetColorKeyBoundMode()) | 834 local b = frame._reactionButton |
| 885 button.border:Show() | 835 if b then |
| 886 end | 836 b.hotkey:SetText( GetHotkey(frame) ) |
| 887 end | |
| 888 end | |
| 889 | |
| 890 local meta = {__index = Button} | |
| 891 | |
| 892 function Button:New( handle, idx, config, barConfig ) | |
| 893 local bar = handle.bar | |
| 894 | |
| 895 -- create new self | |
| 896 self = setmetatable( | |
| 897 { | |
| 898 bar = bar, | |
| 899 idx = idx, | |
| 900 config = config, | |
| 901 barConfig = barConfig, | |
| 902 }, meta ) | |
| 903 | |
| 904 local name = config.name or ("ReAction_%s_%s_%d"):format(bar:GetName(),moduleID,idx) | |
| 905 self.name = name | |
| 906 config.name = name | |
| 907 local lastButton = handle:GetLastButton() | |
| 908 config.actionID = IDAlloc:Acquire(config.actionID, lastButton and lastButton.config.actionID) -- gets a free one if none configured | |
| 909 self.nPages = 1 | |
| 910 | |
| 911 -- have to recycle frames with the same name: CreateFrame() doesn't overwrite | |
| 912 -- existing globals. Can't set to nil in the global because it's then tainted. | |
| 913 local parent = bar:GetFrame() | |
| 914 local f = frameRecycler[name] | |
| 915 if f then | |
| 916 f:SetParent(parent) | |
| 917 else | 837 else |
| 918 f = CreateFrame("CheckButton", name, parent, "ActionBarButtonTemplate") | 838 return UpdateHotkey_old(frame, ...) |
| 919 -- ditch the old hotkey text because it's tied in ActionButton_Update() to the | 839 end |
| 920 -- standard binding. We use override bindings. | 840 end |
| 921 local hotkey = _G[name.."HotKey"] | 841 end |
| 922 hotkey:SetParent(trash) | 842 |
| 923 hotkey = f:CreateFontString(nil, "ARTWORK", "NumberFontNormalSmallGray") | 843 local meta = {__index = Button} |
| 924 hotkey:SetWidth(36) | 844 |
| 925 hotkey:SetHeight(18) | 845 function Button:New( handle, idx, config, barConfig ) |
| 926 hotkey:SetJustifyH("RIGHT") | 846 local bar = handle.bar |
| 927 hotkey:SetJustifyV("TOP") | 847 |
| 928 hotkey:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2) | 848 -- create new self |
| 929 f.hotkey = hotkey | 849 self = setmetatable( |
| 930 f.icon = _G[name.."Icon"] | 850 { |
| 931 f.flash = _G[name.."Flash"] | 851 bar = bar, |
| 932 f:SetScript("OnUpdate",OnUpdate) | 852 idx = idx, |
| 933 end | 853 config = config, |
| 934 | 854 barConfig = barConfig, |
| 935 self.hotkey = f.hotkey | 855 }, meta ) |
| 936 self.border = _G[name.."Border"] | 856 |
| 937 | 857 local name = config.name or ("ReAction_%s_%s_%d"):format(bar:GetName(),moduleID,idx) |
| 938 f:SetAttribute("action", config.actionID) | 858 self.name = name |
| 939 f:SetAttribute("default-action", config.actionID) | 859 config.name = name |
| 940 -- install mind control actions for all buttons just for simplicity | 860 local lastButton = handle:GetLastButton() |
| 941 if self.idx <= 12 then | 861 config.actionID = IDAlloc:Acquire(config.actionID, lastButton and lastButton.config.actionID) -- gets a free one if none configured |
| 942 f:SetAttribute("mindcontrol-action", 120 + self.idx) | 862 self.nPages = 1 |
| 943 end | 863 |
| 944 | 864 -- have to recycle frames with the same name: CreateFrame() doesn't overwrite |
| 945 -- set a _childupdate handler, called within the header's context | 865 -- existing globals. Can't set to nil in the global because it's then tainted. |
| 946 f:SetAttribute("_childupdate", | 866 local parent = bar:GetFrame() |
| 947 -- function _childupdate(self, snippetid, message) | 867 local f = frameRecycler[name] |
| 948 [[ | 868 if f then |
| 949 local action = "default-action" | 869 f:SetParent(parent) |
| 950 if doMindControl and GetBonusBarOffset() == 5 then | 870 else |
| 951 action = "mindcontrol-action" | 871 f = CreateFrame("CheckButton", name, parent, "ActionBarButtonTemplate") |
| 952 elseif page and state and page[state] then | 872 -- ditch the old hotkey text because it's tied in ActionButton_Update() to the |
| 953 action = "action-"..page[state] | 873 -- standard binding. |
| 954 end | 874 local hotkey = _G[name.."HotKey"] |
| 955 local value = self:GetAttribute(action) | 875 hotkey:SetParent(trash) |
| 956 if value then | 876 hotkey = f:CreateFontString(nil, "ARTWORK", "NumberFontNormalSmallGray") |
| 957 self:SetAttribute("action",value) | 877 hotkey:SetWidth(36) |
| 958 end | 878 hotkey:SetHeight(18) |
| 959 ]]) | 879 hotkey:SetJustifyH("RIGHT") |
| 960 | 880 hotkey:SetJustifyV("TOP") |
| 961 -- install drag wrappers to lock buttons | 881 hotkey:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2) |
| 962 bar:GetFrame():WrapScript(f, "OnDragStart", | 882 f.hotkey = hotkey |
| 963 -- OnDragStart(self, button, kind, value, ...) | 883 f.icon = _G[name.."Icon"] |
| 964 [[ | 884 f.flash = _G[name.."Flash"] |
| 965 if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then | 885 f:SetScript("OnUpdate",OnUpdate) |
| 966 return "clear" | 886 end |
| 967 end | 887 |
| 968 ]]) | 888 f._reactionButton = self |
| 969 | 889 |
| 970 self.frame = f | 890 self.hotkey = f.hotkey |
| 971 | 891 self.border = _G[name.."Border"] |
| 972 | 892 |
| 973 -- initialize the hide state | 893 f:SetAttribute("action", config.actionID) |
| 974 f:SetAttribute("showgrid",0) | 894 f:SetAttribute("default-action", config.actionID) |
| 975 self:ShowGrid(not barConfig.hideEmpty) | 895 -- install mind control actions for all buttons just for simplicity |
| 976 if ReAction:GetConfigMode() then | 896 if self.idx <= 12 then |
| 977 self:ShowGrid(true) | 897 f:SetAttribute("mindcontrol-action", 120 + self.idx) |
| 978 end | 898 end |
| 979 | 899 |
| 980 -- show the ID label if applicable | 900 -- set a _childupdate handler, called within the header's context |
| 981 self:ShowActionIDLabel(ReAction:GetConfigMode()) | 901 f:SetAttribute("_childupdate", |
| 982 | 902 -- function _childupdate(self, snippetid, message) |
| 983 -- attach the keybinder | 903 [[ |
| 984 KBAttach(self) | 904 local action = "default-action" |
| 985 | 905 if doMindControl and GetBonusBarOffset() == 5 then |
| 986 -- attach to skinner | 906 action = "mindcontrol-action" |
| 987 bar:SkinButton(self, | 907 elseif page and state and page[state] then |
| 988 { | 908 action = "action-"..page[state] |
| 989 HotKey = self.hotkey, | 909 end |
| 990 } | 910 local value = self:GetAttribute(action) |
| 991 ) | 911 if value then |
| 992 | 912 self:SetAttribute("action",value) |
| 993 self:Refresh() | 913 end |
| 994 return self | 914 ]]) |
| 995 end | 915 |
| 996 | 916 -- install drag wrappers to lock buttons |
| 997 function Button:Destroy() | 917 bar:GetFrame():WrapScript(f, "OnDragStart", |
| 918 -- OnDragStart(self, button, kind, value, ...) | |
| 919 [[ | |
| 920 if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then | |
| 921 return "clear" | |
| 922 end | |
| 923 ]]) | |
| 924 | |
| 925 self.frame = f | |
| 926 | |
| 927 -- initialize the hide state | |
| 928 f:SetAttribute("showgrid",0) | |
| 929 self:ShowGrid(not barConfig.hideEmpty) | |
| 930 if ReAction:GetConfigMode() then | |
| 931 self:ShowGrid(true) | |
| 932 end | |
| 933 | |
| 934 -- set the hotkey text | |
| 935 self.hotkey:SetText( GetHotkey(self.frame) ) | |
| 936 | |
| 937 -- show the ID label if applicable | |
| 938 self:ShowActionIDLabel(ReAction:GetConfigMode()) | |
| 939 | |
| 940 -- attach to skinner | |
| 941 bar:SkinButton(self, | |
| 942 { | |
| 943 HotKey = self.hotkey, | |
| 944 } | |
| 945 ) | |
| 946 | |
| 947 self:Refresh() | |
| 948 return self | |
| 949 end | |
| 950 | |
| 951 function Button:Destroy() | |
| 952 local f = self.frame | |
| 953 f:UnregisterAllEvents() | |
| 954 f:Hide() | |
| 955 f:SetParent(UIParent) | |
| 956 f:ClearAllPoints() | |
| 957 if self.name then | |
| 958 frameRecycler[self.name] = f | |
| 959 end | |
| 960 if self.config.actionID then | |
| 961 IDAlloc:Release(self.config.actionID) | |
| 962 end | |
| 963 if self.config.pageactions then | |
| 964 for _, id in ipairs(self.config.pageactions) do | |
| 965 IDAlloc:Release(id) | |
| 966 end | |
| 967 end | |
| 968 f._reactionButton = nil | |
| 969 self.frame = nil | |
| 970 self.config = nil | |
| 971 self.bar = nil | |
| 972 end | |
| 973 | |
| 974 function Button:Refresh() | |
| 975 local f = self.frame | |
| 976 self.bar:PlaceButton(self, 36, 36) | |
| 977 self:RefreshPages() | |
| 978 end | |
| 979 | |
| 980 function Button:GetFrame() | |
| 981 return self.frame | |
| 982 end | |
| 983 | |
| 984 function Button:GetName() | |
| 985 return self.name | |
| 986 end | |
| 987 | |
| 988 function Button:GetConfig() | |
| 989 return self.config | |
| 990 end | |
| 991 | |
| 992 function Button:GetActionID(page) | |
| 993 if page == nil then | |
| 994 -- get the effective ID | |
| 995 return self.frame.action -- kept up-to-date by Blizzard's ActionButton_CalculateAction() | |
| 996 else | |
| 997 if page == 1 then | |
| 998 return self.config.actionID | |
| 999 else | |
| 1000 return self.config.pageactions and self.config.pageactions[page] or self.config.actionID | |
| 1001 end | |
| 1002 end | |
| 1003 end | |
| 1004 | |
| 1005 function Button:SetActionID( id, page ) | |
| 1006 id = tonumber(id) | |
| 1007 page = tonumber(page) | |
| 1008 if id == nil or id < 1 or id > 120 then | |
| 1009 error("Button:SetActionID - invalid action ID") | |
| 1010 end | |
| 1011 if page and page ~= 1 then | |
| 1012 if not self.config.pageactions then | |
| 1013 self.config.pageactions = { } | |
| 1014 end | |
| 1015 if self.config.pageactions[page] then | |
| 1016 IDAlloc:Release(self.config.pageactions[page]) | |
| 1017 end | |
| 1018 self.config.pageactions[page] = id | |
| 1019 IDAlloc:Acquire(self.config.pageactions[page]) | |
| 1020 self.frame:SetAttribute(("action-page%d"):format(page),id) | |
| 1021 else | |
| 1022 IDAlloc:Release(self.config.actionID) | |
| 1023 self.config.actionID = id | |
| 1024 IDAlloc:Acquire(self.config.actionID) | |
| 1025 self.frame:SetAttribute("action",id) | |
| 1026 if self.config.pageactions then | |
| 1027 self.config.pageactions[1] = id | |
| 1028 self.frame:SetAttribute("action-page1",id) | |
| 1029 end | |
| 1030 end | |
| 1031 end | |
| 1032 | |
| 1033 function Button:RefreshPages( force ) | |
| 1034 local nPages = self.barConfig.nPages | |
| 1035 if nPages and (nPages ~= self.nPages or force) then | |
| 1036 local f = self:GetFrame() | |
| 1037 local c = self.config.pageactions | |
| 1038 if nPages > 1 and not c then | |
| 1039 c = { } | |
| 1040 self.config.pageactions = c | |
| 1041 end | |
| 1042 for i = 1, nPages do | |
| 1043 if i > 1 then | |
| 1044 c[i] = IDAlloc:Acquire(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons()) | |
| 1045 else | |
| 1046 c[i] = self.config.actionID -- page 1 is the same as the base actionID | |
| 1047 end | |
| 1048 f:SetAttribute(("action-page%d"):format(i),c[i]) | |
| 1049 end | |
| 1050 for i = nPages+1, #c do | |
| 1051 IDAlloc:Release(c[i]) | |
| 1052 c[i] = nil | |
| 1053 f:SetAttribute(("action-page%d"):format(i),nil) | |
| 1054 end | |
| 1055 self.nPages = nPages | |
| 1056 end | |
| 1057 end | |
| 1058 | |
| 1059 function Button:ShowGrid( show ) | |
| 1060 if not InCombatLockdown() then | |
| 998 local f = self.frame | 1061 local f = self.frame |
| 999 f:UnregisterAllEvents() | 1062 local count = f:GetAttribute("showgrid") |
| 1000 f:Hide() | 1063 if show then |
| 1001 f:SetParent(UIParent) | 1064 count = count + 1 |
| 1002 f:ClearAllPoints() | |
| 1003 if self.name then | |
| 1004 frameRecycler[self.name] = f | |
| 1005 end | |
| 1006 if self.config.actionID then | |
| 1007 IDAlloc:Release(self.config.actionID) | |
| 1008 end | |
| 1009 if self.config.pageactions then | |
| 1010 for _, id in ipairs(self.config.pageactions) do | |
| 1011 IDAlloc:Release(id) | |
| 1012 end | |
| 1013 end | |
| 1014 self.frame = nil | |
| 1015 self.config = nil | |
| 1016 self.bar = nil | |
| 1017 end | |
| 1018 | |
| 1019 function Button:Refresh() | |
| 1020 local f = self.frame | |
| 1021 self.bar:PlaceButton(self, 36, 36) | |
| 1022 self:RefreshPages() | |
| 1023 end | |
| 1024 | |
| 1025 function Button:GetFrame() | |
| 1026 return self.frame | |
| 1027 end | |
| 1028 | |
| 1029 function Button:GetName() | |
| 1030 return self.name | |
| 1031 end | |
| 1032 | |
| 1033 function Button:GetConfig() | |
| 1034 return self.config | |
| 1035 end | |
| 1036 | |
| 1037 function Button:GetActionID(page) | |
| 1038 if page == nil then | |
| 1039 -- get the effective ID | |
| 1040 return self.frame.action -- kept up-to-date by Blizzard's ActionButton_CalculateAction() | |
| 1041 else | 1065 else |
| 1042 if page == 1 then | 1066 count = count - 1 |
| 1043 return self.config.actionID | 1067 end |
| 1068 if count < 0 then | |
| 1069 count = 0 | |
| 1070 end | |
| 1071 f:SetAttribute("showgrid",count) | |
| 1072 | |
| 1073 if count >= 1 and not f:GetAttribute("statehidden") then | |
| 1074 if LBF then | |
| 1075 LBF:SetNormalVertexColor(self.frame, 1.0, 1.0, 1.0, 0.5) | |
| 1044 else | 1076 else |
| 1045 return self.config.pageactions and self.config.pageactions[page] or self.config.actionID | 1077 self.frame:GetNormalTexture():SetVertexColor(1.0, 1.0, 1.0, 0.5); |
| 1046 end | 1078 end |
| 1047 end | 1079 f:Show() |
| 1048 end | 1080 elseif count < 1 and not HasAction(self:GetActionID()) then |
| 1049 | 1081 f:Hide() |
| 1050 function Button:SetActionID( id, page ) | 1082 end |
| 1051 id = tonumber(id) | 1083 end |
| 1052 page = tonumber(page) | 1084 end |
| 1053 if id == nil or id < 1 or id > 120 then | 1085 |
| 1054 error("Button:SetActionID - invalid action ID") | 1086 function Button:ShowActionIDLabel( show ) |
| 1055 end | 1087 local f = self:GetFrame() |
| 1056 if page and page ~= 1 then | 1088 if show then |
| 1057 if not self.config.pageactions then | 1089 local id = self:GetActionID() |
| 1058 self.config.pageactions = { } | 1090 if not f.actionIDLabel then |
| 1059 end | 1091 local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") |
| 1060 if self.config.pageactions[page] then | 1092 label:SetAllPoints() |
| 1061 IDAlloc:Release(self.config.pageactions[page]) | 1093 label:SetJustifyH("CENTER") |
| 1062 end | 1094 label:SetShadowColor(0,0,0,1) |
| 1063 self.config.pageactions[page] = id | 1095 label:SetShadowOffset(2,-2) |
| 1064 IDAlloc:Acquire(self.config.pageactions[page]) | 1096 f.actionIDLabel = label -- store the label with the frame for recycling |
| 1065 self.frame:SetAttribute(("action-page%d"):format(page),id) | 1097 |
| 1066 else | 1098 f:HookScript("OnAttributeChanged", |
| 1067 IDAlloc:Release(self.config.actionID) | 1099 function(frame, attr, value) |
| 1068 self.config.actionID = id | 1100 if label:IsVisible() and attr:match("action") then |
| 1069 IDAlloc:Acquire(self.config.actionID) | 1101 label:SetText(tostring(frame.action)) |
| 1070 self.frame:SetAttribute("action",id) | 1102 end |
| 1071 if self.config.pageactions then | 1103 end) |
| 1072 self.config.pageactions[1] = id | 1104 end |
| 1073 self.frame:SetAttribute("action-page1",id) | 1105 f.actionIDLabel:SetText(tostring(id)) |
| 1074 end | 1106 f.actionIDLabel:Show() |
| 1075 end | 1107 elseif f.actionIDLabel then |
| 1076 end | 1108 f.actionIDLabel:Hide() |
| 1077 | 1109 end |
| 1078 function Button:RefreshPages( force ) | 1110 end |
| 1079 local nPages = self.barConfig.nPages | 1111 |
| 1080 if nPages and (nPages ~= self.nPages or force) then | 1112 function Button:SetKeybindMode( mode ) |
| 1081 local f = self:GetFrame() | 1113 if mode then |
| 1082 local c = self.config.pageactions | 1114 KBAttach( self ) |
| 1083 if nPages > 1 and not c then | 1115 -- set the border for all buttons to the keybind-enable color |
| 1084 c = { } | 1116 self.border:SetVertexColor(KB:GetColorKeyBoundMode()) |
| 1085 self.config.pageactions = c | 1117 self.border:Show() |
| 1086 end | 1118 elseif IsEquippedAction(self:GetActionID()) then |
| 1087 for i = 1, nPages do | 1119 self.border:SetVertexColor(0, 1.0, 0, 0.35) -- from ActionButton.lua |
| 1088 if i > 1 then | 1120 else |
| 1089 c[i] = IDAlloc:Acquire(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons()) | 1121 self.border:Hide() |
| 1090 else | 1122 end |
| 1091 c[i] = self.config.actionID -- page 1 is the same as the base actionID | 1123 end |
| 1092 end | |
| 1093 f:SetAttribute(("action-page%d"):format(i),c[i]) | |
| 1094 end | |
| 1095 for i = nPages+1, #c do | |
| 1096 IDAlloc:Release(c[i]) | |
| 1097 c[i] = nil | |
| 1098 f:SetAttribute(("action-page%d"):format(i),nil) | |
| 1099 end | |
| 1100 self.nPages = nPages | |
| 1101 end | |
| 1102 end | |
| 1103 | |
| 1104 function Button:ShowGrid( show ) | |
| 1105 if not InCombatLockdown() then | |
| 1106 local f = self.frame | |
| 1107 local count = f:GetAttribute("showgrid") | |
| 1108 if show then | |
| 1109 count = count + 1 | |
| 1110 else | |
| 1111 count = count - 1 | |
| 1112 end | |
| 1113 if count < 0 then | |
| 1114 count = 0 | |
| 1115 end | |
| 1116 f:SetAttribute("showgrid",count) | |
| 1117 | |
| 1118 if count >= 1 and not f:GetAttribute("statehidden") then | |
| 1119 if LBF then | |
| 1120 LBF:SetNormalVertexColor(self.frame, 1.0, 1.0, 1.0, 0.5) | |
| 1121 else | |
| 1122 self.frame:GetNormalTexture():SetVertexColor(1.0, 1.0, 1.0, 0.5); | |
| 1123 end | |
| 1124 f:Show() | |
| 1125 elseif count < 1 and not HasAction(self:GetActionID()) then | |
| 1126 f:Hide() | |
| 1127 end | |
| 1128 end | |
| 1129 end | |
| 1130 | |
| 1131 function Button:ShowActionIDLabel( show ) | |
| 1132 local f = self:GetFrame() | |
| 1133 if show then | |
| 1134 local id = self:GetActionID() | |
| 1135 if not f.actionIDLabel then | |
| 1136 local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") | |
| 1137 label:SetAllPoints() | |
| 1138 label:SetJustifyH("CENTER") | |
| 1139 label:SetShadowColor(0,0,0,1) | |
| 1140 label:SetShadowOffset(2,-2) | |
| 1141 f.actionIDLabel = label -- store the label with the frame for recycling | |
| 1142 | |
| 1143 f:HookScript("OnAttributeChanged", | |
| 1144 function(frame, attr, value) | |
| 1145 if label:IsVisible() and attr:match("action") then | |
| 1146 label:SetText(tostring(frame.action)) | |
| 1147 end | |
| 1148 end) | |
| 1149 end | |
| 1150 f.actionIDLabel:SetText(tostring(id)) | |
| 1151 f.actionIDLabel:Show() | |
| 1152 elseif f.actionIDLabel then | |
| 1153 f.actionIDLabel:Hide() | |
| 1154 end | |
| 1155 end | |
| 1156 | |
| 1157 function Button:DisplayHotkey( key ) | |
| 1158 self.hotkey:SetText(key or "") | |
| 1159 end | |
| 1160 end |
