comparison modules/Action.lua @ 128:729232aeeb5e

Action Button rewrite. (note: pet actions are probably slightly broken right now, they haven't been updated yet)
author Flick <flickerstreak@gmail.com>
date Thu, 05 Mar 2009 01:28:48 +0000
parents fb6c3a642ae3
children 901c91dc1bf2
comparison
equal deleted inserted replaced
127:29dacbecdb52 128:729232aeeb5e
1 --[[
2 ReAction Action button module.
3
4 The button module implements standard action button functionality by wrapping Blizzard's
5 ActionBarButtonTemplate frame and associated functions.
6
7 It also provides action remapping support for multiple pages and possessed targets
8 (Mind Control, Eyes of the Beast, Karazhan Chess event, various quests, etc).
9 --]]
10
11 -- local imports
12 local ReAction = ReAction 1 local ReAction = ReAction
13 local L = ReAction.L 2 local L = ReAction.L
14 local _G = _G 3 local _G = _G
15 local CreateFrame = CreateFrame 4 local CreateFrame = CreateFrame
16 local format = string.format 5 local format = string.format
20 9
21 local weak = { __mode="k" } 10 local weak = { __mode="k" }
22 11
23 -- libraries 12 -- libraries
24 local KB = LibStub("LibKeyBound-1.0") 13 local KB = LibStub("LibKeyBound-1.0")
25 local LBF -- initialized later
26 14
27 -- module declaration 15 -- module declaration
28 local moduleID = "Action" 16 local moduleID = "Action"
29 local module = ReAction:NewModule( moduleID ) 17 local module = ReAction:NewModule( moduleID )
30 18
31 -- Class declarations 19 -- Class declarations
32 local Button = { } 20 local Button = ReAction.Button.Action -- see /classes/ActionButton.lua
33 local Handle = { } 21 local Handle = { }
34 local PropHandler = { } 22 local PropHandler = { }
35 23
36 -- Event handlers 24 -- Event handlers
37 function module:OnInitialize() 25 function module:OnInitialize()
51 ReAction.RegisterCallback(self, "OnDestroyBar") 39 ReAction.RegisterCallback(self, "OnDestroyBar")
52 ReAction.RegisterCallback(self, "OnEraseBar") 40 ReAction.RegisterCallback(self, "OnEraseBar")
53 ReAction.RegisterCallback(self, "OnRenameBar") 41 ReAction.RegisterCallback(self, "OnRenameBar")
54 ReAction.RegisterCallback(self, "OnConfigModeChanged") 42 ReAction.RegisterCallback(self, "OnConfigModeChanged")
55 43
56 LBF = LibStub("LibButtonFacade",true)
57
58 KB.RegisterCallback(self, "LIBKEYBOUND_ENABLED") 44 KB.RegisterCallback(self, "LIBKEYBOUND_ENABLED")
59 KB.RegisterCallback(self, "LIBKEYBOUND_DISABLED") 45 KB.RegisterCallback(self, "LIBKEYBOUND_DISABLED")
60 KB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED") 46 KB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED")
61 end 47 end
62 48
119 end 105 end
120 end 106 end
121 107
122 function module:LIBKEYBOUND_ENABLED(evt) 108 function module:LIBKEYBOUND_ENABLED(evt)
123 for _, h in pairs(self.handles) do 109 for _, h in pairs(self.handles) do
124 h:ShowGrid(true)
125 h:SetKeybindMode(true) 110 h:SetKeybindMode(true)
126 end 111 end
127 end 112 end
128 113
129 function module:LIBKEYBOUND_DISABLED(evt) 114 function module:LIBKEYBOUND_DISABLED(evt)
130 for _, h in pairs(self.handles) do 115 for _, h in pairs(self.handles) do
131 h:ShowGrid(false)
132 h:SetKeybindMode(false) 116 h:SetKeybindMode(false)
133 end 117 end
134 end 118 end
135 119
136 120
158 lockButtons = { 142 lockButtons = {
159 name = L["Lock Buttons"], 143 name = L["Lock Buttons"],
160 desc = L["Prevents picking up/dragging actions.|nNOTE: This setting is overridden by the global setting in Blizzard's Action Buttons tab"], 144 desc = L["Prevents picking up/dragging actions.|nNOTE: This setting is overridden by the global setting in Blizzard's Action Buttons tab"],
161 order = 2, 145 order = 2,
162 type = "toggle", 146 type = "toggle",
163 disabled = "LockButtonsDisabled",
164 get = "GetLockButtons", 147 get = "GetLockButtons",
165 set = "SetLockButtons", 148 set = "SetLockButtons",
166 }, 149 },
167 lockOnlyCombat = { 150 lockOnlyCombat = {
168 name = L["Only in Combat"], 151 name = L["Only in Combat"],
305 for i = 1, n do 288 for i = 1, n do
306 if btnCfg[i] == nil then 289 if btnCfg[i] == nil then
307 btnCfg[i] = {} 290 btnCfg[i] = {}
308 end 291 end
309 if self.btns[i] == nil then 292 if self.btns[i] == nil then
310 local b = Button:New(self, i, btnCfg[i], self.config) 293 local lastButton = self:GetLastButton()
294 local hint = lastButton and lastButton.config.actionID
295 local b = Button:New(i, self.config, self.bar, hint)
311 self.btns[i] = b 296 self.btns[i] = b
312 self.bar:AddButton(i,b) 297 self.bar:AddButton(i,b)
313 end 298 end
314 end 299 end
315 for i = n+1, #self.btns do 300 for i = n+1, #self.btns do
319 self.btns[i] = nil 304 self.btns[i] = nil
320 btnCfg[i] = nil 305 btnCfg[i] = nil
321 end 306 end
322 end 307 end
323 end 308 end
324 local f = self.bar:GetFrame()
325 for _, b in ipairs(self.btns) do 309 for _, b in ipairs(self.btns) do
326 b:Refresh() 310 b:Refresh()
327 end 311 end
328 f:SetAttribute("mindcontrol",self.config.mindcontrol) 312 Button.SetupBarHeader(self.bar,self.config)
329 f:SetAttribute("vehicle",self.config.vehicle)
330 f:Execute(
331 [[
332 doMindControl = self:GetAttribute("mindcontrol")
333 doVehicle = self:GetAttribute("vehicle")
334 control:ChildUpdate()
335 ]])
336
337 f:SetAttribute("_onstate-mc",
338 -- function _onstate-mc(self, stateid, newstate)
339 [[
340 local oldMcVehicleState = mcVehicleState
341 mcVehicleState = newstate
342 control:ChildUpdate()
343 if oldMcVehicleState == "vehicle" or mcVehicleState == "vehicle" then
344 control:ChildUpdate("vehicle")
345 end
346 ]])
347 RegisterStateDriver(f, "mc", "[target=vehicle,exists] vehicle; [bonusbar:5] mc; none")
348
349 self:UpdateButtonLock() 313 self:UpdateButtonLock()
350 end 314 end
351 315
352 function Handle:Destroy() 316 function Handle:Destroy()
353 for _,b in pairs(self.btns) do 317 for _,b in pairs(self.btns) do
357 end 321 end
358 end 322 end
359 323
360 function Handle:SetConfigMode(mode) 324 function Handle:SetConfigMode(mode)
361 for _, b in pairs(self.btns) do 325 for _, b in pairs(self.btns) do
362 b:ShowGrid(mode) 326 b:UpdateActionIDLabel(mode)
363 b:ShowActionIDLabel(mode)
364 end
365 end
366
367 function Handle:ShowGrid(show)
368 for _, b in pairs(self.btns) do
369 b:ShowGrid(show)
370 end 327 end
371 end 328 end
372 329
373 function Handle:UpdateButtonLock() 330 function Handle:UpdateButtonLock()
374 local f = self.bar:GetFrame() 331 Button.SetButtonLock(self.bar, self.config.lockButtons, self.config.lockButtonsCombat)
375 f:SetAttribute("lockbuttons",self.config.lockButtons)
376 f:SetAttribute("lockbuttonscombat",self.config.lockButtonsCombat)
377 f:Execute(
378 [[
379 lockButtons = self:GetAttribute("lockbuttons")
380 lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
381 ]])
382 end 332 end
383 333
384 function Handle:SetKeybindMode(mode) 334 function Handle:SetKeybindMode(mode)
385 for _, b in pairs(self.btns) do 335 for _, b in pairs(self.btns) do
386 b:SetKeybindMode(mode) 336 b:SetKeybindMode(mode)
402 end 352 end
403 353
404 function Handle:SetHideEmpty(info, value) 354 function Handle:SetHideEmpty(info, value)
405 if value ~= self.config.hideEmpty then 355 if value ~= self.config.hideEmpty then
406 self.config.hideEmpty = value 356 self.config.hideEmpty = value
407 self:ShowGrid(not value) 357 for _, b in pairs(self.btns) do
358 b:ShowGrid(not value)
359 end
408 end 360 end
409 end 361 end
410 362
411 function Handle:GetHideEmpty() 363 function Handle:GetHideEmpty()
412 return self.config.hideEmpty 364 return self.config.hideEmpty
413 end 365 end
414 366
415 function Handle:GetLockButtons() 367 function Handle:GetLockButtons()
416 return LOCK_ACTIONBAR == "1" or self.config.lockButtons 368 return self.config.lockButtons
417 end 369 end
418 370
419 function Handle:SetLockButtons(info, value) 371 function Handle:SetLockButtons(info, value)
420 self.config.lockButtons = value 372 self.config.lockButtons = value
421 self:UpdateButtonLock() 373 self:UpdateButtonLock()
422 end 374 end
423 375
424 function Handle:LockButtonsDisabled()
425 return LOCK_ACTIONBAR == "1"
426 end
427
428 function Handle:GetLockButtonsCombat() 376 function Handle:GetLockButtonsCombat()
429 return self.config.lockButtonsCombat 377 return self.config.lockButtonsCombat
430 end 378 end
431 379
432 function Handle:SetLockButtonsCombat(info, value) 380 function Handle:SetLockButtonsCombat(info, value)
433 self.config.lockButtonsCombat = value 381 self.config.lockButtonsCombat = value
434 self:UpdateButtonLock() 382 self:UpdateButtonLock()
435 end 383 end
436 384
437 function Handle:LockButtonsCombatDisabled() 385 function Handle:LockButtonsCombatDisabled()
438 return LOCK_ACTIONBAR == "1" or not self.config.lockButtons 386 return not self.config.lockButtons
439 end 387 end
440 388
441 function Handle:GetNumPages() 389 function Handle:GetNumPages()
442 return self.config.nPages 390 return self.config.nPages
443 end 391 end
703 return self:GetProp(info) or 1 651 return self:GetProp(info) or 1
704 end 652 end
705 653
706 end 654 end
707 655
708 ------ ActionID allocation ------
709 -- this needs to be high performance when requesting new IDs,
710 -- or certain controls will become sluggish. However, the new-request
711 -- infrastructure can be built lazily the first time that a new request
712 -- comes in (which will only happen at user config time: at static startup
713 -- config time all actionIDs should already have been assigned and stored
714 -- in the config file)
715
716 local IDAlloc
717 do
718 local n = 120
719
720 IDAlloc = setmetatable({ wrap = 1, freecount = n }, {__index = function() return 0 end})
721
722 function IDAlloc:Acquire(id, hint)
723 id = tonumber(id)
724 hint = tonumber(hint)
725 if id and (id < 1 or id > n) then
726 id = nil
727 end
728 if hint and (hint < 1 or hint > n) then
729 hint = nil
730 end
731 if id == nil then
732 -- get a free ID
733 if hint and self[hint] == 0 then
734 -- use the hint if it's free
735 id = hint
736 elseif self.freecount > 0 then
737 -- if neither the id nor the hint are defined or free, but
738 -- the list is known to have free IDs, then start searching
739 -- at the hint for a free one
740 for i = hint or 1, n do
741 if self[i] == 0 then
742 id = i
743 break
744 end
745 end
746 -- self.wrap the search
747 if id == nil and hint and hint > 1 then
748 for i = 1, hint - 1 do
749 if self[i] == 0 then
750 id = i
751 break
752 end
753 end
754 end
755 end
756 if id == nil then
757 -- if there are no free IDs, start wrapping at 1
758 id = self.wrap
759 self.wrap = id + 1
760 if self.wrap > n then
761 self.wrap = 1
762 end
763 end
764 end
765 if self[id] == 0 then
766 self.freecount = self.freecount - 1
767 end
768 self[id] = self[id] + 1
769 return id
770 end
771
772 function IDAlloc:Release(id)
773 id = tonumber(id)
774 if id and (id >= 1 or id <= n) then
775 self[id] = self[id] - 1
776 if self[id] == 0 then
777 self.freecount = self.freecount + 1
778 self.wrap = 1
779 end
780 end
781 end
782 end
783
784 ------ Button class ------
785 local frameRecycler = { }
786 local trash = CreateFrame("Frame")
787 local OnUpdate, GetActionName, GetHotkey
788 do
789 local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
790 local IsActionInRange = IsActionInRange
791
792 function OnUpdate(frame, elapsed)
793 -- note: This function taints frame.flashtime and frame.rangeTimer. Both of these
794 -- are only read by ActionButton_OnUpdate (which this function replaces). In
795 -- all other places they're just written, so it doesn't taint any secure code.
796 if frame.flashing == 1 then
797 frame.flashtime = frame.flashtime - elapsed
798 if frame.flashtime <= 0 then
799 local overtime = -frame.flashtime
800 if overtime >= ATTACK_BUTTON_FLASH_TIME then
801 overtime = 0
802 end
803 frame.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
804
805 local flashTexture = frame.flash
806 if flashTexture:IsShown() then
807 flashTexture:Hide()
808 else
809 flashTexture:Show()
810 end
811 end
812 end
813
814 if frame.rangeTimer then
815 frame.rangeTimer = frame.rangeTimer - elapsed;
816
817 if frame.rangeTimer <= 0 then
818 if IsActionInRange(frame.action) == 0 then
819 frame.icon:SetVertexColor(1.0,0.1,0.1)
820 else
821 ActionButton_UpdateUsable(frame)
822 end
823 frame.rangeTimer = 0.1
824 end
825 end
826 end
827
828 function GetActionName(f)
829 local b = f and f._reactionButton
830 if b then
831 return format("%s:%s", b.bar:GetName(), b.idx)
832 end
833 end
834
835 function GetHotkey(f)
836 return KB:ToShortKey(GetBindingKey(format("CLICK %s:LeftButton",f:GetName())))
837 end
838
839 -- This is a bit hokey : install a bare hook on ActionButton_UpdateHotkey because
840 -- even though it's secure it's never called in a way that can cause taint. This is
841 -- for performance reasons to avoid having to hook frame:OnEvent securely.
842 local UpdateHotkey_old = ActionButton_UpdateHotkeys
843 ActionButton_UpdateHotkeys = function( frame, ... )
844 local b = frame._reactionButton
845 if b then
846 b.hotkey:SetText( GetHotkey(frame) )
847 else
848 return UpdateHotkey_old(frame, ...)
849 end
850 end
851 end
852
853 local meta = {__index = Button}
854
855 function Button:New( handle, idx, config, barConfig )
856 local bar = handle.bar
857
858 -- create new self
859 self = setmetatable(
860 {
861 bar = bar,
862 idx = idx,
863 config = config,
864 barConfig = barConfig,
865 }, meta )
866
867 local name = config.name or ("ReAction_%s_%s_%d"):format(bar:GetName(),moduleID,idx)
868 self.name = name
869 config.name = name
870 local lastButton = handle:GetLastButton()
871 config.actionID = IDAlloc:Acquire(config.actionID, lastButton and lastButton.config.actionID) -- gets a free one if none configured
872 self.nPages = 1
873
874 -- have to recycle frames with the same name: CreateFrame() doesn't overwrite
875 -- existing globals. Can't set to nil in the global because it's then tainted.
876 local parent = bar:GetFrame()
877 local f = frameRecycler[name]
878 if f then
879 f:SetParent(parent)
880 else
881 f = CreateFrame("CheckButton", name, parent, "ActionBarButtonTemplate")
882 -- ditch the old hotkey text because it's tied in ActionButton_Update() to the
883 -- standard binding.
884 local hotkey = _G[name.."HotKey"]
885 hotkey:SetParent(trash)
886 hotkey = f:CreateFontString(nil, "ARTWORK", "NumberFontNormalSmallGray")
887 hotkey:SetWidth(36)
888 hotkey:SetHeight(18)
889 hotkey:SetJustifyH("RIGHT")
890 hotkey:SetJustifyV("TOP")
891 hotkey:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2)
892 f.hotkey = hotkey
893 f.icon = _G[name.."Icon"]
894 f.flash = _G[name.."Flash"]
895 f:SetScript("OnUpdate",OnUpdate)
896 end
897
898 f._reactionButton = self
899
900 self.hotkey = f.hotkey
901 self.border = _G[name.."Border"]
902
903 f:SetAttribute("action", config.actionID)
904 f:SetAttribute("default-action", config.actionID)
905 -- install mind control actions for all buttons just for simplicity
906 if self.idx <= 12 then
907 f:SetAttribute("mc-action", 120 + self.idx)
908 end
909
910 -- set a tooltip onEnter
911 f:SetScript("OnEnter",
912 function(frame)
913 if ReAction:GetKeybindMode() then
914 KB:Set(frame)
915 elseif frame.vehicleExitMode then
916 GameTooltip_AddNewbieTip(frame, LEAVE_VEHICLE, 1.0, 1.0, 1.0, nil);
917 else
918 ActionButton_SetTooltip(frame)
919 end
920 end)
921
922 -- set a _childupdate handler, called within the header's context
923 f:SetAttribute("_childupdate",
924 -- function _childupdate(self, snippetid, message)
925 [[
926 local action = "default-action"
927 if (doVehicle and mcVehicleState == "vehicle") or
928 (doMindControl and mcVehicleState == "mc") then
929 action = "mc-action"
930 elseif page and state and page[state] then
931 action = "action-"..page[state]
932 end
933
934 local value = self:GetAttribute(action)
935 if value then
936 self:SetAttribute("action",value)
937 end
938 ]])
939
940 -- Install a handler for the 7th button (only) to show/hide a
941 -- vehicle exit button. This is more than a little bit hack-ish and
942 -- will be replaced in the next iteration with the reimplementation
943 -- of action button functionality.
944 if idx == 7 then
945 local barFrame = bar:GetFrame()
946 function barFrame:ShowVehicleExit(show)
947 local tx = f.vehicleExitTexture
948 if show then
949 if not tx then
950 tx = f:CreateTexture(nil,"ARTWORK")
951 tx:SetAllPoints()
952 -- copied from Blizzard/VehicleMenuBar.lua SkinsData
953 tx:SetTexture("Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up")
954 tx:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
955 f.vehicleExitTexture = tx
956 end
957 tx:Show()
958 f.vehicleExitMode = true
959 elseif tx then
960 tx:SetTexCoord(0,1,0,1)
961 tx:Hide()
962 f.vehicleExitMode = false
963 end
964 end
965
966 f:SetAttribute("macrotext","/run VehicleExit()")
967 f:SetAttribute("_childupdate-vehicle",
968 -- function _childupdate-vehicle(self, snippetid, message)
969 [[
970 local show = (mcVehicleState == "vehicle")
971 if show then
972 self:SetAttribute("type","macro")
973 self:SetAttribute("showgrid",self:GetAttribute("showgrid")+1)
974 self:Show()
975 else
976 self:SetAttribute("type","action")
977 local showgrid = self:GetAttribute("showgrid")
978 showgrid = showgrid - 1
979 if showgrid < 0 then showgrid = 0 end
980 self:SetAttribute("showgrid",self:GetAttribute("showgrid")-1)
981 if showgrid <= 0 then
982 self:Hide()
983 end
984 end
985 control:CallMethod("ShowVehicleExit",show)
986 ]])
987 end
988
989 -- install drag wrappers to lock buttons
990 bar:GetFrame():WrapScript(f, "OnDragStart",
991 -- OnDragStart(self, button, kind, value, ...)
992 [[
993 if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
994 return "clear"
995 end
996 ]])
997
998 self.frame = f
999
1000 -- initialize the hide state
1001 f:SetAttribute("showgrid",0)
1002 self:ShowGrid(not barConfig.hideEmpty)
1003 if ReAction:GetConfigMode() then
1004 self:ShowGrid(true)
1005 end
1006
1007 -- set the hotkey text
1008 self.hotkey:SetText( GetHotkey(self.frame) )
1009
1010 -- show the ID label if applicable
1011 self:ShowActionIDLabel(ReAction:GetConfigMode())
1012
1013 -- attach to skinner
1014 bar:SkinButton(self,
1015 {
1016 HotKey = self.hotkey,
1017 }
1018 )
1019
1020 self:Refresh()
1021 return self
1022 end
1023
1024 function Button:Destroy()
1025 local f = self.frame
1026 f:UnregisterAllEvents()
1027 f:Hide()
1028 f:SetParent(UIParent)
1029 f:ClearAllPoints()
1030 f:SetAttribute("_childupdate",nil)
1031 f:SetAttribute("_childupdate-vehicle",nil)
1032 if self.name then
1033 frameRecycler[self.name] = f
1034 end
1035 if self.config.actionID then
1036 IDAlloc:Release(self.config.actionID)
1037 end
1038 if self.config.pageactions then
1039 for _, id in ipairs(self.config.pageactions) do
1040 IDAlloc:Release(id)
1041 end
1042 end
1043 f._reactionButton = nil
1044 self.frame = nil
1045 self.config = nil
1046 self.bar = nil
1047 end
1048
1049 function Button:Refresh()
1050 local f = self.frame
1051 self.bar:PlaceButton(self, 36, 36)
1052 self:RefreshPages()
1053 end
1054
1055 function Button:GetFrame()
1056 return self.frame
1057 end
1058
1059 function Button:GetName()
1060 return self.name
1061 end
1062
1063 function Button:GetConfig()
1064 return self.config
1065 end
1066
1067 function Button:GetActionID(page)
1068 if page == nil then
1069 -- get the effective ID
1070 return self.frame.action -- kept up-to-date by Blizzard's ActionButton_CalculateAction()
1071 else
1072 if page == 1 then
1073 return self.config.actionID
1074 else
1075 return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
1076 end
1077 end
1078 end
1079
1080 function Button:SetActionID( id, page )
1081 id = tonumber(id)
1082 page = tonumber(page)
1083 if id == nil or id < 1 or id > 120 then
1084 error("Button:SetActionID - invalid action ID")
1085 end
1086 if page and page ~= 1 then
1087 if not self.config.pageactions then
1088 self.config.pageactions = { }
1089 end
1090 if self.config.pageactions[page] then
1091 IDAlloc:Release(self.config.pageactions[page])
1092 end
1093 self.config.pageactions[page] = id
1094 IDAlloc:Acquire(self.config.pageactions[page])
1095 self.frame:SetAttribute(("action-page%d"):format(page),id)
1096 else
1097 IDAlloc:Release(self.config.actionID)
1098 self.config.actionID = id
1099 IDAlloc:Acquire(self.config.actionID)
1100 self.frame:SetAttribute("action",id)
1101 if self.config.pageactions then
1102 self.config.pageactions[1] = id
1103 self.frame:SetAttribute("action-page1",id)
1104 end
1105 end
1106 end
1107
1108 function Button:RefreshPages( force )
1109 local nPages = self.barConfig.nPages
1110 if nPages and (nPages ~= self.nPages or force) then
1111 local f = self:GetFrame()
1112 local c = self.config.pageactions
1113 if nPages > 1 and not c then
1114 c = { }
1115 self.config.pageactions = c
1116 end
1117 for i = 1, nPages do
1118 if i > 1 then
1119 c[i] = IDAlloc:Acquire(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
1120 else
1121 c[i] = self.config.actionID -- page 1 is the same as the base actionID
1122 end
1123 f:SetAttribute(("action-page%d"):format(i),c[i])
1124 end
1125 for i = nPages+1, #c do
1126 IDAlloc:Release(c[i])
1127 c[i] = nil
1128 f:SetAttribute(("action-page%d"):format(i),nil)
1129 end
1130 self.nPages = nPages
1131 end
1132 end
1133
1134 function Button:ShowGrid( show )
1135 if not InCombatLockdown() then
1136 local f = self.frame
1137 local count = f:GetAttribute("showgrid")
1138 if show then
1139 count = count + 1
1140 else
1141 count = count - 1
1142 end
1143 if count < 0 then
1144 count = 0
1145 end
1146 f:SetAttribute("showgrid",count)
1147
1148 if count >= 1 and not f:GetAttribute("statehidden") then
1149 if LBF then
1150 LBF:SetNormalVertexColor(self.frame, 1.0, 1.0, 1.0, 0.5)
1151 else
1152 self.frame:GetNormalTexture():SetVertexColor(1.0, 1.0, 1.0, 0.5);
1153 end
1154 f:Show()
1155 elseif count < 1 and not HasAction(self:GetActionID()) then
1156 f:Hide()
1157 end
1158 end
1159 end
1160
1161 function Button:ShowActionIDLabel( show )
1162 local f = self:GetFrame()
1163 if show then
1164 local id = self:GetActionID()
1165 if not f.actionIDLabel then
1166 local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
1167 label:SetAllPoints()
1168 label:SetJustifyH("CENTER")
1169 label:SetShadowColor(0,0,0,1)
1170 label:SetShadowOffset(2,-2)
1171 f.actionIDLabel = label -- store the label with the frame for recycling
1172
1173 f:HookScript("OnAttributeChanged",
1174 function(frame, attr, value)
1175 if label:IsVisible() and attr:match("action") then
1176 label:SetText(tostring(frame.action))
1177 end
1178 end)
1179 end
1180 f.actionIDLabel:SetText(tostring(id))
1181 f.actionIDLabel:Show()
1182 elseif f.actionIDLabel then
1183 f.actionIDLabel:Hide()
1184 end
1185 end
1186
1187 function Button:SetKeybindMode( mode )
1188 if mode then
1189 self.frame.GetActionName = GetActionName
1190 self.frame.GetHotkey = GetHotkey
1191 -- set the border for all buttons to the keybind-enable color
1192 self.border:SetVertexColor(KB:GetColorKeyBoundMode())
1193 self.border:Show()
1194 elseif IsEquippedAction(self:GetActionID()) then
1195 self.border:SetVertexColor(0, 1.0, 0, 0.35) -- from ActionButton.lua
1196 else
1197 self.border:Hide()
1198 end
1199 end