List of commits:
Subject Hash Author Date (UTC)
feat(choir): Toggle button visibility given roster d193e7b5eb38cb3ac69d74eec1f96e00d90b6098 Vladyslav Bondarenko 2021-11-10 23:46:24
feat(choir)!: Add permanent raid frame 1839c35af4212c09038e972547d6b5893a9ce219 Vladyslav Bondarenko 2021-11-10 16:04:25
feat(choir)!: Employ Clearcasting subset feat 733c81538c3c965f07993fd7ddc482e724121b75 Vladyslav Bondarenko 2021-11-04 22:40:48
fix(choir): Improve shortcut binding keys eb636de6e3f7bada9f0064ffe4db1db3f6433f6c Vladyslav Bondarenko 2021-10-31 18:55:10
fix(choir): Improve choirBindingKey attribute handling 6c5c2214cc1809e5e5e59cd3672da3cca3f2701f Vladyslav Bondarenko 2021-10-31 13:23:24
feat(choir)!: Add spell shortcut prototype d34f22a6983ffc41122acb40d22e3cb29c208a3c Vladyslav Bondarenko 2021-10-31 12:39:39
feat(choir)!: Add spell effects on unit d581df9fce342709267a3221dead4d00b9d14319 Vladyslav Bondarenko 2021-10-31 10:49:19
feat(choir)!: Close spoiler by pressing Esc 22d7370011ac45d25a410a3f569183d0cc9fb232 Vladyslav Bondarenko 2021-10-29 16:10:08
feat(choir)!: Range indicator 931a0510b562986ec76dc22f329f4af4ed723cdf Vladyslav Bondarenko 2021-10-29 10:40:46
fix(choir)!: Health bar in combat a6622578dd5a1b4e4babf699a4cf1e4eb6bb70d6 Vladyslav Bondarenko 2021-10-28 07:42:57
feat(choir)!: Decorate unit buttons 4dc5ed44a9519b275f4256cfe4281110b7a94c9a Vladyslav Bondarenko 2021-10-25 21:20:56
feat(choir)!: Copy action bar binding 70ce056ffda7f12d913ce9a42b128ea257bdd0dc Vladyslav Bondarenko 2021-10-23 23:34:56
feat!: Initial commit 45c4e781e5ff0a69f8b0bea3a869e2384c7ca454 Vladyslav Bondarenko 2021-10-23 06:03:14
Commit d193e7b5eb38cb3ac69d74eec1f96e00d90b6098 - feat(choir): Toggle button visibility given roster
Given a raid, party or non-existant unit, toggle the unit button
visibility accordingly. Party frame is hidden in raid. There is still
problems with the party frame.
Author: Vladyslav Bondarenko
Author date (UTC): 2021-11-10 23:46
Committer name: Vladyslav Bondarenko
Committer date (UTC): 2021-11-10 23:46
Parent(s): 1839c35af4212c09038e972547d6b5893a9ce219
Signer:
Signing key:
Signing status: N
Tree: 162d5cfb6cc13079c93c2ec14d32ca424b812804
File Lines added Lines deleted
.luacheckrc 5 1
choir.lua 194 74
File .luacheckrc changed (mode: 100644) (index dcef242..e289638)
... ... stds.wow = {
11 11 'IsSpellInRange', 'IsSpellInRange',
12 12 'NumberFont_OutlineThick_Mono_Small', 'NumberFont_OutlineThick_Mono_Small',
13 13 'RAID_CLASS_COLORS', 'RAID_CLASS_COLORS',
14 'RegisterUnitWatch',
14 15 'SetOverrideBinding', 'SetOverrideBinding',
15 16 'UIParent', 'UIParent',
16 17 'UnitClass', 'UnitClass',
17 18 'UnitExists', 'UnitExists',
19 'UnitExists',
18 20 'UnitHealth', 'UnitHealth',
19 21 'UnitHealthMax', 'UnitHealthMax',
20 22 'UnitIsDead', 'UnitIsDead',
21 23 'UnitIsGhost', 'UnitIsGhost',
22 24 'UnitName', 'UnitName',
23 'strtrim',
25 'UnitPlayerOrPetInRaid',
26 'UnregisterUnitWatch',
24 27 'date', 'date',
28 'strtrim',
25 29 } --[[ these globals can only be accessed ]]-- } --[[ these globals can only be accessed ]]--
26 30 } }
27 31
File choir.lua changed (mode: 100644) (index 9507a87..8ccf7b6)
... ... local function updateUnitButtonText(self)
171 171 n = n .. ' <' .. key .. '>' n = n .. ' <' .. key .. '>'
172 172 end end
173 173
174 label:SetText(n)
174 local m = math.floor(self:GetWidth() / 8)
175
176 label:SetText(string.sub(n, 1, m))
175 177 end end
176 178
177 179 local function getClassColor(classDesignation) local function getClassColor(classDesignation)
 
