Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --# Passdrag
- Passdrag
- = class() -- Looks odd as code, but nice if it crashes
- local ellipseMesh = function(width, height, top, bottom, change) -- Function to create a(n) circle/ellipse mesh with a gradient
- local pwidth, pheight, ptop, pbototom, pchange
- pwidth = width or 128
- if type(height) == "number" or height == nil then
- pheight = height or width
- ptop = top or color(255)
- if type(bottom) == "userdata" then
- pbottom = bottom or ptop
- pchange = change or 1
- else
- pbottom = ptop
- pchange = bottom or 1
- end
- else
- pheight = width
- ptop = height or color(255)
- if type(top) == "userdata" then
- pbottom = top or ptop
- pchange = bottom or 1
- else
- pbottom = ptop
- pchange = top or 1
- end
- end
- pwidth, pheight = pwidth / 2, pheight / 2
- local m = mesh()
- local v = {}
- local c = {}
- local p = {}
- for d = 0, 360, pchange do
- local r = math.rad(d)
- table.insert(p, vec2(pwidth * math.sin(r), pheight * math.cos(r)))
- end
- v = triangulate(p)
- m.vertices = v
- for k, v in ipairs(v) do
- table.insert(c, ptop:mix(pbottom, v:normalize().y * 0.5 + 0.5))
- end
- m.colors = c
- return m
- end
- function Passdrag:init(x, y, size) -- Passdrag GUI & handler setup
- self.rot = {a = 0}
- self.tid = 0
- self.size = size
- self.x, self.y = x, y
- self.ePos = vec2(0, size)
- self.styles = {
- Light = {
- bg = color(255),
- txt = color(200),
- cFill = color(255),
- cStroke = color(220),
- cDark = color(210),
- pWidth = 5,
- },
- Dark = {
- bg = color(0),
- txt = color(40),
- cFill = color(30),
- cStroke = color(25),
- cDark = color(20),
- pWidth = 5
- },
- Retro = {
- bg = color(128, 96, 64, 255),
- txt = color(64, 24, 16),
- cFill = color(136, 102, 74, 255),
- cStroke = color(74, 32, 24),
- cDark = color(64, 24, 16),
- pWidth = 3,
- },
- Nature = {
- bg = color(191, 255, 191),
- txt = color(31, 63, 31),
- cFill = color(74, 136, 74),
- cStroke = color(63, 127, 63),
- cDark = color(48, 112, 48),
- pWidth = 5,
- },
- Sky = {
- bg = color(191, 223, 255),
- txt = color(255),
- cFill = color(95, 191, 255),
- cStroke = color(240, 240),
- cDark = color(74, 120, 255),
- pWidth = 8,
- },
- }
- self.oldStyles = self.styles
- self.style = "Light"
- self.darkness = {a = 0}
- self:updateMesh()
- self.sequence = ""
- self.lastChar = ""
- end
- function Passdrag:updateMesh() -- Update the gradiented mesh, not recommended for manual use
- self.m = ellipseMesh(self.size / 3 - self.styles[self.style].pWidth, self.styles[self.style].cFill, self.styles[self.style].cDark, 10)
- end
- function Passdrag:setStyle(x) -- Set style to x
- self.style = x
- self:updateMesh()
- end
- function Passdrag:addStyle(x, y) -- Add style x with a preset of y
- self.styles[x] = y
- end
- function Passdrag:duplicateStyle(x, y) -- Make a new style y, with the presets of x
- self.styles[y] = self.styles[x]
- end
- function Passdrag:deleteStyle(x) -- Delete style x
- self.styles[x] = nil
- end
- function Passdrag:restoreStyle(x) -- Restore style (x or current) to its original preset
- x = x or self.style
- self.styles[x] = self.oldStyles[x]
- end
- function Passdrag:restoreStyles() -- Restore all styles to their original presets
- self.styles = self.oldStyles
- end
- function Passdrag:addChar(x) -- Add character to current drag, not recommended for manual use
- if x ~= self.lastChar then
- self.sequence = self.sequence .. x
- self.lastChar = x
- end
- end
- function Passdrag:resetSequence() -- Reset drag
- self.sequence = ""
- self.lastChar = ""
- end
- function Passdrag:draw() -- Draw the GUI and update
- for k, v in pairs(self.styles[self.style]) do
- self["g" .. k] = v
- end
- local checks = {"bg", "txt", "cFill", "cStroke", "cDark", "pWidth"}
- for k, v in ipairs(checks) do
- if self["s" .. v] ~= nil then
- self.styles[style][v] = self["s" .. v]
- self["s" .. v] = nil
- end
- end
- local deg = math.floor(math.abs((math.deg(self.rot.a) - 90) / 45) + 0.5)
- if deg == 8 then
- deg = 0
- end
- for i = 1, 3 do
- if deg <= 5 then
- deg = deg + 2
- elseif deg >= 6 then
- deg = deg - 6
- end
- end
- self:addChar(tostring(deg + 1))
- local c = {}
- for k, v in ipairs(self.m.vertices) do
- table.insert(c, self.styles[self.style].cFill:mix(self.styles[self.style].cDark:mix(self.styles[self.style].cFill, self.darkness.a), v:normalize().y * 0.5 + 0.5))
- end
- self.m.colors = c
- pushMatrix()
- pushStyle()
- fill(self.styles[self.style].cFill)
- stroke(self.styles[self.style].cStroke)
- strokeWidth(self.styles[self.style].pWidth)
- self.ePos.x, self.ePos.y = math.sin(-self.rot.a) * self.size / 2, math.cos(-self.rot.a) * self.size / 2
- translate(self.x, self.y)
- pushMatrix()
- translate(self.ePos.x, self.ePos.y)
- ellipse(0, 0, self.size / 3)
- self.m:draw()
- fill(0, 0)
- ellipse(0, 0, self.size / 3)
- popMatrix()
- for i = 0, 7 do
- pushMatrix()
- rotate(i * (360 / 8))
- line(self.size - self.size / 4, 0, self.size, 0)
- popMatrix()
- end
- popStyle()
- popMatrix()
- end
- function Passdrag:touched(touch) -- Handles touches & animations on the GUI
- if self.tid == 0 and touch.state == BEGAN and vec2(touch.x - self.x, touch.y - self.y):dist(self.ePos) < self.size / 3 then
- self.tid = touch.id
- if self.t ~= nil then
- tween.stop(self.t)
- end
- if self.t2 ~= nil then
- tween.stop(self.t2)
- end
- self.t = tween(0.45, self.darkness, {a = 1}, tween.easing.quadInOut)
- end
- if touch.id == self.tid and (touch.state == BEGAN or touch.state == MOVING) then
- self.rot.a = math.atan2(touch.y - HEIGHT / 2, touch.x - WIDTH / 2) - math.pi / 2
- local deg = math.floor(math.abs((math.deg(self.rot.a) - 90) / 45) + 0.5)
- if deg == 8 then
- deg = 0
- end
- for i = 1, 3 do
- if deg <= 5 then
- deg = deg + 2
- elseif deg >= 6 then
- deg = deg - 6
- end
- end
- self:addChar(tostring(deg + 1))
- end
- if touch.id == self.tid and (touch.state == ENDED or touch.state == CANCELLED) then
- self.tid = 0
- tween.stop(self.t)
- self.t = tween(0.45, self.darkness, {a = 0}, tween.easing.quadInOut)
- self.t2 = tween(0.45, self.rot, {a = math.rad(((math.floor(math.deg(self.rot.a) / 45 - 0.5) + 0.5) + 0.5) * 45)})
- end
- end
- --# Main
- -- Passdrag
- function setup()
- print()
- pd = Passdrag(WIDTH / 2, HEIGHT / 2, 200)
- styles = {"Light", "Dark", "Retro", "Nature", "Sky"}
- parameter.integer("Style", 1, #styles, 1)
- parameter.watch("styles[Style]")
- parameter.watch("pd.sequence")
- parameter.action("Save Passdrag", function()
- savePassdrag()
- output.clear()
- print()
- tween.delay(0.1, function()
- output.clear()
- print()
- print("Passdrag saved")
- end)
- end)
- parameter.watch("Saved_Passdrag")
- parameter.watch("Passdrag_Matches_Saved")
- end
- function draw()
- pd:setStyle(styles[Style])
- background(pd.styles[pd.style].bg)
- Saved_Passdrag = readPassdrag()
- Passdrag_Matches_Saved = pd.sequence == Saved_Passdrag
- pd:draw()
- font("HelveticaNeue-Light")
- fontSize(48)
- fill(pd.styles[pd.style].txt)
- text("Passdrag", WIDTH / 2, HEIGHT - HEIGHT / 16)
- fontSize(24)
- text("Your drag: " .. pd.sequence, WIDTH / 2, HEIGHT - HEIGHT / 8)
- text("Drag length: " .. pd.sequence:len(), WIDTH / 2, HEIGHT - HEIGHT / 6)
- end
- function touched(touch)
- pd:touched(touch)
- end
- function savePassdrag()
- local fileName = "passdrag.txt"
- local file = os.getenv("HOME") .. "/Documents/" .. fileName
- local wFd = io.open(file, "w")
- wFd:write(pd.sequence)
- wFd:close()
- end
- function readPassdrag()
- local fileName = "passdrag.txt"
- local file = os.getenv("HOME") .. "/Documents/" .. fileName
- local rFd = io.open(file, "r")
- local v = ""
- if rFd ~= nil then
- for i in rFd:lines() do
- v = v .. i
- end
- end
- if rFd ~= nil then
- rFd:close()
- end
- return v
- end
RAW Paste Data