/conviction.lua (b81340a71ff6cc02c53ec16480534ce2770e261f) (10177 bytes) (mode 100644) (type blob)

local function getSpellId(spellName)
	assert (spellName ~= nil)
	assert ('string' == type(spellName))
	assert (string.len(spellName) >= 2)
	assert (string.len(spellName) <= 256)

	local _, spellId = GetSpellBookItemInfo(spellName)
	if not spellId then
		return
	end

	assert (spellId ~= nil)
	assert ('number' == type(spellId))
	assert (spellId >= 0)
	return spellId
end

local function createButtonLabel(button)
	assert (button ~= nil)

	local n = (button:GetName() or '') .. 'Text'
	local label = button:CreateFontString(n)
	label:SetPoint('BOTTOMLEFT', -12, -6)
	label:SetPoint('TOPRIGHT', 12, 6)

	local fontObject = ConvictionFont or NumberFont_OutlineThick_Mono_Small
	assert (fontObject ~= nil)
	label:SetFontObject(fontObject)

	button:SetFontString(label)

	label:SetText(nil)

	assert (label ~= nil)
	return label
end

local function createButtonBackground(button)
	assert (button ~= nil)

	local background = button:CreateTexture(button:GetName() .. 'Background', 'BACKGROUND')
	background:SetAllPoints()
	background:SetTexture(0.4, 0.4, 1)

	return background
end

local function createButtonArtwork(button)
	assert (button ~= nil)

	local buttonWidth = button:GetWidth()
	local buttonHeight = button:GetHeight()
	local padding = 3

	local marginBottom = math.max(buttonWidth, buttonHeight) - math.min(buttonWidth, buttonHeight) + padding

	local artwork = button:CreateTexture(button:GetName() .. 'Artwork', 'ARTWORK')
	artwork:SetPoint('TOPLEFT', padding, -padding)
	artwork:SetPoint('TOPRIGHT', -padding, -padding)
	artwork:SetPoint('BOTTOMLEFT', padding, marginBottom)
	artwork:SetPoint('BOTTOMRIGHT', padding, marginBottom)

	local spellId = button:GetAttribute('spell')
	local pictureFile
	if spellId then
		pictureFile = GetSpellTexture(spellId)
	end
	if not pictureFile then
		pictureFile = "Interface\\Icons\\spell_nature_wispsplode"
	end
	artwork:SetTexture(pictureFile)

	local texMargin = 1.0 / 8.0
	artwork:SetTexCoord(texMargin, 1 - texMargin, texMargin, 1 - texMargin)

	button:SetNormalTexture(artwork)

	return artwork
end

local function updateButtonLabel(button)
	assert (button ~= nil)

	local label = button:GetFontString()
	assert (label ~= nil)

	local spellId = button:GetAttribute('spell')
	if not spellId then
		button:Hide()
		return
	end
	assert (spellId ~= nil)
	assert ('number' == type(spellId))
	assert (spellId >= 0)

	local cooldownInstance, duration = GetSpellCooldown(spellId)
	if not cooldownInstance or not duration or cooldownInstance <= 0 or duration <= 0 then
		label:SetText(nil)
		return
	end

	local now = GetTime()
	local durationRemaining = math.floor(duration - (now - cooldownInstance))
	if durationRemaining > 60 then
		label:SetText(nil)
		return
	end

	label:SetText(tostring(durationRemaining))
end

local function updateButtonBackground(button, background)
	assert (button ~= nil)
	assert (background ~= nil)

	local spellId = button:GetAttribute('spell')
	if not spellId then
		button:Hide()
		return
	end
	assert (spellId ~= nil)
	assert ('number' == type(spellId))
	assert (spellId >= 0)

	local usableFlag, manaFlag = IsUsableSpell(spellId)
	local isUsable = 1 == usableFlag
	local isOutOfMana = nil == usableFlag and 1 == manaFlag

	local r, g, b
	if isOutOfMana then
		r = 0.3
		g = 0.0
		b = 1
	elseif not isUsable then
		r = 0
		g = r
		b = r
	else
		r = 0.4
		g = 0.4
		b = 1
	end
	background:SetTexture(r, g, b)
end


