Nenue@0
|
1 --------------------------------------------
|
Nenue@5
|
2 -- SkeletonKey
|
Nenue@5
|
3 -- Krakyn-Mal'Ganis
|
Nenue@0
|
4 -- @project-revision@ @project-hash@
|
Nenue@0
|
5 -- @file-revision@ @file-hash@
|
Nenue@0
|
6 -- Created: 6/16/2016 3:47 AM
|
Nenue@0
|
7 --------------------------------------------
|
Nenue@0
|
8 -- kb
|
Nenue@5
|
9 -- .StoreBinding(button, key) bind current keystroke to command
|
Nenue@5
|
10 -- .GetSlot(index) return display slot
|
Nenue@5
|
11 -- .SetSlot(button, command, name, icon) assign display slot
|
Nenue@5
|
12 -- .ReleaseSlot(button) clear button command
|
Nenue@5
|
13 -- .UpdateSlot(button) update button contents
|
Nenue@5
|
14 -- .SelectProfile(name) set profile character
|
Nenue@5
|
15 -- .ApplyBindings(bindings) walk table with SetBinding()
|
Nenue@0
|
16
|
Nenue@5
|
17 local _
|
Nenue@5
|
18 local kb, print = LibStub("LibKraken").register(KeyBinder)
|
Nenue@1
|
19 local db
|
Nenue@5
|
20 local cprint = DEVIAN_WORKSPACE and function(...) _G.print('Cfg', ...) end or function() end
|
Nenue@1
|
21
|
Nenue@5
|
22 --- Caps Lock literals
|
Nenue@5
|
23 local CLICK_KEYBINDER_MACRO = "CLICK KeyBinderMacro:"
|
Nenue@5
|
24 local BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).'
|
Nenue@5
|
25 local BINDING_REMOVED = '|cFFFFFF00%s|r (|cFF00FFFF%s|r) unbound.'
|
Nenue@5
|
26 local BINDING_FAILED_PROTECTED = '|cFFFF4400Unable to use |r|cFF00FF00%s|r|cFFFF4400 (currently |cFFFFFF00%s|r|cFFFF4400)|r'
|
Nenue@5
|
27 local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES"
|
Nenue@5
|
28 local FOOTER_OFFSET
|
Nenue@5
|
29 local HEADER_OFFSET
|
Nenue@5
|
30 local HELP_1 = "Drag and drop spells/items from your inventory, spellbook, or collections panels."
|
Nenue@5
|
31 local HELP_2 = "While the cursor is above an icon, up to two key combinations will be bound to that action."
|
Nenue@5
|
32 local HELP_3 = "If that key used for a client binding (e.g. game menu), a confirmation popup will appear before making the change."
|
Nenue@5
|
33 local BINDS_PER_ROW = 2
|
Nenue@5
|
34 local BUTTON_HSPACING = 128
|
Nenue@5
|
35 local BUTTON_SPACING = 4
|
Nenue@5
|
36 local BUTTON_PADDING = 12
|
Nenue@5
|
37 local BINDING_TYPE_SPECIALIZATION = 3
|
Nenue@5
|
38 local BINDING_TYPE_CHARACTER = 2
|
Nenue@5
|
39 local BINDING_TYPE_GLOBAL = 1
|
Nenue@5
|
40 local KEY_BUTTON_SIZE = 48
|
Nenue@0
|
41 local MIN_BIND_SLOTS = 32
|
Nenue@5
|
42 local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544
|
Nenue@0
|
43 local TAB_OFFSET = 12
|
Nenue@0
|
44 local TAB_HEIGHT = 40
|
Nenue@0
|
45 local TAB_SPACING = 2
|
Nenue@5
|
46 local BORDER_UNASSIGNED = {0.2,0.2,0.2,1 }
|
Nenue@5
|
47 local BORDER_ASSIGNED = {0.5,0.5,0.5,1 }
|
Nenue@5
|
48 local BORDER_DYNAMIC = {1,1,0,1}
|
Nenue@5
|
49 local BORDER_PENDING = {1,0.5,0,1 }
|
Nenue@5
|
50 local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION
|
Nenue@5
|
51
|
Nenue@5
|
52
|
Nenue@5
|
53 --- Caps Lock derivatives
|
Nenue@5
|
54 local ACTION_SCRIPT = {
|
Nenue@5
|
55 ['mount'] = "/script C_MountJournal.SummonByID(%d)",
|
Nenue@5
|
56 ['macro'] = "%s",
|
Nenue@5
|
57 ['equipset'] = "/script UseEquipmentSet(%d)",
|
Nenue@5
|
58 ['spell'] = "/cast %s",
|
Nenue@5
|
59 ['petaction'] = "/cast %s",
|
Nenue@5
|
60 ['battlepet'] = SLASH_SUMMON_BATTLE_PET1 .. " %s",
|
Nenue@5
|
61 ['item'] = "/use %s"
|
Nenue@5
|
62 }
|
Nenue@5
|
63 local BUTTON_HEADERS = {
|
Nenue@5
|
64 ['spell'] = SPELLS,
|
Nenue@5
|
65 ['macro'] = MACRO,
|
Nenue@5
|
66 ['petaction'] = PET,
|
Nenue@5
|
67 ['mount'] = MOUNT,
|
Nenue@5
|
68 ['battlepet'] = BATTLEPET,
|
Nenue@5
|
69
|
Nenue@5
|
70
|
Nenue@5
|
71 [5] = PROFESSIONS_FIRST_AID,
|
Nenue@5
|
72 [7] = PROFESSIONS_COOKING,
|
Nenue@5
|
73 [9] = PROFESSIONS_FISHING,
|
Nenue@5
|
74 [10] = PROFESSIONS_ARCHAEOLOGY,
|
Nenue@5
|
75
|
Nenue@5
|
76 }
|
Nenue@5
|
77
|
Nenue@5
|
78 local professionMappings = {
|
Nenue@5
|
79 [5] = 3,
|
Nenue@5
|
80 [7] = 4,
|
Nenue@5
|
81 [9] = 5,
|
Nenue@5
|
82 [10] = 6
|
Nenue@5
|
83 }
|
Nenue@5
|
84
|
Nenue@0
|
85 local BINDING_MODE = {
|
Nenue@5
|
86 [BINDING_TYPE_GLOBAL] = 'Global Binds',
|
Nenue@0
|
87 [BINDING_TYPE_CHARACTER] = 'Character: %s',
|
Nenue@5
|
88 [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s'
|
Nenue@0
|
89 }
|
Nenue@5
|
90 local BINDING_DESCRIPTION = {
|
Nenue@5
|
91
|
Nenue@5
|
92 [BINDING_TYPE_GLOBAL] = 'The bindings are applied globally.',
|
Nenue@5
|
93 [BINDING_TYPE_CHARACTER] = 'Applied when you log onto this character.',
|
Nenue@5
|
94 [BINDING_TYPE_SPECIALIZATION] = 'Applied when you log onto this character and are that specialization.',
|
Nenue@5
|
95 }
|
Nenue@5
|
96
|
Nenue@0
|
97 local BINDING_SCHEME_COLOR = {
|
Nenue@5
|
98 [BINDING_TYPE_GLOBAL] = {0,.125,.5,.5},
|
Nenue@0
|
99 [BINDING_TYPE_CHARACTER] = {0,0.25,0,0.5},
|
Nenue@5
|
100 [BINDING_TYPE_SPECIALIZATION] = {.25,0,0,0.5},
|
Nenue@0
|
101 }
|
Nenue@0
|
102 local BINDING_SCHEME_VERTEX = {
|
Nenue@5
|
103 [BINDING_TYPE_GLOBAL] = {0,.5,1,1},
|
Nenue@5
|
104 [BINDING_TYPE_CHARACTER] = {0,1,0,1},
|
Nenue@0
|
105 [BINDING_TYPE_SPECIALIZATION] = {1,1,1,1},
|
Nenue@0
|
106 }
|
Nenue@0
|
107 local BINDING_SCHEME_TEXT = {
|
Nenue@5
|
108 [BINDING_TYPE_SPECIALIZATION] = {0, 1, 1},
|
Nenue@0
|
109 [BINDING_TYPE_CHARACTER] = {0, 1, 0},
|
Nenue@0
|
110 [BINDING_TYPE_GLOBAL] = {0, 1, 1}
|
Nenue@0
|
111 }
|
Nenue@0
|
112
|
Nenue@0
|
113
|
Nenue@0
|
114
|
Nenue@5
|
115 local loadedProfiles = {}
|
Nenue@5
|
116 -- Profiles ordered by precedance
|
Nenue@5
|
117 local priority = {}
|
Nenue@5
|
118 -- Button pointers
|
Nenue@5
|
119 local buttons = {}
|
Nenue@5
|
120 -- Backlog of changes
|
Nenue@5
|
121 local reverts = {}
|
Nenue@5
|
122 -- macro buttons used for mounts and other buttonable non-spells
|
Nenue@5
|
123 local macros = {}
|
Nenue@5
|
124 -- currently active non-blizzard keybinds
|
Nenue@5
|
125 local bindings = {}
|
Nenue@5
|
126 -- unselected talents
|
Nenue@5
|
127 local talentBindings = {}
|
Nenue@5
|
128 kb.inactiveTalentBindings = {}
|
Nenue@5
|
129 -- placeholder for the StaticPopup used for confirmations
|
Nenue@5
|
130 local confirmation
|
Nenue@5
|
131 -- header text
|
Nenue@5
|
132 local configHeaders = {}
|
Nenue@0
|
133
|
Nenue@0
|
134 local protected = {
|
Nenue@0
|
135 ['OPENCHATSLASH'] = true,
|
Nenue@0
|
136 ['OPENCHAT'] = true,
|
Nenue@0
|
137 }
|
Nenue@5
|
138
|
Nenue@5
|
139 --- Used to reflect the current working state
|
Nenue@5
|
140 local bindMode = 3
|
Nenue@5
|
141 local bindHeader, currentHeader = '', ''
|
Nenue@5
|
142 local configProfile, character, specialization, global, character_specialization
|
Nenue@5
|
143 local specID, specGlobalID, specName, specDesc, specTexture, characterHeader = 0, 0, 'SPEC_NAME', 'SPEC_DESCRIPTION', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME'
|
Nenue@5
|
144 local classHeader, className, classID = '', '', 0
|
Nenue@5
|
145 local numButtons = BINDS_PER_ROW * 8
|
Nenue@5
|
146 local bindsCommitted = true
|
Nenue@5
|
147 local forceButtonUpdate = false
|
Nenue@5
|
148
|
Nenue@5
|
149 --- Control handles
|
Nenue@0
|
150 local saveButton, restoreButton, clearButton
|
Nenue@0
|
151
|
Nenue@5
|
152 --- Cursor "pickup" actuators
|
Nenue@5
|
153 local PickupAction = {}
|
Nenue@5
|
154 PickupAction.spell = _G.PickupSpell
|
Nenue@5
|
155 PickupAction.macro = _G.PickupMacro
|
Nenue@5
|
156 PickupAction.item = _G.PickupItem
|
Nenue@5
|
157 PickupAction.mount = _G.C_MountJournal.Pickup
|
Nenue@5
|
158 local GetPickupValue = {}
|
Nenue@5
|
159 GetPickupValue.spell = function(self) return select(7, GetSpellInfo(self.actionID)) end
|
Nenue@5
|
160
|
Nenue@5
|
161 --- Returns conflicting assignment and binding profiles for use in displaying confirmations
|
Nenue@5
|
162 local IsCommandBound = function(self, command)
|
Nenue@5
|
163 local isAssigned, assignedBy = false, bindMode
|
Nenue@5
|
164 local isBound, boundBy = false, bindMode
|
Nenue@5
|
165
|
Nenue@5
|
166
|
Nenue@5
|
167 command = command or self.command
|
Nenue@5
|
168 for i = 1, #BINDING_MODE do
|
Nenue@0
|
169 local tier = priority[i]
|
Nenue@5
|
170 if i ~= bindMode then
|
Nenue@5
|
171
|
Nenue@5
|
172 if tier.commands[command] then
|
Nenue@5
|
173 isAssigned = true
|
Nenue@5
|
174 assignedBy = i
|
Nenue@5
|
175 end
|
Nenue@5
|
176 if tier.bound[command] then
|
Nenue@5
|
177 isBound = true
|
Nenue@5
|
178 boundBy = i
|
Nenue@5
|
179 end
|
Nenue@5
|
180
|
Nenue@5
|
181
|
Nenue@5
|
182 --print(' *', configHeaders[i], tier.commands[command], tier.bound[command])
|
Nenue@5
|
183
|
Nenue@5
|
184 if isAssigned and isBound then
|
Nenue@0
|
185 break
|
Nenue@0
|
186 end
|
Nenue@0
|
187 end
|
Nenue@5
|
188
|
Nenue@0
|
189 end
|
Nenue@5
|
190
|
Nenue@5
|
191 print('|cFFFFFF00IsCommandBound:|r', command:gsub(CLICK_KEYBINDER_MACRO, ''),'|r [profile:', bindMode .. ']', isAssigned, isBound, assignedBy, boundBy)
|
Nenue@5
|
192 return isAssigned, isBound, assignedBy, boundBy
|
Nenue@0
|
193 end
|
Nenue@0
|
194
|
Nenue@5
|
195 local talentSpellHardCodes = {
|
Nenue@5
|
196 [109248] = 'Binding Shot',
|
Nenue@5
|
197 }
|
Nenue@5
|
198
|
Nenue@0
|
199 --- Returns a value for use with Texture:SetDesaturated()
|
Nenue@0
|
200 local BindingIsLocked = function(key)
|
Nenue@0
|
201 local success = false
|
Nenue@0
|
202 for i = 1, bindMode-1 do
|
Nenue@0
|
203 local tier = priority[i]
|
Nenue@0
|
204 if tier.bindings[key] then
|
Nenue@0
|
205 success = true
|
Nenue@0
|
206 break
|
Nenue@0
|
207 end
|
Nenue@0
|
208 end
|
Nenue@0
|
209 return success
|
Nenue@0
|
210 end
|
Nenue@0
|
211
|
Nenue@0
|
212 --- Translates GetBindingKey() results into a printable string.
|
Nenue@0
|
213 local BindingString = function(...)
|
Nenue@0
|
214 local stack = {}
|
Nenue@0
|
215 for i = 1, select('#', ...) do
|
Nenue@0
|
216 local key = select(i, ...)
|
Nenue@5
|
217 stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ')
|
Nenue@0
|
218 end
|
Nenue@0
|
219
|
Nenue@0
|
220 if #stack >= 1 then
|
Nenue@0
|
221 return table.concat(stack, ',')
|
Nenue@0
|
222 else
|
Nenue@0
|
223 return nil
|
Nenue@0
|
224 end
|
Nenue@0
|
225 end
|
Nenue@0
|
226
|
Nenue@5
|
227 local restingAlpha = 0.7
|
Nenue@5
|
228 local fadeTime, fadeDelay = .30, 0.15
|
Nenue@5
|
229
|
Nenue@5
|
230 local portraitLayers = {}
|
Nenue@5
|
231 kb.UpdatePortraits = function()
|
Nenue@5
|
232 for i, layeredRegion in ipairs(portraitLayers) do
|
Nenue@5
|
233 SetPortraitTexture(layeredRegion , 'player')
|
Nenue@5
|
234 end
|
Nenue@5
|
235 end
|
Nenue@5
|
236
|
Nenue@5
|
237
|
Nenue@5
|
238
|
Nenue@5
|
239 local KeyButton_OnKeyDown = function(self, key)
|
Nenue@5
|
240 kb.StoreBinding(self, key)
|
Nenue@5
|
241 end
|
Nenue@5
|
242 local KeyButton_OnClick = function(self, click)
|
Nenue@5
|
243 print(self:GetName(), 'OnMouseDown', click)
|
Nenue@5
|
244 if click == 'LeftButton' then
|
Nenue@5
|
245 kb.DropToSlot(self)
|
Nenue@5
|
246 elseif click == 'RightButton' then
|
Nenue@5
|
247 kb.ReleaseSlot(self)
|
Nenue@5
|
248 else
|
Nenue@5
|
249 kb.StoreBinding(self, click:upper())
|
Nenue@5
|
250 end
|
Nenue@5
|
251 end
|
Nenue@5
|
252
|
Nenue@5
|
253 local KeyButton_OnDragStart = function(self)
|
Nenue@5
|
254 kb.PickupSlot(self)
|
Nenue@5
|
255 end
|
Nenue@5
|
256
|
Nenue@5
|
257 local KeyButton_OnReceiveDrag = function(self, ...)
|
Nenue@5
|
258 kb.DropToSlot(self)
|
Nenue@5
|
259 end
|
Nenue@5
|
260
|
Nenue@5
|
261
|
Nenue@5
|
262 local KeyBinder_OnUpdate = function(self, elapsed)
|
Nenue@5
|
263 self.elapsed = self.elapsed + elapsed
|
Nenue@5
|
264 self.throttle = self.throttle + elapsed
|
Nenue@5
|
265
|
Nenue@5
|
266 if (self.throttle >= 0.032) then
|
Nenue@5
|
267 self.throttle = 0
|
Nenue@5
|
268 else
|
Nenue@5
|
269 return
|
Nenue@5
|
270 end
|
Nenue@5
|
271
|
Nenue@5
|
272 local progress = 1
|
Nenue@5
|
273 if self.elapsed > fadeTime then
|
Nenue@5
|
274 self.elapsed = 0
|
Nenue@5
|
275 self.fadeStep = 0
|
Nenue@5
|
276 --self.statustext:SetText(nil)
|
Nenue@5
|
277 --self.bindingstext:SetText(nil)
|
Nenue@5
|
278 self:SetScript('OnUpdate', nil)
|
Nenue@5
|
279 else
|
Nenue@5
|
280 if self.elapsed < fadeDelay then
|
Nenue@5
|
281 progress = 0
|
Nenue@5
|
282 else
|
Nenue@5
|
283 self.fadeStep = self.fadeStep + 1
|
Nenue@5
|
284 progress = (self.elapsed - fadeDelay) /(fadeTime - fadeDelay)
|
Nenue@5
|
285 end
|
Nenue@5
|
286 --print(self.fadeStep, format('%.02f/%.02f', (self.elapsed - fadeDelay) ,(fadeTime - fadeDelay)) , progress)
|
Nenue@5
|
287 end
|
Nenue@5
|
288
|
Nenue@5
|
289 local alpha = 1 - progress * (1- restingAlpha)
|
Nenue@5
|
290 self.statustext:SetAlpha(alpha)
|
Nenue@5
|
291 self.bindingstext:SetAlpha(alpha)
|
Nenue@5
|
292 end
|
Nenue@5
|
293
|
Nenue@5
|
294 local KeyButton_OnUpdate = function(self)
|
Nenue@0
|
295 if not self.command then
|
Nenue@0
|
296 return
|
Nenue@0
|
297 end
|
Nenue@0
|
298
|
Nenue@0
|
299 if self:IsMouseOver() then
|
Nenue@5
|
300 kb.elapsed = 0
|
Nenue@0
|
301 if not self.active then
|
Nenue@0
|
302 -- only set this handler when the button is activated/mouseOver
|
Nenue@0
|
303 self.active = true
|
Nenue@5
|
304 self:SetScript('OnKeyDown', KeyButton_OnKeyDown)
|
Nenue@0
|
305
|
Nenue@5
|
306 kb.statustext:SetText(self.statusText .. ': '..self.actionName)
|
Nenue@5
|
307 kb.bindingstext:SetText(self.bindingText)
|
Nenue@5
|
308 kb.fadeStep = 0
|
Nenue@5
|
309 kb.throttle = 0
|
Nenue@5
|
310 kb:SetScript('OnUpdate', KeyBinder_OnUpdate)
|
Nenue@0
|
311
|
Nenue@0
|
312 end
|
Nenue@0
|
313 else
|
Nenue@0
|
314 if self.active then
|
Nenue@0
|
315 self.active = nil
|
Nenue@0
|
316 self:SetScript('OnKeyDown', nil)
|
Nenue@0
|
317 end
|
Nenue@0
|
318 end
|
Nenue@0
|
319 end
|
Nenue@0
|
320
|
Nenue@5
|
321 local KeyBinder_OnMouseWheel = function(self, delta)
|
Nenue@5
|
322 print(self, delta, self.scrollOffset, (self.scrollOffset <= 0))
|
Nenue@0
|
323
|
Nenue@5
|
324
|
Nenue@5
|
325 if IsControlKeyDown() then
|
Nenue@5
|
326 KEY_BUTTON_SIZE = KEY_BUTTON_SIZE - delta
|
Nenue@5
|
327 else
|
Nenue@5
|
328
|
Nenue@5
|
329
|
Nenue@5
|
330 if (delta > 0) and (self.scrollOffset <= 0) then
|
Nenue@5
|
331 return
|
Nenue@5
|
332 elseif delta < 0 and kb.scrollOffset >= 42 then
|
Nenue@5
|
333 return
|
Nenue@5
|
334 end
|
Nenue@5
|
335 kb.scrollOffset = ceil(kb.scrollOffset - (delta * BINDS_PER_ROW))
|
Nenue@5
|
336 end
|
Nenue@5
|
337
|
Nenue@5
|
338 kb.ui(true)
|
Nenue@5
|
339 end
|
Nenue@5
|
340
|
Nenue@5
|
341 local KeyBinder_OnHide = function()
|
Nenue@5
|
342 KeyBinderImportLog:Hide()
|
Nenue@5
|
343 end
|
Nenue@5
|
344
|
Nenue@5
|
345 local CloseButton_OnClick = function()
|
Nenue@5
|
346 db.showUI = false
|
Nenue@5
|
347 kb:Hide()
|
Nenue@5
|
348 end
|
Nenue@5
|
349 local CancelButton_OnClick = function()
|
Nenue@5
|
350 kb.RevertBindings()
|
Nenue@5
|
351 end
|
Nenue@5
|
352 local SaveButton_OnClick = function()
|
Nenue@5
|
353 kb.ConfirmBindings()
|
Nenue@5
|
354 end
|
Nenue@5
|
355
|
Nenue@5
|
356 local KeyBinder_Initialize = function()
|
Nenue@5
|
357 for i = 1, GetNumBindings() do
|
Nenue@5
|
358 local command = GetBinding(i)
|
Nenue@5
|
359 bindings[command] = true
|
Nenue@5
|
360 end
|
Nenue@5
|
361
|
Nenue@5
|
362 kb.scrollOffset = 0
|
Nenue@5
|
363 kb.tabAnchor = {'TOPLEFT', kb.profilebg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING}
|
Nenue@5
|
364 kb.tabGrowth = {'TOPLEFT', nil,'TOPRIGHT', BUTTON_SPACING, 0}
|
Nenue@5
|
365 kb.tabSize = {TAB_HEIGHT, TAB_HEIGHT }
|
Nenue@5
|
366 kb.UIPanelAnchor = {'TOPLEFT', kb.sourcesbg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING}
|
Nenue@5
|
367 kb.UIPanelGrowth = {'TOPLEFT', nil, 'BOTTOMLEFT', 0, -2 }
|
Nenue@5
|
368 kb.UIPanelSize = {84, 32 }
|
Nenue@5
|
369 kb.UIPanelIcon = {24, 32, 'LEFT', -12, 0}
|
Nenue@5
|
370 kb.controlsAnchor = {'BOTTOMLEFT', kb.footer, BUTTON_PADDING, BUTTON_PADDING }
|
Nenue@5
|
371 kb.controlsGrowth = {'BOTTOMLEFT', nil, 'BOTTOMRIGHT', BUTTON_SPACING, 0}
|
Nenue@5
|
372
|
Nenue@5
|
373 -- order of these is important
|
Nenue@5
|
374 kb:tab('KeyBinderGlobalTab',
|
Nenue@5
|
375 BINDING_MODE[BINDING_TYPE_GLOBAL] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_GLOBAL], "Interface\\ICONS\\item_azereansphere", {0.15,.85,.15,.85})
|
Nenue@5
|
376 kb:tab('KeyBinderCharacterTab',
|
Nenue@5
|
377 configHeaders[BINDING_TYPE_CHARACTER] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_CHARACTER], nil)
|
Nenue@5
|
378 kb:tab('KeyBinderSpecTab',
|
Nenue@5
|
379 configHeaders[BINDING_TYPE_SPECIALIZATION] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_SPECIALIZATION], specTexture)
|
Nenue@5
|
380 KeyBinderCharacterTab.icon:SetTexCoord(0.15,.85,.15,.85)
|
Nenue@5
|
381
|
Nenue@5
|
382
|
Nenue@5
|
383
|
Nenue@5
|
384 portraitLayers[1] = KeyBinderCharacterTab.icon
|
Nenue@5
|
385
|
Nenue@5
|
386 saveButton = kb:button('KeyBinderSaveButton', 'Save', 'Commit all changes.', SaveButton_OnClick)
|
Nenue@5
|
387 --restoreButton = kb:button('KeyBinderRestoreButton', 'Discard', 'Revert all changes.', CancelButton_OnClick)
|
Nenue@5
|
388 --clearButton = kb:button('KeyBinderClearButton', 'Clear Page', 'Release all buttons.', ResetButton_OnClick)
|
Nenue@5
|
389
|
Nenue@5
|
390 kb:uibutton(
|
Nenue@5
|
391 'KeyBinderSpellBookButton', 'SpellBook', nil,
|
Nenue@5
|
392 function() ToggleSpellBook(BOOKTYPE_SPELL) end,
|
Nenue@5
|
393 "Interface\\BUTTONS\\UI-MicroButton-Spellbook-Up", {0, 1, .4, 1})
|
Nenue@5
|
394 kb:uibutton(
|
Nenue@5
|
395 'KeyBinderTalentFrameButton', TALENTS, SPECIALIZATION,
|
Nenue@5
|
396 function() ToggleTalentFrame() end,
|
Nenue@5
|
397 "Interface\\BUTTONS\\UI-MicroButton-Talents-Up", {0, 1, .4, 1})
|
Nenue@5
|
398
|
Nenue@5
|
399 kb:uibutton(
|
Nenue@5
|
400 'KeyBinderMacroFrameButton', 'Macros', nil,
|
Nenue@5
|
401 function() if MacroFrame and MacroFrame:IsVisible() then
|
Nenue@5
|
402 HideUIPanel(MacroFrame)
|
Nenue@5
|
403 else
|
Nenue@5
|
404 ShowMacroFrame() end
|
Nenue@5
|
405 end,
|
Nenue@5
|
406 "Interface\\BUTTONS\\UI-MicroButton-Help-Up", {0, 1, .4, 1})
|
Nenue@5
|
407
|
Nenue@5
|
408 kb:uibutton(
|
Nenue@5
|
409 'KeyBinderInventoryButton', 'Bags', nil,
|
Nenue@5
|
410 function() OpenAllBags() end,
|
Nenue@5
|
411 "Interface\\BUTTONS\\UI-MicroButtonCharacter-Up", {0, 1, .4, 1})
|
Nenue@5
|
412
|
Nenue@5
|
413
|
Nenue@5
|
414
|
Nenue@5
|
415 kb.info:SetPoint('TOPLEFT', kb.UIPanels[1], 'BOTTOMLEFT', 0, -BUTTON_SPACING)
|
Nenue@5
|
416 HEADER_OFFSET = kb.UIPanels[1]:GetHeight() + BUTTON_PADDING
|
Nenue@5
|
417 + kb.info:GetHeight()
|
Nenue@5
|
418 FOOTER_OFFSET = saveButton:GetHeight() + BUTTON_PADDING
|
Nenue@5
|
419
|
Nenue@5
|
420 kb:SetScript('OnHide', KeyBinder_OnHide)
|
Nenue@5
|
421 kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel)
|
Nenue@5
|
422 kb.CloseButton:SetScript('OnClick', CloseButton_OnClick)
|
Nenue@5
|
423
|
Nenue@5
|
424 kb.UpdatePortraits()
|
Nenue@5
|
425 end
|
Nenue@5
|
426
|
Nenue@5
|
427 kb.DropToSlot = function(self)
|
Nenue@5
|
428
|
Nenue@5
|
429 print(self:GetName(),'|cFF0088FFreceived|r')
|
Nenue@5
|
430 local actionType, actionID, subType, subData = GetCursorInfo()
|
Nenue@5
|
431 print('GetCursorInfo', GetCursorInfo())
|
Nenue@5
|
432
|
Nenue@5
|
433
|
Nenue@5
|
434 if actionType then
|
Nenue@5
|
435
|
Nenue@5
|
436 if actionType == 'flyout' then
|
Nenue@5
|
437 ClearCursor()
|
Nenue@5
|
438 ResetCursor()
|
Nenue@5
|
439 return
|
Nenue@5
|
440 end
|
Nenue@5
|
441
|
Nenue@5
|
442
|
Nenue@5
|
443 local macroName, macroText
|
Nenue@5
|
444 local command, name, icon, _
|
Nenue@5
|
445 local pickupID, pickupBook
|
Nenue@5
|
446
|
Nenue@5
|
447 if actionType == 'spell' then
|
Nenue@5
|
448 actionID = subData
|
Nenue@5
|
449 name, _, icon = GetSpellInfo(actionID)
|
Nenue@5
|
450
|
Nenue@5
|
451 elseif actionType == 'macro' then
|
Nenue@5
|
452 name, icon = GetMacroInfo(actionID)
|
Nenue@5
|
453 actionID = name
|
Nenue@5
|
454 elseif actionType == 'petaction' then
|
Nenue@5
|
455 if not (CURSOR_SPELLSLOT and CURSOR_BOOKTYPE) then
|
Nenue@5
|
456
|
Nenue@5
|
457 ClearCursor()
|
Nenue@5
|
458 ResetCursor()
|
Nenue@0
|
459 end
|
Nenue@0
|
460
|
Nenue@5
|
461 local bookType, spellID = GetSpellBookItemInfo(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE)
|
Nenue@5
|
462 pickupID = CURSOR_SPELLSLOT
|
Nenue@5
|
463 pickupBook = CURSOR_BOOKTYPE
|
Nenue@5
|
464 name, _, icon = GetSpellInfo(spellID)
|
Nenue@5
|
465 actionID = name
|
Nenue@5
|
466
|
Nenue@5
|
467 elseif actionType == 'mount' then
|
Nenue@5
|
468 if subType == 0 then
|
Nenue@5
|
469 name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL)
|
Nenue@5
|
470 actionID = 0
|
Nenue@5
|
471 else
|
Nenue@5
|
472 name, _, icon = C_MountJournal.GetMountInfoByID(actionID)
|
Nenue@5
|
473 end
|
Nenue@5
|
474 elseif actionType == 'item' then
|
Nenue@5
|
475 name = GetItemInfo(actionID)
|
Nenue@5
|
476 icon = GetItemIcon(actionID)
|
Nenue@5
|
477 actionID = name
|
Nenue@5
|
478 elseif actionType == 'battlepet' then
|
Nenue@5
|
479
|
Nenue@5
|
480 local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = C_PetJournal.GetPetInfoByPetID(detail);
|
Nenue@5
|
481 name = customName or petName
|
Nenue@5
|
482 icon = petIcon
|
Nenue@5
|
483
|
Nenue@5
|
484 end
|
Nenue@5
|
485 macroName, macroText, command = kb.RegisterAction(actionType, actionID)
|
Nenue@5
|
486
|
Nenue@5
|
487
|
Nenue@5
|
488 local isAssigned, isBound, assignedBy, boundBy = IsCommandBound(self, command)
|
Nenue@5
|
489 if isAssigned then
|
Nenue@5
|
490 local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"]
|
Nenue@5
|
491 popup.slot = self
|
Nenue@5
|
492 popup.text = "Currently assigned in |cFFFFFF00"..tostring(configHeaders[assignedBy]).."|r. Are you sure?"
|
Nenue@5
|
493 popup.oldProfile = assignedBy
|
Nenue@5
|
494 popup.args = {command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook }
|
Nenue@5
|
495 kb:SetScript('OnMouseWheel', nil) -- disable scrolling
|
Nenue@5
|
496 StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT')
|
Nenue@5
|
497 else
|
Nenue@5
|
498 kb.SetSlot(self, command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook)
|
Nenue@5
|
499 kb.UpdateSlot(self)
|
Nenue@5
|
500 self.active = nil
|
Nenue@5
|
501 KeyButton_OnUpdate(self, 0)
|
Nenue@5
|
502 ClearCursor()
|
Nenue@5
|
503 ResetCursor()
|
Nenue@0
|
504 end
|
Nenue@0
|
505 end
|
Nenue@0
|
506 end
|
Nenue@0
|
507
|
Nenue@5
|
508 kb.PickupSlot = function(self)
|
Nenue@0
|
509 if not self.command then
|
Nenue@0
|
510 return
|
Nenue@0
|
511 end
|
Nenue@5
|
512 print(self.actionType)
|
Nenue@5
|
513 if self.actionType == 'spell' then
|
Nenue@5
|
514 -- It can't be picked up if SpellInfo(name) returns void
|
Nenue@5
|
515 local dummy = GetSpellInfo(self.actionName)
|
Nenue@5
|
516 if not dummy then
|
Nenue@5
|
517 return
|
Nenue@0
|
518 end
|
Nenue@5
|
519 elseif self.actionType == 'petaction' then
|
Nenue@5
|
520 PickupSpellBookItem(self.pickupSlot, self.pickupBook)
|
Nenue@5
|
521 end
|
Nenue@5
|
522 if PickupAction[self.actionType] then
|
Nenue@5
|
523 if GetPickupValue[self.actionType] then
|
Nenue@5
|
524 PickupAction[self.actionType](GetPickupValue[self.actionType](self))
|
Nenue@5
|
525 else
|
Nenue@5
|
526 PickupAction[self.actionType](self.actionID)
|
Nenue@0
|
527 end
|
Nenue@5
|
528 kb.ReleaseSlot(self)
|
Nenue@5
|
529 kb.UpdateSlot(self)
|
Nenue@0
|
530 end
|
Nenue@0
|
531 end
|
Nenue@0
|
532
|
Nenue@5
|
533
|
Nenue@5
|
534 --- Resolve the appropriate command and assign the corresponding secure state driver
|
Nenue@5
|
535 kb.RegisterAction = function(type, id)
|
Nenue@5
|
536
|
Nenue@5
|
537 if type == 'spell' then
|
Nenue@5
|
538
|
Nenue@5
|
539 id = GetSpellInfo(id)
|
Nenue@5
|
540 end
|
Nenue@5
|
541
|
Nenue@5
|
542 local macroText
|
Nenue@5
|
543 local macroName = type ..'_' .. id
|
Nenue@5
|
544
|
Nenue@5
|
545 if kb.ProfessionCache[id] then
|
Nenue@5
|
546 macroName = "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum
|
Nenue@5
|
547 macroText = "/cast " .. kb.ProfessionCache[id].spellName
|
Nenue@5
|
548 macros[macroName] = nil
|
Nenue@0
|
549 else
|
Nenue@5
|
550 macroName = macroName:gsub(' ', '')
|
Nenue@5
|
551 macroText = ACTION_SCRIPT[type]:format(id)
|
Nenue@0
|
552 end
|
Nenue@5
|
553
|
Nenue@5
|
554 local baseName, iterative = macroName, 1
|
Nenue@5
|
555 while (macros[macroName] and macros[macroName][1] ~= macroText) do
|
Nenue@5
|
556 print(' * cannot use|cFF00FF00', macroName, '|r"'.. (macros[macroName][1] or '') .. '"')
|
Nenue@5
|
557 macroName = baseName .. '_' .. iterative
|
Nenue@5
|
558 iterative = iterative + 1
|
Nenue@5
|
559 end
|
Nenue@5
|
560 if macroName ~= baseName then
|
Nenue@5
|
561 print(' * Creating|cFF00FF00', macroName)
|
Nenue@5
|
562 else
|
Nenue@5
|
563 print(' * Re-using|cFF00FF00', macroName)
|
Nenue@5
|
564 end
|
Nenue@5
|
565
|
Nenue@5
|
566 local command = 'CLICK KeyBinderMacro:'.. macroName
|
Nenue@5
|
567 macros[macroName] = {macroText, command }
|
Nenue@5
|
568 print('RegisterAction', command , macroText)
|
Nenue@5
|
569 if type == 'macro' then
|
Nenue@5
|
570 kb.LoadMacro(macroName)
|
Nenue@5
|
571 else
|
Nenue@5
|
572 kb.LoadAction(macroName, macroText, command)
|
Nenue@5
|
573 end
|
Nenue@5
|
574
|
Nenue@5
|
575
|
Nenue@5
|
576 return macroName, macroText, command
|
Nenue@0
|
577 end
|
Nenue@0
|
578
|
Nenue@5
|
579 kb.LoadMacro = function(macroName)
|
Nenue@5
|
580 KeyBinderMacro:SetAttribute('*macro-'..macroName, macros[macroName][1])
|
Nenue@5
|
581 return true
|
Nenue@5
|
582 end
|
Nenue@5
|
583
|
Nenue@5
|
584 kb.LoadAction = function(macroName)
|
Nenue@5
|
585 if not macros[macroName] then
|
Nenue@5
|
586 return false
|
Nenue@5
|
587 end
|
Nenue@5
|
588 KeyBinderMacro:SetAttribute('*macrotext-'..macroName, macros[macroName][1])
|
Nenue@5
|
589 return true
|
Nenue@5
|
590 end
|
Nenue@5
|
591
|
Nenue@5
|
592 local profressionsCache
|
Nenue@5
|
593
|
Nenue@5
|
594 kb.AcceptAssignment = function(self, ...)
|
Nenue@5
|
595 local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"]
|
Nenue@5
|
596 local source = loadedProfiles[popup.oldProfile]
|
Nenue@5
|
597 kb.SetSlot(popup.slot, unpack(popup.args))
|
Nenue@5
|
598 kb.UpdateSlot(popup.slot)
|
Nenue@5
|
599 kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) -- re-enable scrolling
|
Nenue@5
|
600 ClearCursor()
|
Nenue@5
|
601 ResetCursor()
|
Nenue@5
|
602 end
|
Nenue@5
|
603
|
Nenue@0
|
604
|
Nenue@0
|
605 --- Updates the current KeyBinding for the button's command
|
Nenue@5
|
606 kb.StoreBinding = function(self, key)
|
Nenue@0
|
607
|
Nenue@0
|
608 if not self.command then
|
Nenue@0
|
609 return
|
Nenue@0
|
610 end
|
Nenue@0
|
611
|
Nenue@0
|
612 if key:match('[RL]SHIFT') or key:match('[RL]ALT') or key:match('[RL]CTRL') then
|
Nenue@0
|
613 return
|
Nenue@0
|
614 end
|
Nenue@5
|
615 print('|cFFFFFF00received|cFFFFFF00', self:GetID(), '|cFF00FFFF', key)
|
Nenue@0
|
616
|
Nenue@5
|
617 if key == 'ESCAPE' then
|
Nenue@5
|
618 local keys = {GetBindingKey(self.command) }
|
Nenue@5
|
619 --print('detected', #keys, 'bindings')
|
Nenue@5
|
620 for i, key in pairs(keys) do
|
Nenue@5
|
621 --print('clearing', key)
|
Nenue@5
|
622 SetBinding(key, nil)
|
Nenue@5
|
623 SaveBindings(GetCurrentBindingSet())
|
Nenue@5
|
624 if configProfile.bindings[key] then
|
Nenue@5
|
625 kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[bindMode]))
|
Nenue@5
|
626 configProfile.bindings[key] = nil
|
Nenue@5
|
627 end
|
Nenue@5
|
628 if configProfile.talents[self.actionName] then
|
Nenue@5
|
629 configProfile.talents[self.actionName] = nil
|
Nenue@5
|
630 end
|
Nenue@5
|
631 bindings[self.actionType][self.actionID] = nil
|
Nenue@5
|
632 end
|
Nenue@5
|
633 if configProfile.bound[self.command] then
|
Nenue@5
|
634 configProfile.bound[self.command] = nil
|
Nenue@5
|
635 --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[bindMode]))
|
Nenue@5
|
636 end
|
Nenue@5
|
637
|
Nenue@5
|
638 bindsCommitted = false
|
Nenue@5
|
639 self.active = false
|
Nenue@5
|
640 else
|
Nenue@5
|
641
|
Nenue@5
|
642 local modifier = ''
|
Nenue@5
|
643 if IsAltKeyDown() then
|
Nenue@5
|
644 modifier = 'ALT-'
|
Nenue@5
|
645 end
|
Nenue@5
|
646 if IsControlKeyDown() then
|
Nenue@5
|
647 modifier = modifier.. 'CTRL-'
|
Nenue@5
|
648 end
|
Nenue@5
|
649 if IsShiftKeyDown() then
|
Nenue@5
|
650 modifier = modifier..'SHIFT-'
|
Nenue@5
|
651 end
|
Nenue@5
|
652
|
Nenue@5
|
653
|
Nenue@5
|
654 if self.command then
|
Nenue@5
|
655 self.binding = modifier..key
|
Nenue@5
|
656
|
Nenue@5
|
657 local previousKeys
|
Nenue@5
|
658 local previousAction = GetBindingAction(self.binding)
|
Nenue@5
|
659 local binding1, binding2, new1, new2
|
Nenue@5
|
660 print(type(previousAction), previousAction)
|
Nenue@5
|
661 if previousAction ~= "" and previousAction ~= self.command then
|
Nenue@5
|
662 if protected[previousAction] then
|
Nenue@5
|
663 -- bounce out if trying to use a protected key
|
Nenue@5
|
664 kb.statustext:SetText(BINDING_FAILED_PROTECTED:format(key, GetBindingAction(previousAction)))
|
Nenue@5
|
665 kb.bindingstext:SetText(nil)
|
Nenue@5
|
666 return
|
Nenue@5
|
667 else
|
Nenue@5
|
668 kb:print('Discarding keybind for', previousAction)
|
Nenue@5
|
669 -- todo: sort out retcon'd talent spells
|
Nenue@5
|
670 end
|
Nenue@5
|
671 end
|
Nenue@5
|
672
|
Nenue@5
|
673 self.pending = true
|
Nenue@5
|
674
|
Nenue@5
|
675 bindsCommitted = false
|
Nenue@5
|
676 SetBinding(self.binding, self.command)
|
Nenue@5
|
677 SaveBindings(GetCurrentBindingSet())
|
Nenue@5
|
678
|
Nenue@5
|
679 local talentInfo
|
Nenue@5
|
680 if self.actionType == 'spell' and kb.TalentCache[self.actionID] then
|
Nenue@5
|
681 print('conditional binding (talent = "'..self.actionName..'")')
|
Nenue@5
|
682 talentInfo = {self.macroName, self.actionName, self.actionType, self.actionID}
|
Nenue@5
|
683 local bindings = {GetBindingKey(self.command) }
|
Nenue@5
|
684 for i, key in ipairs(bindings) do
|
Nenue@5
|
685 tinsert(talentInfo, key)
|
Nenue@5
|
686 end
|
Nenue@5
|
687 end
|
Nenue@5
|
688
|
Nenue@5
|
689 for level, configProfile in ipairs(priority) do
|
Nenue@5
|
690 if (level == bindMode) then
|
Nenue@5
|
691 configProfile.bound[self.command] = true
|
Nenue@5
|
692 if talentInfo then
|
Nenue@5
|
693 configProfile.bindings[self.binding] = nil
|
Nenue@5
|
694 else
|
Nenue@5
|
695 configProfile.bindings[self.binding] = self.command
|
Nenue@5
|
696 end
|
Nenue@5
|
697 configProfile.talents[self.actionName] = talentInfo
|
Nenue@5
|
698 else
|
Nenue@5
|
699 configProfile.bindings[self.binding] = nil
|
Nenue@5
|
700 configProfile.bound[self.command] = nil
|
Nenue@5
|
701 configProfile.talents[self.actionName] = nil
|
Nenue@5
|
702 end
|
Nenue@5
|
703 if configProfile.talents[self.actionID] then
|
Nenue@5
|
704 configProfile.talents[self.actionID] = nil
|
Nenue@5
|
705 end
|
Nenue@5
|
706
|
Nenue@5
|
707 end
|
Nenue@5
|
708
|
Nenue@5
|
709
|
Nenue@5
|
710
|
Nenue@5
|
711 kb:print(BINDING_ASSIGNED:format(self.binding, self.actionName, configHeaders[bindMode]))
|
Nenue@5
|
712
|
Nenue@5
|
713 end
|
Nenue@0
|
714 end
|
Nenue@0
|
715
|
Nenue@5
|
716 kb.UpdateSlot(self, true)
|
Nenue@5
|
717 KeyBinderSaveButton:Enable()
|
Nenue@0
|
718
|
Nenue@0
|
719 end
|
Nenue@0
|
720
|
Nenue@0
|
721 --- Resets button command
|
Nenue@5
|
722 kb.ReleaseSlot = function(self)
|
Nenue@5
|
723 local slot = self:GetID()
|
Nenue@5
|
724
|
Nenue@5
|
725
|
Nenue@5
|
726 if configProfile.buttons[slot] then
|
Nenue@5
|
727 configProfile.buttons[slot] = nil
|
Nenue@5
|
728 end
|
Nenue@5
|
729 if self.command then
|
Nenue@5
|
730 configProfile.commands[self.command] = nil
|
Nenue@5
|
731 end
|
Nenue@5
|
732 if self.actionType == 'spell' and IsTalentSpell(self.actionName) then
|
Nenue@5
|
733 if configProfile.talents[self.actionID] then
|
Nenue@5
|
734 configProfile.talents[self.actionID] = nil
|
Nenue@5
|
735 end
|
Nenue@5
|
736 end
|
Nenue@5
|
737 local droppedKeys = {}
|
Nenue@5
|
738
|
Nenue@5
|
739 -- doing removal in second loop to avoid possible iterator shenanigans
|
Nenue@5
|
740 for k,v in pairs(configProfile.bindings) do
|
Nenue@5
|
741 if v == self.command then
|
Nenue@5
|
742 tinsert(droppedKeys, k)
|
Nenue@5
|
743 end
|
Nenue@5
|
744 end
|
Nenue@5
|
745 if #droppedKeys >=1 then
|
Nenue@5
|
746 for i, k in ipairs(droppedKeys) do
|
Nenue@5
|
747 configProfile.bindings[k] = nil
|
Nenue@5
|
748 end
|
Nenue@5
|
749 end
|
Nenue@5
|
750
|
Nenue@5
|
751 self.isAvailable = nil
|
Nenue@5
|
752 self.isDynamic = nil
|
Nenue@5
|
753 self.bindingText = nil
|
Nenue@5
|
754 self.statusText = nil
|
Nenue@0
|
755 self.command = nil
|
Nenue@5
|
756 self.actionType = nil
|
Nenue@5
|
757 self.actionID = nil
|
Nenue@0
|
758 self.actionName = nil
|
Nenue@5
|
759 self.pickupSlot = nil
|
Nenue@5
|
760 self.pickupBook = nil
|
Nenue@5
|
761 self.macroName = nil
|
Nenue@0
|
762 self.profile = nil
|
Nenue@0
|
763 self.icon:SetTexture(nil)
|
Nenue@0
|
764 self.border:SetColorTexture(unpack(BORDER_UNASSIGNED))
|
Nenue@0
|
765 self:EnableKeyboard(false)
|
Nenue@0
|
766 self:SetScript('OnKeyDown', nil)
|
Nenue@0
|
767 end
|
Nenue@0
|
768
|
Nenue@5
|
769 kb.SetSlot = function(self, command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook)
|
Nenue@5
|
770 local slot = self:GetID()
|
Nenue@5
|
771 local isDynamic, isAvailable
|
Nenue@0
|
772
|
Nenue@5
|
773 print('|cFFFFFF00SetSlot|r:', self:GetID())
|
Nenue@5
|
774 if command then
|
Nenue@0
|
775
|
Nenue@5
|
776 if actionType == 'spell' then
|
Nenue@5
|
777 local professionNum, spellNum = command:match("profession_(%d)_(%d)")
|
Nenue@0
|
778
|
Nenue@5
|
779 if (professionNum and spellNum) then
|
Nenue@5
|
780 isDynamic = 'profession'
|
Nenue@5
|
781 local cacheInfo = kb.ProfessionCache[professionNum..'_'..spellNum]
|
Nenue@5
|
782 if cacheInfo then
|
Nenue@5
|
783 isAvailable = true
|
Nenue@5
|
784 name = cacheInfo.spellName
|
Nenue@5
|
785 icon = cacheInfo.icon
|
Nenue@5
|
786 actionID = cacheInfo.spellID
|
Nenue@5
|
787 self.profIndex = cacheInfo.profIndex
|
Nenue@5
|
788 self.spellOffset = cacheInfo.spellOffset
|
Nenue@5
|
789 end
|
Nenue@5
|
790 print(' Special slot: |cFF00FFFFProfession|r', professionNum, spellNum, isDynamic, isAvailable)
|
Nenue@5
|
791
|
Nenue@5
|
792 self.professionNum = tonumber(professionNum)
|
Nenue@5
|
793 self.spellNum = tonumber(spellNum)
|
Nenue@5
|
794
|
Nenue@5
|
795 elseif kb.TalentCache[actionID] then
|
Nenue@5
|
796
|
Nenue@5
|
797 isDynamic = 'talent'
|
Nenue@5
|
798 isAvailable = GetSpellInfo(name)
|
Nenue@5
|
799 print(' Special slot: |cFFBBFF00talent|r', name, isAvailable)
|
Nenue@5
|
800 end
|
Nenue@5
|
801 if not actionID then
|
Nenue@5
|
802 actionID = select(7, GetSpellInfo(name))
|
Nenue@5
|
803 end
|
Nenue@5
|
804 elseif actionType == 'macro' then
|
Nenue@5
|
805 if not actionID then
|
Nenue@5
|
806 actionID = GetMacroIndexByName(name)
|
Nenue@5
|
807 end
|
Nenue@5
|
808 else
|
Nenue@5
|
809 --- Journal selections
|
Nenue@5
|
810 -- todo: consider using the deep end of blizzard action bar instead
|
Nenue@5
|
811 if not actionID then
|
Nenue@5
|
812 actionID = command:match("^KeyBinderMacro:(.+)")
|
Nenue@5
|
813 end
|
Nenue@0
|
814 end
|
Nenue@0
|
815
|
Nenue@5
|
816 if not macroName then
|
Nenue@5
|
817 local previousCommand = command
|
Nenue@5
|
818 macroName, macroText, command = kb.RegisterAction(actionType, actionID)
|
Nenue@0
|
819
|
Nenue@5
|
820 -- Clean up conflicting command entry for loaded buttons
|
Nenue@5
|
821 if macroName and command ~= previousCommand then
|
Nenue@5
|
822 print(' Repaired corruption in |cFFFFFF00'..currentHeader..'|r button #'.. self:GetID())
|
Nenue@5
|
823 configProfile.commands[previousCommand] = nil
|
Nenue@5
|
824 configProfile.bound[previousCommand] = nil
|
Nenue@5
|
825 end
|
Nenue@0
|
826 end
|
Nenue@0
|
827
|
Nenue@5
|
828 if actionType == 'petaction' then
|
Nenue@5
|
829 self.pickupSlot = pickupSlot
|
Nenue@5
|
830 self.pickupBook = pickupBook
|
Nenue@5
|
831 else
|
Nenue@5
|
832 self.pickupSlot = nil
|
Nenue@5
|
833 self.pickupBook = nil
|
Nenue@5
|
834 end
|
Nenue@5
|
835
|
Nenue@5
|
836 actionID = actionID or 0
|
Nenue@5
|
837 self:EnableKeyboard(true)
|
Nenue@5
|
838 print(' |cFF00FF00configProfile.buttons['..slot..'] |cFF00FFFF=|r |cFF00FFFF"'.. command.. '"|r |cFF00FF00"'.. name, '"|r |cFFFFFF00icon:'.. icon .. '|r |cFFFF8800"'.. actionType, '"|r |cFFFF0088id:'.. actionID ..'|r |cFF00FF00"'.. macroName .. '"|r')
|
Nenue@5
|
839 configProfile.buttons[slot] = {command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook}
|
Nenue@5
|
840
|
Nenue@5
|
841 -- Clean up conflicting entries for loaded button
|
Nenue@5
|
842 local previous = configProfile.commands[command]
|
Nenue@5
|
843 if previous ~= slot and buttons[previous] then
|
Nenue@5
|
844 kb.ReleaseSlot(buttons[previous])
|
Nenue@5
|
845 end
|
Nenue@5
|
846 configProfile.commands[command] = slot
|
Nenue@0
|
847 end
|
Nenue@0
|
848
|
Nenue@5
|
849 self.isAvailable = isAvailable
|
Nenue@5
|
850 self.isDynamic = isDynamic
|
Nenue@5
|
851
|
Nenue@5
|
852 self.macroText = macroText
|
Nenue@5
|
853 self.macroName = macroName
|
Nenue@5
|
854 self.actionType = actionType
|
Nenue@5
|
855 self.actionID = actionID
|
Nenue@0
|
856 self.actionName = name
|
Nenue@0
|
857 self.command = command
|
Nenue@0
|
858 self.icon:SetTexture(icon)
|
Nenue@5
|
859 self.profile = bindMode
|
Nenue@0
|
860 self:RegisterForDrag('LeftButton')
|
Nenue@0
|
861 end
|
Nenue@0
|
862
|
Nenue@0
|
863 --- Retrieves button at index; creates said button and instates any stored parameters
|
Nenue@5
|
864 local leftSlot, upSlot
|
Nenue@5
|
865 local buttonsDepth = 0
|
Nenue@5
|
866 kb.GetSlot = function(index)
|
Nenue@5
|
867
|
Nenue@5
|
868 local slot = index + kb.scrollOffset
|
Nenue@5
|
869
|
Nenue@0
|
870 if not buttons[index] then
|
Nenue@0
|
871 local button = CreateFrame('CheckButton', 'KeyBinderSlot'..index, kb, 'KeyButton')
|
Nenue@5
|
872 button:SetScript('OnClick', KeyButton_OnClick)
|
Nenue@5
|
873 button:SetScript('OnUpdate', KeyButton_OnUpdate)
|
Nenue@5
|
874 button:SetScript('OnDragStart', KeyButton_OnDragStart)
|
Nenue@5
|
875 button:SetScript('OnReceiveDrag', KeyButton_OnReceiveDrag)
|
Nenue@5
|
876 button:RegisterForClicks('AnyUp')
|
Nenue@0
|
877
|
Nenue@5
|
878
|
Nenue@5
|
879 local newRow = (mod(index, BINDS_PER_ROW) == 1)
|
Nenue@5
|
880
|
Nenue@5
|
881 if index == 1 then
|
Nenue@5
|
882 button:SetPoint('TOPLEFT', kb.bg, 'TOPLEFT', BUTTON_PADDING, - BUTTON_PADDING)
|
Nenue@5
|
883 upSlot = button
|
Nenue@5
|
884 buttonsDepth = KEY_BUTTON_SIZE + BUTTON_PADDING * 2
|
Nenue@5
|
885 elseif newRow then
|
Nenue@5
|
886 button:SetPoint('TOPLEFT', upSlot, 'BOTTOMLEFT', 0, -BUTTON_SPACING)
|
Nenue@5
|
887 upSlot = button
|
Nenue@5
|
888 buttonsDepth = buttonsDepth + KEY_BUTTON_SIZE + BUTTON_SPACING
|
Nenue@0
|
889 else
|
Nenue@5
|
890 button:SetPoint('TOPLEFT', leftSlot, 'TOPRIGHT', BUTTON_HSPACING, 0)
|
Nenue@0
|
891 end
|
Nenue@0
|
892
|
Nenue@0
|
893 button:SetSize(KEY_BUTTON_SIZE, KEY_BUTTON_SIZE)
|
Nenue@0
|
894 button:Show()
|
Nenue@0
|
895 buttons[index] = button
|
Nenue@5
|
896 leftSlot = button
|
Nenue@0
|
897 end
|
Nenue@0
|
898 return buttons[index]
|
Nenue@0
|
899 end
|
Nenue@0
|
900
|
Nenue@0
|
901 --- Updates profile assignment and button contents
|
Nenue@5
|
902 kb.UpdateSlot = function(self, force)
|
Nenue@5
|
903 local slot = self:GetID()
|
Nenue@5
|
904
|
Nenue@5
|
905 if force then
|
Nenue@5
|
906 if configProfile.buttons[slot] then
|
Nenue@5
|
907 kb.SetSlot(self, unpack(configProfile.buttons[slot]))
|
Nenue@0
|
908 else
|
Nenue@5
|
909 kb.ReleaseSlot(self)
|
Nenue@0
|
910 end
|
Nenue@0
|
911 end
|
Nenue@0
|
912
|
Nenue@0
|
913 if self.command then
|
Nenue@5
|
914 print('['..slot..'] =', self.command, GetBindingKey(self.command))
|
Nenue@5
|
915
|
Nenue@0
|
916 if self.pending then
|
Nenue@0
|
917 self.border:SetColorTexture(unpack(BORDER_PENDING))
|
Nenue@5
|
918 elseif self.isDynamic then
|
Nenue@5
|
919 self.border:SetColorTexture(unpack(BORDER_DYNAMIC))
|
Nenue@0
|
920 else
|
Nenue@0
|
921 self.border:SetColorTexture(unpack(BORDER_ASSIGNED))
|
Nenue@0
|
922 end
|
Nenue@5
|
923
|
Nenue@5
|
924 if self.actionType == 'macro' then
|
Nenue@5
|
925 self.macro:Show()
|
Nenue@5
|
926 else
|
Nenue@5
|
927 self.macro:Hide()
|
Nenue@5
|
928 if self.actionType == 'spell' then
|
Nenue@5
|
929 local dummy = GetSpellInfo(self.actionName)
|
Nenue@5
|
930 if not dummy then
|
Nenue@5
|
931 self.icon:SetDesaturated(true)
|
Nenue@5
|
932 else
|
Nenue@5
|
933 self.icon:SetDesaturated(false)
|
Nenue@5
|
934 end
|
Nenue@5
|
935
|
Nenue@5
|
936 end
|
Nenue@5
|
937 end
|
Nenue@5
|
938
|
Nenue@5
|
939 if self.isDynamic then
|
Nenue@5
|
940 print('|cFFFFBB00UpdateSlot|r: ', self.isDynamic, self.isAvailable, self.actionID)
|
Nenue@5
|
941 end
|
Nenue@5
|
942
|
Nenue@5
|
943 if self.isDynamic == 'profession' then
|
Nenue@5
|
944 local profText = (self.spellNum == 1) and TRADE_SKILLS or (BUTTON_HEADERS[self.profIndex] or GetProfessionInfo(self.profIndex))
|
Nenue@5
|
945 if self.isAvailable then
|
Nenue@5
|
946 print(self.profIndex, 'spnum', type(self.spellNum), (self.spellNum == 1))
|
Nenue@5
|
947
|
Nenue@5
|
948 self.statusText = '|cFFFFFF00'..profText..'|r'
|
Nenue@5
|
949 self.bindingText = BindingString(GetBindingKey(self.command))
|
Nenue@5
|
950 else
|
Nenue@5
|
951 self.statusText = '|cFFFF4400'..profText..'|r'
|
Nenue@5
|
952 self.actionName = '(need to train profession #'..self.profNum..')'
|
Nenue@5
|
953 self.bindingText ='?'
|
Nenue@5
|
954 end
|
Nenue@5
|
955 elseif self.isDynamic == 'talent' then
|
Nenue@5
|
956
|
Nenue@5
|
957 self.statusText = '|cFF00FFFF'.. TALENT .. '|r'
|
Nenue@5
|
958 if self.isAvailable then
|
Nenue@5
|
959 self.bindingText = BindingString(GetBindingKey(self.command))
|
Nenue@5
|
960 else
|
Nenue@5
|
961 print(self.actionID, #kb.inactiveTalentBindings[self.actionID])
|
Nenue@5
|
962 self.bindingText= BindingString(unpack(kb.inactiveTalentBindings[self.actionID]))
|
Nenue@5
|
963 end
|
Nenue@5
|
964 else
|
Nenue@5
|
965 self.statusText = '|cFF00FF00'.. (BUTTON_HEADERS[self.actionType] and BUTTON_HEADERS[self.actionType] or self.actionType) .. '|r'
|
Nenue@5
|
966 self.bindingText = BindingString(GetBindingKey(self.command))
|
Nenue@5
|
967 end
|
Nenue@5
|
968
|
Nenue@5
|
969 local locked, layer = IsCommandBound(self)
|
Nenue@5
|
970 if locked then
|
Nenue@5
|
971 self.icon:SetAlpha(0.5)
|
Nenue@5
|
972 else
|
Nenue@5
|
973 self.icon:SetAlpha(1)
|
Nenue@5
|
974 end
|
Nenue@5
|
975
|
Nenue@5
|
976 if self.actionType == 'spell' then
|
Nenue@5
|
977 self.icon:SetTexture(GetSpellTexture(self.actionID))
|
Nenue@5
|
978 end
|
Nenue@5
|
979 end
|
Nenue@5
|
980
|
Nenue@5
|
981 if not self.isAvailable then
|
Nenue@5
|
982 self.bind:SetTextColor(0.7,0.7,0.7,1)
|
Nenue@0
|
983 else
|
Nenue@5
|
984 self.bind:SetTextColor(1,1,1,1)
|
Nenue@5
|
985 end
|
Nenue@5
|
986
|
Nenue@5
|
987 self.header:SetText(self.statusText)
|
Nenue@5
|
988 self.bind:SetText(self.bindingText)
|
Nenue@5
|
989 self.macro:SetText(self.macroName)
|
Nenue@5
|
990 self.details:SetText(self.actionName)
|
Nenue@5
|
991 end
|
Nenue@5
|
992
|
Nenue@5
|
993
|
Nenue@5
|
994 kb.ApplyTalentBinding = function(talentInfo, cache)
|
Nenue@5
|
995 for i = 5, #talentInfo do
|
Nenue@5
|
996 SetBinding(talentInfo[i], "CLICK KeyBinderMacro:".. talentInfo[1])
|
Nenue@5
|
997 tinsert(cache, talentInfo[i])
|
Nenue@0
|
998 end
|
Nenue@0
|
999 end
|
Nenue@5
|
1000 kb.CacheTalentBinding = function(talentInfo, cache)
|
Nenue@5
|
1001 local spellID = talentInfo[4]
|
Nenue@5
|
1002 kb.inactiveTalentBindings[spellID] = kb.inactiveTalentBindings[spellID] or {}
|
Nenue@5
|
1003 kb.inactiveTalentBindings[spellID] = {select(5,unpack(talentInfo)) }
|
Nenue@5
|
1004 cprint(spellID, unpack(kb.inactiveTalentBindings[spellID]))
|
Nenue@0
|
1005 end
|
Nenue@0
|
1006
|
Nenue@5
|
1007 kb.ApplyBinding = function(command, name, icon, actionType, actionID, macroName, macroText )
|
Nenue@5
|
1008
|
Nenue@5
|
1009 if actionType == 'macro' then
|
Nenue@5
|
1010 KeyBinderMacro:SetAttribute("*macro-"..macroName, actionID)
|
Nenue@5
|
1011 else
|
Nenue@5
|
1012 KeyBinderMacro:SetAttribute("*macrotext-"..macroName, macroText)
|
Nenue@5
|
1013 end
|
Nenue@5
|
1014 bindings[actionType] = bindings[actionType] or {}
|
Nenue@5
|
1015 bindings[actionType][actionID] = bindings[actionType][actionID] or {}
|
Nenue@5
|
1016 bindings[command] = bindings[actionType][actionID]
|
Nenue@5
|
1017 return bindings[actionType], actionID
|
Nenue@5
|
1018 end
|
Nenue@5
|
1019
|
Nenue@5
|
1020 kb.ApplyBindings = function (profile)
|
Nenue@5
|
1021 cprint('binding profile', profile)
|
Nenue@5
|
1022 for slot, data in pairs(profile.buttons) do
|
Nenue@5
|
1023 kb.ApplyBinding(unpack(data))
|
Nenue@5
|
1024 end
|
Nenue@5
|
1025
|
Nenue@5
|
1026 for key, command in pairs(profile.bindings) do
|
Nenue@5
|
1027
|
Nenue@5
|
1028 cprint('Bindings data registered', command, key)
|
Nenue@5
|
1029
|
Nenue@5
|
1030 --_G.print('HotKey','loading', key, command)
|
Nenue@5
|
1031 SetBinding(key, command)
|
Nenue@5
|
1032 if bindings[command] and not tContains(bindings[command], key) then
|
Nenue@5
|
1033 tinsert(bindings[command], key)
|
Nenue@5
|
1034 end
|
Nenue@5
|
1035 end
|
Nenue@5
|
1036
|
Nenue@5
|
1037 for spellName, talentInfo in pairs(profile.talents) do
|
Nenue@5
|
1038 local dummy = GetSpellInfo(spellName)
|
Nenue@5
|
1039 local func = kb.CacheTalentBinding
|
Nenue@5
|
1040 local dest = kb.inactiveTalentBindings
|
Nenue@5
|
1041 if dummy then
|
Nenue@5
|
1042 cprint('|cFFBBFF00Active:|r', dummy)
|
Nenue@5
|
1043 local macroName, spellName, actionType, actionID = unpack(talentInfo)
|
Nenue@5
|
1044 bindings[actionType] = bindings[actionType] or {}
|
Nenue@5
|
1045 bindings[actionType][actionID] = {}
|
Nenue@5
|
1046 func = kb.ApplyTalentBinding
|
Nenue@5
|
1047 dest = bindings[actionType][actionID]
|
Nenue@5
|
1048 else
|
Nenue@5
|
1049
|
Nenue@5
|
1050 cprint('|cFFFF4400Inactive:|r', talentInfo[2])
|
Nenue@5
|
1051 end
|
Nenue@5
|
1052 func(talentInfo, dest)
|
Nenue@5
|
1053 end
|
Nenue@5
|
1054
|
Nenue@5
|
1055 SaveBindings(GetCurrentBindingSet())
|
Nenue@5
|
1056 end
|
Nenue@5
|
1057
|
Nenue@5
|
1058 kb.ApplyAllBindings =function ()
|
Nenue@5
|
1059 table.wipe(kb.inactiveTalentBindings)
|
Nenue@5
|
1060
|
Nenue@5
|
1061 for i, profile in ipairs(priority) do
|
Nenue@5
|
1062 kb.ApplyBindings(profile)
|
Nenue@5
|
1063 end
|
Nenue@5
|
1064 -- do this after to ensure that profession binds are properly overridden
|
Nenue@5
|
1065 kb.UpdateProfessionInfo()
|
Nenue@5
|
1066 end
|
Nenue@5
|
1067
|
Nenue@5
|
1068 kb.Command = function(args, editor)
|
Nenue@5
|
1069 if args:match("import") then
|
Nenue@5
|
1070 kb.ImportCommmit(args)
|
Nenue@5
|
1071 return
|
Nenue@5
|
1072 elseif args:match("scan") then
|
Nenue@5
|
1073 kb.ImportScan(args)
|
Nenue@5
|
1074 kb.ui()
|
Nenue@5
|
1075 return
|
Nenue@5
|
1076 elseif args:match("load") then
|
Nenue@5
|
1077 kb:ApplyAllBindings()
|
Nenue@0
|
1078 return
|
Nenue@0
|
1079 end
|
Nenue@0
|
1080
|
Nenue@5
|
1081 if db.showUI then
|
Nenue@5
|
1082 db.showUI = false
|
Nenue@5
|
1083 kb:print('|cFFFFFF00KeyBinds|r trace, |cFFFF0000OFF|r.')
|
Nenue@5
|
1084 kb:Hide()
|
Nenue@5
|
1085 else
|
Nenue@1
|
1086 db.showUI = true
|
Nenue@5
|
1087 kb:print('|cFFFFFF00KeyBinds|r trace, |cFF00FF00ON|r.')
|
Nenue@5
|
1088 end
|
Nenue@5
|
1089 kb.ui(true)
|
Nenue@5
|
1090 end
|
Nenue@5
|
1091
|
Nenue@5
|
1092 kb.InitProfile = function(profile, prototype)
|
Nenue@5
|
1093 if not profile then
|
Nenue@5
|
1094 profile = {}
|
Nenue@5
|
1095 end
|
Nenue@5
|
1096 if prototype then
|
Nenue@5
|
1097 print('appplying prototype', prototype)
|
Nenue@5
|
1098 for k,v in pairs(prototype) do
|
Nenue@5
|
1099 if not profile[k] then
|
Nenue@5
|
1100 profile[k] = v
|
Nenue@5
|
1101 end
|
Nenue@5
|
1102 end
|
Nenue@0
|
1103 end
|
Nenue@0
|
1104
|
Nenue@5
|
1105 profile.bound = profile.bound or {}
|
Nenue@5
|
1106 profile.buttons = profile.buttons or {}
|
Nenue@5
|
1107 profile.commands = profile.commands or {}
|
Nenue@5
|
1108 profile.bindings = profile.bindings or {}
|
Nenue@5
|
1109 profile.macros = profile.macros or {}
|
Nenue@5
|
1110 profile.talents = profile.talents or {}
|
Nenue@5
|
1111 return profile
|
Nenue@5
|
1112 end
|
Nenue@5
|
1113
|
Nenue@5
|
1114 kb.ResetProfile = function(profile, prototype)
|
Nenue@5
|
1115 if profile == configProfile then
|
Nenue@5
|
1116 for i, button in pairs(buttons) do
|
Nenue@5
|
1117 kb.ReleaseSlot(button)
|
Nenue@5
|
1118 end
|
Nenue@5
|
1119 end
|
Nenue@5
|
1120 table.wipe(profile)
|
Nenue@5
|
1121 kb.InitProfile(profile, prototype)
|
Nenue@5
|
1122 end
|
Nenue@5
|
1123
|
Nenue@5
|
1124
|
Nenue@5
|
1125
|
Nenue@5
|
1126 --- Handles constructing spec profiles as they are selected
|
Nenue@5
|
1127
|
Nenue@5
|
1128
|
Nenue@5
|
1129 kb.TalentCache = {}
|
Nenue@5
|
1130
|
Nenue@5
|
1131 kb.UpdateSpecInfo = function()
|
Nenue@5
|
1132 specID = GetSpecialization()
|
Nenue@5
|
1133 specGlobalID, specName, specDesc , specTexture = GetSpecializationInfo(specID)
|
Nenue@5
|
1134 loadedProfiles[BINDING_TYPE_CHARACTER][specID] = kb.InitProfile(loadedProfiles[BINDING_TYPE_CHARACTER][specID], {
|
Nenue@5
|
1135 specID = specID})
|
Nenue@5
|
1136
|
Nenue@5
|
1137 configHeaders[BINDING_TYPE_SPECIALIZATION] = BINDING_MODE[BINDING_TYPE_SPECIALIZATION]:format(specName)
|
Nenue@5
|
1138 loadedProfiles[BINDING_TYPE_SPECIALIZATION] = loadedProfiles[BINDING_TYPE_CHARACTER][specID]
|
Nenue@5
|
1139 configProfile = loadedProfiles[bindMode]
|
Nenue@5
|
1140 print('|cFF00FF00bindMode:|r', bindMode)
|
Nenue@5
|
1141
|
Nenue@5
|
1142 priority = {loadedProfiles[BINDING_TYPE_GLOBAL], loadedProfiles[BINDING_TYPE_CHARACTER], loadedProfiles[BINDING_TYPE_SPECIALIZATION]}
|
Nenue@5
|
1143
|
Nenue@5
|
1144 print('|cFF00FF00current spec:|r', specID, 'of', GetNumSpecializations())
|
Nenue@5
|
1145 end
|
Nenue@5
|
1146
|
Nenue@5
|
1147 kb.UpdateTalentInfo = function()
|
Nenue@5
|
1148 if kb.talentsPushed then
|
Nenue@5
|
1149 return
|
Nenue@5
|
1150 end
|
Nenue@5
|
1151
|
Nenue@5
|
1152
|
Nenue@5
|
1153 table.wipe(kb.TalentCache)
|
Nenue@5
|
1154
|
Nenue@5
|
1155 for row =1, MAX_TALENT_TIERS do
|
Nenue@5
|
1156 for col = 1, NUM_TALENT_COLUMNS do
|
Nenue@5
|
1157 local talentID, talentName, icon, selected, available, spellID = GetTalentInfo(row, col, 1)
|
Nenue@5
|
1158 local talentInfo = kb.TalentCache[spellID] or {}
|
Nenue@5
|
1159 talentInfo.row = 1
|
Nenue@5
|
1160 talentInfo.col = col
|
Nenue@5
|
1161 talentInfo.name = talentName
|
Nenue@5
|
1162 talentInfo.talentID = talentID
|
Nenue@5
|
1163 talentInfo.selected = selected
|
Nenue@5
|
1164 talentInfo.available = available
|
Nenue@5
|
1165 talentInfo.spellID = spellID
|
Nenue@5
|
1166 kb.TalentCache[spellID] = talentInfo
|
Nenue@5
|
1167 print('Talent ', row, col, spellID, talentName)
|
Nenue@5
|
1168 end
|
Nenue@5
|
1169 end
|
Nenue@5
|
1170 kb.talentsPushed = true
|
Nenue@5
|
1171 end
|
Nenue@5
|
1172
|
Nenue@5
|
1173
|
Nenue@5
|
1174 kb.ProfessionCache = {}
|
Nenue@5
|
1175 kb.UpdateProfessionInfo = function()
|
Nenue@5
|
1176 table.wipe(kb.ProfessionCache)
|
Nenue@5
|
1177 local profs = {GetProfessions() }
|
Nenue@5
|
1178 local primaryNum = 0
|
Nenue@5
|
1179 for i, index in ipairs(profs) do
|
Nenue@5
|
1180 local profName, texture, rank, maxRank, numSpells, spellOffset = GetProfessionInfo(index)
|
Nenue@5
|
1181 cprint(i, index, profName, numSpells, spellOffset)
|
Nenue@5
|
1182 if not professionMappings[index] then
|
Nenue@5
|
1183 primaryNum = primaryNum + 1
|
Nenue@5
|
1184 end
|
Nenue@5
|
1185 local profNum = professionMappings[index] or primaryNum
|
Nenue@5
|
1186
|
Nenue@5
|
1187
|
Nenue@5
|
1188 kb.ProfessionCache[profNum] = kb.ProfessionCache[i] or {}
|
Nenue@5
|
1189
|
Nenue@5
|
1190 for j = 1, numSpells do
|
Nenue@5
|
1191 local spellName, _, icon, _, _, _, spellID = GetSpellInfo(spellOffset+j, BOOKTYPE_PROFESSION)
|
Nenue@5
|
1192
|
Nenue@5
|
1193 local profInfo = {
|
Nenue@5
|
1194 spellName = spellName,
|
Nenue@5
|
1195 spellID = spellID,
|
Nenue@5
|
1196 icon = icon,
|
Nenue@5
|
1197 profOffset = i,
|
Nenue@5
|
1198 profIndex = index,
|
Nenue@5
|
1199 spellOffset = (spellOffset+j),
|
Nenue@5
|
1200 spellNum = j
|
Nenue@5
|
1201 }
|
Nenue@5
|
1202 KeyBinderMacro:SetAttribute("*macrotext-profession_"..i .. '_' ..j, "/cast ".. spellName)
|
Nenue@5
|
1203
|
Nenue@5
|
1204 kb.ProfessionCache[i .. '_' .. j] = profInfo
|
Nenue@5
|
1205 kb.ProfessionCache[spellName] = profInfo
|
Nenue@5
|
1206 kb.ProfessionCache[spellID] = profInfo
|
Nenue@5
|
1207 cprint(' |cFF0088FF['..i..']|r|cFFFF44BB['..spellOffset+i..']|r', spellName, "*macrotext-profession_"..i .. '_' ..j)
|
Nenue@5
|
1208 end
|
Nenue@5
|
1209
|
Nenue@5
|
1210 end
|
Nenue@5
|
1211
|
Nenue@5
|
1212 end
|
Nenue@5
|
1213
|
Nenue@5
|
1214 --- Obtains profile data or creates the necessary tables
|
Nenue@5
|
1215 kb.SelectProfileSet = function(name)
|
Nenue@5
|
1216
|
Nenue@5
|
1217 --- General info
|
Nenue@5
|
1218 classHeader, className, classID = UnitClass('player')
|
Nenue@5
|
1219 print('|cFF00FF00profile:|r', name)
|
Nenue@5
|
1220 print('|cFF00FF00class:|r', UnitClass('player'))
|
Nenue@5
|
1221
|
Nenue@5
|
1222 --- Global
|
Nenue@5
|
1223 bindMode = BINDING_TYPE_GLOBAL
|
Nenue@5
|
1224 kb.InitProfile(db)
|
Nenue@5
|
1225 loadedProfiles[BINDING_TYPE_GLOBAL] = db
|
Nenue@5
|
1226
|
Nenue@5
|
1227 --- Character
|
Nenue@5
|
1228 if name then
|
Nenue@5
|
1229 db[name] = kb.InitProfile(db[name],
|
Nenue@5
|
1230 {classHeader = classHeader, className = className, classID = classID})
|
Nenue@5
|
1231 loadedProfiles[BINDING_TYPE_CHARACTER] = db[name]
|
Nenue@5
|
1232 bindMode = BINDING_TYPE_CHARACTER
|
Nenue@5
|
1233 end
|
Nenue@5
|
1234
|
Nenue@5
|
1235 --- Mutable skills data
|
Nenue@5
|
1236 kb.UpdateSpecInfo()
|
Nenue@5
|
1237 kb.UpdateTalentInfo()
|
Nenue@5
|
1238
|
Nenue@5
|
1239 priority = {loadedProfiles[BINDING_TYPE_GLOBAL], loadedProfiles[BINDING_TYPE_CHARACTER], loadedProfiles[BINDING_TYPE_SPECIALIZATION]}
|
Nenue@5
|
1240 if db.bindMode and loadedProfiles[db.bindMode] then
|
Nenue@5
|
1241 bindMode = db.bindMode
|
Nenue@5
|
1242 end
|
Nenue@5
|
1243
|
Nenue@5
|
1244 db.bindMode = bindMode
|
Nenue@5
|
1245
|
Nenue@5
|
1246 if not BINDING_MODE[bindMode] then
|
Nenue@5
|
1247 bindMode = 3
|
Nenue@5
|
1248 db.bindMode = 3
|
Nenue@5
|
1249 print('overriding', bindMode)
|
Nenue@5
|
1250 end
|
Nenue@5
|
1251
|
Nenue@5
|
1252 print(BINDING_TYPE_GLOBAL)
|
Nenue@5
|
1253 configHeaders[BINDING_TYPE_GLOBAL] = BINDING_MODE[BINDING_TYPE_GLOBAL]
|
Nenue@5
|
1254 configHeaders[BINDING_TYPE_CHARACTER] = BINDING_MODE[BINDING_TYPE_CHARACTER]:format(UnitName('player', true))
|
Nenue@5
|
1255 configHeaders[BINDING_TYPE_SPECIALIZATION] = BINDING_MODE[BINDING_TYPE_SPECIALIZATION]:format(specName)
|
Nenue@5
|
1256
|
Nenue@5
|
1257
|
Nenue@5
|
1258 setmetatable(loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return configHeaders[BINDING_TYPE_GLOBAL] end})
|
Nenue@5
|
1259 setmetatable(loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return configHeaders[BINDING_TYPE_CHARACTER] end})
|
Nenue@5
|
1260 setmetatable(loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return configHeaders[BINDING_TYPE_SPECIALIZATION] end})
|
Nenue@5
|
1261
|
Nenue@5
|
1262 print('|cFF00FF00bindMode:|r', bindMode)
|
Nenue@5
|
1263 configProfile = loadedProfiles[bindMode]
|
Nenue@5
|
1264 end
|
Nenue@5
|
1265
|
Nenue@5
|
1266 local scrollCache = {}
|
Nenue@5
|
1267 kb.SelectTab = function(self)
|
Nenue@5
|
1268 scrollCache[bindMode] = kb.scrollOffset
|
Nenue@5
|
1269 bindMode = self:GetID()
|
Nenue@5
|
1270 configProfile = loadedProfiles[self:GetID()]
|
Nenue@5
|
1271 db.bindMode = self:GetID()
|
Nenue@5
|
1272 kb.scrollOffset = scrollCache[bindMode] or 0
|
Nenue@5
|
1273 kb.ui(true)
|
Nenue@5
|
1274 end
|
Nenue@5
|
1275
|
Nenue@5
|
1276 kb.RevertBindings = function()
|
Nenue@5
|
1277 -- todo: reversion code
|
Nenue@5
|
1278 end
|
Nenue@5
|
1279
|
Nenue@5
|
1280 kb.ConfirmBindings = function()
|
Nenue@5
|
1281 SaveBindings(GetCurrentBindingSet())
|
Nenue@5
|
1282 bindsCommitted = true
|
Nenue@5
|
1283 for i, button in ipairs(buttons) do
|
Nenue@5
|
1284 button.pending = false
|
Nenue@5
|
1285 end
|
Nenue@5
|
1286 kb.ApplyAllBindings()
|
Nenue@5
|
1287
|
Nenue@5
|
1288 kb.ui()
|
Nenue@5
|
1289 kb:print('Keybinds saved.')
|
Nenue@5
|
1290 end
|
Nenue@5
|
1291
|
Nenue@5
|
1292
|
Nenue@5
|
1293
|
Nenue@5
|
1294
|
Nenue@5
|
1295
|
Nenue@5
|
1296
|
Nenue@5
|
1297 --- push current information into living UI
|
Nenue@5
|
1298 kb.ui = function(force)
|
Nenue@5
|
1299 for i, module in ipairs(kb.modules) do
|
Nenue@5
|
1300 if module.ui then
|
Nenue@5
|
1301 module.ui(force)
|
Nenue@5
|
1302 end
|
Nenue@5
|
1303 end
|
Nenue@5
|
1304
|
Nenue@5
|
1305 if not db.showUI then
|
Nenue@5
|
1306 print('---end of refresh')
|
Nenue@5
|
1307 return
|
Nenue@5
|
1308 end
|
Nenue@0
|
1309 if not kb.loaded then
|
Nenue@5
|
1310 KeyBinder_Initialize()
|
Nenue@0
|
1311 kb.loaded = true
|
Nenue@0
|
1312 end
|
Nenue@0
|
1313 for i = 1, numButtons do
|
Nenue@5
|
1314 local button = kb.GetSlot(i)
|
Nenue@5
|
1315 button:SetID(i+kb.scrollOffset)
|
Nenue@5
|
1316 kb.UpdateSlot(button, force)
|
Nenue@0
|
1317 end
|
Nenue@0
|
1318
|
Nenue@0
|
1319 if bindsCommitted then
|
Nenue@0
|
1320 KeyBinderSaveButton:Disable()
|
Nenue@5
|
1321 --KeyBinderRestoreButton:Disable()
|
Nenue@0
|
1322 else
|
Nenue@0
|
1323 KeyBinderSaveButton:Enable()
|
Nenue@5
|
1324 --KeyBinderRestoreButton:Enable()
|
Nenue@0
|
1325 end
|
Nenue@0
|
1326
|
Nenue@5
|
1327 --- Frame Sizing
|
Nenue@5
|
1328 kb.profilebg:SetHeight(kb.tabSize[2] + BUTTON_PADDING * 2 + kb.profiletext:GetStringHeight())
|
Nenue@5
|
1329
|
Nenue@5
|
1330 kb.bg:SetWidth((KEY_BUTTON_SIZE + BUTTON_HSPACING + BUTTON_SPACING) * BINDS_PER_ROW + BUTTON_PADDING*2 - BUTTON_SPACING)
|
Nenue@0
|
1331 local numRows = numButtons/BINDS_PER_ROW
|
Nenue@5
|
1332
|
Nenue@5
|
1333 kb.bg:SetHeight((KEY_BUTTON_SIZE + BUTTON_SPACING) * numRows + BUTTON_PADDING*2 - BUTTON_SPACING)
|
Nenue@5
|
1334
|
Nenue@5
|
1335 kb:SetHeight(kb.headerbg:GetHeight() + kb.profilebg:GetHeight() + kb.bg:GetHeight() + kb.footer:GetHeight())
|
Nenue@5
|
1336 kb:SetWidth((kb.sourcesbg:GetWidth() +(BINDS_PER_ROW * (KEY_BUTTON_SIZE + BUTTON_HSPACING) + (BINDS_PER_ROW - 1) * BUTTON_SPACING + BUTTON_PADDING * 2) ))
|
Nenue@5
|
1337
|
Nenue@0
|
1338 kb.bg:SetColorTexture(unpack(BINDING_SCHEME_COLOR[bindMode]))
|
Nenue@0
|
1339 for i, tab in ipairs(kb.tabButtons) do
|
Nenue@5
|
1340 local border = tab:GetNormalTexture()
|
Nenue@0
|
1341 local tabTexture = "Interface\\Buttons\\UI-Quickslot2"
|
Nenue@0
|
1342 local left, top, right, bottom = -12, 12, 13, -13
|
Nenue@0
|
1343 if i == bindMode then
|
Nenue@0
|
1344 tabTexture = "Interface\\Buttons\\CheckButtonGlow"
|
Nenue@0
|
1345 left, top, right, bottom = -14, 14, 15, -15
|
Nenue@5
|
1346 tab.icon:SetDesaturated(false)
|
Nenue@5
|
1347 if tab.icon2 then tab.icon2:SetDesaturated(false) end
|
Nenue@5
|
1348 border:SetDesaturated(true)
|
Nenue@5
|
1349 border:SetVertexColor(1,1,1, 1)
|
Nenue@5
|
1350 else
|
Nenue@5
|
1351 tab.icon:SetDesaturated(true)
|
Nenue@5
|
1352 if tab.icon2 then tab.icon2:SetDesaturated(true) end
|
Nenue@5
|
1353 border:SetDesaturated(false)
|
Nenue@5
|
1354 border:SetVertexColor(1,1,1)
|
Nenue@0
|
1355 end
|
Nenue@5
|
1356 border:SetTexture(tabTexture)
|
Nenue@5
|
1357 border:SetPoint('TOPLEFT', tab, 'TOPLEFT', left, top)
|
Nenue@5
|
1358 border:SetPoint('BOTTOMRIGHT', tab, 'BOTTOMRIGHT', right, bottom)
|
Nenue@0
|
1359 end
|
Nenue@5
|
1360
|
Nenue@5
|
1361 KeyBinderSpecTab.icon:SetTexture(specTexture)
|
Nenue@5
|
1362
|
Nenue@5
|
1363 kb.profiletext:SetText(configHeaders[bindMode])
|
Nenue@5
|
1364 print(bindMode, configHeaders[bindMode], kb:GetSize())
|
Nenue@5
|
1365 print(kb:GetPoint(1))
|
Nenue@5
|
1366
|
Nenue@5
|
1367 kb:Show()
|
Nenue@5
|
1368
|
Nenue@5
|
1369 -- Reset this so talent cache can be rebuilt
|
Nenue@5
|
1370 kb.talentsPushed = nil
|
Nenue@0
|
1371 end
|
Nenue@0
|
1372
|
Nenue@5
|
1373 --- post ADDON_LOADED
|
Nenue@5
|
1374 kb.variables = function()
|
Nenue@5
|
1375 SkeletonKeyDB = SkeletonKeyDB or {spec = {}}
|
Nenue@5
|
1376 kb.db = SkeletonKeyDB
|
Nenue@5
|
1377 kb.playerName = UnitName('player')
|
Nenue@5
|
1378 kb.playerRealm = SelectedRealmName()
|
Nenue@5
|
1379 kb.profileName = kb.playerRealm .. '_' .. kb.playerName
|
Nenue@5
|
1380 db = kb.db
|
Nenue@5
|
1381
|
Nenue@5
|
1382 kb.SelectProfileSet(kb.profileName)
|
Nenue@5
|
1383 if not configProfile.imported then
|
Nenue@5
|
1384 kb.ImportScan()
|
Nenue@0
|
1385 end
|
Nenue@5
|
1386 kb.ApplyAllBindings()
|
Nenue@5
|
1387
|
Nenue@5
|
1388 kb.ui(true)
|
Nenue@0
|
1389 end
|
Nenue@0
|
1390
|
Nenue@1
|
1391
|
Nenue@5
|
1392 kb.wrap = function(module)
|
Nenue@5
|
1393 kb.modules = kb.modules or {}
|
Nenue@5
|
1394 tinsert(kb.modules, module)
|
Nenue@0
|
1395 end
|
Nenue@0
|
1396
|
Nenue@5
|
1397 -- Volatiles Access
|
Nenue@5
|
1398 kb.BindingIsLocked = BindingIsLocked
|
Nenue@5
|
1399 kb.BindingString = BindingString
|
Nenue@5
|
1400 kb.GetBindings = function() return bindings end
|
Nenue@5
|
1401 kb.GetButtons = function() return buttons end
|
Nenue@5
|
1402 kb.GetCharacterProfile = function () return loadedProfiles[BINDING_TYPE_CHARACTER] end
|
Nenue@5
|
1403 kb.GetGlobalProfile = function () return loadedProfiles[BINDING_TYPE_GLOBAL] end
|
Nenue@5
|
1404 kb.GetLooseTalents = function() return talentBindings end
|
Nenue@5
|
1405 kb.GetProfileStack = function() return priority end
|
Nenue@5
|
1406 kb.GetReverts = function() return reverts end
|
Nenue@5
|
1407 kb.GetSpecProfile = function () return loadedProfiles[BINDING_TYPE_SPECIALIZATION] end
|
Nenue@0
|
1408
|
Nenue@5
|
1409 --- Add to blizzard interfaces
|
Nenue@5
|
1410 StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] = {
|
Nenue@5
|
1411 text = "Confirm moving an assigned command.",
|
Nenue@5
|
1412 button1 = OKAY,
|
Nenue@5
|
1413 button2 = CANCEL,
|
Nenue@5
|
1414 timeout = 0,
|
Nenue@5
|
1415 whileDead = 1,
|
Nenue@5
|
1416 showAlert = 1,
|
Nenue@5
|
1417 OnAccept = kb.AcceptAssignment,
|
Nenue@5
|
1418 OnCancel = function() kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) end
|
Nenue@5
|
1419 }
|
Nenue@0
|
1420
|
Nenue@5
|
1421 SLASH_SKB1 = "/skb"
|
Nenue@5
|
1422 SLASH_SKB2 = "/skeletonkey"
|
Nenue@5
|
1423 SlashCmdList.SKB = kb.Command
|
Nenue@0
|
1424
|
Nenue@5
|
1425 -- This is needed to identify a spells that aren't reflected by GetCursorInfo()
|
Nenue@5
|
1426 hooksecurefunc("PickupSpellBookItem", function(slot, bookType)
|
Nenue@5
|
1427 print('|cFFFF4400PickupSpellBookItem(..', tostring(slot),', '..tostring(bookType)..')')
|
Nenue@5
|
1428 CURSOR_SPELLSLOT = slot
|
Nenue@5
|
1429 CURSOR_BOOKTYPE = bookType
|
Nenue@5
|
1430 end)
|
Nenue@0
|
1431
|
Nenue@5
|
1432 -- Pet actions
|
Nenue@5
|
1433 local isPickup
|
Nenue@5
|
1434 hooksecurefunc("PickupPetAction", function(slot, ...)
|
Nenue@5
|
1435 isPickup = GetCursorInfo()
|
Nenue@0
|
1436
|
Nenue@5
|
1437 CURSOR_PETACTION = isPickup and slot
|
Nenue@5
|
1438 print('|cFFFF4400PickupPetAction|r', isPickup, CURSOR_PETACTION)
|
Nenue@5
|
1439 end) |