My UI library (Toggles & Textboxes so far)

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. :slight_smile:



--# 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

Nice

I have been focusing a lot on Python lately (for the past few months) and I’ve forgotten so much about Lua it’s not even funny. I wish I knew what the heck was going here.

I am probably gonna stick with my Python considering it’s so much more versatile, readable, and just all out better in my opinion. I can make games with it, while also being able to make basic workflow programs. I can use it to develop UI games, and so much more. You can do anything there. Lua is a lost cause for me…

Although this library does look really good for what you have so far (and for my blind eyes considering I cannot understand some of this because I am just coming back after multiple months).

@WilkeNine_Co, not to derail the conversation… But you can do all of those things in Lua. They will work faster and use less memory. And about readable … that is really language agnostic.

Both Python and Lua have their uses, and to say one language is better than the other is just plain wrong.