local function updateButtonArtwork(button, artwork)
	assert (button ~= nil)
	assert (artwork ~= nil)

	local spellId = button:GetAttribute('spell')
	if not spellId then
		button:Hide()
		return
	end
	assert (spellId ~= nil)
	assert ('number' == type(spellId))
	assert (spellId >= 0)

	local a = 1
	if 1 ~= IsUsableSpell(spellId) then
		a = 1 / 3
	end

	if GetSpellCooldown(spellId) > 0 then
		a = 1 / 3
	end
	artwork:SetVertexColor(1, 1, 1, a)
end

local function buttonUpdateProcessorFactory(self, background, artwork)

return function(button)
	assert (button ~= nil)
	assert (background ~= nil)
	assert (artwork ~= nil)

	local now = GetTime()

	local lastUpdateInstance = button.lastUpdateInstance
	if not lastUpdateInstance then
		lastUpdateInstance = 0
	end

	local delaySec = 1 / 3
	if now - lastUpdateInstance > delaySec then
		lastUpdateInstance = now
		updateButtonLabel(button)
		updateButtonBackground(button, background)
		updateButtonArtwork(button, artwork)
	end
	button.lastUpdateInstance = lastUpdateInstance
end

end

local function buttonEventProcessorFactory(self, background, artwork)

return function(button)
	assert (button ~= nil)
	assert (background ~= nil)
	assert (artwork ~= nil)

	updateButtonLabel(button)
	updateButtonBackground(button, background)
	updateButtonArtwork(button, artwork)
end

end

local function createButton(parentFrame, spellId)
	assert (parentFrame ~= nil)

	if not spellId then
		return
	end
	assert (spellId ~= nil)
	assert ('number' == type(spellId))
	assert (spellId >= 0)

	local size = math.min(parentFrame:GetWidth(), parentFrame:GetHeight())
	size = math.min(math.max(12, size), 48)

	local padding = 4

	local t = {parentFrame:GetChildren()}
	local i = #t or 0
	local n = (parentFrame:GetName() or '') .. 'Button' .. tostring(i + 1)

	local b = CreateFrame('BUTTON', n, parentFrame, 'SecureActionButtonTemplate')

	b:SetSize(size, size)

	local x = i * (size + padding)
	local y = 0
	b:SetPoint('BOTTOMLEFT', x, y)

	b:SetAttribute('checkfocuscast', true)
	b:SetAttribute('checkselfcast', true)
	b:SetAttribute('type', 'spell')
	b:SetAttribute('spell', spellId)

	local label = createButtonLabel(b)
	local background = createButtonBackground(b)
	local artwork = createButtonArtwork(b)

	local buttonUpdateProcessor = buttonUpdateProcessorFactory(b, background, artwork)
	b:SetScript('OnUpdate', buttonUpdateProcessor)

	local buttonEventProcessor = buttonEventProcessorFactory(b, background, artwork)
	b:SetScript('OnEvent', buttonEventProcessor)
	b:RegisterEvent('UNIT_SPELLCAST_FAILED_QUIET')
	b:RegisterEvent('UNIT_SPELLCAST_INTERRUPTED')
	b:RegisterEvent('UNIT_SPELLCAST_SENT')
	b:RegisterEvent('UNIT_SPELLCAST_START')
	b:RegisterEvent('UNIT_SPELLCAST_STOP')
	b:RegisterEvent('UNIT_SPELLCAST_SUCCEEDED')
	b:RegisterEvent('PLAYER_TARGET_CHANGED')
	b:RegisterEvent('PLAYER_FOCUS_CHANGED')
	b:RegisterEvent('SPELLS_CHANGED')

	assert (b ~= nil)
	return b
end

