function imgui.AnimatedButton(label, size, speed, rounded)
local size = size or imgui.ImVec2(0, 0)
local bool = false
local text = label:gsub('##.+$', '')
local ts = imgui.CalcTextSize(text)
speed = speed and speed or 0.4
if not AnimatedButtons then AnimatedButtons = {} end
if not AnimatedButtons[label] then
local color = imgui.GetStyle().Colors[imgui.Col.ButtonHovered]
AnimatedButtons[label] = {circles = {}, hovered = false, state = false, time = os.clock(), color = imgui.ImVec4(color.x, color.y, color.z, 0.2)}
end
local button = AnimatedButtons[label]
local dl = imgui.GetWindowDrawList()
local p = imgui.GetCursorScreenPos()
local c = imgui.GetCursorPos()
local CalcItemSize = function(size, width, height)
local region = imgui.GetContentRegionMax()
if (size.x == 0) then
size.x = width
elseif (size.x < 0) then
size.x = math.max(4.0, region.x - c.x + size.x);
end
if (size.y == 0) then
size.y = height;
elseif (size.y < 0) then
size.y = math.max(4.0, region.y - c.y + size.y);
end
return size
end
size = CalcItemSize(size, ts.x+imgui.GetStyle().FramePadding.x*2, ts.y+imgui.GetStyle().FramePadding.y*2)
local ImSaturate = function(f) return f < 0.0 and 0.0 or (f > 1.0 and 1.0 or f) end
if #button.circles > 0 then
local PathInvertedRect = function(a, b, col)
local rounding = rounded and imgui.GetStyle().FrameRounding or 0
if rounding <= 0 or not rounded then return end
local dl = imgui.GetWindowDrawList()
dl:PathLineTo(a)
dl:PathArcTo(imgui.ImVec2(a.x + rounding, a.y + rounding), rounding, -3.0, -1.5)
dl:PathFillConvex(col)
dl:PathLineTo(imgui.ImVec2(b.x, a.y))
dl:PathArcTo(imgui.ImVec2(b.x - rounding, a.y + rounding), rounding, -1.5, -0.205)
dl:PathFillConvex(col)
dl:PathLineTo(imgui.ImVec2(b.x, b.y))
dl:PathArcTo(imgui.ImVec2(b.x - rounding, b.y - rounding), rounding, 1.5, 0.205)
dl:PathFillConvex(col)
dl:PathLineTo(imgui.ImVec2(a.x, b.y))
dl:PathArcTo(imgui.ImVec2(a.x + rounding, b.y - rounding), rounding, 3.0, 1.5)
dl:PathFillConvex(col)
end
for i, circle in ipairs(button.circles) do
local time = os.clock() - circle.time
local t = ImSaturate(time / speed)
local color = imgui.GetStyle().Colors[imgui.Col.ButtonActive]
local color = imgui.GetColorU32Vec4(imgui.ImVec4(color.x, color.y, color.z, (circle.reverse and (255-255*t) or (255*t))/255))
local radius = math.max(size.x, size.y) * (circle.reverse and 1.5 or t)
imgui.PushClipRect(p, imgui.ImVec2(p.x+size.x, p.y+size.y), true)
dl:AddRectFilled(p, imgui.ImVec2(p.x+size.x, p.y+size.y), color) -- from circle to rect
PathInvertedRect(p, imgui.ImVec2(p.x+size.x, p.y+size.y), imgui.GetColorU32Vec4(imgui.GetStyle().Colors[imgui.Col.WindowBg]))
imgui.PopClipRect()
if t == 1 then
if not circle.reverse then
circle.reverse = true
circle.time = os.clock()
else
table.remove(button.circles, i)
end
end
end
end
local t = ImSaturate((os.clock()-button.time) / speed)
button.color.w = button.color.w + (button.hovered and 0.8 or -0.8)*t
button.color.w = button.color.w < 0.2 and 0.2 or (button.color.w > 1 and 1 or button.color.w)
color = imgui.GetStyle().Colors[imgui.Col.Button]
color = imgui.GetColorU32Vec4(imgui.ImVec4(color.x, color.y, color.z, 0.2))
dl:AddRectFilled(p, imgui.ImVec2(p.x+size.x, p.y+size.y), color, rounded and imgui.GetStyle().FrameRounding or 0)
dl:AddRect(p, imgui.ImVec2(p.x+size.x, p.y+size.y), imgui.GetColorU32Vec4(button.color), rounded and imgui.GetStyle().FrameRounding or 0)
local align = imgui.GetStyle().ButtonTextAlign
imgui.SetCursorPos(imgui.ImVec2(c.x+(size.x-ts.x)*align.x, c.y+(size.y-ts.y)*align.y))
imgui.Text(text)
imgui.SetCursorPos(c)
if imgui.InvisibleButton(label, size) then
bool = true
table.insert(button.circles, {animate = true, reverse = false, time = os.clock(), clickpos = imgui.ImVec2(getCursorPos())})
end
button.hovered = imgui.IsItemHovered()
if button.hovered ~= button.state then
button.state = button.hovered
button.time = os.clock()
end
return bool
end