Thread Tools Display Modes
11-25-16, 10:25 PM   #1
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
LibCandyBar groups and animation

I would like to create groups of bars from LibCandyBar-3.0 but the default API does not have this functionality; presumably I can use metatables to simulate, but as many times as I've read the official docs or other people have asked similar questions, I just can't wrap my head around the concept.

In order to do what I'd like, I think I'd need to sort the bars within the group by duration, but LCB's API doesn't have a GetDuration. It does have a Get, which returns a user key, but I don't know if this is the same thing.

To further complicate things, the idea of animating the bars sounds appealing, and I sort of grasp Blizzard's animation API. But melding it to the group of bars is breaking my brain to the point where I can't even pseudo-code.

Attached is a picture of SmartRes2's bars, using LibBars-1.0 (which I am trying to replace) to provide an idea of what I want to accomplish, minus the animation because LB1's animation API predates Blizzard's, and thus isn't usable.
Attached Thumbnails
Click image for larger version

Name:	TestBars.jpg
Views:	152
Size:	21.9 KB
ID:	8883  
  Reply With Quote
11-25-16, 11:57 PM   #2
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
Metatables to emulate bar groups, what about just a table?

What about using GetMinMaxValues() on the StatusBar?
Lua Code:
  1. bar.candyBarDuration

Melding, like in the image? Just sort by time remaining, maxValue - GetValue() every time a new bar is added or removed.
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison

Last edited by jeruku : 11-25-16 at 11:57 PM. Reason: Things come and things go.
  Reply With Quote
11-26-16, 12:09 AM   #3
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Melding the two ideas (groups and animating the bars) together. Sorry for the confusion.

A simple table, like this?
Lua Code:
  1. local barGroups = {}
  2. local bar = table.remove(barGroups)
  3. if not bar then
  4.     bar = LibCandyBar:New(...)
  5. end
  6.  
  7. -- bar ended
  8. table.insert(barGroups, bar)
  Reply With Quote
11-27-16, 08:05 AM   #4
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
I think that that was about what I was thinking.
  Reply With Quote
11-28-16, 03:33 AM   #5
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Re: Grouping bars

Just handle it like any other variable-length collection of objects or values.

Creating a bar group:
Code:
local barGroup = CreateFrame("Frame", nil, UIParent)
-- add title bar, backdrop, etc. here
barGroup.bars = {}
Adding a bar to the group:
Code:
local bar = LibStub("LibCandyBar-3.0"):New(texture, 100, 16)
bar:SetDuration(90)
bar:SetLabel("Something")
bar:Start()

bar:SetParent(barGroup)
table.insert(barGroup.bars, bar)
MyAddon:ArrangeBars()
Code:
function MyAddon:ArrangeBars()
    for i = 1, #barGroup.bars do
        local bar = barGroup.bars[i]
        bar:SetPoint("LEFT", 1, 0)
        bar:SetPoint("RIGHT", -1, 0)
        if i > 1 then
            bar:SetPoint("TOP", barGroup.bars[i - 1], "BOTTOM", 0, -1)
        else
            bar:SetPoint("TOP", barGroup, 0, -1)
        end
    end
end
Removing references to the bar when it ends:
Code:
LibStub("LibCandyBar-3.0"):RegisterCallback(MyAddon, "LibCandyBar_Stop")

function MyAddon:LibCandyBar_Stop(_, bar)
    for i = 1, #barGroup.bars do
        if barGroup.bars[i] == bar then
            table.remove(barGroup.bars, i)
            break
        end
    end
    self:ArrangeBars()
end
Please note that I have never used LibCandyBar-3.0, so all of the above is based on a quick reading of the API documentation you linked, and a few assumptions since that documentation is somewhat lacking.

Re: Animation

What are you trying to animate? Any half-decent timer bar library should already handle animating the bar to show time elapsed/remaining. The animations you see on Blizzard bars like your health bar would not make sense on a timer bar, since the value of a timer bar changes very frequently in very small increments -- there are no sudden large changes you want to smooth out or call attention to (eg. by flashing).

Re: Sorting

Just sort the table that contains a list of active bars before you position them:

Code:
local function sortBarsByRemainingTime(a, b)
    return a.remaining < b.remaining
end

function MyAddon:ArrangeBars()
    table.sort(barGroup.bars, sortBarsByRemainingTime)
    for i = 1, #barGroup.bars do
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
11-28-16, 01:50 PM   #6
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Wow Phanx. My mind is blown as usual. The impressive thing is that you always make everything so clear and easy to understand.