local function createSection(parentFrame, width, height)
	assert (parentFrame ~= nil)

	assert (width ~= nil)
	assert ('number' == type(width))
	assert (width >= 12 and width <= 1024)

	assert (height ~= nil)
	assert ('number' == type(height))
	assert (height >= 12 and height <= 768)

	local t = {parentFrame:GetChildren()}
	local n = (parentFrame:GetName() or '') .. 'Section' .. tostring((#t or 0) + 1)
	local f = CreateFrame('FRAME', n, parentFrame)
	f:SetSize(width, height)

	local x = parentFrame:GetWidth() / 2 - f:GetWidth() / 2
	local y = 0

	local padding = 6

	local i = #t
	while (i > 0) do
		local r = t[i]
		if not r then
			break
		end
		y = y + r:GetHeight() + padding
		i = i - 1
	end

	f:SetPoint('BOTTOMLEFT', x, y)

	assert (f ~= nil)
	return f
end

local function sortSection(section)
	assert (section ~= nil)

	local size = math.min(section:GetWidth(), section:GetHeight())
	local padding = 4
	local paddedSize = size + padding


	local t = {section:GetChildren()}
	local j = #t
	local marginLeft = section:GetWidth() / 2 - (paddedSize * j / 2)
	local i = 0
	while (i < j) do
		i = i + 1
		local f = t[i]
		if not f then
			break
		end
		local x = marginLeft + paddedSize * (i - 1)
		local y = 0
		f:SetPoint('BOTTOMLEFT', x, y)
	end
end

local function init(rootFrame)
	assert (rootFrame ~= nil)
	rootFrame:UnregisterAllEvents()

	rootFrame:SetSize(144, 36)
	local x = UIParent:GetWidth() / 2 - rootFrame:GetWidth() / 2
	local y = 144
	rootFrame:SetPoint('BOTTOMLEFT', x, y)

	local section0 = createSection(rootFrame, rootFrame:GetWidth(), 24)
	local section3 = createSection(rootFrame, rootFrame:GetWidth(), 36)
	local section4 = createSection(rootFrame, rootFrame:GetWidth(), 36)

	createButton(section4, getSpellId('Holy Shock'))
	createButton(section4, getSpellId('Crusader Strike'))
	createButton(section4, getSpellId("Avenger's Shield"))
	createButton(section4, getSpellId('Hammer of the Righteous'))
	createButton(section4, getSpellId('Word of Glory'))
	createButton(section4, getSpellId('Light of Dawn'))
	createButton(section4, getSpellId('Shield of the Righteous'))


	createButton(section3, getSpellId('Lay on Hands'))
	createButton(section3, getSpellId('Divine Shield'))
	createButton(section3, getSpellId('Hand of Protection'))
	createButton(section3, getSpellId('Hand of Sacrifice'))
	createButton(section3, getSpellId('Divine Guardian'))
	createButton(section3, getSpellId('Hand of Freedom'))
	createButton(section3, getSpellId('Hammer of Justice'))
	createButton(section3, getSpellId('Divine Protection'))
	createButton(section3, getSpellId('Holy Shield'))
	createButton(section3, getSpellId('Avenging Wrath'))
	createButton(section3, getSpellId('Aura Mastery'))
	createButton(section3, getSpellId('Divine Favor'))
	createButton(section3, getSpellId('Divine Plea'))
	createButton(section3, getSpellId('Rebuke'))

	createButton(section0, getSpellId('Flash of Light'))
	createButton(section0, getSpellId('Divine Light'))
	createButton(section0, getSpellId('Holy Light'))
	createButton(section0, getSpellId('Holy Radiance'))

	createButton(section0, getSpellId('Hammer of Wrath'))
	createButton(section0, getSpellId('Turn Evil'))
	createButton(section0, getSpellId('Holy Wrath'))
	createButton(section0, getSpellId('Exorcism'))
	createButton(section0, getSpellId('Judgement'))

	createButton(section0, getSpellId('Lifeblood'))
	createButton(section0, getSpellId('Gift of the Naaru'))
	createButton(section0, getSpellId('Stoneform'))
	createButton(section0, getSpellId('Every Man for Himself'))
	createButton(section0, getSpellId('War Stomp'))

	sortSection(section0)
	sortSection(section3)
	sortSection(section4)

	return rootFrame
end

local function main()
	local rootFrame = CreateFrame('FRAME', 'ConvictionFrame', UIParent)
	rootFrame:RegisterEvent('PLAYER_LOGIN')
	rootFrame:SetScript('OnEvent', init)
end

do
	main()
end


Mode Type Size Ref File
100644 blob 10177 b81340a71ff6cc02c53ec16480534ce2770e261f conviction.lua
100644 blob 130 f6a196ba676acc37cc3fe382a2bb3e7a596b9676 conviction.toc
100644 blob 469 522923963b82e1c08a0c1a8d69651236b801fb21 conviction.xml
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/conviction

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

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

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