... ... local function createInheritanceHandler(unitButton)
320 322 return inheritor return inheritor
321 323 end end
322 324
325 local function createUnitButtonExistanceHandler(unitButton)
326 assert (unitButton ~= nil)
327
328 RegisterUnitWatch(unitButton, true)
329 local n = (unitButton:GetName() or '') .. 'UnitExistsHandler'
330 local unitexistsHandler = CreateFrame('FRAME', n, unitButton, 'SecureHandlerAttributeTemplate')
331 unitexistsHandler:WrapScript(unitButton, 'OnAttributeChanged', [=[
332 local existanceFlag = self:GetAttribute('state-unitexists')
333 if existanceFlag then
334 self:Show()
335 else
336 self:Hide()
337 end
338 ]=])
339
340 return unitexistsHandler
341 end
342
323 343 local function createUnitButton(parentFrame, frameName, unit, width, height) local function createUnitButton(parentFrame, frameName, unit, width, height)
324 344 assert (parentFrame ~= nil) assert (parentFrame ~= nil)
325 345 assert (frameName ~= nil) assert (frameName ~= nil)
 
... ... local function createUnitButton(parentFrame, frameName, unit, width, height)
331 351 -- That way, user may cast something without targeting or hiding the selection spoiler. -- That way, user may cast something without targeting or hiding the selection spoiler.
332 352 -- The problem is that it is class dependant.]]-- -- The problem is that it is class dependant.]]--
333 353 local u = CreateFrame('BUTTON', frameName, parentFrame, 'SecureUnitButtonTemplate') local u = CreateFrame('BUTTON', frameName, parentFrame, 'SecureUnitButtonTemplate')
334 u:SetAttribute('type', 'target')
335 u:SetAttribute('unit', unit)
336 354
337 355 createBindingKeyHandler(u) createBindingKeyHandler(u)
338 356 createInheritanceHandler(u) createInheritanceHandler(u)
 
... ... local function createUnitButton(parentFrame, frameName, unit, width, height)
360 378 local bar = createUnitButtonBar(u) local bar = createUnitButtonBar(u)
361 379 u.bar = bar u.bar = bar
362 380
381 createUnitButtonExistanceHandler(u)
382
383 u:SetAttribute('type', 'target')
384 u:SetAttribute('unit', unit)
385
363 386 u:SetScript('OnEvent', unitButtonEventProcessor) u:SetScript('OnEvent', unitButtonEventProcessor)
364 387 u:RegisterEvent('PARTY_CONVERTED_TO_RAID') u:RegisterEvent('PARTY_CONVERTED_TO_RAID')
365 388 u:RegisterEvent('PARTY_MEMBERS_CHANGED') u:RegisterEvent('PARTY_MEMBERS_CHANGED')
 
... ... local function createGroup(rootFrame, groupNumber, unitTable)
520 543
521 544 local spoiler = createSpoiler(rootFrame, 'ChoirSpoiler' .. tostring(groupNumber)) local spoiler = createSpoiler(rootFrame, 'ChoirSpoiler' .. tostring(groupNumber))
522 545
546 local bgr = createBackground(spoiler)
547 bgr:SetTexture(0, 0, 0, 0.2)
548
523 549 local i = 0 local i = 0
524 550 local marginLeft = 0 local marginLeft = 0
525 551 local padding = 4 local padding = 4
 
