List of commits:
Subject Hash Author Date (UTC)
feat!: Initial commit 45c4e781e5ff0a69f8b0bea3a869e2384c7ca454 Vladyslav Bondarenko 2021-10-23 06:03:14
Commit 45c4e781e5ff0a69f8b0bea3a869e2384c7ca454 - feat!: Initial commit
On keyboard hotkey, render a context menu. The menu contains subset of
raid units that player character can target. The menu overrides key
bindings temporarily to allow to target a unit with another hot key
press. Works in combat.

This allows to quickly target a specific member of even a fourty men
raid with a sequence of hot key presses. Currently each raid group from
one to eight, and player character party, should be assigned a hot key.
Then a selection of either raid group members or party members is
rendered.

There is a key binding section in the native key bindings settings menu
in the game, that corresponds to this add-on's key bindings.

For example to target first member of the player's party and not the
player character, bind "Player party" to 'CTRL-P' and "Unit 2" to
'CTRL-S'. Then in game press first CTRL-P, then CTRL-A. To target second
member of the first raid group bind "Group 1" to 'CTRL-Y' and "Unit 2"
to 'CTRL-S'.
Author: Vladyslav Bondarenko
Author date (UTC): 2021-10-23 06:03
Committer name: Vladyslav Bondarenko
Committer date (UTC): 2021-10-23 06:03
Parent(s):
Signer:
Signing key:
Signing status: N
Tree: 5966e7fc00b5178a326ac7040cacb0f2d10b03c0
File Lines added Lines deleted
.gitignore 2 0
.luacheckrc 23 0
bindings.xml 16 0
choir.lua 190 0
choir.toc 6 0
File .gitignore added (mode: 100644) (index 0000000..b72f9be)
1 *~
2 *.swp
File .luacheckrc added (mode: 100644) (index 0000000..0a45ba8)
1 --[[ http://luacheck.readthedocs.io/en/stable/config.html ]]--
2 stds.wow = {
3 globals = {}, --[[ these globals can be set and accessed ]]--
4 read_globals = {
5 'CreateFrame',
6 'NumberFont_OutlineThick_Mono_Small',
7 'SetOverrideBinding',
8 'UIParent',
9 'UnitName',
10 'strtrim',
11 } --[[ these globals can only be accessed ]]--
12 }
13
14 stds.choir = {
15 globals = {
16 'BINDING_HEADER_CHOIR',
17 },
18 read_globals = {
19 'ChoirSpoiler1',
20 }
21 }
22
23 std = "min+wow+choir"
File bindings.xml added (mode: 100644) (index 0000000..73158d3)
1 <Bindings>
2 <Binding name="CLICK ChoirSpoiler9:LeftButton" header="CHOIR"/>
3 <Binding name="CLICK ChoirSpoiler1:LeftButton" header="CHOIR"/>
4 <Binding name="CLICK ChoirSpoiler2:LeftButton" header="CHOIR"/>
5 <Binding name="CLICK ChoirSpoiler3:LeftButton" header="CHOIR"/>
6 <Binding name="CLICK ChoirSpoiler4:LeftButton" header="CHOIR"/>
7 <Binding name="CLICK ChoirSpoiler5:LeftButton" header="CHOIR"/>
8 <Binding name="CLICK ChoirSpoiler6:LeftButton" header="CHOIR"/>
9 <Binding name="CLICK ChoirSpoiler7:LeftButton" header="CHOIR"/>
10 <Binding name="CLICK ChoirSpoiler8:LeftButton" header="CHOIR"/>
11 <Binding name="CLICK ChoirUnitButton1:LeftButton" header="CHOIR"/>
12 <Binding name="CLICK ChoirUnitButton2:LeftButton" header="CHOIR"/>
13 <Binding name="CLICK ChoirUnitButton3:LeftButton" header="CHOIR"/>
14 <Binding name="CLICK ChoirUnitButton4:LeftButton" header="CHOIR"/>
15 <Binding name="CLICK ChoirUnitButton5:LeftButton" header="CHOIR"/>
16 </Bindings>
File choir.lua added (mode: 100644) (index 0000000..a88feb6)
1 local function createLabel(ownerFrame, fontObject)
2 assert (ownerFrame ~= nil)
3
4 local t = ownerFrame:CreateFontString((ownerFrame:GetName() or '') .. 'Text', 'OVERLAY')
5 fontObject = fontObject or NumberFont_OutlineThick_Mono_Small
6 assert (fontObject ~= nil)
7 t:SetFontObject(fontObject)
8 t:SetAllPoints()
9
10 return t
11 end
12
13 local function createBackground(ownerFrame)
14 assert (ownerFrame ~= nil)
15
16 local background = ownerFrame:CreateTexture(ownerFrame:GetName() .. 'Background', 'BACKGROUND')
17 background:SetAllPoints()
18 background:SetTexture(0, 0, 0, 0.8)
19
20 return background
21 end
22
23 local function createUnitButton(parentFrame, frameName, unit)
24 assert (parentFrame ~= nil)
25 assert (frameName ~= nil)
26 assert (unit ~= nil)
27
28 local u = CreateFrame('BUTTON', frameName, parentFrame, 'SecureUnitButtonTemplate')
29 u:SetAttribute('type', 'target')
30 u:SetAttribute('unit', unit)
31
32 u:SetSize(12 * 6, 12 * 2)
33
34 u.text = createLabel(u)
35
36 local b = createBackground(u)
37 b:SetTexture(1.0, 0.0, 0.4, 1.0)
38 u.background = b
39
40 u:SetScript('OnEvent', function(self)
41 assert (self ~= nil)
42 local label = self.text
43 assert (label ~= nil)
44 local unitDesignation = self:GetAttribute('unit')
45 assert (unitDesignation ~= nil)
46 label:SetText(UnitName(unitDesignation) or unitDesignation)
47 end)
48 u:RegisterEvent('PARTY_CONVERTED_TO_RAID')
49 u:RegisterEvent('PARTY_MEMBERS_CHANGED')
50 u:RegisterEvent('PLAYER_ALIVE')
51 u:RegisterEvent('RAID_ROSTER_UPDATE')
52 u:RegisterEvent('UPDATE_BATTLEFIELD_SCORE')
53 u:RegisterEvent('ADDON_LOADED')
54
55 assert (u ~= nil)
56 return u
57 end
58
59 local function createSpoiler(spoilerParent, spoilerDesignation)
60 local spoiler = CreateFrame('BUTTON', spoilerDesignation, spoilerParent, 'SecureHandlerClickTemplate')
61 spoiler:EnableMouse(true)
62 spoiler:SetAttribute('_onclick', [=[
63 local debugFlag = true
64 local parentFrame = self:GetParent()
65 local siblingTable = parentFrame:GetChildList(newtable())
66 local i = 0
67 while (i < #siblingTable) do
68 i = i + 1
69 local sibling = siblingTable[i]
70 sibling:ClearBindings()
71 sibling:Hide()
72 end
73
74 self:Show()
75 local j = 0
76 local childTable = self:GetChildList(newtable())
77 --[[local bindingTable = newtable(
78 'A', 'S', 'D', 'F', 'G'
79 )]]--
80 while (j < #childTable) do
81 j = j + 1
82 local child = childTable[j]
83 local unitDesignation = child:GetAttribute('unit')
84 if unitDesignation ~= nil and UnitExists(unitDesignation) and not debugFlag then
85 child:Show()
86 elseif debugFlag then
87 child:Show()
88 else
89 child:Hide()
90 end
91 print('child', child:GetName())
92 local key = GetBindingKey('CLICK ChoirUnitButton' .. tostring(j) .. ':LeftButton')
93 --local key = bindingTable[math.min(j, #childTable)]
94 if key then
95 self:SetBindingClick(true, key, child)
96 end
97 end
98 ]=])
99
100 return spoiler
101 end
102
103 local function createGroup(rootFrame, groupNumber, unitTable)
104 assert (rootFrame ~= nil)
105
106 assert (groupNumber ~= nil)
107 groupNumber = math.floor(math.abs(groupNumber))
108 assert ((groupNumber >= 1 and groupNumber <= 8) or unitTable ~= nil)
109
110 local groupSize = 5
111
112 local u
113 if unitTable then
114 u = unitTable
115 else
116 local q = 0
117 u = {}
118 while (q < groupSize) do
119 q = q + 1
120 u[q] = 'raid' .. tostring((groupNumber - 1) * groupSize + q)
121 end
122 end
123 assert (u ~= nil)
124 assert ('table' == type(u))
125 assert (#u == groupSize)
126
127 local spoiler = createSpoiler(rootFrame, 'ChoirSpoiler' .. tostring(groupNumber))
128 spoiler:SetSize(12 * 6, 12 * 2)
129 spoiler:SetPoint('CENTER', 0, 144)
130
131 local i = 0
132 local marginLeft = spoiler:GetWidth()
133 local padding = 4
134 while (i < #u) do
135 i = i + 1
136 local unitDesignation = u[i]
137 assert (unitDesignation ~= nil)
138 local memberNumber = (groupNumber - 1) * groupSize + i
139 local b = createUnitButton(spoiler, 'ChoirUnitButton' .. tostring(memberNumber), unitDesignation)
140 b:SetPoint('BOTTOMLEFT', marginLeft + padding, 0)
141 marginLeft = marginLeft + b:GetWidth() + padding
142
143 spoiler:WrapScript(b, 'OnClick', [=[
144 print('OnClick', self:GetName())
145 local parentFrame = self:GetParent()
146 parentFrame:Hide()
147 ]=])
148 b:Hide()
149
150 _G['BINDING_NAME_CLICK ' .. b:GetName() .. ':LeftButton'] = 'Unit ' .. tostring(i)
151 end
152
153 _G['BINDING_NAME_CLICK ' .. spoiler:GetName() .. ':LeftButton'] = 'Group ' .. tostring(groupNumber)
154
155 return spoiler
156 end
157
158 local function init(rootFrame)
159 assert (rootFrame ~= nil)
160
161 rootFrame:UnregisterAllEvents()
162
163 rootFrame:SetSize(1024, 768)
164 rootFrame:SetPoint('CENTER', 0, 0)
165
166 createGroup(rootFrame, 1)
167 createGroup(rootFrame, 2)
168 createGroup(rootFrame, 3)
169 createGroup(rootFrame, 4)
170 createGroup(rootFrame, 5)
171 createGroup(rootFrame, 6)
172 createGroup(rootFrame, 7)
173 createGroup(rootFrame, 8)
174
175 --[[ TODO Add Esc key that closes the spoiler without clicking any of the children buttons ]]--
176 --[[ TODO Generalize the interface to be used with any kind of child frames, especially nested spoilers and spell buttons ]]--
177 local spoilerParty = createGroup(rootFrame, 9, {'player', 'party1', 'party2', 'party3', 'party4'})
178 _G['BINDING_NAME_CLICK ' .. spoilerParty:GetName() .. ':LeftButton'] = 'Player party'
179
180 BINDING_HEADER_CHOIR = 'Choir'
181
182 print('[Choir]: init')
183 end
184
185 local function main()
186 local rootFrame = CreateFrame('FRAME', 'ChoirFrame', UIParent)
187 rootFrame:RegisterEvent('ADDON_LOADED')
188 rootFrame:SetScript('OnEvent', init)
189 end
190 main()
File choir.toc added (mode: 100644) (index 0000000..db7ba66)
1 ##Interface: 30300
2 ##Notes: Raid targeting aid for healers
3 ##Title: Choir
4 ##Version: 0
5 bindings.xml
6 choir.lua
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/choir

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

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

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