diff --git a/libs/simple-button.lua b/libs/simple-button.lua index a5766e6..8b969e2 100644 --- a/libs/simple-button.lua +++ b/libs/simple-button.lua @@ -1,51 +1,246 @@ -local defaultFont = love.graphics.newFont(20) -local function defaultDrawingTextFunc(name, x, y, w, h) - love.graphics.setFont(defaultFont) - love.graphics.printf(name, x, y, w, "center") -end +local NULL = function () end -local button = {}; button.__index = button +---@class BUTTON.button +---@field name string +---@field x number +---@field y number +---@field w number +---@field h number +--- +---@field borderWidth? number +---@field borderJoin? "bevel"|"milter"|"none" +---@field borderStyle? "rough"|"smooth" +--- +---@field font? love.Font +--- +---@field codeWhenPressed? function +---@field codeWhenReleased? function +---@field drawingTextFunc? function +--- +---@field _hovering? boolean +--- +---@field draw? function +---@field update? function +local button = { + name = "NEW BUTTON", + x = 0, y = 0, w = 0, h = 0, + + backgroundColor = {0,0,0,0}, + hoverColor = {1,1,1,0.5}, + borderColor = {1,1,1}, + textColor = {1,1,1}, + + font = love.graphics.newFont(15), + + borderWidth = 1, + borderJoin = "none", + borderStyle = "smooth", + + drawingBackgroundFunc = function(self) + love.graphics.setLineWidth(self.borderWidth) + love.graphics.setLineStyle(self.borderStyle) + love.graphics.setLineJoin(self.borderJoin) + + love.graphics.setColor(unpack(self.backgroundColor)) + love.graphics.rectangle('fill', self.x, self.y, self.w, self.h) + + if self._hovering then + love.graphics.setColor(unpack(self.hoverColor)) + love.graphics.rectangle('fill', self.x, self.y, self.w, self.h) + end + + love.graphics.setColor(unpack(self.borderColor)) + love.graphics.rectangle('line', self.x, self.y, self.w, self.h) + end, + drawingTextFunc = function(self) + love.graphics.setFont(self.font) + love.graphics.printf(self.name, self.x, self.y + (self.h * 0.25), self.w, "center") + end, + codeWhenPressed = NULL, + codeWhenReleased = NULL, + + _hovering = false +}; button.__index = button function button:draw() - love.graphics.setColor(1,1,1) - love.graphics.setLineWidth(self.lineWidth) - love.graphics.rectangle('line', self.x, self.y, self.w, self.h) - self.drawingTextFunc(self.name, self.x, self.y, self.w, self.h) + self:drawingBackgroundFunc() + self:drawingTextFunc() +end +function button:isHovering(x,y) + if + x >= self.x and + y >= self.y and + x <= self.x + self.w and + y <= self.y + self.h + then + self._hovering = true + else + self._hovering = false + end +end +---@param touch? boolean @ If the button is touched, remember to pass true into touch param +function button:press(touch) + if touch or self._hovering then + self.codeWhenPressed() + end +end +---@param touch? boolean @ If the button is touched, remember to pass true into touch param +function button:release(touch) + if touch or self._hovering then + self.codeWhenReleased() + end end local BUTTON = {} ----@param name string @ Name of the button, will be shown ----@param x number ----@param y number ----@param w number ----@param h number ----@param drawingTextFunc? function ----@param lineWidth? number|1 @ Line width will be used to draw button -function BUTTON.new(name, x, y, w, h, lineWidth, drawingTextFunc) - assert(type(name) == "string", "[name] is missing or not valid") - assert(type(x) == "number" and x > 0, "[x] must be a positive integer") - assert(type(y) == "number" and y > 0, "[y] must be a positive integer") - assert(type(w) == "number" and w > 0, "[w] must be a positive integer") - assert(type(h) == "number" and h > 0, "[h] must be a positive integer") - assert(type(drawingTextFunc) == "function" or type(drawingTextFunc) == "nil", "[drawingTextFunc] must be a function or nil") - assert((type(lineWidth) == "number" and lineWidth > 0) or type(drawingTextFunc) == "nil", "[lineWidth] must be a postive integer") +---@param D BUTTON.newData +---Validate the provided data, will be called by ``BUTTON.new`` and ``BUTTON.setDefaultOption``
+---***WARNING! THIS FUNCTION WILL RAISE EXCEPTION IF DATA IS INVALID!*** +function BUTTON.checkDataValidation(D) + assert(type(D.name) == "string", "[name] is missing or not valid") + assert(type(D.x) == "number" and D.x > 0, "[x] must be a positive integer") + assert(type(D.y) == "number" and D.y > 0, "[y] must be a positive integer") + assert(type(D.w) == "number" and D.w > 0, "[w] must be a positive integer") + assert(type(D.h) == "number" and D.h > 0, "[h] must be a positive integer") + assert((type(D.borderWidth) == "number" and D.borderWidth > 0) or D.drawingTextFunc == nil, "[borderWidth] must be a postive integer") + assert(table.contains({"bevel", "milter", "none"}, D.borderJoin) or D.borderJoin == nil, "[borderJoin] must be 'bevel', 'milter' or 'none") + assert(table.contains({"rough", "smooth"}, D.borderStyle) or D.borderStyle == nil, "[borderStyle] must be 'rough' or 'smooth'") + assert((D.font and D.font.typeOf and D.font:typeOf("Font")) or D.font == nil, "[font] must be love.Font") + + local red_flag = false + if D.backgroundColor then + if type(D.backgroundColor) == "table" then + if #D.backgroundColor == 3 or #D.backgroundColor == 4 then + for _, v in pairs(D.backgroundColor) do + if type(v) ~= "number" or v<0 or v>1 then red_flag = true end + end + else + red_flag = true + end + else + red_flag = true + end + end + if red_flag then error("[backgroundColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1") end + + if D.hoverColor then + if type(D.hoverColor) == "table" then + if #D.hoverColor == 3 or #D.hoverColor == 4 then + for _, v in pairs(D.hoverColor) do + if type(v) ~= "number" or v<0 or v>1 then red_flag = true end + end + else + red_flag = true + end + else + red_flag = true + end + end + if red_flag then error("[hoverColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1") end + + if D.borderColor then + if type(D.borderColor) == "table" then + if #D.borderColor == 3 or #D.borderColor == 4 then + for _, v in pairs(D.borderColor) do + if type(v) ~= "number" or v<0 or v>1 then red_flag = true end + end + else + red_flag = true + end + else + red_flag = true + end + end + if red_flag then error("[borderColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1") end + + if D.textColor then + if type(D.textColor) == "table" then + if #D.textColor == 3 or #D.textColor == 4 then + for _, v in pairs(D.textColor) do + if type(v) ~= "number" or v<0 or v>1 then red_flag = true end + end + else + red_flag = true + end + else + red_flag = true + end + end + if red_flag then error("[textColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1") end + + assert(type(D.codeWhenPressed) == "function" or D.codeWhenPressed == nil, "[codeWhenPressed] must be a function or nil") + assert(type(D.codeWhenReleased) == "function" or D.codeWhenReleased == nil, "[codeWhenReleased] must be a function or nil") + assert(type(D.drawingTextFunc) == "function" or D.drawingTextFunc == nil, "[drawingTextFunc] must be a function or nil") +end + + +---@class BUTTON.newData +---@field name string # Name of the button, will be shown +---@field x number +---@field y number +---@field w number +---@field h number +--- +---@field borderWidth? number|1 # Line width will be used to draw button +---@field borderJoin? "bevel"|"milter"|"none" +---@field borderStyle? "rough"|"smooth" +--- +---@field font? love.Font +--- +---@field backgroundColor? table<[r,g,b,a]> +---@field hoverColor? table<[r,g,b,a]> +---@field borderColor? table<[r,g,b,a]> +---@field textColor? table<[r,g,b,a]> +--- +---@field codeWhenPressed? function|nil # Code will be execute when pressed +---@field codeWhenReleased? function|nil # Code will be execute when released +---@field drawingTextFunc? function|defaultDrawingTextFunc + +---@param D BUTTON.newData +---@return BUTTON.button +---Create a new button, provide you a table with 2 functions inside: draw and update
+---You need to put them into intended callbacks :) +function BUTTON.new(D) + BUTTON.checkDataValidation(D) return setmetatable({ - name = name, - x = x, - y = y, - w = w, - h = h, - drawingTextFunc = drawingTextFunc or defaultDrawingTextFunc, - lineWidth = lineWidth or 1 + name = D.name, + x = D.x, + y = D.y, + w = D.w, + h = D.h, + + borderWidth = D.borderWidth, + borderJoin = D.borderJoin, + borderStyle = D.borderStyle, + + backgroundColor = D.backgroundColor, + hoverColor = D.hoverColor, + borderColor = D.borderColor, + textColor = D.textColor, + + codeWhenPressed = D.codeWhenPressed, + codeWhenReleased = D.codeWhenReleased, + drawingTextFunc = D.drawingTextFunc, }, button) end --- Set the default funciton used to drawing text, will be passed name, x, y, w and h function BUTTON.setDefaultDrawingTextFunction(f) assert(type(f) == "function", "[f] must be a function!") - defaultDrawingTextFunc = f + button.drawingTextFunc = f +end + +---@param D BUTTON.newData +function BUTTON.setDefaultOption(D) + BUTTON.checkDataValidation(D) + for k, v in pairs(D) do + if button[k] ~= nil then + button[k] = v + else + error("There is no "..k.." parameter in BUTTON!") + end + end end return BUTTON \ No newline at end of file