... ... local function createGroup(rootFrame, groupNumber, unitTable)
551 577 createUnitButtonSpellShortcut(b, i) createUnitButtonSpellShortcut(b, i)
552 578 createClearcastingSubset(b) createClearcastingSubset(b)
553 579 end end
554 spoiler:SetSize(marginLeft, 144)
580 spoiler:SetSize(marginLeft, 144 + 24)
555 581 spoiler:SetPoint('CENTER', 0, 12 * 6) spoiler:SetPoint('CENTER', 0, 12 * 6)
556 582
583 local title = createLabel(spoiler)
584 title:SetPoint('TOPRIGHT', 0, 0)
585 title:SetPoint('BOTTOMLEFT', spoiler, 'TOPLEFT', spoiler:GetWidth() / 2 - title:GetWidth() / 2, -24)
586 title:SetText('Group ' .. tostring(groupNumber))
587 spoiler.text = title
588
557 589 _G['BINDING_NAME_CLICK ' .. spoiler:GetName() .. ':LeftButton'] = 'Group ' .. tostring(groupNumber) _G['BINDING_NAME_CLICK ' .. spoiler:GetName() .. ':LeftButton'] = 'Group ' .. tostring(groupNumber)
558 590
559 591 spoiler:Hide() spoiler:Hide()
 
