local self = {} local icon = { inease = love.graphics.newImage('assets/textures/inease-icon.png'), outease = love.graphics.newImage('assets/textures/outease-icon.png'), inoutease = love.graphics.newImage('assets/textures/inoutease-icon.png'), transientease = love.graphics.newImage('assets/textures/transientease-icon.png'), unknownease = love.graphics.newImage('assets/textures/unknownease-icon.png'), linearease = love.graphics.newImage('assets/textures/linearease-icon.png'), instantease = love.graphics.newImage('assets/textures/instantease-icon.png'), pulseease = love.graphics.newImage('assets/textures/pulseease-icon.png'), } local dropdowns = {} local dropdownValueCache = {} local dropdownScrollCache = {} local maxDropdown = 16 self.openDropdown = 0 local dropdownScroll = 0 local dropdownScrollE = 0 local scrollbarSize = 6 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 function self.swap(key, key2) local a, b = self.kget(key), self.kget(key2) local s = a.selected a.selected = b.selected b.selected = s 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), tooltip = 'The a in b(a(x))' }) insertDropdown(d, { x = outerpadding + dropdownWidth + padding + dropdownWidth + padding, y = outerpadding, width = dropdownWidth, options = eases, name = 'ease2', icons = icons(eases), params = params(eases), tooltip = 'The b in b(a(x))' }) 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) maxDropdown = math.floor(math.min(16 * (margin + fontHeight), love.graphics.getHeight() * 0.75) / (margin + fontHeight)) 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 if love.mouse.isDown(1) then local x, y = getMousePosition() 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 - scrollbarSize and y > v.y + h and y < v.y + h * (math.min(#v.options, maxDropdown) + 1) and not (#v.options < maxDropdown) then dropdownScroll = ((y - (v.y + h)) / (h * (math.min(#v.options, maxDropdown)))) * -(#v.options - maxDropdown + 1) end end end end end function self.render() local mx, my = getMousePosition() 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 mx > x and mx < x + w and my > y and my < y + h then love.graphics.setColor(0.8, 0.8, 1, love.mouse.isDown(1) and 0.4 or 0.3) if v.tooltip then tooltips.show(v.tooltip) end 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.setFont(getFont(0.8, true)) love.graphics.setColor(0.8, 0.8, 1, 0.8 * a) love.graphics.printf(str, x, y, w - 2, 'right') love.graphics.setFont(interfaceFont) 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 = scrollbarSize 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 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 and (x < v.x + v.width - scrollbarSize or #v.options < maxDropdown) 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 = getMousePosition() 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