As for animating, I was thinking of having an option to flash bars, yet you suggest not to do that because the duration will be too short? Since I will be dealing with resurrections, that is cast time as provided by LibResInfo. I thought about one flash per second, nothing epileptic.
  Reply With Quote
11-29-16, 09:20 AM   #7
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Flashing every second sounds pretty annoying, and wouldn't actually communicate any useful information. Generally a UI element should only flash to grab the user's attention. However, if nothing important has changed (a spellcast going from having 8s left to having 7s left isn't imporant) then you're just distracting the user for no reason.

What could be a good animation would be to animate the height of incoming (just added) bars -- start them at 1px height and quickly grow them up to full height. This would make it easier to see which bar was added, and make it feel less "jumpy" when other bars were pushed up/down as a result.

Animating outgoing bars in a similar way would be a nice touch, too, but I'm not sure how feasible that is within the framework of LibCandyBar. Maybe you could use the "pause" API to freeze the bar just before it ended, animate its height down to 1px, then use the "cancel" API to remove it.

If the bars are anchored to each other, then animating the height of the incoming/outgoing bar automatically animates the position change of the surrounding bars.

Otherwise, since the value of a timer bar is constantly changing, I just don't think any additional animation on top of that would be useful; at that point you're just adding noise. If you wanted to highlight "ending soon" bars, just change the bar color --- at, say, 3s remaining, start a 1s transition to your highlight color, so 2s and below is the new color.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
11-29-16, 04:31 PM   #8
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Hmm, I guess my mind's eye film was more entertaining than reality. You are probably right about the noise. At this point, I most likely won't put in any animation, but to be clear, I wanted to flash the collision bars (any bar in the default colour of red).

That would definitely be distracting if the player just wanted to see non-collision or mass resurrection bars clearly. So toss the flash animation idea into the bin.

*edit* I like your idea of animating in and out via height, but that's something else I know nothing about. When I get to working bars without that feature, I'll revisit the topic. Basics first.

Last edited by myrroddin : 11-29-16 at 04:40 PM. Reason: animating in/out
  Reply With Quote
11-30-16, 05:44 AM   #9
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Okay, I have turned Phanx's code into a library that is a wrapper (zing! ) for LibCandyBar-3.0. I will test it after some sleep.

LibCandyStore-1.0 adds three functions to LibCandyBar:
  • CreateBarGroup
  • AddBarToGroup
  • RemoveBarFromGroup
I think I can safely remove lines 36, 37, 85 and 86 but first testing. The code is fully documented, but if there are issues (probably) or questions, please let me know.
Lua Code:
  1. --[[
  2.     Whom is doing what with this library
  3.     $Date: $
  4.     $Author: $
  5.     $URL: $
  6.     $Id: $
  7.     @class file
  8.     @name LibCandyStore-1.0.lua
  9. ]]--
  10.  
  11. -- register with LibStub ------------------------------------------------------
  12. local lib = LibStub:NewLibrary("LibCandyStore-1.0", "$Revision: 1 $")
  13. if not lib then
  14.     return -- no upgrade necessary
  15. end
  16.  
  17. -- embed library into addons --------------------------------------------------
  18. lib.embeds = lib.embeds or {}
  19. local mixins = {
  20.     "CreateBarGroup",
  21.     "AddBarToGroup",
  22.     "RemoveBarFromGroup"
  23. }
  24. function lib:Embed(target)
  25.     for k, v in pairs(mixins) do
  26.         target[v] = self[v]
  27.     end
  28.     self.embeds[target] = true
  29.     return target
  30. end
  31.  
  32. -- register with LibCandyBar-3.0 ----------------------------------------------
  33. LibStub("LibCandyBar-3.0"):RegisterCallback(lib, "LibCandyBar_Stop", lib.BarStopped)
  34.  
  35. -- local variables ------------------------------------------------------------
  36. lib.barGroups = {}
  37. local barGroups = lib.barGroups -- less typing
  38.  
  39. local default_backdrop = {
  40.     bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
  41.     edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
  42.     inset = 4,
  43.     edgeSize = 8,
  44.     tile = true,
  45.     insets = {left = 2, right = 2, top = 2, bottom = 2}
  46. }
  47.  
  48. -- APIs -----------------------------------------------------------------------
  49.  
  50. --- Creates a bar group with its parameters
  51. -- @name //MyAddOn//:CreateBarGroup
  52. -- @paramsig backdrop, width, height, [name, point, x, y]
  53. -- @param name The global string name of the group frame
  54. -- Like CreateFrame, name can be nil, and unique if it is not
  55. -- @param backdrop Table used in SetBackdrop
  56. -- Default table uses UI-Tooltip data
  57. -- @param width Number of pixels wide for the bar group
  58. -- Defaults to 100
  59. -- @param height Number of pixels high for the bar group
  60. -- Defaults to 160
  61. -- @param point Where in UIParent do you want the frame
  62. -- ("CENTER", "TOPLEFT", "BOTTOM", etc). Optional, defaults to "CENTER"
  63. -- @param x The number of pixels for horizontal offset from point
  64. -- Optional, defaults to 0
  65. -- @param y The number of pixels for vertical offset from point
  66. -- Optional, defaults to 0
  67. -- @return barGroup Your new bar group frame
  68. function lib:CreateBarGroup(backdrop, width, height, name, point, x, y)
  69.     name = name and string.trim(name) or name
  70.     backdrop = backdrop or default_backdrop
  71.     width = width or 100
  72.     height = height or 160
  73.     point = point or "CENTER"
  74.     x = x or 0
  75.     y = y or 0
  76.  
  77.     local barGroup = CreateFrame("Frame", name, UIParent)
  78.     barGroup:SetClampedToScreen(true)
  79.     barGroup:SetSize(width, height)
  80.     barGroup:SetPoint(point)
  81.  
  82.     barGroup:SetBackdrop(backdrop)
  83.     barGroup.name = name
  84.     barGroup.bars = {}
  85.     barGroup:Show()
  86.     table.insert(barGroups, barGroup)
  87.     return barGroup
  88. end
  89.  
  90. --- Moves a LibCandyBar-3.0 bar to a bar group
  91. -- @name //MyAddOn//:AddBarToGroup
  92. -- @param bar The bar created by LCB-3
  93. -- @param barGroup The return value from MyAddOn:CreateBarGroup()
  94. -- @usage local bar = LibStub("LibCandyBar-3.0"):New(texture, 100, 16)
  95. -- bar:SetDuration(90)
  96. -- bar:SetLabel("Something")
  97. -- bar:Start()
  98. -- MyAddOn:AddBarToGroup(bar, someBarGroup)
  99. function lib:AddBarToGroup(bar, barGroup)
  100.     -- might need to remove bar
  101.     -- get its data first
  102.     bar.oldParent = bar:GetParent()
  103.     bar.oldPoint, bar.oldRelTo, bar.oldRelPoint, bar.oldxOffset, bar.oldyOffset = bar:GetPoint()
  104.  
  105.     bar:SetParent(barGroup)
  106.     table.insert(barGroup.bars, bar)
  107.     self:ArrangeBars(barGroup.bars)
  108. end
  109.  
  110. --- Removes a bar from a group
  111. -- Then restores its parent and SetPoint
  112. -- @name //MyAddOn//:RemoveBarFromGroup
  113. -- @param bar The bar to be removed
  114. -- @param barGroup From which to remove the bar
  115. function lib:RemoveBarFromGroup(bar, barGroup)
  116.     bar:SetParent(bar.oldParent)
  117.     bar:SetPoint(bar.oldPoint, bar.oldRelTo, bar.oldRelPoint, bar.oldxOffset, bar.oldyOffset)
  118.     table.remove(barGroup.bars, bar)
  119.     self:ArrangeBars(barGroup.bars)
  120. end
  121.  
  122. -- internal use bar sorting ---------------------------------------------------
  123. local function SortBarsByRemainingTime(a, b)
  124.     return a.remaining < b.remaining
  125. end
  126.  
  127. function lib:ArrangeBars(barGroup)
  128.     table.sort(barGroup.bars, SortBarsByRemainingTime)
  129.     for i = 1, #barGroup.bars do
  130.         local bar = barGroup.bars[i]
  131.         bar:SetPoint("LEFT", 1, 0)
  132.         bar:SetPoint("RIGHT", -1, 0)
  133.         if i > 1 then
  134.             bar:SetPoint("TOP", barGroup.bars[i - 1], "BOTTOM", 0, -1)
  135.         else
  136.             bar:SetPoint("TOP", barGroup, 0, -1)
  137.         end
  138.     end
  139. end
  140.  
  141. -- handle LibCandyBar callback ------------------------------------------------
  142. function lib:BarStopped(_, bar, barGroup)
  143.     for i = 1, #barGroup.bars do
  144.         if barGroup.bars[i] == bar then
  145.             table.remove(barGroup.bars, i)
  146.             break
  147.         end
  148.     end
  149.     self:ArrangeBars(barGroup.bars)
  150. end
  151.  
  152. -- EoF embed cleanup ----------------------------------------------------------
  153. for AddOn in pairs(lib.embeds) do
  154.     lib:Embed(AddOn)
  155. end
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » LibCandyBar groups and animation

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off