mirror of
https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile.git
synced 2025-01-08 17:33:09 +08:00
V0 version
Add ``.gitignore``
Update ``.vscode\settings.json``
Main file changed a bit
Replace every single ``io.open`` into ``fs.read()``
Add ``input.waiting2trigger`` as buffer for too quick inputs
Replace ``binser`` with ``bitser``
Add the missing buffer logical code in training mode
Add a debug connector
Not a big update
Update VirtualControl.lua
Update in vctrl system
Trimming some unnecessary empty lines in classic library
Update virtual control stuff
Replace ``table.getn`` with ``#`` and ``scene`` with ``SCENE``
Renaming and moving some modules
Removing unnecessary ``local mino = {...}``
Add loading screen
Update loading screen
Apply replay patch
Not showing virtual control on computer
Adding touch screen configuration scene (placeholder)
Fix loading screen
update virtual control texture
Do some preparation for touch config screen
Quick patch
Compress background
Not important uodates
Small changes on how virtual key call action
Add ``SCENE:onInputMove``
Apply V2.2 patch
Clean up unnecessary imports
Test
.
Remove a redudant global variable
Small change
Split up alpha number
Sorting code
Update storeInput function
Optimize replay storing, saving and reading
Add VCTRL.export (for saving feature)
Remove unnecessary imports
Redesign loading screen
Replace loading screen
Make a simple BUTTON module
Update BUTTON module
Update button module
Add new callback
Add new callback
TEST
Update simple-button module
Update simple button module
Set default draw function for button
Add scene type notation
TEST
Not important updates
Design a error screen
Small update
Remove error key
Update
TEST
TEST
Test
TEST
TEST
Update button module
TEST
TEST
TEST
TEST
TEST
TEST
TEST
TEST
test
TEST
TEST
TEST
test
TEST
test
Fix a bug in VCTRL module that affect to SCENE:onInputRelease
Moving VCTRL related calls and adding buttons for name entry screen
Add type notation
Update modules
Final update for touch configuration scene
Fix 2 buttons can be highlighted at the same time in simple-button module
Narrow the safe border
Remove id = b (it was there for test)
Update of touch configuration scene
Add touch gesture for replay and input configuration scene
Add buttons for Replay, add MENU to go out after finishing game or in 20G Training mode
TEST
Fix some bugs (TEST)
Fix lỗi giữa đêm
Fix bug again
It should work imo
TEST
Fix SCENE:onInputMove{type="touch"} is not working
Fix bug once again (DONE!)
Temproraily allowing save
Fix settings module
Fix VCTRL.exportAll()
Fix VCTRL.exportAll returns userdata
Reverse a change
Fix forgetting to import virtual control settings
Fix grid drawing
Fix bugs related to the first time launching game
Add README file
Add README file
Update README and add LICENSE files
Update README
Add TV remote code
Disable debug code
Fix Android code
Small fix
Rename LICENSE to COPYING
Moving scene.lua to modules folder
Add new libraries
Make a new FILE API and add a simple error screen in case most thing went down
Change special code, add a way to skip keys
Update icon + README file
Rename screenshot file
Update README
Updating README file
Replace loading screen
Update README
Update virtual control texture
Fix virtual button method
Update README
Add icon font
Add importing and exporting replays
Update touch control
Update conf.lua
Replacing font, to avoid license issue
convert indents to spaces
Update font related stuff
Replace font
Updating README file
Update virtual control texture
This commit is contained in:
314
libs/simple-button.lua
Normal file
314
libs/simple-button.lua
Normal file
@@ -0,0 +1,314 @@
|
||||
-- SIMPLE-BUTTON.lua<br>
|
||||
-- A simple module that aims to help you quickly create buttons<br>
|
||||
-- It is can be used as a base class to help you quickly creating button<br>
|
||||
-- This module has type notations so IntelliSense should give you some suggestions<br>
|
||||
local BUTTON = {}
|
||||
|
||||
-- MIT License
|
||||
|
||||
-- Copyright (c) 2024 SweetSea-ButImNotSweet
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local NULL = function() end
|
||||
local function checkColorTableValidation(C)
|
||||
if C and type(C) == "table" and (#C == 3 or #C == 4) then
|
||||
for _, v in pairs(C) do
|
||||
if type(v) ~= "number" or v<0 or v>1 then return false end
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
---@class BUTTON.button
|
||||
---@field text? string|function # Name of the button, will be used to show
|
||||
---@field textOrientation? "center"|"justify"|"left"|"right"
|
||||
---
|
||||
---@field x? number # Position of the button (x, y, w, h)
|
||||
---@field y? number # Position of the button (x, y, w, h)
|
||||
---@field w? number # Position of the button (x, y, w, h)
|
||||
---@field h? number # Position of the button (x, y, w, h)
|
||||
---@field r? number # Radius corner, cannot larger than half of button's width and half of button's height
|
||||
---
|
||||
---@field borderWidth? number|1 # Line width will be used to draw button
|
||||
---@field borderJoin? "bevel"|"miter"|"none"
|
||||
---@field borderStyle? "rough"|"smooth"
|
||||
---
|
||||
---@field font? love.Font
|
||||
---
|
||||
---@field backgroundColor? integer[]
|
||||
---@field textColor? integer[]
|
||||
---@field borderColor? integer[]
|
||||
---@field hoverColor? integer[]
|
||||
---@field pressColor? integer[]
|
||||
---
|
||||
---@field codeWhenPressed? function| # Code will be execute when pressed
|
||||
---@field codeWhenReleased? function| # Code will be execute when released
|
||||
---@field drawingButtonFunc? function| # The function is used to draw text<br>You can override the default one if you feel the default text drawing function is not suitable for you
|
||||
---
|
||||
---@field draw? function
|
||||
---@field update? function
|
||||
local button = {
|
||||
textOrientation = "center",
|
||||
r = 0,
|
||||
|
||||
backgroundColor = {0,0,0,0},
|
||||
hoverColor = {1,1,1,0.5},
|
||||
pressColor = {0, 1, 0.5, 0.5},
|
||||
borderColor = {1,1,1},
|
||||
textColor = {1,1,1},
|
||||
|
||||
font = love.graphics.newFont(15),
|
||||
|
||||
borderWidth = 1,
|
||||
borderJoin = "none",
|
||||
borderStyle = "smooth",
|
||||
|
||||
codeWhenPressed = NULL,
|
||||
codeWhenReleased = NULL,
|
||||
update = NULL,
|
||||
|
||||
_hovering = false,
|
||||
_pressed = false,
|
||||
_touchID = false,
|
||||
}; button.__index = button
|
||||
function button:draw()
|
||||
love.graphics.setLineWidth(self.borderWidth)
|
||||
love.graphics.setLineStyle(self.borderStyle)
|
||||
love.graphics.setLineJoin(self.borderJoin)
|
||||
|
||||
love.graphics.setColor(self.backgroundColor)
|
||||
love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r)
|
||||
|
||||
if self._pressed then
|
||||
love.graphics.setColor(self.pressColor)
|
||||
love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r)
|
||||
elseif self._hovering then
|
||||
love.graphics.setColor(self.hoverColor)
|
||||
love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r)
|
||||
end
|
||||
|
||||
love.graphics.setColor(self.textColor)
|
||||
love.graphics.setFont(self.font)
|
||||
|
||||
local text = type(self.text) == 'function' and self.text() or self.text
|
||||
|
||||
local lineAmount
|
||||
do
|
||||
local _, t = self.font:getWrap(text, self.w)
|
||||
lineAmount = #t
|
||||
end
|
||||
local textHeight = self.font:getHeight() * (lineAmount * 0.5)
|
||||
local textPos = self.y + (self.h * 0.5) - textHeight
|
||||
love.graphics.printf(text, self.x, textPos, self.w, self.textOrientation)
|
||||
|
||||
love.graphics.setColor(self.borderColor)
|
||||
love.graphics.rectangle('line', self.x, self.y, self.w, self.h, self.r)
|
||||
end
|
||||
---Check if current position is hovering the button, if it is, return true
|
||||
function button:isHovering(x,y)
|
||||
if not y then return false end
|
||||
if
|
||||
x >= self.x and
|
||||
y >= self.y and
|
||||
x <= self.x + self.w and
|
||||
y <= self.y + self.h
|
||||
then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
---Trigger press action, only when ``self._hovering`` is true
|
||||
function button:press(x, y, touchID)
|
||||
if (touchID and self:isHovering(x, y) or self._hovering) and not self._pressed then
|
||||
self.codeWhenPressed()
|
||||
|
||||
self._touchID = touchID
|
||||
self._pressed = true
|
||||
self:draw()
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
---Trigger release action, don't need ``self._hovering`` to ``true``
|
||||
function button:release(x, y, touchID)
|
||||
local valid = true
|
||||
if touchID then
|
||||
valid = touchID == self._touchID
|
||||
elseif x and y then
|
||||
valid = true
|
||||
end
|
||||
|
||||
if valid then
|
||||
self._pressed = false
|
||||
self._touchID = false
|
||||
|
||||
if touchID then
|
||||
self._hovering = false
|
||||
else
|
||||
self._hovering = self:isHovering(x, y)
|
||||
end
|
||||
|
||||
if self:isHovering(x, y) then
|
||||
self.codeWhenReleased()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param D BUTTON.button|BUTTON.newData
|
||||
---@param safe? boolean @ Creating widget? If not then ignore accept missing important parameters
|
||||
---@return nil
|
||||
---Validate the provided data, will be called by ``BUTTON.new`` and ``BUTTON.setDefaultOption``<br>
|
||||
---***WARNING! THIS FUNCTION WILL RAISE EXCEPTION IF DATA IS INVALID!***
|
||||
function BUTTON.checkDataValidation(D, safe)
|
||||
if not safe then
|
||||
if type(D.text) == 'function' then
|
||||
assert(type(D.text()) == 'string', "[text] is a function but it doesn't return any string?!")
|
||||
elseif type(D.text) ~= 'string' then
|
||||
error("[text] must be a string or a function returns string, got "..type(D.text))
|
||||
end
|
||||
|
||||
assert(type(D.x) == "number" , "[x] must be a integer")
|
||||
assert(type(D.y) == "number" , "[y] must be a 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.r) == "number" and D.r >= 0 and D.r <= D.w * 0.5 and D.r <= D.h * 0.5) or D.r == nil, "[r] must be a positive integer and cannot larger than half of button's width and half of button's height")
|
||||
else
|
||||
assert(type(D.r) == "number" and D.r >= 0 or D.r == nil, "[r] must be a positive integer (CAUTION: a extra condition is temproraily ignored because you are setting default option)")
|
||||
end
|
||||
assert(table.contains({"center","justify","left","right"}, D.textOrientation) or D.textOrientation == nil, "[borderJoin] must be 'bevel', 'miter' or 'none")
|
||||
assert((type(D.borderWidth) == "number" and D.borderWidth > 0) or D.borderWidth == nil, "[borderWidth] must be a postive integer")
|
||||
assert(table.contains({"bevel", "miter", "none"}, D.borderJoin) or D.borderJoin == nil, "[borderJoin] must be 'bevel', 'miter' 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")
|
||||
|
||||
assert(checkColorTableValidation(D.backgroundColor), "[backgroundColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1")
|
||||
assert(checkColorTableValidation(D.hoverColor), "[hoverColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1")
|
||||
assert(checkColorTableValidation(D.pressColor), "[hoverColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1")
|
||||
assert(checkColorTableValidation(D.borderColor), "[borderColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1")
|
||||
assert(checkColorTableValidation(D.textColor), "[textColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1")
|
||||
|
||||
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.drawingButtonFunc) == "function" or D.drawingButtonFunc == nil, "[drawingButtonFunc] must be a function or nil")
|
||||
end
|
||||
|
||||
---@class BUTTON.newData
|
||||
---@field text string|function # Name of the button, will be used to show. If function provided, it should return the string!
|
||||
---@field textOrientation? "center"|"justify"|"left"|"right"
|
||||
---
|
||||
---@field x number # Position of the button (x, y, w, h)
|
||||
---@field y number # Position of the button (x, y, w, h)
|
||||
---@field w number # Position of the button (x, y, w, h)
|
||||
---@field h number # Position of the button (x, y, w, h)
|
||||
---@field r? number # Radius corner, cannot larger than half of button's width and half of button's height
|
||||
---
|
||||
---@field borderWidth? number|1 # Line width will be used to draw button
|
||||
---@field borderJoin? "bevel"|"miter"|"none"
|
||||
---@field borderStyle? "rough"|"smooth"
|
||||
---
|
||||
---@field font? love.Font
|
||||
---
|
||||
---@field backgroundColor? integer[]
|
||||
---@field textColor? integer[]
|
||||
---@field borderColor? integer[]
|
||||
---@field hoverColor? integer[]
|
||||
---@field pressColor? integer[]
|
||||
---
|
||||
---@field codeWhenPressed? function| # Code will be execute when pressed
|
||||
---@field codeWhenReleased? function| # Code will be execute when released
|
||||
---@field drawingButtonFunc? function| # The function is used to draw text<br>You can override the default one if you feel the default text drawing function is not suitable for you
|
||||
---
|
||||
---@field draw? function
|
||||
---@field update? function
|
||||
|
||||
---@param D BUTTON.newData
|
||||
---@nodiscard
|
||||
---Create a new button, provide you a table with 4 functions inside: draw and update, press and release<br>
|
||||
---You need to put them into intended callbacks :)
|
||||
---
|
||||
---Remember to fill 5 necessary parameters: name, x, y, w and h
|
||||
function BUTTON.new(D)
|
||||
local B = setmetatable(D, button)
|
||||
BUTTON.checkDataValidation(B)
|
||||
return B
|
||||
end
|
||||
|
||||
---@param D BUTTON.button
|
||||
function BUTTON.setDefaultOption(D)
|
||||
BUTTON.checkDataValidation(setmetatable(D, button), true)
|
||||
for k, v in pairs(D) do
|
||||
if button[k] ~= nil then
|
||||
button[k] = v
|
||||
else
|
||||
error("Parameter named ["..k.."] is not existed or cannot be set default value, in BUTTON!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- < EXTRA GENERAL OPTIONS >
|
||||
|
||||
---Draw all buttons in provided list
|
||||
---@param list table<any,BUTTON.button>
|
||||
function BUTTON.draw(list)
|
||||
for _, v in pairs(list) do v:draw() end
|
||||
end
|
||||
---Update all buttons in provided list
|
||||
---@param list table<any,BUTTON.button>
|
||||
function BUTTON.update(list)
|
||||
for _, v in pairs(list) do v:update() end
|
||||
end
|
||||
|
||||
---Check if current mouse position is inside button<br>
|
||||
---Calling BUTTON.press will trigger this, but you can call it when moving mouse so button can be highlighted when being hovered
|
||||
---@param list table<BUTTON.button>
|
||||
---@param x number # Mouse position
|
||||
---@param y number # Mouse position
|
||||
function BUTTON.checkHovering(list, x, y)
|
||||
local highlighted_a_button = false
|
||||
for _, v in pairs(list) do
|
||||
if highlighted_a_button then
|
||||
v._hovering = false
|
||||
else
|
||||
v._hovering = v:isHovering(x, y)
|
||||
end
|
||||
|
||||
if not highlighted_a_button and v._hovering then highlighted_a_button = true end
|
||||
end
|
||||
end
|
||||
|
||||
--- Trigger the press action, only if ``button._hovering == true``
|
||||
---@param list table<BUTTON.button>
|
||||
---@param x number # Mouse position
|
||||
---@param y number # Mouse position
|
||||
function BUTTON.press(list, x, y, touchID)
|
||||
for _, v in pairs(list) do if v:press(x, y, touchID) then return true end end
|
||||
end
|
||||
|
||||
---Trigger the release action
|
||||
---@param list table<BUTTON.button>
|
||||
function BUTTON.release(list, x, y, touchID)
|
||||
for _, v in pairs(list) do if v:release(x, y, touchID) then return true end end
|
||||
end
|
||||
|
||||
return BUTTON
|
||||
Reference in New Issue
Block a user