... ... local function createGroup(rootFrame, groupNumber, unitTable)
561 593 return spoiler return spoiler
562 594 end end
563 595
564 local function createRaidFrame(rootFrame, spoilerHolder)
565 assert (rootFrame ~= nil)
566 assert (spoilerHolder ~= nil)
596 local function raidGroupEventProcessor(groupFrame)
597 assert (groupFrame ~= nil)
598
599 local u0, u1, u2, u3, u4 = groupFrame:GetChildren()
600 assert (u0 ~= nil)
601 assert (u1 ~= nil)
602 assert (u2 ~= nil)
603 assert (u3 ~= nil)
604 assert (u4 ~= nil)
605
606 local groupExists = UnitExists(u0:GetAttribute('unit') or 'none') or
607 UnitExists(u1:GetAttribute('unit') or 'none') or
608 UnitExists(u2:GetAttribute('unit') or 'none') or
609 UnitExists(u3:GetAttribute('unit') or 'none') or
610 UnitExists(u4:GetAttribute('unit') or 'none')
611
612 if groupExists then
613 groupFrame:Show()
614 else
615 groupFrame:Hide()
616 end
617 end
618
619 local function partyFrameEventProcessor(playerPartyFrame)
620 assert (playerPartyFrame ~= nil)
621
622 local isRaid = UnitPlayerOrPetInRaid('player')
623 if isRaid then
624 local p0, p1, p2, p3, p4 = playerPartyFrame:GetChildren()
625 UnregisterUnitWatch(p0)
626 UnregisterUnitWatch(p1)
627 UnregisterUnitWatch(p2)
628 UnregisterUnitWatch(p3)
629 UnregisterUnitWatch(p4)
630 playerPartyFrame:Hide()
631 elseif not playerPartyFrame:IsShown() then
632 local p0, p1, p2, p3, p4 = playerPartyFrame:GetChildren()
633 RegisterUnitWatch(p0, true)
634 RegisterUnitWatch(p1, true)
635 RegisterUnitWatch(p2, true)
636 RegisterUnitWatch(p3, true)
637 RegisterUnitWatch(p4, true)
638 playerPartyFrame:Show()
639 end
640 end
641
642 local function createRaidGroupLabel(groupFrame, groupNumber)
643 assert (groupFrame ~= nil)
644 assert (groupNumber >= 1 and groupNumber <= 8 + 1)
645
646 local labelWidth = 60
647
648 local groupLabel = groupFrame:CreateFontString(groupFrame:GetName() .. 'Label', 'OVERLAY')
649 local fontObject = NumberFont_OutlineThick_Mono_Small
650 assert (fontObject ~= nil)
651 groupLabel:SetFontObject(fontObject)
652 groupLabel:SetPoint('BOTTOMLEFT', groupFrame, 'BOTTOMLEFT', 0, 0)
653 groupLabel:SetPoint('TOPRIGHT', groupFrame, 'TOPLEFT', labelWidth, 0)
654
655 local labelContent
656 --[[ FIXME Update hotkey label at runtime without needing UI /reload. ]]--
657 local hotkey = GetBindingKey('CLICK ChoirSpoiler' .. tostring(groupNumber) .. ':LeftButton')
658 if hotkey then
659 labelContent = _G['BINDING_NAME_CLICK ChoirSpoiler' .. tostring(groupNumber) .. ':LeftButton']
660 labelContent = labelContent .. ' <' .. tostring(hotkey) .. '>'
661 else
662 labelContent = tostring(groupNumber)
663 end
664 groupLabel:SetText(labelContent)
665
666 return groupLabel
667 end
668
669 local function createRaidGroupFrame(raidFrame, groupNumber, unitSetOverride)
670 assert (raidFrame ~= nil)
671
672 assert (groupNumber ~= nil)
673 groupNumber = math.floor(groupNumber)
674 assert ('number' == type(groupNumber))
675 assert (groupNumber >= 1 and groupNumber <= 8 + 1)
567 676
568 677 local maxPartySize = 5 local maxPartySize = 5
569 local maxSubgroupQuantity = 8
570 local maxRaidSize = maxPartySize * maxSubgroupQuantity
678
679 if unitSetOverride ~= nil then
680 assert ('table' == type(unitSetOverride))
681 assert (#unitSetOverride == maxPartySize)
682 end
571 683
572 684 local buttonWidth = 48 local buttonWidth = 48
573 685 local buttonHeight = 24 + 12 + 8 local buttonHeight = 24 + 12 + 8
574 686 local padding = 2 local padding = 2
575
576 687 local labelWidth = 60 local labelWidth = 60
577 local raidFrame = CreateFrame('FRAME', 'ChoirRaidFrame', rootFrame)
578 raidFrame:SetSize(labelWidth + (padding + buttonWidth) * maxPartySize,
579 (padding + buttonHeight) * (maxSubgroupQuantity + 1))
580 raidFrame:SetPoint('TOPLEFT', 0, -144)
581 688
582 --[[ TODO Add party frame ]]--
583 --[[ TODO Add any debuff indicator ]]--
584 --[[ TODO Render only buttons for existing units ]]--
585 local memberNumber = 0
586 local j = 0
587 --[[ NOTE The extra number is for the party frame.
588 -- Highly coupled with initSpoiler implementation. ]]--
589 while (j < maxSubgroupQuantity + 1) do
590 j = j + 1
689 local unitSet
690 if unitSetOverride ~= nil then
691 unitSet = unitSetOverride
692 else
693 unitSet = {}
694 local p = 0
695 while (p < maxPartySize) do
696 p = p + 1
697 unitSet[p] = 'raid' .. (groupNumber - 1) * maxPartySize + p
698 end
699 end
591 700
592 local groupFrame = CreateFrame('FRAME', 'ChoirRaidGroupFrame' .. tostring(j), raidFrame)
593 groupFrame:SetSize(labelWidth + maxPartySize * (buttonWidth + padding), buttonHeight + padding)
594 groupFrame:SetPoint('BOTTOMLEFT', 0, (j - 1) * (buttonHeight + padding))
701 local groupFrame = CreateFrame('FRAME', 'ChoirRaidGroupFrame' .. tostring(groupNumber), raidFrame)
702 groupFrame:SetSize(labelWidth + maxPartySize * (buttonWidth + padding), buttonHeight + padding)
595 703
596 local groupLabel = groupFrame:CreateFontString(groupFrame:GetName() .. 'Label', 'OVERLAY')
597 local fontObject = NumberFont_OutlineThick_Mono_Small
598 assert (fontObject ~= nil)
599 groupLabel:SetFontObject(fontObject)
600 groupLabel:SetPoint('BOTTOMLEFT', groupFrame, 'BOTTOMLEFT', 0, 0)
601 groupLabel:SetPoint('TOPRIGHT', groupFrame, 'TOPLEFT', labelWidth, 0)
602
603 local labelContent
604 --[[ FIXME Update hotkey label at runtime without needing UI /reload. ]]--
605 local hotkey = GetBindingKey('CLICK ChoirSpoiler' .. tostring(j) .. ':LeftButton')
606 if hotkey then
607 labelContent = _G['BINDING_NAME_CLICK ChoirSpoiler' .. tostring(j) .. ':LeftButton']
608 labelContent = labelContent .. ' <' .. tostring(hotkey) .. '>'
609 else
610 labelContent = 'Group ' .. tostring(j)
611 end
612 groupLabel:SetText(labelContent)
704 createRaidGroupLabel(groupFrame, groupNumber)
613 705
614 local i = 0
615 while (i < maxPartySize) do
616 memberNumber = memberNumber + 1
617
618 local unitDesignation
619 local groupType
620 if memberNumber > maxRaidSize and memberNumber <= maxRaidSize + 5 then
621 groupType = 'party'
622 local partyMemberNumber = memberNumber - maxRaidSize
623 if partyMemberNumber > 1 then
624 unitDesignation = groupType .. tostring(memberNumber)
625 else
626 unitDesignation = 'player'
627 end
628 else
629 groupType = 'raid'
630 unitDesignation = groupType .. tostring(memberNumber)
631 end
706 local i = 0
707 while (i < #unitSet) do
708 i = i + 1
632 709
633 local n = 'ChoirRaidUnitButton' .. tostring(memberNumber)
634 local debug = false
635 if debug then
636 unitDesignation = 'player'
637 end
638 local b = createUnitButton(groupFrame, n, unitDesignation)
639 b:SetSize(buttonWidth, buttonHeight)
640 b:SetPoint('BOTTOMLEFT', labelWidth + i * (padding + b:GetWidth()), 0)
641 i = i + 1
642 end
710 local unitDesignation = unitSet[i]
711 assert (unitDesignation ~= nil)
712
713 local n = groupFrame:GetName() .. 'RaidUnitButton' .. tostring(i)
714 local b = createUnitButton(groupFrame, n, unitDesignation, buttonWidth, buttonHeight)
715 b:SetPoint('BOTTOMLEFT', labelWidth + (i - 1) * (padding + b:GetWidth()), 0)
643 716 end end
644 717
718 groupFrame:RegisterEvent('PARTY_CONVERTED_TO_RAID')
719 groupFrame:RegisterEvent('PARTY_MEMBERS_CHANGED')
720 groupFrame:RegisterEvent('PLAYER_ALIVE')
721 groupFrame:RegisterEvent('RAID_ROSTER_UPDATE')
722 groupFrame:RegisterEvent('UPDATE_BATTLEFIELD_SCORE')
723 groupFrame:RegisterEvent('ADDON_LOADED')
724 groupFrame:SetScript('OnEvent', raidGroupEventProcessor)
725
726 return groupFrame
727 end
728
729 local function createRaidFrameToggleHandler(raidFrame, spoilerHolder)
645 730 --[[ Given any spoiler is shown, then hide the raid frame. ]]-- --[[ Given any spoiler is shown, then hide the raid frame. ]]--
646 731 --[[ Given all spoilers are hidden, show the raid frame. ]]-- --[[ Given all spoilers are hidden, show the raid frame. ]]--
647 732 local spoilerList = {spoilerHolder:GetChildren()} local spoilerList = {spoilerHolder:GetChildren()}
 
... ... local function createRaidFrame(rootFrame, spoilerHolder)
651 736 local spoiler = spoilerList[p] local spoiler = spoilerList[p]
652 737
653 738 local handler = CreateFrame('FRAME', 'ChoirRaidFrameToggleHandler' .. tostring(p), local handler = CreateFrame('FRAME', 'ChoirRaidFrameToggleHandler' .. tostring(p),
654 raidFrame, 'SecureHandlerShowHideTemplate')
739 raidFrame, 'SecureHandlerShowHideTemplate')
655 740
656 741 spoiler:SetFrameRef('ChoirRaidFrame', raidFrame) spoiler:SetFrameRef('ChoirRaidFrame', raidFrame)
657 742 handler:WrapScript(spoiler, 'OnShow', [=[ handler:WrapScript(spoiler, 'OnShow', [=[
 
... ... local function createRaidFrame(rootFrame, spoilerHolder)
678 763 end end
679 764 ]=]) ]=])
680 765 end end
766 end
767
768 local function createRaidFrame(rootFrame, spoilerHolder)
769 assert (rootFrame ~= nil)
770 assert (spoilerHolder ~= nil)
771
772 local maxPartySize = 5
773 local maxSubgroupQuantity = 8
774
775 local buttonWidth = 48
776 local buttonHeight = 24 + 12 + 8
777 local padding = 2
778
779 local labelWidth = 60
780 local raidFrame = CreateFrame('FRAME', 'ChoirRaidFrame', rootFrame)
781 raidFrame:SetSize(labelWidth + (padding + buttonWidth) * maxPartySize,
782 (padding + buttonHeight) * (maxSubgroupQuantity + 1))
783 raidFrame:SetPoint('TOPLEFT', 0, -144)
784
785 --[[ TODO Add any debuff indicator ]]--
786 local j = 0
787 while (j < maxSubgroupQuantity) do
788 j = j + 1
789 local groupFrame = createRaidGroupFrame(raidFrame, j)
790 groupFrame:SetPoint('BOTTOMLEFT', 0, (j - 1) * (buttonHeight + padding))
791 end
792
793 --[[ NOTE Appearance of the party frame is conditional, only shown outside of raid.
794 -- Therefore corner case code is implemented. ]]--
795 local partyUnitSet = {'player', 'party1', 'party2', 'party3', 'party4'}
796 local playerPartyFrame = createRaidGroupFrame(raidFrame, maxSubgroupQuantity + 1, partyUnitSet)
797 playerPartyFrame:SetPoint('BOTTOMLEFT', 0, (maxSubgroupQuantity + 1) * (buttonHeight + padding))
798 playerPartyFrame:SetScript('OnEvent', partyFrameEventProcessor)
799
800 createRaidFrameToggleHandler(rootFrame, spoilerHolder)
681 801
682 802 return raidFrame return raidFrame
683 803 end end
 
... ... local function initSpoiler(rootFrame)
762 882 createGroup(spoilerHolder, 7) createGroup(spoilerHolder, 7)
763 883 createGroup(spoilerHolder, 8) createGroup(spoilerHolder, 8)
764 884
765 --[[ TODO Add Esc key that closes the spoiler without clicking any of the children buttons ]]--
766 885 --[[ TODO Generalize the interface to be used with any kind of child frames, --[[ TODO Generalize the interface to be used with any kind of child frames,
767 886 -- especially nested spoilers and spell buttons. ]]-- -- especially nested spoilers and spell buttons. ]]--
768 887 --[[ NOTE To get a saved variables kind of table from a restricted frame snippet, use ``` --[[ NOTE To get a saved variables kind of table from a restricted frame snippet, use ```
 
... ... local function initSpoiler(rootFrame)
771 890 -- ``` -- ```
772 891 -- See http://www.iriel.org/wow/docs/SecureHeadersGuide-4.0-r1.pdf ]]-- -- See http://www.iriel.org/wow/docs/SecureHeadersGuide-4.0-r1.pdf ]]--
773 892 local spoilerParty = createGroup(spoilerHolder, 9, {'player', 'party1', 'party2', 'party3', 'party4'}) local spoilerParty = createGroup(spoilerHolder, 9, {'player', 'party1', 'party2', 'party3', 'party4'})
774 _G['BINDING_NAME_CLICK ' .. spoilerParty:GetName() .. ':LeftButton'] = 'Player party'
893 spoilerParty.text:SetText('Party')
894 _G['BINDING_NAME_CLICK ' .. spoilerParty:GetName() .. ':LeftButton'] = 'Party'
775 895
776 896 BINDING_HEADER_CHOIR = 'Choir' BINDING_HEADER_CHOIR = 'Choir'
777 897
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/vrtc/wowaddons

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/vrtc/wowaddons

Clone this repository using git:
git clone git://git.rocketgit.com/user/vrtc/wowaddons

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main