vrtc / chorus (public) (License: CC0) (since 2023-08-12) (hash sha1)
World of Warcraft add-on stub. The overall goal is to create a specialized raid frame.
List of commits:
Subject Hash Author Date (UTC)
feat!: replace deprecated unit status bars dd8056c5ba236667f8dd340f8e74e837757bed80 Vladyslav Bondarenko 2025-02-26 19:26:47
feat!: add new unit health display 6b2b9d93bdda1f5f8284b37d2bbe21e35387eedd Vladyslav Bondarenko 2025-02-26 15:17:19
feat: add tiny auras to small unit frame 835541052fb5452ef35573faf39a5faacc243be3 Vladyslav Bondarenko 2025-02-14 18:32:36
feat: add chorus slash command 11427128e833d0f7acaaf720d5fe13746ea95e72 Vladyslav Bondarenko 2025-02-12 20:45:56
fix: make user configuration frame more robust f6423c6113559ed00f07a79584e6ef24f78e81d7 Vladyslav Bondarenko 2025-02-12 19:51:35
feat: prepare release 0.13.0 adc28078888e57f0f8f221d56ecc297044202b5f Vladyslav Bondarenko 2025-02-11 06:36:02
fix: remove invisible buttons obstructing clicks b4701b9c13fbdea44089eae83444e4a24a878a03 Vladyslav Bondarenko 2025-02-11 06:30:13
fix: position past party member correctly 91fad9b3decb82a8e289ca38b06a15c25dce19b0 Vladyslav Bondarenko 2025-02-10 20:24:23
fix: ensure pets party frame loads correctly 1dd2e348bd15aa642c36057c2f92484755a4cb57 Vladyslav Bondarenko 2025-02-09 23:14:40
feat!: integrate party pets frame f34c334ca838ca8c26106f89fa7e088bf74af36b Vladyslav Bondarenko 2025-02-09 22:59:14
fix: add robustness check to button factories b7e195cf9623c0e7280a2a76d34de2f078373852 Vladyslav Bondarenko 2025-02-09 20:48:36
feat: integrate pet frame with raid profiles 856c7021197a301ab04428bc0dfff4eaa77a0a43 Vladyslav Bondarenko 2025-02-09 20:47:03
fix!: update pet frame correctly 3d9a3ac39962ca2e39f7a330abe74a229b822e4e Vladyslav Bondarenko 2025-02-09 00:56:36
feat: add pet frame stub 4cbc49b6720943fb9929f3bce34887d425c36629 Vladyslav Bondarenko 2025-02-08 23:21:15
fix: trigger unit button on mouse down 730a9f8483b0ccf6d8bccae71c1ab83bbae08920 Vladyslav Bondarenko 2025-02-08 18:41:46
doc: fix minor documentation markup issues fc0a3ac65c9a4682025639d416083bbfc690023f Vladyslav Bondarenko 2025-02-05 11:40:51
fix: move role widget 2832bd50f728bb89412aff98d8d1776ce102fb92 Vladyslav Bondarenko 2025-02-04 20:02:58
feat: aura duration of less than one second 9d2be37d502e438ebb1c79bc9278fd7f189ec8d3 Vladyslav Bondarenko 2025-02-04 19:29:50
feat!: add ready check widget 54f77e083a30b5d2ea3d7c0facc4f04ae5a50524 Vladyslav Bondarenko 2025-02-04 18:56:01
fix: add numerical identifiers to raid frames 7805568e6500ba652f5489a84d78697dc81d1017 Vladyslav Bondarenko 2025-02-04 18:54:04
Commit dd8056c5ba236667f8dd340f8e74e837757bed80 - feat!: replace deprecated unit status bars
Use the new implementation of the unit health and power status bars,
instead of the deprecated one.

Additionally, smooth out some quirks of the old unit frame
implementation. Unit frame implementation might require serious
redesign.

Next is to refine the small unit frame profile, since it is by far the
most used one. Right now the small unit auras, first, suffer poor
runtime performance in large player groups, and second, not ergonomic
enough.
Author: Vladyslav Bondarenko
Author date (UTC): 2025-02-26 19:26
Committer name: Vladyslav Bondarenko
Committer date (UTC): 2025-02-26 19:26
Parent(s): 6b2b9d93bdda1f5f8284b37d2bbe21e35387eedd
Signer:
Signing key: EFF9624877D25D02
Signing status: E
Tree: 3059405ac9721e0c4bbe097625fd03206288518c
File Lines added Lines deleted
conf/make/src.mk 4 3
src/Chorus.lua 8 0
src/Chorus.xml 2 6
src/ChorusFrame.lua 9 5
src/ChorusHealthFrameTemplate.xml 0 44
src/ChorusHugeUnitFrameTemplate.xml 28 2
src/ChorusLargeUnitFrameTemplate.xml 28 2
src/ChorusPowerFrameTemplate.xml 0 30
src/ChorusProgressFrameTemplate.lua 0 569
src/ChorusSmallUnitFrameTemplate.xml 20 4
src/ChorusTinyUnitFrameTemplate.xml 1 1
src/ChorusUnitFrameTemplate.lua 24 65
src/ChorusUnitFrameTemplate.xml 1 0
src/ChorusUnitHealthFrameTemplate.lua 101 9
src/ChorusUnitHealthStatusBarTemplate.lua 9 4
src/ChorusUnitHealthStatusBarTemplate.xml 0 73
src/ChorusUnitPowerFrameTemplate.xml 32 0
src/ChorusUnitPowerStatusBarTemplate.lua 113 0
src/ChorusUnitPowerStatusBarTemplate.xml 18 0
File conf/make/src.mk changed (mode: 100644) (index c0c90d0..9a6928f)
... ... ${srcdir}src/ChorusUnitHealthFrameTemplate.lua \
36 36 ${srcdir}src/ChorusUnitHealthStatusBarTemplate.lua \ ${srcdir}src/ChorusUnitHealthStatusBarTemplate.lua \
37 37 ${srcdir}src/ChorusUnitLevelFrameTemplate.lua \ ${srcdir}src/ChorusUnitLevelFrameTemplate.lua \
38 38 ${srcdir}src/ChorusUnitNameFrameTemplate.lua \ ${srcdir}src/ChorusUnitNameFrameTemplate.lua \
39 ${srcdir}src/ChorusUnitPowerStatusBarTemplate.lua \
39 40 ${srcdir}src/local.lua ${srcdir}src/local.lua
40 41
41 42 XMLFILES = \ XMLFILES = \
 
... ... ${srcdir}src/ChorusFocusFrame.xml \
51 52 ${srcdir}src/ChorusFont.xml \ ${srcdir}src/ChorusFont.xml \
52 53 ${srcdir}src/ChorusFrame.xml \ ${srcdir}src/ChorusFrame.xml \
53 54 ${srcdir}src/ChorusGroupFrame.xml \ ${srcdir}src/ChorusGroupFrame.xml \
54 ${srcdir}src/ChorusHealthFrameTemplate.xml \
55 55 ${srcdir}src/ChorusHugeUnitFrameTemplate.xml \ ${srcdir}src/ChorusHugeUnitFrameTemplate.xml \
56 56 ${srcdir}src/ChorusLargeRaidFrame.xml \ ${srcdir}src/ChorusLargeRaidFrame.xml \
57 57 ${srcdir}src/ChorusLargeUnitFrameTemplate.xml \ ${srcdir}src/ChorusLargeUnitFrameTemplate.xml \
58 58 ${srcdir}src/ChorusPartyFrame.xml \ ${srcdir}src/ChorusPartyFrame.xml \
59 59 ${srcdir}src/ChorusPetFrameTemplate.xml \ ${srcdir}src/ChorusPetFrameTemplate.xml \
60 60 ${srcdir}src/ChorusPlayerFrame.xml \ ${srcdir}src/ChorusPlayerFrame.xml \
61 ${srcdir}src/ChorusPowerFrameTemplate.xml \
62 61 ${srcdir}src/ChorusProgressFrameTemplate.xml \ ${srcdir}src/ChorusProgressFrameTemplate.xml \
63 62 ${srcdir}src/ChorusRaidFrameTemplate.xml \ ${srcdir}src/ChorusRaidFrameTemplate.xml \
64 63 ${srcdir}src/ChorusRaidTargetIconFrameTemplate.xml \ ${srcdir}src/ChorusRaidTargetIconFrameTemplate.xml \
 
