-
Posted by Orangestick on Mon, 19 Jan 2009 15:29:07
Posted this in the wrong forum, so re-posting it here :p
----
Great book, really enjoyed it. Inspired me to try my own hand at addons but have run into a problem (:p)
I have been trying to use the blizz Cooldown frame, but haven't been able to find too much about it either from the book or the internet. It seems easy enough to use EXCEPT for one problem.
This is the background. While levelling a death knight, I really liked the RunePack addon, but decided to add a couple of things to it to make it work even better for me. One was the ability to click on the runes directly to cast spells (done), another was to change the color of the rune frames to reflect the target debuffs (so I wouldn't have to look at a DOT timer quite as much- also done).
Here is what I've got working so far (props to the original author of the RunePack addon):
http://www.youtube.com/watch?v=KPcJwxkJS5Y
I am struggling with the third bit of what I'd like to be able to do now. I am trying to make the runes show the global cooldown using the Cooldown frame object (the "sweeping clockface" animation). However, the image used to depict runes is a circular button - the problem is that the cooldown animation seems to assume a square frame. I can't find any way of masking the cooldown animation so that it is limited to the circular area of the rune. I know it can be done (since I see it in the addon ButtonFacade).
Confused? A video here is, I am sure, worth a thousand words:
http://www.youtube.com/watch?v=fxP1QmnBwtY
I've tried every combination of frame level and frame strata I could think of to try and make this work without success.
Once again, great book. Any help you could give on this endeavour you inspired would be much appreciated :p
-
Posted by Orangestick on Mon, 19 Jan 2009 15:29:07
Posted this in the wrong forum, so re-posting it here :p
----
Great book, really enjoyed it. Inspired me to try my own hand at addons but have run into a problem (:p)
I have been trying to use the blizz Cooldown frame, but haven't been able to find too much about it either from the book or the internet. It seems easy enough to use EXCEPT for one problem.
This is the background. While levelling a death knight, I really liked the RunePack addon, but decided to add a couple of things to it to make it work even better for me. One was the ability to click on the runes directly to cast spells (done), another was to change the color of the rune frames to reflect the target debuffs (so I wouldn't have to look at a DOT timer quite as much- also done).
Here is what I've got working so far (props to the original author of the RunePack addon):
http://www.youtube.com/watch?v=KPcJwxkJS5Y
I am struggling with the third bit of what I'd like to be able to do now. I am trying to make the runes show the global cooldown using the Cooldown frame object (the "sweeping clockface" animation). However, the image used to depict runes is a circular button - the problem is that the cooldown animation seems to assume a square frame. I can't find any way of masking the cooldown animation so that it is limited to the circular area of the rune. I know it can be done (since I see it in the addon ButtonFacade).
Confused? A video here is, I am sure, worth a thousand words:
http://www.youtube.com/watch?v=fxP1QmnBwtY
I've tried every combination of frame level and frame strata I could think of to try and make this work without success.
Once again, great book. Any help you could give on this endeavour you inspired would be much appreciated :p
-
Posted by jnwhiteh on Tue, 20 Jan 2009 03:18:52
I see what you're describing in the video.. but I'm not entirely sure how to tell you how to fix it. The best way to start is to look into ButtonFacade (or any addon that can create circular buttons like that) and see how they are doing it. From what I can tell, they use TexCoords to chop off the original border of the icon and then throw that behind a circular border.
It really has to do with the fact that you don't have the button properly hidden behind the border, so you can see the square edges. The animation will seem circular once you've hidden the edges and you can no longer see that the icon is a sqaure.
Hope that makes sense..
-
Posted by Orangestick on Tue, 20 Jan 2009 11:26:39
I can see what you mean.
I can get rid of the border on the icon easily enough using TexCoords to "clip" it as you suggest. However, the overall shape will still be a square, won't it? So if I place a image of a circular border on top of it, it will still not be masked into the shape of a circle. It will either be too large, or too small.
I looked at the ButtonFacade code, and as far as I can tell, the work is being done in the LibButtonFacade.lua file. But I confess I don't understand how the layers / frames are being arranged. If I understand it right, it is using more layers than are present in the standard Blizz interface? There is certainly an extra "gloss" layer which can be added.
As far as I can tell, when I use the default Blizz ActionButtonTemplate, the cooldown animation remains a square, with no obvious way to clip the animation.
I am wondering whether there is something I don't understand about alpha modes. Is there some way to mask one texture with another? and somehow apply that to the cooldown animation?
I will try writing to the author of ButtonFacade to see if he can provide some insight :p
Cheers
-
Posted by jnwhiteh on Wed, 21 Jan 2009 04:52:25
You really don't need to clip the animation. If the animation happens behind a circular border that is filled with the icon, then it will appear to be circular. Your problem is clipping the icon behind a border so it appears to be a circle inside the border circle. You shouldn't think/worry about "clipping" the animation, because that's not really your problem.
It may be as simple as masking the inner icon, but I'm not sure how they would/do accomplish that.
-
Posted by Orangestick on Fri, 23 Jan 2009 06:45:03
XSSFilter could not parse (X)HTML: <p>I have read through the ButtonFacade code properly now, and as far as I can see, this is what it does. The skin data is specified in a table. This table is parsed by the SkinLayer function in LibButtonFacade to create the final appearance of the action button. The relevant code is:</p> <p>In the skin:</p> <p> </p> <p><code> </code></p> <p><code> <p>LBF:AddSkin("Serenity", {</p> <p>-- Skin data start.</p> <p><span> </span>Backdrop = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 44,</p> <p><span style="white-space: pre;"> </span>Color = {1, 1, 1, 1},</p> <p><span style="white-space: pre;"> </span>Texture = <a href="/Interface_AddOns_ButtonFacade_Serenity_Textures_Round_Backdrop.html">Interface\AddOns\ButtonFacade_Serenity\Textures\Round\Backdrop</a>,</p> <p><span> </span>},</p> <p><span> </span>Icon = {</p> <p><span style="white-space: pre;"> </span>Width = 26,</p> <p><span style="white-space: pre;"> </span>Height = 26,</p> <p><span style="white-space: pre;"> </span>TexCoords = {0.07,0.93,0.07,0.93},</p> <p><span> </span>},</p> <p><span> </span>Flash = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 44,</p> <p><span style="white-space: pre;"> </span>Color = {1, 0, 0, 1},</p> <p><span style="white-space: pre;"> </span>Texture = <a href="/Interface_AddOns_ButtonFacade_Serenity_Textures_Round_Overlay.html">Interface\AddOns\ButtonFacade_Serenity\Textures\Round\Overlay</a>,</p> <p><span> </span>},</p> <p><span> </span>Cooldown = {</p> <p><span style="white-space: pre;"> </span>Width = 26,</p> <p><span style="white-space: pre;"> </span>Height = 26,</p> <p><span> </span>},</p> <p><span style="white-space: pre;"> </span>AutoCast = {</p> <p><span style="white-space: pre;"> </span>Width = 24,</p> <p><span style="white-space: pre;"> </span>Height = 24,</p> <p><span style="white-space: pre;"> </span>OffsetX = 1,</p> <p><span style="white-space: pre;"> </span>OffsetY = -1,</p> <p><span style="white-space: pre;"> </span>AboveNormal = true,</p> <p><span> </span>},</p> <p><span> </span>Normal = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 44,</p> <p><span style="white-space: pre;"> </span>Static = true,</p> <p><span style="white-space: pre;"> </span>Color = {1, 1, 1, 1},</p> <p><span style="white-space: pre;"> </span>Texture = <a href="/Interface_AddOns_ButtonFacade_Serenity_Textures_Round_Normal.html">Interface\AddOns\ButtonFacade_Serenity\Textures\Round\Normal</a>,</p> <p><span> </span>},</p> <p><span> </span>Pushed = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 44,</p> <p><span style="white-space: pre;"> </span>Color = {0, 0, 0, 1},</p> <p><span style="white-space: pre;"> </span>Texture = <a href="/Interface_AddOns_ButtonFacade_Serenity_Textures_Round_Overlay.html">Interface\AddOns\ButtonFacade_Serenity\Textures\Round\Overlay</a>,</p> <p><span> </span>},</p> <p><span> </span>Border = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 44,</p> <p><span style="white-space: pre;"> </span>BlendMode = "ADD",</p> <p><span style="white-space: pre;"> </span>--Color = {0, 1, 0, 1},</p> <p><span style="white-space: pre;"> </span>Texture = <a href="/Interface_AddOns_ButtonFacade_Serenity_Textures_Round_Border.html">Interface\AddOns\ButtonFacade_Serenity\Textures\Round\Border</a>,</p> <p><span> </span>},</p> <p><span> </span>Disabled = {</p> <p><span style="white-space: pre;"> </span>Hide = true,</p> <p><span> </span>},</p> <p><span> </span>Checked = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 44,</p> <p><span style="white-space: pre;"> </span>BlendMode = "ADD",</p> <p><span style="white-space: pre;"> </span>Color = {0, 0.75, 1, 1},</p> <p><span style="white-space: pre;"> </span>Texture = <a href="/Interface_AddOns_ButtonFacade_Serenity_Textures_Round_Border.html">Interface\AddOns\ButtonFacade_Serenity\Textures\Round\Border</a>,</p> <p><span> </span>},</p> <p><span> </span>AutoCastable = {</p> <p><span style="white-space: pre;"> </span>Width = 48,</p> <p><span style="white-space: pre;"> </span>Height = 48,</p> <p><span style="white-space: pre;"> </span>Texture = <a href="/Interface_Buttons_UI-AutoCastableOverlay.html">Interface\Buttons\UI-AutoCastableOverlay</a>,</p> <p><span> </span>},</p> <p><span> </span>Highlight = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 44,</p> <p><span style="white-space: pre;"> </span>BlendMode = "ADD",</p> <p><span style="white-space: pre;"> </span>Color = {1, 1, 1, 1},</p> <p><span style="white-space: pre;"> </span>Texture = <a href="/Interface_AddOns_ButtonFacade_Serenity_Textures_Round_Highlight.html">Interface\AddOns\ButtonFacade_Serenity\Textures\Round\Highlight</a>,</p> <p><span> </span>},</p> <p><span> </span>Gloss = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 44,</p> <p><span style="white-space: pre;"> </span>Texture = <a href="/Interface_AddOns_ButtonFacade_Serenity_Textures_Round_Gloss.html">Interface\AddOns\ButtonFacade_Serenity\Textures\Round\Gloss</a>,</p> <p><span> </span>},</p> <p><span> </span>HotKey = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 10,</p> <p><span style="white-space: pre;"> </span>OffsetX = -12,</p> <p><span style="white-space: pre;"> </span>OffsetY = 8,</p> <p><span> </span>},</p> <p><span> </span>Count = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 10,</p> <p><span style="white-space: pre;"> </span>OffsetX = -12,</p> <p><span style="white-space: pre;"> </span>OffsetY = -6,</p> <p><span> </span>},</p> <p><span> </span>Name = {</p> <p><span style="white-space: pre;"> </span>Width = 44,</p> <p><span style="white-space: pre;"> </span>Height = 12,</p> <p><span style="white-space: pre;"> </span>OffsetY = -6,</p> <p><span> </span>},</p> <p><span> </span>-- Skin data end.</p> <p>}, true)</p> <p></code></p></p> <p> </p> <p>In the SkinLayer function, these are parsed according to this table:</p> <p> </p> <p><code>local layerTypes = { -- Draw Layer and frame level. </code></p> <p><code>Backdrop = "Texture", -- BACKGROUND 1 </code></p> <p><code>Icon = "Icon", -- BORDER 1 </code></p> <p><code>Flash = "Texture", -- OVERLAY 1 </code></p> <p><code>Cooldown = "Model", -- 2 </code></p> <p><code>AutoCast = "Model", -- 3 </code></p> <p><code>Normal = "Special", -- BORDER 4 </code></p> <p><code>Pushed = "Special", -- ARTWORK 4 </code></p> <p><code>AutoCastable = "Texture", -- OVERLAY 4 </code></p> <p><code>Border = "Texture", -- OVERLAY 4 </code></p> <p><code>Disabled = "Special", -- OVERLAY 4 </code></p> <p><code>Checked = "Special", -- OVERLAY 4 </code></p> <p><code>Highlight = "Special", -- HIGHLIGHT 4 </code></p> <p><code>Gloss = "Texture", -- OVERLAY 6 </code></p> <p><code>HotKey = "Text", -- OVERLAY 6 </code></p> <p><code>Count = "Text", -- OVERLAY 6 </code></p> <p><code>Name = "Text", -- OVERLAY 6 }</code></p> <p>To me, it seems pretty clear they are setting up 5 frames (1,2,3,4 and 6, 5 is missing for some reason), each set to the indicated frame level. Within each frame, each texture is set to the indicated layer (BACKGROUND, BORDER etc) if present.</p> <p>So I tried to re-create the appearance of an icon manually by loading up Wow Lua and creating the relevant frames and textures and calling Frame:SetFrameLevel and Texture:SetDrawLayer individually. While I can recreate the look of the icon, it does not have the right masking properties. As you said, the problem is the mask the icon behind a circular border - this does not seem to do it :(</p>
-
Posted by Orangestick on Fri, 23 Jan 2009 06:50:56
The actual SkinLayer function is reproduced here.
local function SkinLayer(skin,button,btndata,layer,btnlayer,xscale,yscale,Color)
local skinlayer = assert(skin[layer],"Missing layer in skin definition: "..layer)
if not btnlayer then return end
local layerType = layerTypes[layer]
if skinlayer.Hide then
if layerType == "Texture" then
btnlayer:SetTexture("")
end
btnlayer:Hide()
return
end
btnlayer:SetWidth((skinlayer.Width or 36) * (skinlayer.Scale or 1) * xscale)
btnlayer:SetHeight((skinlayer.Height or 36) * (skinlayer.Scale or 1) * yscale)
btnlayer:ClearAllPoints()
btnlayer:SetPoint("CENTER",button,"CENTER",skinlayer.OffsetX or 0,skinlayer.OffsetY or 0)
if layerType == "Texture" then
local parent = button.__bf_framelevel[FrameLevels[layer]]
btnlayer:SetParent(parent or button)
btnlayer:SetTexture(skinlayer.Texture)
btnlayer:SetTexCoord(unpack(skinlayer.TexCoords or defaultTexCoords))
btnlayer:SetDrawLayer(DrawLayers[layer])
btnlayer:SetBlendMode(skinlayer.BlendMode or "BLEND")
SetTextureColor(btnlayer,GetLayerColor(skinlayer,Color,layer))
elseif layerType == "Icon" then
local parent = button.__bf_framelevel[FrameLevels[layer]]
btnlayer:SetParent(parent or button)
btnlayer:SetTexCoord(unpack(skinlayer.TexCoords or defaultTexCoords))
btnlayer:SetDrawLayer(DrawLayers[layer])
elseif layerType == "Text" then
local parent = button.__bf_framelevel[FrameLevels[layer]]
btnlayer:SetParent(parent or button)
btnlayer:SetDrawLayer(DrawLayers[layer])
SetTextColor(btnlayer,GetLayerColor(skinlayer,Color,layer))
elseif layerType == "Model" then
local FrameLevel = skinlayer.AboveNormal and 5 or FrameLevels[layer]
btnlayer:SetFrameLevel(FrameLevel)
if skinlayer.ModelX or skinlayer.ModelY then
btnlayer:SetPosition(skinlayer.ModelX or 0, skinlayer.ModelY or 0,0)
end
-- HotFix-3.0.2: Disable ModelScale to fix AutoCast (It's not a model anymore).
-- if skinlayer.ModelScale then
-- btnlayer:SetModelScale(skinlayer.ModelScale)
-- end
end
end
local skinlayer = assert(skin[layer],"Missing layer in skin definition: "..layer)
if not btnlayer then return end
local layerType = layerTypes[layer]
if skinlayer.Hide then
if layerType == "Texture" then
btnlayer:SetTexture("")
end
btnlayer:Hide()
return
end
btnlayer:SetWidth((skinlayer.Width or 36) * (skinlayer.Scale or 1) * xscale)
btnlayer:SetHeight((skinlayer.Height or 36) * (skinlayer.Scale or 1) * yscale)
btnlayer:ClearAllPoints()
btnlayer:SetPoint("CENTER",button,"CENTER",skinlayer.OffsetX or 0,skinlayer.OffsetY or 0)
if layerType == "Texture" then
local parent = button.__bf_framelevel[FrameLevels[layer]]
btnlayer:SetParent(parent or button)
btnlayer:SetTexture(skinlayer.Texture)
btnlayer:SetTexCoord(unpack(skinlayer.TexCoords or defaultTexCoords))
btnlayer:SetDrawLayer(DrawLayers[layer])
btnlayer:SetBlendMode(skinlayer.BlendMode or "BLEND")
SetTextureColor(btnlayer,GetLayerColor(skinlayer,Color,layer))
elseif layerType == "Icon" then
local parent = button.__bf_framelevel[FrameLevels[layer]]
btnlayer:SetParent(parent or button)
btnlayer:SetTexCoord(unpack(skinlayer.TexCoords or defaultTexCoords))
btnlayer:SetDrawLayer(DrawLayers[layer])
elseif layerType == "Text" then
local parent = button.__bf_framelevel[FrameLevels[layer]]
btnlayer:SetParent(parent or button)
btnlayer:SetDrawLayer(DrawLayers[layer])
SetTextColor(btnlayer,GetLayerColor(skinlayer,Color,layer))
elseif layerType == "Model" then
local FrameLevel = skinlayer.AboveNormal and 5 or FrameLevels[layer]
btnlayer:SetFrameLevel(FrameLevel)
if skinlayer.ModelX or skinlayer.ModelY then
btnlayer:SetPosition(skinlayer.ModelX or 0, skinlayer.ModelY or 0,0)
end
-- HotFix-3.0.2: Disable ModelScale to fix AutoCast (It's not a model anymore).
-- if skinlayer.ModelScale then
-- btnlayer:SetModelScale(skinlayer.ModelScale)
-- end
end
end
I think I can see what most of it is doing except the last bit, particuarly,
elseif layerType == "Model" then
local FrameLevel = skinlayer.AboveNormal and 5 or FrameLevels[layer]
btnlayer:SetFrameLevel(FrameLevel)
if skinlayer.ModelX or skinlayer.ModelY then
btnlayer:SetPosition(skinlayer.ModelX or 0, skinlayer.ModelY or 0,0)
end
I am not sure what this part is trying to accomplish?
-
Posted by Orangestick on Fri, 23 Jan 2009 21:49:50
Yay I've solved it.
This example code creates a circular button with a correct cooldown animation. The correct thing for me to have done was to set all points of the cooldown frame to the icon texture, not the frame. Then it works great.
t1 = CreateFrame("Frame", "t1", UIParent)
t1:SetPoint("CENTER")
t1:SetHeight(44)
t1:SetWidth(44)
t1Icon = t1:CreateTexture()
t1Icon:SetTexture( GetSpellTexture("Scourge Strike"))
t1Icon:SetTexCoord(0.07,0.93,0.07,0.93)
t1Icon:SetWidth(26)
t1Icon:SetHeight(26)
t1Icon:SetPoint("CENTER")
t1Icon:SetDrawLayer("BORDER")
t1:Show()
t4 = CreateFrame("Frame", "t4", t1)
t4:SetWidth(44)
t4:SetHeight(44)
t4:SetPoint("CENTER")
t4Border = t4:CreateTexture()
t4Border:SetTexture(Interface\AddOns\ButtonFacade_Serenity\Textures\Round\Normal)
t4Border:SetPoint("CENTER")
t4Border:SetDrawLayer("OVERLAY")
t4Border:SetWidth(44)
t4Border:SetHeight(44)
t4:Show()
t2 = CreateFrame("Cooldown", "t1", UIParent, "CooldownFrameTemplate")
t2:SetWidth(26)
t2:SetHeight(26)
t2:SetFrameLevel(2)
t2:SetAllPoints(t1Icon)
Then calling t2:SetCooldown(GetTime(),10) would do a 10 second cooldown animation.
I am using t1, t2, t4 to indicate the frame strata from the ButtonFacade table (excuse the lazy naming of variables) :p
Thanks for your help!
-
Posted by jnwhiteh on Mon, 26 Jan 2009 06:11:15
You're welcome, glad I could point you in the right direction. Please don't just post code here willy-nilly.. either use the editor to turn it into a code block so it is formatted correctly, or even better use http://pastey.net to post the code. This makes it much nicer for everyone.
-
Posted by ns66 on Sun, 10 Oct 2010 23:08:05
i ran this code but i only see a square sweep... what i am missing here? thanks