diff --git a/dropdown.lua b/dropdown.lua new file mode 100644 index 0000000..bef1599 --- /dev/null +++ b/dropdown.lua @@ -0,0 +1,235 @@ +local self = {} + +local dropdowns = {} + +local dropdownValueCache = {} + +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 + +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 + return table.insert(tab, f) +end +function self.createDropdowns() + local d = {} + dropdownId = 0 + insertDropdown(d, { + x = padding, + y = padding, + width = 128, + options = { + 'Preview Ease', + 'Mix Eases', + 'Create Ease' + }, + name = 'mode' + }) + + if d[dropdownId].selected == 1 then -- preview ease + insertDropdown(d, { + x = padding + 128 + padding, + y = padding, + width = 128, + options = skeys(eases), + name = 'ease1' + }) + ease = eases[d[dropdownId].options[d[dropdownId].selected]].f + elseif d[dropdownId].selected == 2 then -- mix eases + insertDropdown(d, { + x = padding + 128 + padding, + y = padding, + width = 128, + options = skeys(eases), + name = 'ease1' + }) + insertDropdown(d, { + x = padding + 128 + padding + 128 + padding, + y = padding, + width = 128, + options = skeys(eases), + name = 'ease2' + }) + ease = mixEase(eases[d[dropdownId - 1].options[d[dropdownId - 1].selected]].f, eases[d[dropdownId].options[d[dropdownId].selected]].f, mixpoint) + elseif d[dropdownId].selected == 3 then -- create eases + insertDropdown(d, { + x = padding + 128 + padding, + y = padding, + width = 128, + options = skeys(eases), + name = 'ease1' + }) + end + + dropdowns = d + minEase = (self.kselected('ease1') and eases[self.kselected('ease1')].min == -1) or (self.kselected('ease2') and eases[self.kselected('ease2')].min == -1) + + return ease, minEase +end + +function self.update(dt) + if self.openDropdown ~= 0 then + dropdownScroll = math.max(dropdownScroll, -(#self.get(self.openDropdown).options - maxDropdown)) + dropdownScroll = math.min(dropdownScroll, 0) + dropdownScrollE = mix(dropdownScrollE, dropdownScroll, dt * 10) + 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, love.graphics.getFont():getHeight() + margin + + love.graphics.setColor(0, 0, 0, 0.3) + 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) + love.graphics.print(self.selected(i), x + margin/2, y + margin/2) + love.graphics.rectangle('line', x + w - h, y, h, h) + 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 then + for i,o in ipairs(v.options) do + local x, y, w, h = x, y + i * h, w, h + + y = y + dropdownScrollE * h + local gi = y / h + if gi > maxDropdown or gi < 1 then + goto continue + end + + local a = 1 - math.min(math.max((1 - (maxDropdown - gi)) * (1 - (math.abs(dropdownScrollE) /(#v.options - maxDropdown))), 0), 1) + + love.graphics.setColor(0, 0, 0, 0.3 * a) + 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) * 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) + love.graphics.print(v.options[i], x + 2, y + 2) + + ::continue:: + end + + -- scrollwheel + + if #v.options > maxDropdown then + local displayed = maxDropdown / #v.options + local scroll = math.abs(dropdownScrollE) / (#v.options - maxDropdown) + local size = margin + + love.graphics.setColor(1, 1, 1, 0.9) + love.graphics.rectangle('fill', x + w - size, y + h + scroll * (1 - displayed) * (maxDropdown - 1) * h, size, displayed * (maxDropdown - 1) * h) + end + end + end +end + +function self.mousepressed(x, y, m) + local clickedDropdown = false + for i,v in ipairs(dropdowns) do + local h = love.graphics.getFont():getHeight() + 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 = 0 + dropdownScrollE = 0 + elseif m == 3 then + dropdowns[i].selected = math.random(1, #dropdowns[i].options) + self.createDropdowns() + 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 + self.openDropdown = 0 + return true + end +end + +function self.mousereleased(x, y, m) + for i,v in ipairs(dropdowns) do + local h = love.graphics.getFont():getHeight() + 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} + self.createDropdowns() + 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 = love.graphics.getFont():getHeight() + 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 + self.createDropdowns() + end + end + end +end + +return self \ No newline at end of file diff --git a/main.lua b/main.lua index 14a104e..7c072c9 100644 --- a/main.lua +++ b/main.lua @@ -1,28 +1,21 @@ +local default_G = {} +for k, v in pairs(_G) do + table.insert(default_G, k) +end + local easelib = require 'easelib' +local dropdown = require 'dropdown' + -- utils -local function keys(t) - local k = {} - for n in pairs(t) do table.insert(k, n) end - return k -end -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 mix(x, y, a) +function mix(x, y, a) return x * (1 - a) + y * a end -- eases -local function mixEase(e1, e2, point) +function mixEase(e1, e2, point) if not point then point = 0.5 end return function(a) @@ -34,7 +27,7 @@ local function mixEase(e1, e2, point) end end -local eases = {} +eases = {} for i,v in pairs(easelib) do local min = 0 @@ -52,122 +45,31 @@ for i,v in pairs(easelib) do } end -local ease -local minEase = false +ease = nil +minEase = false -- rendering constants -local padding = 6 -local margin = 4 -local quality = 256 +padding = 6 +margin = 4 +local quality = 256 local mixpoint = 0.5 local oldmixpoint = 0.5 local mixpointtimer = 0 -- easter egg thing local mixpointspin = 0 -local maxDropdown = 16 - -- graph local graph = {} -- dropdown bullshit -local dropdowns = {} - -local dropdownValueCache = {} - -local openDropdown = 0 -local dropdownScroll = 0 -local dropdownScrollE = 0 - -local function selected(index) - return dropdowns[index].options[dropdowns[index].selected] -end - -local function kget(key) - for _, v in ipairs(dropdowns) do - if v.name == key then - return v - end - end -end - -local function 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 = (kget(f.name) or dropdownValueCache[f.name] or {selected = 1}).selected - f.selected = (f.selected - 1) % #f.options + 1 - return table.insert(tab, f) -end -local function createDropdowns() - local d = {} - dropdownId = 0 - insertDropdown(d, { - x = padding, - y = padding, - width = 128, - options = { - 'Preview Ease', - 'Mix Eases', - 'Create Ease' - }, - name = 'mode' - }) - - if d[dropdownId].selected == 1 then -- preview ease - insertDropdown(d, { - x = padding + 128 + padding, - y = padding, - width = 128, - options = skeys(eases), - name = 'ease1' - }) - ease = eases[d[dropdownId].options[d[dropdownId].selected]].f - elseif d[dropdownId].selected == 2 then -- mix eases - insertDropdown(d, { - x = padding + 128 + padding, - y = padding, - width = 128, - options = skeys(eases), - name = 'ease1' - }) - insertDropdown(d, { - x = padding + 128 + padding + 128 + padding, - y = padding, - width = 128, - options = skeys(eases), - name = 'ease2' - }) - ease = mixEase(eases[d[dropdownId - 1].options[d[dropdownId - 1].selected]].f, eases[d[dropdownId].options[d[dropdownId].selected]].f, mixpoint) - elseif d[dropdownId].selected == 3 then -- create eases - insertDropdown(d, { - x = padding + 128 + padding, - y = padding, - width = 128, - options = skeys(eases), - name = 'ease1' - }) - end - - minEase = (kselected('ease1') and eases[kselected('ease1')].min == -1) or (kselected('ease2') and eases[kselected('ease2')].min == -1) - - dropdowns = d -end -- rendering function love.load() - createDropdowns() + dropdown.createDropdowns() end function love.update(dt) @@ -196,15 +98,11 @@ function love.update(dt) mixpointspin = mix(mixpointspin, 0, dt * 3) - if openDropdown ~= 0 then - dropdownScroll = math.max(dropdownScroll, -(#dropdowns[openDropdown].options - maxDropdown)) - dropdownScroll = math.min(dropdownScroll, 0) - dropdownScrollE = mix(dropdownScrollE, dropdownScroll, dt * 10) - end + dropdown.update(dt) end function love.draw() - local mode = kget('mode').selected + local mode = dropdown.kget('mode').selected local sw, sh = love.graphics.getDimensions() local mx, my = love.mouse.getPosition() @@ -255,68 +153,13 @@ function love.draw() end -- dropdowns - for i,v in ipairs(dropdowns) do - local x, y, w, h = v.x, v.y, v.width, love.graphics.getFont():getHeight() + margin - - love.graphics.setColor(0, 0, 0, 0.3) - 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) - love.graphics.print(selected(i), x + margin/2, y + margin/2) - love.graphics.rectangle('line', x + w - h, y, h, h) - 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 openDropdown == i then - for i,o in ipairs(v.options) do - local x, y, w, h = x, y + i * h, w, h - - y = y + dropdownScrollE * h - local gi = y / h - if gi > maxDropdown or gi < 1 then - goto continue - end - - local a = 1 - math.min(math.max((1 - (maxDropdown - gi)) * (1 - (math.abs(dropdownScrollE) /(#v.options - maxDropdown))), 0), 1) - - love.graphics.setColor(0, 0, 0, 0.3 * a) - 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) * 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) - love.graphics.print(v.options[i], x + 2, y + 2) - - ::continue:: - end - - -- scrollwheel - - if #v.options > maxDropdown then - local displayed = maxDropdown / #v.options - local scroll = math.abs(dropdownScrollE) / (#v.options - maxDropdown) - local size = margin - - love.graphics.setColor(1, 1, 1, 0.9) - love.graphics.rectangle('fill', x + w - size, y + h + scroll * (1 - displayed) * (maxDropdown - 1) * h, size, displayed * (maxDropdown - 1) * h) - end - end - end - + dropdown.render() -- graph if mode == 1 or mode == 2 then local csize = 10 -- preview point size - local size = math.min((sw - padding) - ((kget('ease2') or kget('ease1')).x + 128 + padding), sh - padding * 5 - csize) + local size = math.min((sw - padding) - ((dropdown.kget('ease2') or dropdown.kget('ease1')).x + 128 + padding), sh - padding * 5 - csize) local x, y, w, h = sw - padding - size, padding, size, size love.graphics.setColor(1, 1, 1, 1) @@ -384,62 +227,27 @@ function love.draw() end function love.mousepressed(x, y, m) - local clickedDropdown = false - for i,v in ipairs(dropdowns) do - local h = love.graphics.getFont():getHeight() + margin - if 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 - openDropdown = i - clickedDropdown = true - dropdownScroll = 0 - dropdownScrollE = 0 - elseif m == 3 then - dropdowns[i].selected = math.random(1, #dropdowns[i].options) - createDropdowns() - end - end - end - if 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 - openDropdown = 0 - end + if dropdown.mousepressed(x, y, m) then return end end function love.mousereleased(x, y, m) - for i,v in ipairs(dropdowns) do - local h = love.graphics.getFont():getHeight() + margin - if 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) - openDropdown = 0 - dropdownValueCache[v.name] = {selected = v.selected} - createDropdowns() - end - end - end + if dropdown.mousereleased(x, y, m) then return end end function love.wheelmoved(x, y) if y == 0 then return end - if openDropdown ~= 0 then - dropdownScroll = dropdownScroll + y - else - local mx, my = love.mouse.getPosition() - for i,v in ipairs(dropdowns) do - local h = love.graphics.getFont():getHeight() + 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 - createDropdowns() + if dropdown.wheelmoved(x, y) then return end +end + +function love.keypressed(key) + if key == 'f6' then -- print all globals + for k, v in pairs(_G) do + for _, g in ipairs(default_G) do + if g == k then goto continue end end + print(k, v) + ::continue:: end end -end +end \ No newline at end of file