Hey all, this is the UI library I have been working on for a few days… Please comment and tell me what I should do next (My current task is buttons…), and how I should fix my existing code.
--# Functions
-- A modification to the clip() function to use translate and scale.
function matrixClip(x, y, w, h)
local m = modelMatrix()
x = x * m[1] + m[13]
y = y * m[6] + m[14]
w = w * m[1]
h = h * m[6]
clip(x, y, w, h)
end
-- A function to determine whether an area has been touched (with a hit radius)
function touchedHit(u, v, x, y, w, h)
if u > x - 2.5 and u < x + w + 5 and v > y - 2.5 and v < y + h + 5 then
return true
end
return false
end
--# Main
function setup()
box = Textbox(WIDTH / 2, HEIGHT / 2, "Enter name")
box:setFont("HelveticaNeue")
box:setFunction(print)
boxTog = Toggle("showBox", WIDTH / 2, HEIGHT / 4)
end
function draw()
background(127, 127, 127, 255)
if showBox then
box:draw()
end
boxTog:draw()
end
function touched(touch)
if showBox then
box:touched(touch)
end
boxTog:touched(touch)
end
function keyboard(key)
if showBox then
box:keyboard(key)
end
end
--# Textbox
Textbox = class()
function Textbox:init(x, y, default)
self.x = x
self.y = y
self.w = 150
self.h = 30
self.f = function () end
self.font = "Inconsolata"
self.size = 20
self.default = default or ""
self.text = ""
self.selected = false
end
function Textbox:setFont(newFont)
self.font = newFont
end
function Textbox:setFunction(f)
self.f = f
end
function Textbox:fit()
local count = -1
local len = textSize(string.sub(self.text, -1))
while true do
len = textSize(string.sub(self.text, count))
if len > 150 then
return count + 1
end
count = count - 1
if -count > string.len(self.text) then return 1 end
end
end
function Textbox:draw()
pushMatrix()
pushStyle()
translate(self.x, self.y)
rectMode(CENTER)
textMode(CENTER)
font(self.font)
fontSize(self.size)
fill(255, 255, 255, 255)
rect(0, 0, self.w, self.h)
fill(0, 0, 0, 255)
if self.text ~= "" then
if textSize(self.text) > self.w then
text(string.sub(self.text, self:fit()), 0, 0)
else
text(self.text, 0, 0)
end
elseif not self.selected then
fill(127, 127, 127, 255)
text(self.default, 0, 0)
end
if self.selected then
if ElapsedTime % 1 > .5 then
stroke(0, 0, 255, 255)
smooth()
lineCapMode(SQUARE)
strokeWidth(4)
line(0 + textSize(string.sub(self.text, self:fit())) / 2, -self.h / 3,
0 + textSize(string.sub(self.text, self:fit())) / 2, self.h / 3)
end
if not isKeyboardShowing() then
self.selected = false
self.f(self.text)
end
end
popStyle()
popMatrix()
end
function Textbox:touched(touch)
if touchedHit(touch.x, touch.y, self.x, self.y, self.w, self.h) then
self.selected = true
showKeyboard()
end
end
function Textbox:keyboard(key)
if key == RETURN then
self.selected = false
hideKeyboard()
self.f(self.text)
elseif key == BACKSPACE then
self.text = string.sub(self.text, 1, -2)
else
self.text = self.text .. key
end
end
--# Toggle
Toggle = class()
--[[
Version 1.1
Changes =
A new parameter, value, which is a boolean, the current toggle of the switch.
A white border around the toggle
The switch colour changes when touched
if the variable passed to toggle already exists, then the toggle will default to its value
Version 1.2
Changes = --(Thanks to @Codeslinger)
Fixes the default value for selected to false
Various speed ups and optimisations
Enlarged the hit radius of the toggle
Made the text slightly copy the colouring of the toggle (If you look closely at a native toggle, you will notice this)
Syntax =
myToggle = Toggle("VariableName", x, y)--like the parameter and watch functions, it takes the string of the name
-- To move the toggle without redefining it
myToggle.x = newX
myToggle.y = newY
-- To switch the value
myToggle:switch()
]]
function Toggle:init(var, x, y)
_G[var] = _G[var] and true or false
self.var = var
self.x = x
self.y = y
self.w = 50
self.h = 30
self.selected = false
self.value = _G[var]
self.toggle = (self.value and 1 or -1) * (self.w / 2)
end
function Toggle:draw()
pushMatrix()
pushStyle()
ellipseMode(CENTER)
lineCapMode(ROUND)
textMode(CENTER)
smooth()
translate(self.x, self.y)
strokeWidth(self.h + 1)
stroke(255, 255, 255, 255)
line(0, 0, self.w, 0)
strokeWidth(self.h - 4)
stroke(239, 239, 239, 255)
line(self.w / 2 + self.toggle, 0, self.w, 0)
stroke(0, 127, 239, 255)
line(0, 0, self.w / 2 + self.toggle, 0)
strokeWidth(self.h / 2 - 2)
stroke(255, 255, 255, 255)
line(self.w / 2 + self.toggle, -self.h / 4, self.w, -self.h / 4)
stroke(79, 159, 238, 255)
line(0, -self.h / 4, self.w / 2 + self.toggle, -self.h / 4)
matrixClip(-self.h / 2 + 4, -self.h / 2, self.w + self.h - 8, self.h)
font("HelveticaNeue-Bold")
fontSize(self.h / 3 * 2)
fill(0, 0, 0, 127)
text("ON", self.toggle - self.w / 4, 0)
text("OFF",self.toggle + self.w * 1.25, 0)
clip()
noStroke()
fill(239, 255)
ellipse(self.w / 2 + self.toggle, 0, self.h)
fill(self.selected and 223 or 255, 255)
ellipse(self.w / 2 + self.toggle, 0, self.h - 4)
popStyle()
popMatrix()
end
function Toggle:touched(touch)
if touch.state == BEGAN
and touchedHit(touch.x, touch.y,
self.x - self.h / 2, self.y - self.h / 2,
self.w + self.h, self.h) then
self.selected = true
self.startTime = ElapsedTime
elseif touch.state == MOVING and self.selected then
self.toggle = math.min(self.w / 2, math.max(-self.w / 2, self.toggle + touch.deltaX))
elseif touch.state == ENDED and self.selected then
if ElapsedTime - self.startTime < .25 then
self.value = not self.value
self:switch()
self.selected = false
return
end
if self.value then
self.value = self.toggle > self.w / 4
else
self.value = self.toggle > -self.w / 4
end
self:switch()
self.selected = false
end
end
function Toggle:switch()
_G[self.var] = self.value
self.toggle = (self.value and 1 or -1) * self.w / 2
end