local self = {} local icon = { inease = love.graphics.newImage('inease-icon.png'), outease = love.graphics.newImage('outease-icon.png'), inoutease = love.graphics.newImage('inoutease-icon.png'), transientease = love.graphics.newImage('transientease-icon.png'), unknownease = love.graphics.newImage('unknownease-icon.png'), linearease = love.graphics.newImage('linearease-icon.png'), instantease = love.graphics.newImage('instantease-icon.png'), pulseease = love.graphics.newImage('pulseease-icon.png'), } local dropdowns = {} local dropdownValueCache = {} local dropdownScrollCache = {} local maxDropdown = 16 self.openDropdown = 0 local dropdownScroll = 0 local dropdownScrollE = 0 local function skeys(t) local k = {} for n,v in pairs(t) do table.insert(k, {n, v}) end table.sort(k, function(a, b) return a[2].i < b[2].i end) local k2 = {} for _,v in ipairs(k) do table.insert(k2, v[1]) end return k2 end local function icons(keys) local e = {} for i,v in ipairs(keys) do table.insert(e, (ease.eases[v].type or 'unknown') .. 'ease') end return e end local function params(keys) local e = {} for i,v in ipairs(keys) do table.insert(e, ease.eases[v].params) end return e end function self.get(index) return dropdowns[index] end function self.selected(index) return dropdowns[index].options[dropdowns[index].selected] end function self.kget(key) for _, v in ipairs(dropdowns) do if v.name == key then return v end end end function self.kselected(key) for _, v in ipairs(dropdowns) do if v.name == key then return v.options[v.selected] end end end local dropdownId local function insertDropdown(tab, f) dropdownId = dropdownId + 1 f.selected = (self.kget(f.name) or dropdownValueCache[f.name] or {selected = 1}).selected f.selected = (f.selected - 1) % #f.options + 1 f.open = (self.kget(f.name) or {open = 0}).open return table.insert(tab, f) end function self.createDropdowns() local d = {} dropdownId = 0 insertDropdown(d, { x = outerpadding, y = outerpadding, width = dropdownWidth, options = { 'Preview Ease', 'Mix Eases', 'Multiply Eases', 'Create Ease' }, name = 'mode' }) local param1 = {} local param2 = {} local eases = skeys(ease.eases) if d[dropdownId].selected == modes.preview then -- preview ease insertDropdown(d, { x = outerpadding + dropdownWidth + padding, y = outerpadding, width = dropdownWidth, options = eases, name = 'ease1', icons = icons(eases), params = params(eases) }) local _e = ease.eases[d[dropdownId].options[d[dropdownId].selected]] param1[1] = slider.kvalue(_e.name .. 'param11') or (_e.params[1] and _e.params[1].default) or 1 param1[2] = slider.kvalue(_e.name .. 'param12') or (_e.params[2] and _e.params[2].default) or 1 ease.ease = function(x) return _e.f(x, param1[1], param1[2]) end elseif d[dropdownId].selected == modes.mix then -- mix eases insertDropdown(d, { x = outerpadding + dropdownWidth + padding, y = outerpadding, width = dropdownWidth, options = eases, name = 'ease1', icons = icons(eases), params = params(eases) }) insertDropdown(d, { x = outerpadding + dropdownWidth + padding + dropdownWidth + padding, y = outerpadding, width = dropdownWidth, options = eases, name = 'ease2', icons = icons(eases), params = params(eases) }) local _e1 = ease.eases[d[dropdownId - 1].options[d[dropdownId - 1].selected]] local _e2 = ease.eases[d[dropdownId].options[d[dropdownId].selected]] param1[1] = slider.kvalue(_e1.name .. 'param11') or (_e1.params[1] and _e1.params[1].default) or 1 param1[2] = slider.kvalue(_e1.name .. 'param12') or (_e1.params[2] and _e1.params[2].default) or 1 param2[1] = slider.kvalue(_e2.name .. 'param21') or (_e2.params[1] and _e2.params[1].default) or 1 param2[2] = slider.kvalue(_e2.name .. 'param22') or (_e2.params[2] and _e2.params[2].default) or 1 ease.ease = ease.mixEase(_e1.f, _e2.f, slider.kvalue('mix'), param1, param2) elseif d[dropdownId].selected == modes.multiply then -- mult eases insertDropdown(d, { x = outerpadding + dropdownWidth + padding, y = outerpadding, width = dropdownWidth, options = eases, name = 'ease1', icons = icons(eases), params = params(eases) }) insertDropdown(d, { x = outerpadding + dropdownWidth + padding + dropdownWidth + padding, y = outerpadding, width = dropdownWidth, options = eases, name = 'ease2', icons = icons(eases), params = params(eases) }) local _e1 = ease.eases[d[dropdownId - 1].options[d[dropdownId - 1].selected]] local _e2 = ease.eases[d[dropdownId].options[d[dropdownId].selected]] param1[1] = slider.kvalue(_e1.name .. 'param11') or (_e1.params[1] and _e1.params[1].default) or 1 param1[2] = slider.kvalue(_e1.name .. 'param12') or (_e1.params[2] and _e1.params[2].default) or 1 param2[1] = slider.kvalue(_e2.name .. 'param21') or (_e2.params[1] and _e2.params[1].default) or 1 param2[2] = slider.kvalue(_e2.name .. 'param22') or (_e2.params[2] and _e2.params[2].default) or 1 ease.ease = function(x) return _e2.f(_e1.f(x, param1[1], param1[2]), param2[1], param2[2]) end elseif d[dropdownId].selected == modes.create then -- create eases insertDropdown(d, { x = outerpadding + dropdownWidth + padding, y = outerpadding, width = dropdownWidth, options = eases, name = 'ease1', icons = icons(eases) }) end dropdowns = d minEase = (self.kselected('ease1') and ease.eases[self.kselected('ease1')].min == -1) or (self.kselected('ease2') and ease.eases[self.kselected('ease2')].min == -1) mode = dropdown.kget('mode').selected end function self.update(dt) if self.openDropdown ~= 0 then dropdownScroll = math.max(dropdownScroll, -(#self.get(self.openDropdown).options - maxDropdown + 1)) dropdownScroll = math.min(dropdownScroll, 0) dropdownScrollE = mix(dropdownScrollE, dropdownScroll, dt * 10) end for i, v in ipairs(dropdowns) do if i == self.openDropdown then v.open = mix(v.open, 1, dt * 14) else v.open = mix(v.open, 0, dt * 20) end end end function self.render() local mx, my = love.mouse.getPosition() for i,v in ipairs(dropdowns) do local x, y, w, h = v.x, v.y, v.width, fontHeight + margin love.graphics.setColor(0.06, 0.06, 0.12, 0.6) if love.mouse.getX() > x and love.mouse.getX() < x + w and love.mouse.getY() > y and love.mouse.getY() < y + h then love.graphics.setColor(0.8, 0.8, 1, love.mouse.isDown(1) and 0.4 or 0.3) end love.graphics.rectangle('fill', x, y, w, h) love.graphics.setColor(1, 1, 1, 1) love.graphics.rectangle('line', x, y, w, h) if v.icons and v.icons[v.selected] then local sprite = icon[v.icons[v.selected]] love.graphics.draw(sprite, x + 2, y + 2, 0, fontHeight / sprite:getWidth(), fontHeight / sprite:getHeight()) love.graphics.print(self.selected(i), x + margin/2 + fontHeight, y + margin/2) else love.graphics.print(self.selected(i), x + margin/2, y + margin/2) end -- love.graphics.rectangle('line', x + w - h, y, h, h) love.graphics.setLineWidth(1) love.graphics.polygon('line', x + w - h/2 + 0.3 * h, y + h/2 - 0.3 * h, x + w - h/2 - 0.3 * h, y + h/2 - 0.3 * h, x + w - h/2, y + h/2 + 0.3 * h) if self.openDropdown == i or v.open > 0.01 then for i,o in ipairs(v.options) do local x, y, w, h = x, y + ((i - 1) * v.open + 1) * h, w, h * v.open y = y + dropdownScrollE * h * v.open local gi = y / h if gi > (maxDropdown + 1) or gi < 1 then goto continue end -- help local a = (1 - math.min(math.max((1 - (maxDropdown - gi)) * (1 - (math.abs(dropdownScrollE) / (#v.options - maxDropdown + 1))), 0), 1)) * math.max(math.min(gi - 1, 1), 0) * v.open love.graphics.setColor(0.06, 0.06, 0.12, 0.6 * a) if mx > x and mx < x + w and my > y and my < y + h then love.graphics.setColor(0.4, 0.4, 1, (love.mouse.isDown(1) and 0.8 or 0.7) * a) end love.graphics.rectangle('fill', x, y, w, h) love.graphics.setColor(1, 1, 1, 0.75 * a) love.graphics.rectangle('line', x, y, w, h) love.graphics.setColor(1, 1, 1, 1 * a) if i == v.selected then love.graphics.setColor(0.5, 0.5, 1, 1 * a) end if v.icons and v.icons[i] then local sprite = icon[v.icons[i]] love.graphics.draw(sprite, x + 2, y + 2, 0, fontHeight / sprite:getWidth(), fontHeight / sprite:getHeight()) love.graphics.print(v.options[i], x + 2 + fontHeight, y + 2) else love.graphics.print(v.options[i], x + 2, y + 2) end if v.params and v.params[i] then local str = '' for _,p in ipairs(v.params[i]) do str = str .. ' ' .. string.sub(p.name, 1, 1) end love.graphics.push() love.graphics.translate(x + w, y + lineWidth/2) love.graphics.shear(-0.2, 0) love.graphics.scale(0.8, 0.8) love.graphics.setColor(0.8, 0.8, 1, 0.8 * a) love.graphics.printf(str, -w, -lineWidth/2, w - 2, 'right') love.graphics.pop() end ::continue:: end -- scrollwheel if #v.options > maxDropdown then local displayed = maxDropdown / (#v.options) local scroll = math.abs(dropdownScrollE) / (#v.options - maxDropdown + 1) local size = 3 love.graphics.setColor(1, 1, 1, 0.8 * v.open) love.graphics.rectangle('fill', x + w - size, y + h + scroll * (1 - displayed) * (maxDropdown - 1) * h * v.open, size, displayed * (maxDropdown - 1) * h * v.open) end end love.graphics.setLineWidth(lineWidth) end end function self.mousepressed(x, y, m) local clickedDropdown = false for i,v in ipairs(dropdowns) do local h = fontHeight + margin if self.openDropdown == 0 then if x > v.x and x < v.x + v.width and y > v.y and y < v.y + h + margin then if m == 1 then self.openDropdown = i clickedDropdown = true dropdownScroll = dropdownScrollCache[i] or 0 dropdownScrollE = dropdownScrollCache[i] or 0 elseif m == 3 then dropdowns[i].selected = math.random(1, #dropdowns[i].options) createUI() end end elseif self.openDropdown == i then if x > v.x and x < v.x + v.width and y > v.y + h and y < v.y + h * (math.min(#v.options, maxDropdown) + 1) and m == 1 then clickedDropdown = true end end end if not clickedDropdown and m == 1 then dropdownScrollCache[self.openDropdown] = dropdownScroll self.openDropdown = 0 return true end end function self.mousereleased(x, y, m) for i,v in ipairs(dropdowns) do local h = fontHeight + margin if self.openDropdown == i then if x > v.x and x < v.x + v.width and y > v.y + h and y < v.y + h * (math.min(#v.options, maxDropdown) + 1) and m == 1 then v.selected = math.floor((y - v.y) / h - dropdownScrollE) self.openDropdown = 0 dropdownValueCache[v.name] = {selected = v.selected} dropdownScrollCache[i] = dropdownScroll createUI() end end end end function self.wheelmoved(x, y) if self.openDropdown ~= 0 then dropdownScroll = dropdownScroll + y else local mx, my = love.mouse.getPosition() for i,v in ipairs(dropdowns) do local h = fontHeight + margin if mx > v.x and mx < v.x + v.width and my > v.y and my < v.y + h + margin then dropdowns[i].selected = dropdowns[i].selected - math.floor(y) dropdowns[i].selected = (dropdowns[i].selected - 1) % #dropdowns[i].options + 1 createUI() end end end end return self