comparison BindingsFrame.lua @ 70:131d9190db6b

Curseforge migration
author Nenue
date Wed, 28 Dec 2016 16:31:15 -0500
parents
children ca3118127e5e
comparison
equal deleted inserted replaced
69:b14d0611c8d9 70:131d9190db6b
1 -- KrakTool
2 -- BindingsFrame.lua
3 -- Created: 7/28/2016 3:39 PM
4 -- %file-revision%
5 -- Handles the arrangement of and interaction with the SkeletonKey frame
6 --[=[
7 -- some useful texture paths
8 [[Interface\PaperDollInfoFrame\UI-GearManager-Undo]]
9 [[Interface\PetPaperDollFrame\UI-PetHappiness]]
10 [[Interface\RAIDFRAME\ReadyCheck-Waiting]]
11 [[Interface\RAIDFRAME\ReadyCheck-Read]]
12 [[Interface\RAIDFRAME\ReadyCheck-NotReady]]
13 [[Interface\TradeSkillFrame\UI-TradeSkill-LinkButton]]
14 [[Interface\TUTORIALFRAME\UI-TUTORIAL-FRAME]]
15 [[Interface\UI-TutorialFrame-QuestGiver\UI-TutorialFrame-QuestGray]]
16 --]=]
17
18 SkeletonKeyButtonMixin = {}
19 local _, kb = ...
20 local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('SK', ...) end or nop
21 local L = kb.L
22 local BINDS_PER_ROW = 2
23 local BINDING_TYPE_SPECIALIZATION = 3
24 local BINDING_TYPE_CHARACTER = 2
25 local BINDING_TYPE_GLOBAL = 1
26 local BUTTON_HSPACING = 128
27 local BUTTON_SPACING = 4
28 local BUTTON_PADDING = 12
29 local TAB_HEIGHT = 24
30 local KEY_BUTTON_SIZE = 48
31 local NUM_KEY_SLOTS = BINDS_PER_ROW * 8
32 local TAB_HEIGHT = 40
33 local BG_INSET = 4
34
35 local BINDING_SCHEME_COLOR = {
36 [BINDING_TYPE_GLOBAL] = {0,.125,.5,.8},
37 [BINDING_TYPE_CHARACTER] = {0,0.25,0,0.8},
38 [BINDING_TYPE_SPECIALIZATION] = {.25,0,0,0.8},
39 }
40 local BINDING_SCHEME_VERTEX = {
41 [BINDING_TYPE_GLOBAL] = {0,.5,1,1},
42 [BINDING_TYPE_CHARACTER] = {0,1,0,1},
43 [BINDING_TYPE_SPECIALIZATION] = {1,1,1,1},
44 }
45 local BINDING_SCHEME_TEXT = {
46 [BINDING_TYPE_SPECIALIZATION] = {0, 1, 1},
47 [BINDING_TYPE_CHARACTER] = {0, 1, 0},
48 [BINDING_TYPE_GLOBAL] = {0, 1, 1}
49 }
50
51 local match, strupper = string.match, string.upper
52 local tremove, tinsert, ipairs, pairs, unpack = table.remove, table.insert, ipairs, pairs, unpack
53 local tonumber, tostring = tonumber, tostring
54 local GetCursorInfo, ClearCursor, ResetCursor = GetCursorInfo, ClearCursor, ResetCursor
55 local IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown = IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown
56 local GetBindingAction, GetBindingKey, GetCurrentBindingSet = GetBindingAction, GetBindingKey, GetCurrentBindingSet
57 local SetBinding, SaveBindings = SetBinding, SaveBindings
58 local GetSpellInfo, InCombatLockdown = GetSpellInfo, InCombatLockdown
59
60
61 local ActionListPanel = {
62 tabButtons = {
63 [BINDING_TYPE_GLOBAL] = {
64 icon = "Interface\\WORLDMAP\\WorldMap-Icon",
65 label = "Global",
66 },
67 [BINDING_TYPE_CHARACTER] ={
68 func = function(self, index)
69 SetPortraitTexture(self.Icon, 'player')
70 self.Label:SetText(kb.configHeaders[index])
71 self.tooltipText = kb.configHeaders[index]
72 end
73 },
74 [BINDING_TYPE_SPECIALIZATION] = {
75 func = function(self, index)
76 self.Icon:SetTexture(kb.specInfo.texture)
77 self.Label:SetText(kb.configHeaders[index])
78 self.tooltipText = kb.configHeaders[index]
79 end
80 },
81 }
82 }
83 local SystemBindingsPanel = {
84 tabButtons = {
85 {label = "Global"},
86 {label = "Character"}
87 }
88 }
89 function SkeletonKeyMixin:ProcessInput (key)
90 if self.currentPanel then
91 if self.currentPanel:OnInput(key) then
92 self:Update(true)
93 end
94 end
95 end
96
97 local lastFolder
98 local restingAlpha = 0.7
99 local fadeTime, fadeDelay = .30, 0.15
100 local saveButton
101
102
103
104 local frameCount = 0
105 local lastCheckFrame
106 local KeyBinder_CheckButton = function(frame ,enableText, disableText, dbKey, tooltipText, callback, header)
107 if kb.db[dbKey] then
108 frame:SetChecked(true)
109 end
110
111 frame.header:SetText(header)
112
113 frame:SetScript('OnClick', function(self)
114 kb.db[dbKey] = self:GetChecked()
115 if callback then
116 callback(self)
117 end
118 kb.ui()
119 end)
120
121 frame:SetScript('OnEnter', function(self)
122 if tooltipText then
123 GameTooltip:SetOwner(self)
124 GameTooltip:SetText(tooltipText)
125 GameTooltip:Show()
126 end
127 end)
128
129 frame:SetScript('OnLeave', function(self)
130 if tooltipText and GameTooltip:GetOwner() == self then
131 GameTooltip:Hide()
132 end
133 end)
134
135 if frame:GetID() == 0 then
136 frameCount = frameCount + 1
137 frame:SetID(frameCount)
138 print('checkbutton #', frameCount)
139 if frameCount == 1 then
140 frame:ClearAllPoints()
141 frame:SetPoint('TOP', KeyBinderInventoryButton, 'BOTTOM', 0, -22)
142 frame:SetPoint('LEFT', SkeletonKey 'LEFT', 2, 0)
143 else
144 frame:ClearAllPoints()
145 frame:SetPoint('TOPLEFT', lastCheckFrame, 'BOTTOMLEFT', 0, -2)
146 end
147
148 frame.header:ClearAllPoints()
149 frame.header:SetPoint('LEFT', frame, 'RIGHT', 2, 0)
150
151 lastCheckFrame = frame
152 end
153 end
154
155
156
157 function SkeletonKeyMixin:OnMouseWheel(delta)
158
159 -- let the updaters handle range
160 if IsControlKeyDown() then
161 self.zoomScale = self.zoomScale - (delta/10)
162 else
163 self.scrollOffset = ceil(self.scrollOffset - delta)
164 end
165
166 self:Update(true)
167 print(self.zoomScale, self.scrollOffset)
168 end
169
170 function SkeletonKeyMixin:OnHide()
171 KeyBinderImportLog:Hide()
172 end
173
174
175 local tabID = 0
176 local prevTab
177
178 function SkeletonKeyMixin:SetupTabButton (index, text, icon, func)
179 print('|cFF00FFFF'..self:GetName()..':SetupTabButton()', index, text, icon, func)
180 local tabName = 'SkeletonKeyProfileTab'..index
181 local tab = _G[tabName]
182
183 if not tab then
184 tab = CreateFrame('Button', tabName, self, 'SkeletonKeyTabTemplate')
185 self.numTabs = self.numTabs + 1
186 tab:SetID(self.numTabs)
187 TAB_HEIGHT = tab:GetHeight()
188
189 if self.numTabs == 1 then
190 tab:SetPoint('TOPLEFT', self.profilebg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING)
191 else
192 tab:SetPoint('TOPLEFT', self.lastTab,'TOPRIGHT', BUTTON_SPACING, 0)
193 end
194
195 tab.tooltipText = text
196 tab:SetScript('OnEnter', function(button)
197 if button.tooltipText then
198 GameTooltip:SetOwner(button)
199 GameTooltip:SetText(button.tooltipText)
200 GameTooltip:Show()
201 end
202 end)
203
204 tab:SetScript('OnLeave', function(button)
205 if GameTooltip:IsOwned(button) then
206 GameTooltip:Hide()
207 end
208 end)
209
210 tab:SetScript('OnClick', function(button)
211 self.selectedTabIndex = button:GetID()
212 self:Update(true)
213 end)
214 self.lastTab = tab
215 end
216 if text then
217
218 tab.Label:SetText(text)
219 end
220
221 if icon then
222 tab.Icon:SetTexture(icon)
223 end
224 if func then
225 func(tab, index, text)
226 end
227
228 local selected = (index == self.selectedTabIndex)
229 if selected then
230 tab.Icon:SetDesaturated(false)
231 tab.Label:SetTextColor(0,1,0, 1)
232 else
233
234 tab.Icon:SetDesaturated(true)
235 tab.Label:SetTextColor(1,1,1,0.7)
236 end
237
238 tab.used = true
239
240 tab:SetSize(tab.Icon:GetWidth()+tab.Label:GetStringWidth()+3, tab.Icon:GetHeight())
241 tab:Show()
242 print(tab:GetPoint(1))
243 print(tab:GetSize())
244
245 return tab
246 end
247
248
249
250 --- push current information into living UI
251 function SkeletonKeyMixin:Update(force)
252 print('|cFFFF8800'..self:GetName()..':Update()|r', InCombatLockdown() and 'combat', self:IsShown())
253 for index, frame in ipairs(self.Plugins) do
254 if frame.Update then
255 frame:Update(force)
256 end
257 end
258
259 self.currentPanel = self.currentPanel or self.Panels[1]
260 if InCombatLockdown() or not self:IsShown() then
261 return
262 end
263
264 self.numTabs = 0
265 for index, tab in ipairs(self.tabButtons) do
266 tab.used = nil
267 tab:Hide()
268 end
269
270 for index, panel in ipairs(self.Panels) do
271 print(panel:GetName())
272 if panel == self.currentPanel then
273 print('Updating panel:', panel:GetName())
274 panel:SetAllPoints(self.bg)
275 self.selectedTabIndex, self.scrollOffset = panel:Update(force)
276 panel:Show()
277
278 for tabIndex, info in ipairs(panel.tabButtons) do
279 self:SetupTabButton(tabIndex, info.label, info.icon, info.func)
280 end
281
282 else
283 panel:Hide()
284 end
285 end
286
287
288
289 --- Frame Sizing
290 self.profilebg:SetHeight(TAB_HEIGHT + BUTTON_PADDING * 2 + self.profiletext:GetStringHeight())
291
292 self.bg:SetWidth((KEY_BUTTON_SIZE + BUTTON_HSPACING + BUTTON_SPACING) * BINDS_PER_ROW + BUTTON_PADDING*2 - BUTTON_SPACING - BG_INSET*2)
293 local numRows = NUM_KEY_SLOTS/BINDS_PER_ROW
294
295 self.bg:SetHeight((KEY_BUTTON_SIZE + BUTTON_SPACING) * numRows + BUTTON_PADDING*2 - BUTTON_SPACING - BG_INSET*2)
296
297
298 self:SetHeight(self.headerbg:GetHeight() + self.profilebg:GetHeight() + self.bg:GetHeight() + self.footer:GetHeight()+BG_INSET*2)
299 self:SetWidth(((BINDS_PER_ROW * (KEY_BUTTON_SIZE + BUTTON_HSPACING) + (BINDS_PER_ROW - 1) * BUTTON_SPACING + BUTTON_PADDING * 2) ))
300
301
302 self.backdrop.insets.left = BG_INSET
303 self.backdrop.insets.right = BG_INSET
304 self.backdrop.insets.top = BG_INSET
305 self.backdrop.insets.bottom = BG_INSET
306 self:SetBackdrop(self.backdrop)
307 self:SetBackdropColor(unpack(self.backdropColor))
308 self:SetBackdropBorderColor(unpack(self.backdropBorder))
309
310 self:SetScale(self.zoomScale)
311
312 self.profiletext:SetText(kb.configHeaders[kb.db.bindMode])
313 print(kb.db.bindMode, kb.configHeaders[kb.db.bindMode], self:GetSize())
314 print(self:GetPoint(1))
315
316
317 self:EnableKeyboard((kb.saveTarget and true) or false)
318 print('keyboard input:', (kb.saveTarget and true) or false)
319
320 -- Reset this so talent cache can be rebuilt
321 kb.talentsPushed = nil
322 end
323
324 local SkeletonKeyPanel = {}
325 function SkeletonKeyPanel:OnShow()
326 print('|cFFFFFF00'..self:GetName()..':OnShow()|r')
327 end
328
329 function ActionListPanel:OnLoad()
330
331
332 self.UnbindButton:SetScript('OnClick', function()
333 self:UnbindSlot(kb.saveTarget)
334 SkeletonKey:Update()
335 end)
336 end
337
338 function ActionListPanel:Update(force)
339 local parent = self:GetParent()
340 local tabID = parent.selectedTabIndex
341 local scrollOffset = parent.scrollOffset
342 if not tabID then
343 tabID = kb.db.bindMode or BINDING_TYPE_GLOBAL
344 end
345 print('|cFF0088FF'..self:GetName()..':Update()|r', 'tab', parent.selectedTabIndex, 'scroll', parent.scrollOffset)
346
347 local selectedProfile = kb.loadedProfiles[tabID]
348 if selectedProfile then
349 kb.currentProfile = selectedProfile
350 kb.db.bindMode = tabID
351 else
352 tabID = BINDING_TYPE_GLOBAL
353 end
354 scrollOffset = scrollOffset or 0
355
356 local leftSlot, upSlot
357 local buttonTable = self.buttons or {}
358 for index = 1, NUM_KEY_SLOTS do
359 if not buttonTable[index] then
360 local button = CreateFrame('CheckButton', 'KeyBinderSlot'..index, self, 'KeyButton')
361 local newRow = (mod(index, BINDS_PER_ROW) == 1)
362
363 if index == 1 then
364 button:SetPoint('TOPLEFT', self, 'TOPLEFT', BUTTON_PADDING, - BUTTON_PADDING)
365 upSlot = button
366 elseif newRow then
367 button:SetPoint('TOPLEFT', upSlot, 'BOTTOMLEFT', 0, -BUTTON_SPACING)
368 upSlot = button
369 else
370 button:SetPoint('TOPLEFT', leftSlot, 'TOPRIGHT', BUTTON_HSPACING, 0)
371 end
372
373 button:SetSize(KEY_BUTTON_SIZE, KEY_BUTTON_SIZE)
374 button:Show()
375 buttonTable[index] = button
376 leftSlot = button
377 end
378 end
379 self.buttons = buttonTable
380
381 local startIndex = scrollOffset * BINDS_PER_ROW
382 for i, button in ipairs(self.buttons) do
383 button:SetID(startIndex+i)
384 button:UpdateSlot(force)
385 button:SetFrameLevel(50 + i + (button.isActive and #self.buttons or 0))
386 end
387
388
389 local r,g,b,a = unpack(BINDING_SCHEME_COLOR[kb.db.bindMode])
390 self.profileStripe:SetColorTexture(r,g,b)
391 if kb.saveTarget then
392 self.bg:SetColorTexture(.2,.5, .2, .5)
393 self.UnbindButton:SetFrameLevel(kb.saveTarget:GetFrameLevel()-1)
394 self.UnbindButton:SetPoint('TOPLEFT', kb.saveTarget, 'BOTTOMLEFT', 0, -1)
395 self.UnbindButton:Show()
396
397 else
398 self.bg:SetColorTexture(.2,.2,.2,1)
399 self.UnbindButton:Hide()
400 end
401
402 return tabID, scrollOffset
403 end
404
405
406 function ActionListPanel:ActivateSlot (button)
407 if kb.saveTarget then
408 kb.saveTarget.isActive = nil
409 end
410 button.isActive = true
411 kb.saveTarget = button
412 return true
413 end
414
415 function ActionListPanel:DeactivateSlot (button)
416 button.isActive = nil
417 kb.saveTarget = nil
418 return true
419 end
420
421 function ActionListPanel:OnInput(key)
422
423 if key == 'ESCAPE' then
424 return self:DeactivateSlot(kb.saveTarget)
425 end
426
427 if (match(key, '[RL]SHIFT') or match(key, '[RL]ALT') or match(key, '[RL]CTRL')) then
428 return
429 end
430
431 if kb.saveTarget then
432 if kb.saveTarget:SaveSlot(key) then
433 if not (kb.db.stickyMode or kb.db.hoverInput) then
434 return self:DeactivateSlot(kb.saveTarget)
435 end
436 return true
437 end
438 end
439 end
440
441
442 function SystemBindingsPanel:Update(force)
443 end
444
445 --- Associate processed input with the given slot's metadata
446 function SkeletonKeyButtonMixin:SaveSlot (key)
447
448 if not self.command then
449 return
450 end
451 if InCombatLockdown() then
452 kb:print(L('Bindings cannot be changed during combat.'))
453 return
454 end
455
456 local spellName = self.actionName
457
458 print('|cFFFFFF00received|cFFFFFF00', self:GetID(), '|cFF00FFFF', key)
459
460 local modifier = ''
461 if IsAltKeyDown() then
462 modifier = 'ALT-'
463 end
464 if IsControlKeyDown() then
465 modifier = modifier.. 'CTRL-'
466 end
467 if IsShiftKeyDown() then
468 modifier = modifier..'SHIFT-'
469 end
470 local binding = modifier..key
471
472 -- check for system bindings
473 --bprint('|cFFFFFF00SaveBind|r', 'protectKeys', kb.db.protectBlizKeys)
474 if kb.db.protectBlizKeys and kb.SystemBindings[binding] then
475 kb:print(L('BINDING_FAILED_PROTECTED', binding, kb.SystemBindings[binding]))
476 return false
477 end
478
479 -- check for other keys
480 local previousCommand = GetBindingAction(binding)
481 if previousCommand ~= "" and previousCommand ~= self.command then
482 local actionType, actionID, name = kb.GetCommandAction(previousCommand)
483 if actionType then
484 local keys = {GetBindingKey(previousCommand) }
485 local i = 1
486 while keys[i] do
487 if keys[i] == binding then
488 tremove(keys, i)
489 kb.UpdateBindingsCache(actionType, actionID, keys)
490 break
491 end
492 i = i + 1
493 end
494 end
495 end
496
497
498 if self.isAvailable then
499 print('Binding available spell', binding, self.command)
500 SetBinding(binding, self.command)
501 SaveBindings(GetCurrentBindingSet())
502 self.assignedKeys = {GetBindingKey(self.command) }
503
504 kb:print(L('BINDING_ASSIGNED', binding, self.actionName, kb.currentHeader))
505 else
506 kb:print(L('UNSELECTED_TALENT_ASSIGNED', binding, self.actionName, kb.currentHeader))
507 end
508
509 if not tContains(self.assignedKeys, binding) then
510 tinsert(self.assignedKeys, 1, binding)
511 end
512
513 local talentInfo
514 if spellName and kb.TalentCache[spellName] then
515 print('store dynamicType talent')
516 talentInfo = {
517 macroName = self.macroName,
518 actionName = self.actionName,
519 actionType = self.actionType,
520 actionID = self.actionID,
521 assignedKeys = self.assignedKeys
522 }
523 kb.currentProfile.talents[spellName] = talentInfo
524 end
525
526 for _, key in ipairs(self.assignedKeys) do
527 if not kb.currentProfile.bindings[key] then
528 kb.currentProfile.bindings[key] = self.command
529 end
530 end
531
532 for level, profile in ipairs(kb.orderedProfiles) do
533 if (level > kb.db.bindMode) then
534 profile.bindings[binding] = nil
535 profile.commands[self.command] = nil
536 profile.bound[self.command] = nil
537 if spellName then
538 profile.talents[spellName] = nil
539 end
540 end
541 end
542
543 kb.UpdateBindingsCache(self.actionType, self.actionID, self.assignedKeys)
544
545 self.binding = binding
546
547 return true
548 end
549
550 function SkeletonKeyMixin:OnKeyDown(key)
551 self:ProcessInput(key)
552 end
553 function SkeletonKeyMixin:OnKeyUp(key)
554 end
555
556 function SkeletonKeyMixin:OnDragStart()
557 self:StartMoving()
558 end
559 function SkeletonKeyMixin:OnDragStop()
560 self:StopMovingOrSizing()
561 end
562
563 function ActionListPanel:UnbindSlot (button)
564
565 local button = button or kb.saveTarget
566 if not button then
567 return
568 end
569
570 local command = button.command
571 local actionType = button.actionType
572 local actionID = button.actionID
573
574 local keys = {GetBindingKey(command) }
575 if #keys >= 1 then
576 kb.UpdateBindingsCache(actionType, actionID, {})
577 end
578
579 local talentName = button.actionName
580 if actionType == 'macro' then
581 local spellName, _, spellID = GetMacroSpell(actionID)
582 talentName = spellName
583 end
584
585
586 --print('detected', #keys, 'bindings')
587 for i, key in pairs(keys) do
588 --print('clearing', key)
589 SetBinding(key, nil)
590 SaveBindings(GetCurrentBindingSet())
591 if kb.currentProfile.bindings[key] then
592 --kb:print(L('BINDING_REMOVED', self.actionName, kb.currentHeader))
593 kb.currentProfile.bindings[key] = nil
594 end
595 if kb.currentProfile.talents[talentName] then
596 kb.currentProfile.talents[talentName] = nil
597 end
598
599 kb.bindings[tostring(actionType)..'_'..tostring(actionID)] = nil
600 end
601 if kb.currentProfile.bound[command] then
602 kb.currentProfile.bound[command] = nil
603 --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode]))
604 end
605 kb.saveTarget = nil
606
607 return true
608 end
609
610 kb.AcceptAssignment = function(self, ...)
611 local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"]
612 local source = kb. loadedProfiles[popup.oldProfile]
613 popup.slot:SetSlot(unpack(popup.args))
614 popup.slot:UpdateSlot()
615 --kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) -- re-enable scrolling
616 ClearCursor()
617 ResetCursor()
618 end
619
620 --- Add to blizzard interfaces
621 StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] = {
622 text = "Confirm moving an assigned command.",
623 button1 = OKAY,
624 button2 = CANCEL,
625 timeout = 0,
626 whileDead = 1,
627 showAlert = 1,
628 OnAccept = kb.AcceptAssignment,
629 --OnCancel = function() kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) end
630 }
631
632
633
634 do
635 local MACRO_SELECTED_ID = 1
636 local MACRO_SELECTED_NAME = GetMacroInfo(1)
637 kb.CreateMacroHooks = function()
638 print('|cFF00FF00setting up MacroUI hooks')
639 hooksecurefunc("MacroFrame_SelectMacro", function(id)
640 print('|cFF0088FFMacroFrame_SelectMacro|r', id)
641 MACRO_SELECTED_ID = id
642 for k,v in pairs(kb.bindings) do
643 --print(k,v)
644 end
645
646 end)
647 end
648 end
649
650
651 SkeletonKeyActionListMixin = Mixin(ActionListPanel, SkeletonKeyPanel)
652 SkeletonKeySystemBindingsMixin = Mixin(SystemBindingsPanel, SkeletonKeyPanel)