... ... ${srcdir}src/ChorusUnitGroupRoleFrameTemplate.xml \
80 79 ${srcdir}src/ChorusUnitHealthFrameTemplate.xml \ ${srcdir}src/ChorusUnitHealthFrameTemplate.xml \
81 80 ${srcdir}src/ChorusUnitHealthStatusBarTemplate.xml \ ${srcdir}src/ChorusUnitHealthStatusBarTemplate.xml \
82 81 ${srcdir}src/ChorusUnitLevelFrameTemplate.xml \ ${srcdir}src/ChorusUnitLevelFrameTemplate.xml \
83 ${srcdir}src/ChorusUnitNameFrameTemplate.xml
82 ${srcdir}src/ChorusUnitNameFrameTemplate.xml \
83 ${srcdir}src/ChorusUnitPowerFrameTemplate.xml \
84 ${srcdir}src/ChorusUnitPowerStatusBarTemplate.xml
File src/Chorus.lua changed (mode: 100644) (index ac8e35a..40194fa)
... ... function Chorus.luacheckrcDump()
40 40 end end
41 41 table.sort(dump) table.sort(dump)
42 42 end end
43
44 local function trace(...)
45 print(date('%X'), '[Chorus]:', ...)
46 end
47
48 Chorus.trace = function(...)
49 return trace(...)
50 end
File src/Chorus.xml changed (mode: 100644) (index 2d06df2..a88c615)
11 11 <Include file="ChorusAuraTooltipToggleButtonTemplate.xml"/> <Include file="ChorusAuraTooltipToggleButtonTemplate.xml"/>
12 12 <Include file="ChorusUnitHealthFrameTemplate.xml"/> <Include file="ChorusUnitHealthFrameTemplate.xml"/>
13 13 <Include file="ChorusUnitHealthStatusBarTemplate.xml"/> <Include file="ChorusUnitHealthStatusBarTemplate.xml"/>
14 <!--<Include file="ChorusUnitPowerFrameTemplate.xml"/>-->
15 <!-- Do Deprecated -->
16 <Include file="ChorusProgressFrameTemplate.xml"/>
17 <Include file="ChorusHealthFrameTemplate.xml"/>
18 <Include file="ChorusPowerFrameTemplate.xml"/>
19 <!-- End Deprecated -->
14 <Include file="ChorusUnitPowerFrameTemplate.xml"/>
15 <Include file="ChorusUnitPowerStatusBarTemplate.xml"/>
20 16 <Include file="ChorusCastFrameTemplate.xml"/> <Include file="ChorusCastFrameTemplate.xml"/>
21 17 <Include file="ChorusUnitNameFrameTemplate.xml"/> <Include file="ChorusUnitNameFrameTemplate.xml"/>
22 18 <Include file="ChorusRangeFrameTemplate.xml"/> <Include file="ChorusRangeFrameTemplate.xml"/>
File src/ChorusFrame.lua changed (mode: 100644) (index 8ddb83a..91da581)
... ... local function applyLayout(self)
50 50 self:UnregisterAllEvents(); self:UnregisterAllEvents();
51 51 self:SetScript('OnEvent', nil) self:SetScript('OnEvent', nil)
52 52
53 ChorusPlayerFrameHealthFrame.strategy = 'UnitClass'
54 ChorusFocusFrameHealthFrame.strategy = 'UnitIsFriend'
55 ChorusFocusFrameUnitNameFrame.strategy = 'UnitClass'
53 --[[-- @todo Add separate template for target and focus frames to
54 account for events unique to the frames, instead of implementing
55 target and focus frame features for every raid member frame template.
56 ]]
56 57
57 ChorusTargetFrameHealthFrame.strategy = 'UnitIsFriend'
58 ChorusTargetFrameUnitNameFrame.strategy = 'UnitClass'
58 ChorusFocusFrameHealthStatusBar:SetAttribute('chorus-strategy', 'UnitIsFriend')
59 ChorusPlayerFrameHealthStatusBar:SetAttribute('chorus-strategy', 'UnitClass')
60 ChorusTargetFrameHealthStatusBar:SetAttribute('chorus-strategy', 'UnitIsFriend')
59 61
62 ChorusFocusFrameUnitNameFrame.strategy = 'UnitClass'
63 ChorusTargetFrameUnitNameFrame.strategy = 'UnitClass'
60 64 end end
61 65
62 66 --[[-- --[[--
File src/ChorusHealthFrameTemplate.xml deleted (index 858f085..0000000)
1 <?xml version="1.0" encoding="UTF-8"?>
2 <Ui xmlns="http://www.blizzard.com/wow/ui/">
3 <!-- Requries ChorusProgressFrameTemplate.xml -->
4 <StatusBar name="ChorusHealthFrameTemplate" inherits="ChorusProgressFrameTemplate" virtual="true">
5 <Scripts>
6 <OnLoad>Chorus.healthFrameMain(self);</OnLoad>
7 </Scripts>
8 <Attributes>
9 <Attribute name="useparent-unit" type="boolean" value="true"/>
10 </Attributes>
11 </StatusBar>
12 <!-- Huge health bar shows percentage, current amount and current deficit in the middle of the frame. -->
13 <StatusBar name="ChorusHugeHealthFrameTemplate" inherits="ChorusHealthFrameTemplate" virtual="true">
14 <Layers>
15 <Layer level="OVERLAY">
16 <FontString name="$parentText1" inherits="ChorusFont12Mono" justifyH="LEFT" justifyV="MIDDLE" setAllPoints="true"/>
17 <FontString name="$parentText2" inherits="ChorusFont12Mono" justifyH="CENTER" justifyV="MIDDLE" setAllPoints="true"/>
18 <FontString name="$parentText3" inherits="ChorusFont12Mono" justifyH="RIGHT" justifyV="MIDDLE" setAllPoints="true">
19 <Color r="1" g="0" b="0"/>
20 </FontString>
21 </Layer>
22 </Layers>
23 </StatusBar>
24 <!-- Large health bar shows percentage and current amount in the middle of the frame. -->
25 <StatusBar name="ChorusLargeHealthFrameTemplate" inherits="ChorusHealthFrameTemplate" virtual="true">
26 <Layers>
27 <Layer level="OVERLAY">
28 <FontString name="$parentText1" inherits="ChorusFont12Mono" justifyH="LEFT" justifyV="MIDDLE" setAllPoints="true"/>
29 <FontString name="$parentText2" inherits="ChorusFont12Mono" justifyH="RIGHT" justifyV="MIDDLE" setAllPoints="true"/>
30 </Layer>
31 </Layers>
32 </StatusBar>
33 <!-- Small health bar shows percentage at the bottom of the frame. -->
34 <StatusBar name="ChorusSmallHealthFrameTemplate" inherits="ChorusHealthFrameTemplate" virtual="true">
35 <Layers>
36 <Layer level="OVERLAY">
37 <FontString name="$parentText1" inherits="ChorusFont12Mono" justifyH="LEFT" justifyV="BOTTOM" setAllPoints="true"/>
38 </Layer>
39 </Layers>
40 </StatusBar>
41 <!-- Tiny health bar shows no amounts. -->
42 <StatusBar name="ChorusTinyHealthFrameTemplate" inherits="ChorusHealthFrameTemplate" virtual="true">
43 </StatusBar>
44 </Ui>
File src/ChorusHugeUnitFrameTemplate.xml changed (mode: 100644) (index 5b6fdab..88c8efe)
81 81 </Anchors> </Anchors>
82 82 </Frame> </Frame>
83 83 <!-- Main --> <!-- Main -->
84 <StatusBar name="$parentHealthFrame" inherits="ChorusHugeHealthFrameTemplate">
84 <StatusBar name="$parentHealthStatusBar" inherits="ChorusUnitHealthUnitClassStatusBarTemplate">
85 <Size>
86 <AbsDimension x="200" y="174"/>
87 </Size>
85 88 <Anchors> <Anchors>
86 89 <Anchor point="TOPRIGHT"> <Anchor point="TOPRIGHT">
87 90 <Offset x="0" y="-16"/> <Offset x="0" y="-16"/>
 
91 94 </Anchor> </Anchor>
92 95 </Anchors> </Anchors>
93 96 </StatusBar> </StatusBar>
94 <StatusBar name="$parentPowerFrame" inherits="ChorusHugePowerFrameTemplate">
97 <Frame name="$parentHealthFrame" inherits="ChorusUnitHealthHugeFrameTemplate">
98 <Anchors>
99 <Anchor point="TOPRIGHT">
100 <Offset x="0" y="-16"/>
101 </Anchor>
102 <Anchor point="BOTTOMLEFT" relativeTo="$parent" relativePoint="TOPLEFT">
103 <Offset x="0" y="-40"/>
104 </Anchor>
105 </Anchors>
106 </Frame>
107 <StatusBar name="$parentPowerStatusBar" inherits="ChorusUnitPowerStatusBarTemplate">
108 <Size>
109 <AbsDimension x="200" y="174"/>
110 </Size>
95 111 <Anchors> <Anchors>
96 112 <Anchor point="TOPRIGHT"> <Anchor point="TOPRIGHT">
97 113 <Offset x="0" y="-40"/> <Offset x="0" y="-40"/>
 
101 117 </Anchor> </Anchor>
102 118 </Anchors> </Anchors>
103 119 </StatusBar> </StatusBar>
120 <Frame name="$parentPowerFrame" inherits="ChorusUnitPowerLargeFrameTemplate">
121 <Anchors>
122 <Anchor point="TOPRIGHT">
123 <Offset x="0" y="-40"/>
124 </Anchor>
125 <Anchor point="BOTTOMLEFT" relativeTo="$parent" relativePoint="TOPLEFT">
126 <Offset x="0" y="-56"/>
127 </Anchor>
128 </Anchors>
129 </Frame>
104 130 <Frame name="$parentThreatFrame" inherits="ChorusThreatFrameTemplate"> <Frame name="$parentThreatFrame" inherits="ChorusThreatFrameTemplate">
105 131 <Anchors> <Anchors>
106 132 <Anchor point="TOPRIGHT"> <Anchor point="TOPRIGHT">
File src/ChorusLargeUnitFrameTemplate.xml changed (mode: 100644) (index ec0627d..c0c799c)
81 81 </Anchors> </Anchors>
82 82 </Frame> </Frame>
83 83 <!-- Main --> <!-- Main -->
84 <StatusBar name="$parentHealthFrame" inherits="ChorusHugeHealthFrameTemplate">
84 <StatusBar name="$parentHealthStatusBar" inherits="ChorusUnitHealthUnitClassStatusBarTemplate">
85 <Size>
86 <AbsDimension x="160" y="130"/>
87 </Size>
85 88 <Anchors> <Anchors>
86 89 <Anchor point="TOPRIGHT"> <Anchor point="TOPRIGHT">
87 90 <Offset x="0" y="-16"/> <Offset x="0" y="-16"/>
 
91 94 </Anchor> </Anchor>
92 95 </Anchors> </Anchors>
93 96 </StatusBar> </StatusBar>
94 <StatusBar name="$parentPowerFrame" inherits="ChorusHugePowerFrameTemplate">
97 <Frame name="$parentHealthFrame" inherits="ChorusUnitHealthLargeFrameTemplate">
98 <Anchors>
99 <Anchor point="TOPRIGHT">
100 <Offset x="0" y="-16"/>
101 </Anchor>
102 <Anchor point="BOTTOMLEFT" relativeTo="$parent" relativePoint="TOPLEFT">
103 <Offset x="0" y="-40"/>
104 </Anchor>
105 </Anchors>
106 </Frame>
107 <StatusBar name="$parentPowerStatusBar" inherits="ChorusUnitPowerStatusBarTemplate">
108 <Size>
109 <AbsDimension x="160" y="130"/>
110 </Size>
95 111 <Anchors> <Anchors>
96 112 <Anchor point="TOPRIGHT"> <Anchor point="TOPRIGHT">
97 113 <Offset x="0" y="-40"/> <Offset x="0" y="-40"/>
 
101 117 </Anchor> </Anchor>
102 118 </Anchors> </Anchors>
103 119 </StatusBar> </StatusBar>
120 <Frame name="$parentPowerFrame" inherits="ChorusUnitPowerLargeFrameTemplate">
121 <Anchors>
122 <Anchor point="TOPRIGHT">
123 <Offset x="0" y="-40"/>
124 </Anchor>
125 <Anchor point="BOTTOMLEFT" relativeTo="$parent" relativePoint="TOPLEFT">
126 <Offset x="0" y="-56"/>
127 </Anchor>
128 </Anchors>
129 </Frame>
104 130 <Frame name="$parentThreatFrame" inherits="ChorusThreatFrameTemplate"> <Frame name="$parentThreatFrame" inherits="ChorusThreatFrameTemplate">
105 131 <Anchors> <Anchors>
106 132 <Anchor point="TOPRIGHT"> <Anchor point="TOPRIGHT">
File src/ChorusPowerFrameTemplate.xml deleted (index c34dbb7..0000000)
1 <?xml version="1.0" encoding="UTF-8"?>
2 <Ui xmlns="http://www.blizzard.com/wow/ui/">
3 <!-- Requries ChorusProgressFrameTemplate.xml -->
4 <StatusBar name="ChorusPowerFrameTemplate" inherits="ChorusProgressFrameTemplate" virtual="true">
5 <Scripts>
6 <OnLoad>Chorus.powerFrameMain(self);</OnLoad>
7 </Scripts>
8 <Attributes>
9 <Attribute name="useparent-unit" type="boolean" value="true"/>
10 </Attributes>
11 </StatusBar>
12 <StatusBar name="ChorusHugePowerFrameTemplate" inherits="ChorusPowerFrameTemplate" virtual="true">
13 <Layers>
14 <Layer level="OVERLAY">
15 <FontString name="$parentText1" inherits="ChorusFont12Mono" justifyH="LEFT" justifyV="MIDDLE" setAllPoints="true"/>
16 <FontString name="$parentText2" inherits="ChorusFont12Mono" justifyH="RIGHT" justifyV="MIDDLE" setAllPoints="true"/>
17 </Layer>
18 </Layers>
19 </StatusBar>
20 <StatusBar name="ChorusLargePowerFrameTemplate" inherits="ChorusHugePowerFrameTemplate" virtual="true"/>
21 <StatusBar name="ChorusSmallPowerFrameTemplate" inherits="ChorusPowerFrameTemplate" virtual="true">
22 <Layers>
23 <Layer level="OVERLAY">
24 <FontString name="$parentText1" inherits="ChorusFont12Mono" justifyH="LEFT" justifyV="BOTTOM" setAllPoints="true"/>
25 </Layer>
26 </Layers>
27 </StatusBar>
28 <StatusBar name="ChorusTinyPowerFrameTemplate" inherits="ChorusPowerFrameTemplate" virtual="true">
29 </StatusBar>
30 </Ui>
File src/ChorusProgressFrameTemplate.lua deleted (index b1fa384..0000000)
1 --[[--
2 @submodule chorus
3 ]]
4
5 local Chorus = Chorus
6
7 local UnitClass = Chorus.test.UnitClass or UnitClass
8 local UnitExists = Chorus.test.UnitExists or UnitExists
9 local UnitHealth = Chorus.test.UnitHealth or UnitHealth
10 local UnitHealthMax = Chorus.test.UnitHealthMax or UnitHealthMax
11 local UnitIsConnected = Chorus.test.UnitIsConnected or UnitIsConnected
12 local UnitIsCorpse = Chorus.test.UnitIsCorpse or UnitIsCorpse
13 local UnitIsDead = Chorus.test.UnitIsDead or UnitIsDead
14 local UnitIsGhost = Chorus.test.UnitIsGhost or UnitIsGhost
15 local UnitIsPlayer = Chorus.test.UnitIsPlayer or UnitIsPlayer
16 local UnitPower = Chorus.test.UnitPower or UnitPower
17 local UnitPowerMax = Chorus.test.UnitPowerMax or UnitPowerMax
18 local UnitPowerType = Chorus.test.UnitPowerType or UnitPowerType
19
20 --[[ See `FrameXML/GlobalStrings.lua`. ]]--
21 local CORPSE = CORPSE or 'CORPSE'
22 local DEAD = DEAD or 'DEAD'
23 local DEATH_RELEASE = DEATH_RELEASE or 'DEATH_RELEASE'
24 local PLAYER_OFFLINE = PLAYER_OFFLINE or 'PLAYER_OFFLINE'
25
26 local PowerBarColor = PowerBarColor
27 local RAID_CLASS_COLORS = RAID_CLASS_COLORS
28 local SecureButton_GetUnit = Chorus.test.SecureButton_GetUnit or SecureButton_GetUnit
29
30 local function validateProgressFrame(self)
31 assert(self ~= nil)
32
33 local artwork = self.artwork
34 assert(artwork ~= nil)
35
36 local ratio = self:GetValue()
37 assert(ratio ~= nil)
38 assert('number' == type(ratio))
39 assert(ratio >= 0.0)
40 assert(ratio <= 1.0)
41
42 local strategy = self.strategy
43 if strategy then
44 assert('string' == type(strategy))
45 strategy = strtrim(strategy)
46 assert(string.len(strategy) >= 1)
47 assert(string.len(strategy) <= 8192)
48 end
49 end
50
51 local function getRatio(a, b)
52 if not a or not b then
53 return 0
54 end
55
56 assert(a ~= nil)
57 assert('number' == type(a))
58 assert(a >= 0)
59
60 if a <= 0 or b <= 0 then
61 return 0
62 end
63
64 assert(b ~= nil)
65 assert('number' == type(b))
66 assert(b > 0)
67
68 assert(a <= b)
69
70 local x = math.min(math.abs(a), math.abs(b))
71 local y = math.max(math.abs(a), math.abs(b))
72 y = math.max(y, 1)
73 assert(y > 0)
74
75 local ratio = x / y
76 ratio = math.min(math.max(0, math.abs(ratio)), 1)
77
78 return ratio
79 end
80
81 local function applyRatio(self, a, b)
82 assert(self ~= nil)
83
84 local ratio = 0
85
86 --[[ Strict sanitization to work around WoW API quirks. ]]--
87 if a and b then
88 assert('number' == type(a))
89 assert('number' == type(b))
90 local x = math.min(a, b)
91 local y = math.max(a, b)
92 if x <= y then
93 ratio = getRatio(x, y)
94 end
95 end
96
97 self:SetValue(ratio)
98 end
99
100 local function formatQuantity(quantity)
101 assert(quantity ~= nil)
102 assert('number' == type(quantity))
103
104 local t
105 if math.abs(quantity) < 1000 then
106 t = string.format('%d',quantity)
107 elseif math.abs(quantity) < 1000000 then
108 t = string.format('%.2f K', quantity / 1000)
109 else
110 t = string.format('%.2f M', quantity / 1000000)
111 end
112
113 return t
114 end
115
116 local function applyOverlay(self, a, b)
117 assert(self ~= nil)
118
119 assert(a ~= nil)
120 assert('number' == type(a))
121 assert(a >= 0)
122
123 assert(b ~= nil)
124 assert('number' == type(b))
125 --[[ Work around quirks of the native API. ]]--
126 b = math.max(b, 1)
127 assert(b > 0)
128
129 if a > b then
130 return
131 end
132 assert(a <= b)
133
134 local ratio = getRatio(a, b)
135
136 local label1 = self.label1 or _G[self:GetName() .. 'Text1']
137 if label1 then
138 local e = string.format('%.0f%%', ratio * 100)
139 label1:SetText(e)
140
141 --[[ ShadowedUnitFrames recommend this approach for adjusting font size. ]]--
142 if e ~= nil and string.len(e) >= 1 then
143 local fontSize = 12
144 self:SetScale(label1:GetStringHeight() / fontSize)
145 end
146 else
147 return
148 end
149
150 local label2 = self.label2 or _G[self:GetName() .. 'Text2']
151 if label2 then
152 local t = formatQuantity(a)
153 label2:SetText(t)
154
155 --[[ ShadowedUnitFrames recommend this approach for adjusting font size. ]]--
156 if t ~= nil and string.len(t) >= 1 then
157 local fontSize = 12
158 self:SetScale(label2:GetStringHeight() / fontSize)
159 end
160 else
161 return
162 end
163 end
164
165 local function applyRatioHealth(self, unitDesignation)
166 assert(self ~= nil)
167
168 assert(unitDesignation ~= nil)
169
170 local a
171 local b
172 if not UnitExists(unitDesignation) or
173 not UnitIsConnected(unitDesignation) or
174 UnitIsDead(unitDesignation) or
175 UnitIsCorpse(unitDesignation) or
176 UnitIsGhost(unitDesignation) then
177 a = 0
178 b = 1
179 else
180 a = UnitHealth(unitDesignation) or 0
181 b = UnitHealthMax(unitDesignation) or 1
182 end
183
184 applyRatio(self, a, b)
185 end
186
187 local function applyOverlayHealthDeficit(self, a, b)
188 assert(self ~= nil)
189
190 local label3 = self.label3 or _G[self:GetName() .. 'Text3']
191 if not label3 then
192 return
193 end
194
195 if a and b and a >= 1 and b >= 1 and a < b then
196 local c = a - b
197 local t = formatQuantity(c)
198 label3:SetText(t)
199 else
200 label3:SetText(nil)
201 end
202 end
203
204 --[[--
205 Update this health frame with the state of the given unit.
206
207 @see FrameXML/GlobalStrings.lua:CORPSE
208
209 @function applyOverlayHealth
210 @tparam frame self this health frame
211 @tparam string unitDesignation given unit
212 ]]
213 local function applyOverlayHealth(self, unitDesignation)
214 assert(self ~= nil)
215
216 assert(unitDesignation ~= nil)
217
218 local u = unitDesignation
219 local a = UnitHealth(u)
220 local b = UnitHealthMax(u)
221
222 if a and b and a <= b and b >= 1 and
223 UnitExists(u) and
224 UnitIsConnected(u) and
225 not UnitIsDead(u) and
226 not UnitIsCorpse(u) and
227 not UnitIsGhost(u) then
228 applyOverlay(self, a, b)
229 applyOverlayHealthDeficit(self, a, b)
230 else
231 --[[-- @todo Separate health status bar and unit statues.
232 ]]
233 local t = {self.label1, self.label2, self.label3}
234 local i = 0
235 while (i < #t) do
236 i = i + 1
237 local label = t[i]
238 if label then
239 label:SetText(nil)
240 end
241 end
242
243 local label1 = self.label1
244 if not label1 then
245 return
246 end
247
248 local s = nil
249 if UnitIsCorpse(unitDesignation) then
250 s = '(' .. (CORPSE or 'CORPSE') .. ')'
251 elseif UnitIsGhost(unitDesignation) then
252 s = '(' .. (DEATH_RELEASE or 'GHOST') .. ')'
253 elseif UnitIsDead(unitDesignation) then
254 s = '(' .. (DEAD or 'DEAD') .. ')'
255 elseif not UnitIsConnected(unitDesignation) then
256 ---- @fixme The 'Player offline' label is never rendered.
257
258 ---- @todo Add separate offline indicator widget.
259 s = '(' .. (PLAYER_OFFLINE or 'PLAYER_OFFLINE') .. ')'
260 end
261 label1:SetText(s)
262 end
263 end
264
265 local function applyRatioPower(self, unitDesignation, powerTypeEnum)
266 assert(self ~= nil)
267 assert(unitDesignation ~= nil)
268 assert(powerTypeEnum ~= nil)
269
270 local a = UnitPower(unitDesignation, powerTypeEnum) or 0
271 local b = UnitPowerMax(unitDesignation, powerTypeEnum) or 1
272 applyRatio(self, a, b)
273 end
274
275 local function applyOverlayPower(self, unitDesignation, powerTypeEnum)
276 assert(self ~= nil)
277 assert(unitDesignation ~= nil)
278 assert(powerTypeEnum ~= nil)
279
280 local a = UnitPower(unitDesignation, powerTypeEnum) or 0
281 local b = UnitPowerMax(unitDesignation, powerTypeEnum) or 1
282 applyOverlay(self, a, b)
283 end
284
285 local function applyHealthFrameColorUnitClass(self, unitDesignation)
286 assert(self ~= nil)
287 assert(unitDesignation ~= nil)
288
289 local _, classDesignation = UnitClass(unitDesignation)
290 if not classDesignation then
291 return
292 end
293
294 local map = RAID_CLASS_COLORS
295 assert(map ~= nil)
296 assert('table' == type(map))
297 local colorTuple = map[classDesignation]
298
299 local r = 1
300 local g = 1
301 local b = 1
302 if colorTuple then
303 assert('table' == type(colorTuple))
304 r = math.min(math.max(0, math.abs(colorTuple.r)), 1)
305 g = math.min(math.max(0, math.abs(colorTuple.g)), 1)
306 b = math.min(math.max(0, math.abs(colorTuple.b)), 1)
307 end
308
309 local artwork = self.artwork
310 assert(artwork ~= nil)
311
312 local image = artwork:GetTexture()
313 if image then
314 artwork:SetVertexColor(r, g, b)
315 else
316 artwork:SetTexture(r, g, b)
317 end
318 end
319
320 local function applyHealthFrameColorUnitIsFriend(self, unitDesignation)
321 assert(self ~= nil)
322 assert(unitDesignation ~= nil)
323
324 local r = 255 / 255
325 local g = 215 / 255
326 local b = 0 / 255
327
328 if UnitIsFriend('player', unitDesignation) then
329 r = 124 / 255
330 g = 252 / 255
331 b = 0 / 255
332 elseif UnitIsEnemy('player', unitDesignation) then
333 r = 255 / 255
334 g = 69 / 255
335 b = 0 / 255
336 end
337
338 local artwork = self.artwork
339 assert(artwork ~= nil)
340
341 local image = artwork:GetTexture()
342 if image then
343 artwork:SetVertexColor(r, g, b)
344 else
345 artwork:SetTexture(r, g, b)
346 end
347 end
348
349 local function healthFrameEventIsRelevant(self, eventCategory, ...)
350 assert(self ~= nil)
351
352 assert(eventCategory ~= nil)
353
354 local targetUnit = select(1, ...)
355 if targetUnit then
356 local unitDesignation = SecureButton_GetUnit(self) or 'none'
357 return UnitIsUnit(unitDesignation, targetUnit)
358 end
359 return true
360 end
361
362 local function healthFrameEventProcessor(self, eventCategory, ...)
363 validateProgressFrame(self)
364
365 if not healthFrameEventIsRelevant(self, eventCategory, ...) then
366 return
367 end
368
369 local unitDesignation = SecureButton_GetUnit(self) or 'none'
370
371 assert(unitDesignation ~= nil)
372 assert('string' == type(unitDesignation))
373 unitDesignation = string.lower(strtrim(unitDesignation))
374 assert(string.len(unitDesignation) >= 1)
375 assert(string.len(unitDesignation) <= 256)
376
377 if UnitExists(unitDesignation) and UnitIsConnected(unitDesignation) then
378 self:Show()
379 else
380 self:Hide()
381 return
382 end
383
384 applyRatioHealth(self, unitDesignation)
385 applyOverlayHealth(self, unitDesignation)
386
387 local strategy = self.strategy
388 assert(strategy ~= nil)
389 assert('string' == type(strategy))
390 strategy = strtrim(strategy)
391 assert(string.len(strategy) >= 1)
392 assert(string.len(strategy) <= 256)
393
394 assert(strategy == 'UnitClass' or strategy == 'UnitIsFriend')
395
396 if 'UnitClass' == strategy then
397 --[[ `function UnitClass` only works for player units. ]]--
398 if UnitIsPlayer(unitDesignation) then
399 applyHealthFrameColorUnitClass(self, unitDesignation)
400 else
401 applyHealthFrameColorUnitIsFriend(self, unitDesignation)
402 end
403 elseif 'UnitIsFriend' == strategy then
404 applyHealthFrameColorUnitIsFriend(self, unitDesignation)
405 else
406 error('invalid enum: strategy must be either UnitClass or UnitIsFriend')
407 end
408 end
409
410 local function applyPowerFrameColor(self, powerTypeEnum)
411 assert(self ~= nil)
412
413 local r = 1
414 local g = 0
415 local b = 1
416 if powerTypeEnum then
417 --[[ See FrameXML/UnitFrame.lua:PowerBarColor ]]--
418 local map = PowerBarColor
419 assert(map ~= nil)
420 assert('table' == type(map))
421
422 local colorTuple = map[powerTypeEnum]
423 if colorTuple then
424 assert('table' == type(colorTuple))
425 r = math.min(math.max(0, math.abs(colorTuple.r)), 1)
426 g = math.min(math.max(0, math.abs(colorTuple.g)), 1)
427 b = math.min(math.max(0, math.abs(colorTuple.b)), 1)
428 end
429 end
430
431 local artwork = self.artwork
432 assert(artwork ~= nil)
433
434 local image = artwork:GetTexture()
435 if image then
436 artwork:SetVertexColor(r, g, b)
437 else
438 artwork:SetTexture(r, g, b)
439 end
440 end
441
442 local function powerFrameEventProcessor(self, eventCategory, ...)
443 validateProgressFrame(self)
444
445 if not healthFrameEventIsRelevant(self, eventCategory, ...) then
446 return
447 end
448
449 local unitDesignation = SecureButton_GetUnit(self) or 'none'
450
451 assert(unitDesignation ~= nil)
452 assert('string' == type(unitDesignation))
453 unitDesignation = string.lower(strtrim(unitDesignation))
454 assert(string.len(unitDesignation) >= 1)
455 assert(string.len(unitDesignation) <= 256)
456
457 if UnitExists(unitDesignation) and UnitIsConnected(unitDesignation) and UnitPowerMax(unitDesignation) >= 1 then
458 self:Show()
459 else
460 self:Hide()
461 return
462 end
463
464 local powerTypeEnum
465 local strategy = self.strategy
466 assert(strategy ~= nil)
467 assert('string' == type(strategy))
468 strategy = strtrim(strategy)
469 assert(string.len(strategy) >= 1)
470 assert(string.len(strategy) <= 256)
471 if 'UnitPowerType' == strategy then
472 local enum, category = UnitPowerType(unitDesignation)
473 if category then
474 powerTypeEnum = enum
475 else
476 self:Hide()
477 return
478 end
479 else
480 --[[ See FrameXML/Constants.lua:SPELL_POWER_MANA ]]--
481 powerTypeEnum = _G[strategy]
482 end
483 assert(powerTypeEnum ~= nil)
484 assert('number' == type(powerTypeEnum))
485 assert(powerTypeEnum >= 0)
486 powerTypeEnum = math.min(math.max(0, math.floor(math.abs(powerTypeEnum))), 8192)
487
488 if UnitPowerMax(unitDesignation, powerTypeEnum) >= 1 then
489 self:Show()
490 applyRatioPower(self, unitDesignation, powerTypeEnum)
491 applyOverlayPower(self, unitDesignation, powerTypeEnum)
492 applyPowerFrameColor(self, powerTypeEnum)
493 else
494 self:Hide()
495 end
496 end
497
498 --[[--
499 `ChorusProgressFrameTemplate` is a generalization for health bars and power
500 (mana) bars.
501
502 The features are shared between both health and power bars, but there exist
503 separate corresponding templates: `ChorusHealthFrameTemplate` and
504 `ChorusPowerFrameTemplate`.
505
506 Frames that inherit from this template may define field `strategy`. This field
507 may be either `UnitIsFriend` or `UnitPowerType`. The bar will be colored by
508 either unit reaction to the player, or the power type (blue for mana, red for
509 rage, etc.).
510
511 @function progressFrameMain
512 ]]
513 function Chorus.progressFrameMain(self)
514 assert(self ~= nil)
515
516 local frameDesignation = self:GetName()
517 assert(frameDesignation ~= nil)
518 assert('string' == type(frameDesignation))
519 frameDesignation = strtrim(frameDesignation)
520 assert(string.len(frameDesignation) >= 1)
521 assert(string.len(frameDesignation) <= 256)
522
523 local artwork = _G[frameDesignation .. 'Artwork']
524 assert(artwork ~= nil, self:GetName() .. ': invalid state')
525 self.artwork = artwork
526
527 local label1 = _G[frameDesignation .. 'Text1'] or nil
528 self.label1 = label1
529
530 local label2 = _G[frameDesignation .. 'Text2'] or nil
531 self.label2 = label2
532
533 local label3 = _G[frameDesignation .. 'Text3'] or nil
534 self.label3 = label3
535
536 self:RegisterEvent('PARTY_CONVERTED_TO_RAID')
537 self:RegisterEvent('PARTY_MEMBERS_CHANGED')
538 self:RegisterEvent('PARTY_MEMBER_DISABLE')
539 self:RegisterEvent('PARTY_MEMBER_ENABLE')
540 self:RegisterEvent('PLAYER_ALIVE')
541 self:RegisterEvent('PLAYER_FOCUS_CHANGED')
542 self:RegisterEvent('PLAYER_LOGIN')
543 self:RegisterEvent('PLAYER_TARGET_CHANGED')
544 self:RegisterEvent('RAID_ROSTER_UPDATE')
545
546 self:SetMinMaxValues(0, 1)
547 self:SetValue(1)
548 end
549
550 function Chorus.healthFrameMain(self, ...)
551 Chorus.progressFrameMain(self, ...)
552 self.strategy = 'UnitIsFriend'
553 self:SetScript('OnEvent', healthFrameEventProcessor)
554
555 self:RegisterEvent('UNIT_HEALTH')
556 end
557
558 function Chorus.powerFrameMain(self, ...)
559 Chorus.progressFrameMain(self, ...)
560 self.strategy = 'UnitPowerType'
561 self:SetScript('OnEvent', powerFrameEventProcessor)
562
563 self:RegisterEvent('UNIT_ENERGY')
564 self:RegisterEvent('UNIT_MANA')
565 self:RegisterEvent('UNIT_MAXPOWER')
566 self:RegisterEvent('UNIT_POWER')
567 self:RegisterEvent('UNIT_RAGE')
568 self:RegisterEvent('UNIT_RUNIC_POWER')
569 end
File src/ChorusSmallUnitFrameTemplate.xml changed (mode: 100644) (index c48bcf1..401cd08)
38 38 </Anchors> </Anchors>
39 39 </Frame> </Frame>
40 40 <!-- Main --> <!-- Main -->
41 <StatusBar name="$parentHealthFrame" inherits="ChorusSmallHealthFrameTemplate">
41 <StatusBar name="$parentHealthStatusBar" inherits="ChorusUnitHealthUnitClassStatusBarTemplate">
42 <Size>
43 <AbsDimension x="96" y="48"/>
44 </Size>
42 45 <Anchors> <Anchors>
43 46 <Anchor point="TOPRIGHT"> <Anchor point="TOPRIGHT">
44 47 <Offset x="0" y="0"/> <Offset x="0" y="0"/>
 
48 51 </Anchor> </Anchor>
49 52 </Anchors> </Anchors>
50 53 </StatusBar> </StatusBar>
51 <StatusBar name="$parentPowerFrame" inherits="ChorusTinyPowerFrameTemplate">
54 <Frame name="$parentHealthFrame" inherits="ChorusUnitHealthSmallFrameTemplate">
55 <Anchors>
56 <Anchor point="TOPRIGHT">
57 <Offset x="0" y="0"/>
58 </Anchor>
59 <Anchor point="BOTTOMLEFT">
60 <Offset x="0" y="6"/>
61 </Anchor>
62 </Anchors>
63 </Frame>
64 <StatusBar name="$parentPowerStatusBar" inherits="ChorusUnitPowerStatusBarTemplate">
65 <Size>
66 <AbsDimension x="96" y="48"/>
67 </Size>
52 68 <Anchors> <Anchors>
53 69 <Anchor point="TOPRIGHT" relativeTo="$parent" relativePoint="BOTTOMRIGHT"> <Anchor point="TOPRIGHT" relativeTo="$parent" relativePoint="BOTTOMRIGHT">
54 70 <Offset x="0" y="6"/> <Offset x="0" y="6"/>
 
60 76 </StatusBar> </StatusBar>
61 77 <Frame name="$parentBuffFrame" inherits="ChorusSmallAuraFrameTemplate"> <Frame name="$parentBuffFrame" inherits="ChorusSmallAuraFrameTemplate">
62 78 <Anchors> <Anchors>
63 <Anchor point="TOPLEFT" relativeTo="$parentUnitNameFrame" relativePoint="BOTTOMLEFT">
64 <Offset x="0" y="0"/>
79 <Anchor point="BOTTOMLEFT" relativeTo="$parent" relativePoint="BOTTOMLEFT">
80 <Offset x="0" y="6"/>
65 81 </Anchor> </Anchor>
66 82 </Anchors> </Anchors>
67 83 <Attributes> <Attributes>
File src/ChorusTinyUnitFrameTemplate.xml changed (mode: 100644) (index 3b64225..19f3ec8)
22 22 </Anchors> </Anchors>
23 23 </Frame> </Frame>
24 24 <!-- Main --> <!-- Main -->
25 <StatusBar name="$parentHealthFrame" inherits="ChorusTinyHealthFrameTemplate" setAllPoints="true"/>
25 <StatusBar name="$parentHealthStatusBar" inherits="ChorusUnitHealthUnitClassStatusBarTemplate" setAllPoints="true"/>
26 26 </Frames> </Frames>
27 27 </Frame> </Frame>
28 28 </Ui> </Ui>
File src/ChorusUnitFrameTemplate.lua changed (mode: 100644) (index d64b953..6aa019c)
... ... local function applyTOT(self)
25 25 return return
26 26 end end
27 27
28 local unitNameFrame = self.unitNameFrame
29 if unitNameFrame then
30 local callback0 = unitNameFrame:GetScript('OnEvent')
31 callback0(unitNameFrame, 'UNIT_NAME_UPDATE', u)
32 end
33
34 local healthFrame = self.healthFrame
35 if healthFrame then
36 local callback1 = healthFrame:GetScript('OnEvent')
37 callback1(healthFrame, 'UNIT_HEALTH', u)
38 end
39
40 local powerFrame = self.powerFrame
41 if powerFrame then
42 local callback2 = powerFrame:GetScript('OnEvent')
43 callback2(powerFrame, 'UNIT_POWER', u)
44 end
45
46 --[[ Notify backdrop to toggle visibility when appropriate. ]]--
47 local backdropFrame = self.backdropFrame
48 if backdropFrame then
49 local callback3 = backdropFrame:GetScript('OnEvent')
50 --[[ Skip checks and error handing for performance. ]]--
51 callback3(backdropFrame)
52 end
53
54 --[[-- @fixme Optimize target of target frames.
55 ]]
56
57 local buffFrame = self.buffFrame
58 if buffFrame then
59 local callback4 = buffFrame:GetScript('OnEvent')
60 callback4(buffFrame, 'UNIT_AURA', u)
61 end
62
63 local debuffFrame = self.debuffFrame
64 if debuffFrame then
65 local callback5 = debuffFrame:GetScript('OnEvent')
66 callback5(debuffFrame, 'UNIT_AURA', u)
28 local t = {self:GetChildren()}
29 local i = 0
30 while(i < #t) do
31 i = i + 1
32 local f = t[i]
33 if f then
34 local callback = f:GetScript('OnEvent')
35 if callback then
36 callback(f, 'PLAYER_LOGIN')
37 end
38 end
67 39 end end
68 40 end end
69 41
 
... ... local function applyUnitInRange(self)
84 56 return return
85 57 end end
86 58
87 --[[ Only apply transparency to select subset of children or referenced
88 frames. Specifically exclude ChorusAuraTooltipFrame instances. ]]--
89
90 local healthFrame = self.healthFrame
91 local powerFrame = self.powerFrame
92 local buffFrame = self.buffFrame
93 local debuffFrame = self.debuffFrame
94
95 if healthFrame then
96 healthFrame:SetAlpha(a)
97 end
98
99 if powerFrame then
100 powerFrame:SetAlpha(a)
101 end
102
103 if buffFrame then
104 buffFrame:SetAlpha(a)
105 end
106
107 if debuffFrame then
108 debuffFrame:SetAlpha(a)
109 end
59 self:SetAlpha(a)
110 60 end end
111 61
112 62 function Chorus.unitFrameUnitInRangeUpdateProcessor(self) function Chorus.unitFrameUnitInRangeUpdateProcessor(self)
 
... ... end
272 222
273 223 local function unitMemberFrameMain(self, ...) local function unitMemberFrameMain(self, ...)
274 224 unitFrameMain(self, ...) unitFrameMain(self, ...)
225 end
226
227 local function unitTOTFrameMain(self, ...)
228 unitFrameMain(self, ...)
275 229
276 local healthFrame = self.healthFrame
277 if healthFrame then
278 healthFrame.strategy = 'UnitClass'
230 local n = tostring(self:GetName())
231 local healthStatusBar = _G[n .. 'HealthStatusBar']
232 if healthStatusBar then
233 healthStatusBar:SetAttribute('chorus-strategy', 'UnitIsFriend')
279 234 end end
280 235 end end
281 236
 
... ... Chorus.unitFrameMain = function(...)
283 238 return unitFrameMain(...) return unitFrameMain(...)
284 239 end end
285 240
241 Chorus.unitTOTFrameMain = function(...)
242 return unitTOTFrameMain(...)
243 end
244
286 245 Chorus.unitMemberFrameMain = function(...) Chorus.unitMemberFrameMain = function(...)
287 246 return unitMemberFrameMain(...) return unitMemberFrameMain(...)
288 247 end end
File src/ChorusUnitFrameTemplate.xml changed (mode: 100644) (index ccf6071..7fa2f1f)
22 22 <!-- Target-of-target (TOT) unit frame is updated multiple times a second. Use sparingly. --> <!-- Target-of-target (TOT) unit frame is updated multiple times a second. Use sparingly. -->
23 23 <Frame name="ChorusTOTUnitFrameTemplate" inherits="ChorusUnitFrameTemplate" virtual="true" protected="false"> <Frame name="ChorusTOTUnitFrameTemplate" inherits="ChorusUnitFrameTemplate" virtual="true" protected="false">
24 24 <Scripts> <Scripts>
25 <OnLoad>Chorus.unitTOTFrameMain(self);</OnLoad>
25 26 <OnUpdate>Chorus.unitFrameTOTUpdateProcessor(self);</OnUpdate> <OnUpdate>Chorus.unitFrameTOTUpdateProcessor(self);</OnUpdate>
26 27 </Scripts> </Scripts>
27 28 </Frame> </Frame>
File src/ChorusUnitHealthFrameTemplate.lua changed (mode: 100644) (index 68d2cad..6fd966f)
... ... local function apply3(label, amountCurrent, amountMax)
104 104 label:SetText(s) label:SetText(s)
105 105 end end
106 106
107 local function apply(unitHealthFrame, u)
107 local function applyUnitHealth(unitHealthFrame, u)
108 108 assert(unitHealthFrame ~= nil) assert(unitHealthFrame ~= nil)
109 109
110 110 assert(u ~= nil) assert(u ~= nil)
 
... ... local function apply(unitHealthFrame, u)
129 129 end end
130 130 end end
131 131
132 local function eventProcessor(unitHealthFrame, eventCategory, unitDesignation)
132 local function eventProcessorUnitHealth(unitHealthFrame, eventCategory, unitDesignation)
133 133 assert(unitHealthFrame ~= nil) assert(unitHealthFrame ~= nil)
134 134
135 135 local thisUnit = SecureButton_GetUnit(unitHealthFrame) or 'none' local thisUnit = SecureButton_GetUnit(unitHealthFrame) or 'none'
 
... ... local function eventProcessor(unitHealthFrame, eventCategory, unitDesignation)
149 149 not UnitIsGhost(thisUnit) then not UnitIsGhost(thisUnit) then
150 150
151 151 unitHealthFrame:Show() unitHealthFrame:Show()
152 apply(unitHealthFrame, thisUnit)
152 applyUnitHealth(unitHealthFrame, thisUnit)
153 153 else else
154 154 unitHealthFrame:Hide() unitHealthFrame:Hide()
155 155 end end
156 156 end end
157 157
158 local function main(unitHealthFrame)
158 local function mainUnitHealth(unitHealthFrame)
159 159 assert(unitHealthFrame ~= nil) assert(unitHealthFrame ~= nil)
160 160
161 161 local n = unitHealthFrame:GetName() local n = unitHealthFrame:GetName()
 
... ... local function main(unitHealthFrame)
172 172 --[[ `label3` displays health deficite amount. ]]-- --[[ `label3` displays health deficite amount. ]]--
173 173 unitHealthFrame.label3 = unitHealthFrame.label3 or _G[n .. 'Text3'] unitHealthFrame.label3 = unitHealthFrame.label3 or _G[n .. 'Text3']
174 174
175 assert(unitHealthFrame.label1 ~= nil)
176 assert(unitHealthFrame.label2 ~= nil)
177 assert(unitHealthFrame.label3 ~= nil)
175 assert(unitHealthFrame.label1 ~= nil
176 or unitHealthFrame.label2 ~= nil
177 or unitHealthFrame.label3 ~= nil)
178 178
179 179 unitHealthFrame:UnregisterAllEvents() unitHealthFrame:UnregisterAllEvents()
180 180
 
... ... local function main(unitHealthFrame)
189 189 unitHealthFrame:RegisterEvent('RAID_ROSTER_UPDATE') unitHealthFrame:RegisterEvent('RAID_ROSTER_UPDATE')
190 190 unitHealthFrame:RegisterEvent('UNIT_HEALTH') unitHealthFrame:RegisterEvent('UNIT_HEALTH')
191 191
192 unitHealthFrame:SetScript('OnEvent', eventProcessor)
192 unitHealthFrame:SetScript('OnEvent', eventProcessorUnitHealth)
193 end
194
195 local function applyUnitPower(unitPowerFrame, u)
196 assert(unitPowerFrame ~= nil)
197
198 assert(u ~= nil)
199
200 local label1 = unitPowerFrame.label1
201 local label2 = unitPowerFrame.label2
202 assert(label1 ~= nil or label2 ~= nil,
203 'invalid state: at least one label must exist for unit power frame')
204
205 local powerTypeIndex = unitPowerFrame:GetAttribute('chorus-unitpowertype') or UnitPowerType(u)
206 --[[ Skip validation since this function is called frequently. ]]--
207
208 local a = UnitPower(u, powerTypeIndex)
209 local b = UnitPowerMax(u, powerTypeIndex)
210
211 if label1 then
212 apply1(label1, a, b)
213 end
214 if label2 then
215 apply2(label2, a)
216 end
217 end
218
219 local function eventProcessorUnitPower(unitPowerFrame, eventCategory, unitDesignation)
220 assert(unitPowerFrame ~= nil)
221 assert(eventCategory ~= nil)
222
223 local thisUnit = SecureButton_GetUnit(unitPowerFrame) or 'none'
224 assert(thisUnit ~= nil)
225
226 if unitDesignation and not UnitIsUnit(unitDesignation, thisUnit) then
227 return
228 end
229
230 if UnitExists(thisUnit) and
231 UnitIsConnected(thisUnit) and
232 not UnitIsDead(thisUnit) and
233 not UnitIsCorpse(thisUnit) and
234 not UnitIsGhost(thisUnit) then
235
236 unitPowerFrame:Show()
237 applyUnitPower(unitPowerFrame, thisUnit)
238 else
239 unitPowerFrame:Hide()
240 end
241 end
242
243 local function mainUnitPower(unitPowerFrame)
244 assert(unitPowerFrame ~= nil)
245
246 local n = unitPowerFrame:GetName()
247 assert(n ~= nil)
248 assert('string' == type(n))
249 n = strtrim(n)
250 assert(string.len(n) >= 1)
251 assert(string.len(n) <= 256)
252
253 --[[ `label1` displays mana percentage. ]]--
254 unitPowerFrame.label1 = unitPowerFrame.label1 or _G[n .. 'Text1']
255 --[[ `label2` displays mana amount. ]]--
256 unitPowerFrame.label2 = unitPowerFrame.label2 or _G[n .. 'Text2']
257
258 assert(unitPowerFrame.label1 ~= nil)
259 assert(unitPowerFrame.label2 ~= nil)
260
261 unitPowerFrame:UnregisterAllEvents()
262
263 unitPowerFrame:RegisterEvent('PARTY_CONVERTED_TO_RAID')
264 unitPowerFrame:RegisterEvent('PARTY_MEMBERS_CHANGED')
265 unitPowerFrame:RegisterEvent('PARTY_MEMBER_DISABLE')
266 unitPowerFrame:RegisterEvent('PARTY_MEMBER_ENABLE')
267 unitPowerFrame:RegisterEvent('PLAYER_ALIVE')
268 unitPowerFrame:RegisterEvent('PLAYER_FOCUS_CHANGED')
269 unitPowerFrame:RegisterEvent('PLAYER_LOGIN')
270 unitPowerFrame:RegisterEvent('PLAYER_TARGET_CHANGED')
271 unitPowerFrame:RegisterEvent('RAID_ROSTER_UPDATE')
272
273 unitPowerFrame:RegisterEvent('UNIT_ENERGY')
274 unitPowerFrame:RegisterEvent('UNIT_MANA')
275 unitPowerFrame:RegisterEvent('UNIT_MAXPOWER')
276 unitPowerFrame:RegisterEvent('UNIT_POWER')
277 unitPowerFrame:RegisterEvent('UNIT_RAGE')
278 unitPowerFrame:RegisterEvent('UNIT_RUNIC_POWER')
279
280 unitPowerFrame:SetScript('OnEvent', eventProcessorUnitPower)
193 281 end end
194 282
195 283 Chorus.unitHealthFrameMain = function(...) Chorus.unitHealthFrameMain = function(...)
196 return main(...)
284 return mainUnitHealth(...)
285 end
286
287 Chorus.unitPowerFrameMain = function(...)
288 return mainUnitPower(...)
197 289 end end
File src/ChorusUnitHealthStatusBarTemplate.lua changed (mode: 100644) (index 30adf3d..126f822)
... ... event, and `false` if it should abort
57 57 local function eventUnitFilter(thisUnit, eventCategory, eventUnit) local function eventUnitFilter(thisUnit, eventCategory, eventUnit)
58 58 eventCategory = tostring(eventCategory) eventCategory = tostring(eventCategory)
59 59
60 --[[-- @fixme Trigger for PLAYER_TARGET_CHANGED does not work properly.
61 There is a logic error. TOT frames linger like this when unit does not
62 exist.
63 ]]
64
60 65 if 'UNIT_HEALTH' == eventCategory then if 'UNIT_HEALTH' == eventCategory then
61 66 return UnitIsUnit(eventUnit, thisUnit) return UnitIsUnit(eventUnit, thisUnit)
62 elseif 'PLAYER_TARGET_CHANGED' == eventCategory then
63 return UnitIsUnit('target', thisUnit)
64 elseif 'PLAYER_FOCUS_CHANGED' == eventCategory then
65 return UnitIsUnit('focus', thisUnit)
67 --elseif 'PLAYER_TARGET_CHANGED' == eventCategory then
68 --return UnitIsUnit('target', thisUnit)
69 --elseif 'PLAYER_FOCUS_CHANGED' == eventCategory then
70 --return UnitIsUnit('focus', thisUnit)
66 71 elseif 'UNIT_THREAT_SITUATION_UPDATE' == eventCategory then elseif 'UNIT_THREAT_SITUATION_UPDATE' == eventCategory then
67 72 return UnitIsUnit(eventUnit, thisUnit) return UnitIsUnit(eventUnit, thisUnit)
68 73 end end
File src/ChorusUnitHealthStatusBarTemplate.xml changed (mode: 100644) (index bea66f0..b94dd38)
6 6 <Size> <Size>
7 7 <AbsDimension x="144" y="24"/> <AbsDimension x="144" y="24"/>
8 8 </Size> </Size>
9 <Layers>
10 <Layer level="BACKGROUND">
11 <Texture name="$parentBackground" nonBlocking="true" setAllPoints="true">
12 <Color r="0" g="0" b="0" a="0.4"/>
13 </Texture>
14 </Layer>
15 </Layers>
16 9 <Scripts> <Scripts>
17 10 <OnLoad>Chorus.unitHealthStatusBarMain(self);</OnLoad> <OnLoad>Chorus.unitHealthStatusBarMain(self);</OnLoad>
18 11 <OnAttributeChanged>Chorus.unitHealthStatusBarAttributeProcessor(self, name, value);</OnAttributeChanged> <OnAttributeChanged>Chorus.unitHealthStatusBarAttributeProcessor(self, name, value);</OnAttributeChanged>
 
59 52 <Attribute name="chorus-strategy" type="string" value="LowHealth"/> <Attribute name="chorus-strategy" type="string" value="LowHealth"/>
60 53 </Attributes> </Attributes>
61 54 </StatusBar> </StatusBar>
62 <!-- FIXME Remove test unit health status bar. -->
63 <StatusBar name="ChorusTest13" inherits="ChorusUnitHealthUnitClassStatusBarTemplate">
64 <Anchors>
65 <Anchor point="BOTTOMLEFT">
66 <Offset x="300" y="300"/>
67 </Anchor>
68 </Anchors>
69 <Attributes>
70 <Attribute name="unit" type="string" value="player"/>
71 </Attributes>
72 </StatusBar>
73 <Frame name="ChorusTest16" inherits="ChorusUnitHealthHugeFrameTemplate">
74 <Anchors>
75 <Anchor point="BOTTOMLEFT">
76 <Offset x="300" y="300"/>
77 </Anchor>
78 </Anchors>
79 <Attributes>
80 <Attribute name="unit" type="string" value="player"/>
81 </Attributes>
82 </Frame>
83 <StatusBar name="ChorusTest14" inherits="ChorusUnitHealthLowHealthStatusBarTemplate">
84 <Anchors>
85 <Anchor point="BOTTOMLEFT">
86 <Offset x="500" y="300"/>
87 </Anchor>
88 </Anchors>
89 <Attributes>
90 <Attribute name="unit" type="string" value="target"/>
91 </Attributes>
92 </StatusBar>
93 <Frame name="ChorusTest17" inherits="ChorusUnitHealthHugeFrameTemplate">
94 <Anchors>
95 <Anchor point="BOTTOMLEFT">
96 <Offset x="500" y="300"/>
97 </Anchor>
98 </Anchors>
99 <Attributes>
100 <Attribute name="unit" type="string" value="target"/>
101 </Attributes>
102 </Frame>
103 <Frame name="ChorusVakh">
104 <Size>
105 <AbsDimension x="300" y="200"/>
106 </Size>
107 <Anchors>
108 <Anchor point="BOTTOMLEFT">
109 <Offset x="300" y="400"/>
110 </Anchor>
111 </Anchors>
112 <Frames>
113 <StatusBar name="ChorusTest15" inherits="ChorusUnitHealthLowHealthStatusBarTemplate">
114 <Anchors>
115 <Anchor point="BOTTOMLEFT">
116 <Offset x="0" y="0"/>
117 </Anchor>
118 </Anchors>
119 <Attributes>
120 <Attribute name="unit" type="string" value="target"/>
121 </Attributes>
122 </StatusBar>
123 </Frames>
124 <Attributes>
125 <Attribute name="chorus-strategy" type="string" value="UnitClass"/>
126 </Attributes>
127 </Frame>
128 55 </Ui> </Ui>
File src/ChorusUnitPowerFrameTemplate.xml added (mode: 100644) (index 0000000..cb1c837)
1 <?xml version="1.0" encoding="UTF-8"?>
2 <Ui xmlns="http://www.blizzard.com/wow/ui/">
3 <!-- See `ChorusUnitHealthFrameTemplate.lua`.
4 All event processors for unit power label frames are defined there,
5 to avoid duplicating code. -->
6 <Frame name="ChorusUnitPowerFrameTemplate" virtual="true">
7 <Size>
8 <AbsDimension x="144" y="24"/>
9 </Size>
10 <Attributes>
11 <Attribute name="useparent-unit" type="boolean" value="true"/>
12 </Attributes>
13 <Scripts>
14 <OnLoad>Chorus.unitPowerFrameMain(self);</OnLoad>
15 </Scripts>
16 </Frame>
17 <Frame name="ChorusUnitPowerLargeFrameTemplate" inherits="ChorusUnitPowerFrameTemplate" virtual="true">
18 <Layers>
19 <Layer level="OVERLAY">
20 <FontString name="$parentText1" inherits="ChorusFont12Mono" justifyH="LEFT" justifyV="MIDDLE" setAllPoints="true"/>
21 <FontString name="$parentText2" inherits="ChorusFont12Mono" justifyH="RIGHT" justifyV="MIDDLE" setAllPoints="true"/>
22 </Layer>
23 </Layers>
24 </Frame>
25 <Frame name="ChorusUnitPowerSmallFrameTemplate" inherits="ChorusUnitPowerFrameTemplate" virtual="true">
26 <Layers>
27 <Layer level="OVERLAY">
28 <FontString name="$parentText1" inherits="ChorusFont12Mono" justifyH="LEFT" justifyV="MIDDLE" setAllPoints="true"/>
29 </Layer>
30 </Layers>
31 </Frame>
32 </Ui>
File src/ChorusUnitPowerStatusBarTemplate.lua added (mode: 100644) (index 0000000..1f2a061)
1 --[[--
2 @submodule chorus
3 ]]
4
5 --[[ See `FrameXML/UnitFrame.lua:PowerBarColor`. ]]--
6 local PowerBarColor = PowerBarColor
7
8 local Chorus = Chorus
9
10 local function setColor(statusBar, r, g, b)
11 assert(statusBar ~= nil)
12
13 local artwork = statusBar.artwork
14 assert(artwork ~= nil)
15
16 local image = artwork:GetTexture()
17 if image then
18 artwork:SetVertexColor(r, g, b)
19 else
20 artwork:SetTexture(r, g, b)
21 end
22 end
23
24 local function apply(unitPowerStatusBar, u, powerTypeIndex)
25 assert(unitPowerStatusBar ~= nil)
26
27 local a = UnitPower(u, powerTypeIndex)
28 local b = UnitPowerMax(u, powerTypeIndex)
29
30 unitPowerStatusBar:SetMinMaxValues(0, b)
31 unitPowerStatusBar:SetValue(a)
32 end
33
34 local function applyColor(unitPowerStatusBar, powerTypeIndex)
35 local d = PowerBarColor[powerTypeIndex]
36 setColor(unitPowerStatusBar, d.r, d.g, d.b)
37 end
38
39 local function eventProcessor(unitPowerStatusBar, eventCategory, unitDesignation)
40 assert(unitPowerStatusBar ~= nil)
41
42 eventCategory = tostring(eventCategory)
43
44 local thisUnit = SecureButton_GetUnit(unitPowerStatusBar)
45 if unitDesignation and not UnitIsUnit(thisUnit, unitDesignation) then
46 return
47 end
48
49 if UnitExists(thisUnit) and UnitIsConnected(thisUnit) then
50 unitPowerStatusBar:Show()
51 else
52 unitPowerStatusBar:Hide()
53 return
54 end
55
56 local powerTypeIndex = unitPowerStatusBar:GetAttribute('chorus-unitpowertype') or UnitPowerType(thisUnit)
57 --[[ Skip validation since this function is called frequently. ]]--
58
59 apply(unitPowerStatusBar, thisUnit, powerTypeIndex)
60 if 'UNIT' == string.sub(eventCategory, 1, 4) then
61 return
62 end
63
64 if 'PLAYER_TARGET_CHANGED' == eventCategory and UnitIsUnit('target', thisUnit) then
65 applyColor(unitPowerStatusBar, powerTypeIndex)
66 elseif 'PLAYER_FOCUS_CHANGED' == eventCategory and UnitIsUnit('focus', thisUnit) then
67 applyColor(unitPowerStatusBar, powerTypeIndex)
68 else
69 applyColor(unitPowerStatusBar, powerTypeIndex)
70 end
71 end
72
73 local function attributeProcessor(unitPowerStatusBar, name)
74 if name == 'chorus-unitpowertype' then
75 eventProcessor(unitPowerStatusBar)
76 end
77 end
78
79 local function main(unitPowerStatusBar)
80 assert(unitPowerStatusBar ~= nil)
81
82 local n = unitPowerStatusBar:GetName()
83 assert(n ~= nil)
84 n = tostring(n)
85
86 unitPowerStatusBar.artwork = _G[n .. 'Artwork']
87
88 unitPowerStatusBar:UnregisterAllEvents()
89
90 unitPowerStatusBar:RegisterEvent('PARTY_CONVERTED_TO_RAID')
91 unitPowerStatusBar:RegisterEvent('PARTY_MEMBERS_CHANGED')
92 unitPowerStatusBar:RegisterEvent('PARTY_MEMBER_DISABLE')
93 unitPowerStatusBar:RegisterEvent('PARTY_MEMBER_ENABLE')
94 unitPowerStatusBar:RegisterEvent('PLAYER_ALIVE')
95 unitPowerStatusBar:RegisterEvent('PLAYER_FOCUS_CHANGED')
96 unitPowerStatusBar:RegisterEvent('PLAYER_LOGIN')
97 unitPowerStatusBar:RegisterEvent('PLAYER_TARGET_CHANGED')
98 unitPowerStatusBar:RegisterEvent('RAID_ROSTER_UPDATE')
99
100 unitPowerStatusBar:RegisterEvent('UNIT_ENERGY')
101 unitPowerStatusBar:RegisterEvent('UNIT_MANA')
102 unitPowerStatusBar:RegisterEvent('UNIT_MAXPOWER')
103 unitPowerStatusBar:RegisterEvent('UNIT_POWER')
104 unitPowerStatusBar:RegisterEvent('UNIT_RAGE')
105 unitPowerStatusBar:RegisterEvent('UNIT_RUNIC_POWER')
106
107 unitPowerStatusBar:SetScript('OnEvent', eventProcessor)
108 unitPowerStatusBar:SetScript('OnAttributeChanged', attributeProcessor)
109 end
110
111 Chorus.unitPowerStatusBarMain = function(...)
112 return main(...)
113 end
File src/ChorusUnitPowerStatusBarTemplate.xml added (mode: 100644) (index 0000000..931433c)
1 <?xml version="1.0" encoding="UTF-8"?>
2 <Ui xmlns="http://www.blizzard.com/wow/ui/">
3 <Script file="ChorusUnitPowerStatusBarTemplate.lua"/>
4 <!-- Base health status bar template. It's further specialized by different strategies. -->
5 <StatusBar name="ChorusUnitPowerStatusBarTemplate" minValue="0" maxValue="1" defaultValue="1" virtual="true">
6 <Size>
7 <AbsDimension x="144" y="24"/>
8 </Size>
9 <Scripts>
10 <OnLoad>Chorus.unitPowerStatusBarMain(self);</OnLoad>
11 </Scripts>
12 <Attributes>
13 <Attribute name="useparent-unit" type="boolean" value="true"/>
14 </Attributes>
15 <BarTexture name="$parentArtwork" file="Interface\TargetingFrame\UI-StatusBar"/>
16 <BarColor r="1" g="0" b="1" a="1"/>
17 </StatusBar>
18 </Ui>
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/chorus

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

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

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