提交 aad33efe 编写于 作者: baidwwy's avatar baidwwy 🏋

lua

上级 874fc53e
-- @Author : GGELUA
-- @Date : 2021-09-17 08:26:43
-- @Last Modified by : baidwwy
-- @Last Modified time : 2022-02-06 14:23:10
require('ggelua') --preload dll
io.stdout:setvbuf('no', 0)
local entry = ...
local function 分割路径(path)
local t, n = {}, 1
for match in path:gmatch('([^;]+)') do
t[n] = match
n = n + 1
end
return t
end
local lpath, lpath_, cpath
if gge.platform == 'Windows' then
--lua脚本搜索
lpath = '!/ggelua/?.lua;!/ggelua/?/?.lua;ggelua/?.lua;ggelua/?/?.lua;?.lua;lua/?.lua;lua/?/?.lua'
lpath = lpath:gsub('!', gge.getrunpath())
lpath_ = 分割路径(lpath)
--lua模块搜索
cpath = '?.dll;lib/?.dll;!/?.dll;!/lib/?.dll'
cpath = cpath:gsub('!', gge.getrunpath())
elseif gge.platform == 'Android' then
lpath = 'ggelua/?.lua;ggelua/?/?.lua;?.lua;lua/?.lua;lua/?/?.lua'
lpath_ = 分割路径(lpath)
cpath = gge.arg[1] .. '/lib?.so'
end
package.path = nil
package.cpath = nil
setmetatable(
package,
{
__newindex = function(t, k, v)
if v and k == 'path' then
lpath = v:lower():gsub('\\', '/')
lpath_ = 分割路径(lpath)
elseif k == 'cpath' then
cpath = v
else
rawset(t, k, v)
end
end,
__index = function(t, k)
if k == 'path' then
return lpath
elseif k == 'cpath' then
return cpath
end
end
}
)
-- if gge.platform=='Android' then
-- error("找不到脚本")
-- return
-- end
local function 处理路径(path)
--相对路径
-- local t = {}
-- for match in path:gmatch("([^/]+)") do
-- if match=='..' then
-- table.remove(t)
-- elseif match~='.' then
-- table.insert(t, match)
-- end
-- end
-- path = table.concat(t, "/")
path = path:lower()
path = path:gsub('%.', '/')
path = path:gsub('\\', '/')
return path
end
local 读取文件, 是否存在
if gge.isdebug then
function 是否存在(path)
local file = io.open(path, 'rb')
if file then
file:close()
return true
end
end
function 读取文件(path)
local file = io.open(path, 'rb')
if file then
local data = file:read('a')
file:close()
return data
end
end
function gge.dirscript(path, ...)
if select('#', ...) > 0 then
path = path:format(...)
end
local lfs = require('lfs')
local dir, u = lfs.dir(path)
local pt = {}
return function()
repeat
local file = dir(u)
if file then
local f = path .. '/' .. file
local attr = lfs.attributes(f)
if attr and attr.mode == 'directory' then
if file ~= '.' and file ~= '..' then
table.insert(pt, f)
end
file = '.'
else
return f
end
elseif pt[1] then
path = table.remove(pt, 1)
dir, u = lfs.dir(path)
file = '.'
end
until file ~= '.'
end
end
else
local script = gge.script
gge.script = nil
local list = {}
for _, v in ipairs(script.getlist()) do
list[v] = true
end
function 是否存在(file)
return list[file]
end
function 读取文件(file)
return script.getdata(file)
end
function gge.dirscript(path, ...)
if select('#', ...) > 0 then
path = path:format(...)
end
local k
return function()
repeat
k = next(list, k)
if k and k:find(path) then
return k
end
until not k
end
end
end
local function 搜索路径(path)
for _, v in ipairs(lpath_) do
local file = v:gsub('?', path)
if 是否存在(file) then
return file
end
end
end
local loaded = package.loaded
table.insert(
package.searchers,
2, --1是preload
function(path)
local npath = 处理路径(path)
if loaded[npath] ~= nil then
return function()
return loaded[npath]
end
end
local fpath = 搜索路径(npath)
if fpath then
return function()
local data = 读取文件(fpath)
local r, err = load(data, fpath)
if err then
return error(err, 2)
end
local r = r()
loaded[npath] = r == nil and true or r
return loaded[npath]
end
end
end
)
package.loaded =
setmetatable(
{},
{
__index = function(t, k)
k = 处理路径(k)
return loaded[k]
end,
__newindex = function(t, k, v)
k = 处理路径(k)
loaded[k] = v
end,
__pairs = function()
return next, loaded
end
}
)
function gge.require(path, env, ...)
path = path:gsub('\\', '/'):lower()
local data = 读取文件(path)
if data then
return assert(load(data, path, 'bt', env))(...)
end
end
require('GGE')
ggexpcall(require, entry)
-- @Author : GGELUA
-- @Date : 2021-10-30 13:05:32
-- @Last Modified by : baidwwy
-- @Last Modified time : 2022-02-06 14:19:33
class = require('GGE.class')
warn('@on') --开启警告
collectgarbage('generational') --使用分代GC
local type = type
local unpack = table.unpack
local pcall = pcall
local xpcall = xpcall
local function _traceback(L, t)
local i = 1
repeat
local r = debug.getinfo(L, i)
if r and r.what ~= 'C' then -- and not r.source:match('%a:')
table.insert(t, string.format('%s:%s: %s', r.short_src, r.currentline, r.name or r.namewhat or 'no'))
-- local l = 1
-- repeat
-- local k,v = debug.getlocal(L,i,l)
-- if k and k:sub(1,1)~='(' then
-- if type(v)=='string' then
-- if #v>64 then
-- table.insert(t, string.format(' [local] %s = %s...', k,v:sub(64)))
-- else
-- table.insert(t, string.format(' [local] %s = "%s"', k,v))
-- end
-- else
-- table.insert(t, string.format(' [local] %s = %s', k,v))
-- end
-- end
-- l=l+1
-- until not k
-- local u = 1
-- repeat
-- local k,v = debug.getupvalue(r.func,u)
-- if k and k~='_ENV' then
-- table.insert(t, string.format(' [upvalue] %s = %s;', k,v))
-- end
-- u=u+1
-- until not k
end
i = i + 1
until not r
return t
end
local function _errfun(err)
local t
if type(err) == 'table' then --协程
t = err
else
t = {'[\x1b[41;30mERROR\x1b[0m]', err}
end
_traceback(coroutine.running(), t)
err = table.concat(t, '\n')
if gge.platform == 'Windows' then
print(err)
else
local SDL = require('SDL')
SDL.Log(SDL.GetError())
SDL.Log(err)
gge.messagebox(err)
end
if type(gge.onerror) == 'function' then
gge.onerror(err)
elseif gge.isdebug then
os.exit(-1)
end
end
function ggexpcall(fun, ...)
local r = {xpcall(fun, _errfun, ...)}
if r[1] ~= nil then
return unpack(r, 2)
end
return nil, unpack(r, 2)
end
function ggepcall(fun, ...)
local r = {pcall(fun, ...)}
if r[1] then
return unpack(r, 2)
end
warn(r[2])
return nil
end
function ggetype(v)
local t = type(v)
if t == 'table' or (t == 'userdata' and getmetatable(v)) then
return v.__name or t
end
return t
end
function ggeassert(condition, err, level)
if condition then
return condition
else
error(err, level + 1)
end
end
coroutine.FALSE = {}
function coroutine.xpcall(fun, ...)
local L
if type(fun) == 'function' then
L = coroutine.create(fun)
else
L = fun
end
local r = {coroutine.resume(L, ...)}
if r[1] == false then
local t = _traceback(L, type(r[2]) == 'table' and r[2] or {'[\x1b[41;30mcoroutine.xpcall\x1b[0m]', r[2]})
for i, v in ipairs(t) do
print(v)
end
if os.getenv('LOCAL_LUA_DEBUGGER_VSCODE') == '1' then
error(r[2], 1)
else
error('')
end
return coroutine.FALSE
end
return unpack(r, 2)
end
function ggesethook(...)
end
if gge.getplatform() == 'Android' then
print = function(...)
local arg = {}
for i = 1, select('#', ...) do
arg[i] = tostring(select(i, ...))
end
--log是变长va_list所以要转换%
gge.log(table.concat(arg, ' '):gsub('%%','%%%%'))
end
warn = function(...)
local arg = {}
for i = 1, select('#', ...) do
arg[i] = tostring(select(i, ...))
end
gge.warn(table.concat(arg, ' '))
end
os.clock = gge.getticks
end
if gge.entry == 'main' then
print('--------------------------------------------------------------------------------------------------------------------')
print(string.format('GGE %s %s %s', gge.version, gge.getluaversion(), gge.getsdlversion()))
print(string.format('平台:%s 调试:%s 控制台:%s', gge.getplatform(), gge.isdebug, gge.isconsole))
print('--------------------------------------------------------------------------------------------------------------------')
-- print("引擎目录:"..gge.getrunpath())
-- print("项目目录:"..gge.getcurpath())
-- print('--------------------------------------------------------------------------------------------------------------------')
-- print('package.path',string.format('"%s"', package.path))
-- print('package.cpath',string.format('"%s"', package.cpath))
-- print('--------------------------------------------------------------------------------------------------------------------')
end
-- @Author : GGELUA
-- @Date : 2021-09-17 08:26:43
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-13 17:59:05
local _CLASS, _METAS = package.loaded, {}
local type = type
local ipairs = ipairs
local getmetatable = getmetatable
local setmetatable = setmetatable
local unpack = table.unpack
local assert = assert
local pcall = pcall
local xpcall = xpcall
--类() 语法糖
local function class_call(cobj, ...)
return cobj.创建(...)
end
--类.创建(),递归所有父初始化
local function class_new(self, cobj, meta, ...)
local super = meta.__super
if super then
for _, v in ipairs(super) do
class_new(self, v, _METAS[v], ...)
end
end
if cobj.初始化 then
return cobj.初始化(self, ...)
end
end
--类:方法()索引
local function class_index(self, k, meta)
if not meta then
meta = getmetatable(self)
end
--self[class]:XXX()指定类方法
if meta.__cobj then
local r = meta.__cobj[k]
meta.__cobj = nil
return r
elseif _METAS[k] then --self[class]
meta.__cobj = _METAS[k]
return self
end
local r = meta[k] --自身方法
if r == nil and meta.__super then --找父方法
for _, cobj in ipairs(meta.__super) do
r = cobj.__index(self, k, _METAS[cobj])
if r ~= nil then
return r
end
end
end
return r
end
--检验是否是类(因为_CLASS是package.loaded,所以可能会出现冲突)
local function assert_class(t)
if type(t) == 'table' then
if getmetatable(t) == 'ggeclass' then
return t
end
end
error('非class')
end
--检验父类是否正确
local function assert_super(t)
if type(t) == 'table' and #t > 0 then
for i, v in ipairs(t) do
if type(v) == 'string' then --用类名索引
assert_class(_CLASS[v])
t[i] = _CLASS[v]
elseif type(v) == 'table' then
assert_class(v)
else
error('错误的父参数')
end
--t[v] = _METAS[v]--用于重载后调用父函数
end
return t
end
end
local function class(name, ...)
assert(type(name) == 'string', '必须要有类名')
assert(_CLASS[name] == nil, name .. ':类名已经存在')
local meta, cobj
meta = {
__name = name,
__index = class_index,
__super = assert_super {...}
}
meta.__metatable = meta --禁止修改
cobj = {
--初始化 = false,[name] = false,
创建 = function(...)
local obj = setmetatable({}, meta)
if cobj[name] then --初始化
return obj, cobj[name](obj, ...)
end
return obj, class_new(obj, cobj, meta, ...)
end
}
--_METAS[name] = meta
_METAS[cobj] = meta --_METAS[class] = meta
_CLASS[name] = cobj --package.loaded
return setmetatable(
cobj,
{
__index = meta,
__call = class_call,
__name = 'ggeclass',
__metatable = 'ggeclass',
__newindex = function(t, k, value)
if k == '__super' then
value = assert_super(value)
elseif k == '__gc' then
if type(value) == 'function' then
meta.__gc = function(t)
value(t)
local super = meta.__super
if super then
for i = #super, 1, -1 do
local v = super[i]
if _METAS[v].__gc then
_METAS[v].__gc(t)
end
end
end
end
return
else
error('not a function')
end
elseif k == '__index' then
if type(value) == 'table' then
meta.__index = function(t, k, m)
local r = class_index(t, k, m)
if r == nil then
return value[k]
end
return r
end
elseif type(value) == 'function' then
meta.__index = function(t, k, m)
local r = class_index(t, k, m) --先判断类属性或方法不存在
if r == nil then
return value(t, k) --外部定义
end
return r
end
else
error('not a function or table')
end
return
-- elseif k == '__newindex' then
-- if type(value) == 'function' then
-- meta.__newindex = function(t, k, v)
-- local r = class_index(t, k) --先判断类属性或方法不存在
-- if r == nil then
-- value(t, k, v) --外部定义
-- else
-- rawset(t, k, v)
-- end
-- end
-- end
-- return
end
meta[k] = value
end
}
)
end
return class
-- @Author: GGELUA
-- @Date: 2021-09-01 21:04:09
-- @Last Modified by : GGELUA
-- @Last Modified time : 2022-01-25 20:08:37
local gge = gge
local _ENV = setmetatable({}, {__index = _G})
MD5 = require('md5')
function isnan(v) --tostring(v)=='nan'
return v ~= v
end
local inf = 1 / 0
function isinf(v)
return v == inf
end
function insert(t) --比table.insert 快
local i = #t + 1
return function(data)
if data ~= nil then
t[i] = data
i = i + 1
end
end
end
function pairsi(t) --泛型倒序
local i = #t + 1
return function()
i = i - 1
if i >= 1 then
return i, t[i]
end
end
end
_G.pairsi = pairsi
function 分割字符(str, tv)
local t = tv or {}
local add = insert(t)
for p, c in utf8.codes(str) do
add(utf8.char(c))
end
return t
end
splitchar = 分割字符
function 分割文本(str, mark, num)
if str then
local r = {}
local add = insert(r)
if mark == '%' then
mark = '([^' .. mark .. '%]+)'
else
mark = '([^' .. mark .. ']+)'
end
for match in tostring(str):gmatch(mark) do
if num and tonumber(match) then
match = tonumber(match)
end
add(match)
end
return r
end
return {}
end
split = 分割文本
function 替换文本(str, as, bs)
repeat
local a, b = str:find(as, 1, true)
if a then
str = str:sub(1, a - 1) .. bs .. str:sub(b + 1)
end
until a == nil
return str
end
gsub = 替换文本
function 复制表(t)
local r = {}
if type(t) == 'table' then
for k, v in pairs(t) do
local tp = type(v)
if tp == 'table' then
r[k] = 复制表(v)
elseif tp == 'string' or tp == 'number' or tp == 'boolean' then
r[k] = v
end
end
end
return r
end
tablecopy = 复制表
function 随机表(t, n)
local r = {}
if type(t) == 'table' then
local tk = {}
for k in pairs(t) do
table.insert(tk, k)
end
n = n or math.random(#tk)
while n > 0 do
n = n - 1
local k = table.remove(tk, math.random(#tk))
r[k] = t[k]
end
end
return r
end
function 是否邮箱(str)
return str:match('[%d%a]+@%a+.%a+') == str
end
function 删首尾空(str)
return str:match('%s*(.-)%s*$')
end
function 去除扩展名(str)
local idx = str:match('.+()%.%w+$')
if (idx) then
return str:sub(1, idx - 1)
else
return str
end
end
function 取文件名(str, ex)
local r = string.match(str:gsub('/', '\\'), '.+\\([^/]*%.%w+)$')
return ex and 去除扩展名(r) or r
end
getfilename = 取文件名
function 取扩展名(str)
return str:match('.+%.(%w+)$')
end
getextname = 取扩展名
function 格式化货币(n) -- credit http://richard.warburton.it
local left, num, right = string.match(n, '^([^%d]*%d)(%d*)(.-)$')
return left .. (num:reverse():gsub('(%d%d%d)', '%1,'):reverse()) .. right
end
function ini(str, len)
local section
local data = {}
local function Parser(line)
local tempSection = line:match('^%[([^%[%]]+)%]$') --节点
if tempSection then
section = tonumber(tempSection) and tonumber(tempSection) or tempSection
data[section] = data[section] or {}
end
local param, value = line:match('^(.-)%s*=%s*(.+)$') --line:match('^([%w|_]+)%s-=%s-(.+)$');
if param then
if tonumber(param) then
param = tonumber(param)
elseif param == 'true' then
param = true
elseif param == 'false' then
param = false
end
if tonumber(value) then
value = tonumber(value)
elseif value == 'true' then
value = true
elseif value == 'false' then
value = false
end
if section then
data[section][param] = value
else
data[param] = value
end
end
end
if len and #str == len then
for line in str:gmatch('([^\r\n]+)') do
if line ~= '' then
Parser(line)
end
end
else
local file = assert(io.open(str, 'r'))
for line in file:lines() do
if line ~= '' then
Parser(line)
end
end
file:close()
end
return data
end
function argb(a, r, g, b)
return a << 24 | r << 16 | g << 8 | b
end
ARGB = argb
function rgb(r, g, b)
return r << 16 | g << 8 | b
end
RGB = rgb
function xrgb(r, g, b)
return ARGB(255, r, g, b)
end
XRGB = xrgb
function HSVtoRGB(h, s, v, a)
if s == 0 then --gray
return v, v, v, a
end
h = math.fmod(h, 1) / (60 / 360)
local i = math.floor(h)
local f = h - i
local p = v * (1 - s)
local q = v * (1 - s * f)
local t = v * (1 - s * (1 - f))
if i == 0 then
return v, t, p
elseif i == 1 then
return q, v, p
elseif i == 2 then
return p, v, t
elseif i == 3 then
return p, q, v
elseif i == 4 then
return t, p, v
else
return v, p, q
end
end
function 四舍五入(v)
return math.floor(v + 0.5)
end
round = 四舍五入
function 遍历目录(path, ...)
if select('#', ...) > 0 then
path = path:format(...)
end
local sep = package.config:sub(1, 1)
local lfs = require('lfs')
local dir, u = lfs.dir(path)
local pt = {}
return function()
repeat
local file = dir(u)
if file then
local f = path .. sep .. file
local attr = lfs.attributes(f)
if attr and attr.mode == 'directory' then
if file ~= '.' and file ~= '..' then
table.insert(pt, f)
end
file = '.'
else
return f
end
elseif pt[1] then
path = table.remove(pt, 1)
dir, u = lfs.dir(path)
file = '.'
end
until file ~= '.'
end
end
dir = 遍历目录
function 创建目录(path, ...)
if not path then
return
end
if select('#', ...) > 0 then
path = path:format(...)
end
local lfs = require('lfs')
path = path:gsub('\\', '/'):match('(.+)/')
path = 分割文本(path, '/')
for i, v in ipairs(path) do
lfs.mkdir(table.concat(path, '/', 1, i))
end
end
mkdir = 创建目录
function 复制文件(old, new)
local rf = io.open(old, 'rb')
if rf then
local wf = io.open(new, 'wb')
if wf then
wf:write(rf:read('a'))
rf:close()
wf:close()
return true
end
rf:close()
end
return false
end
copyfile = 复制文件
function 读入文件(path, def)
if not path then
return def
end
local file = io.open(path, 'rb')
if file then
local data = file:read('a')
file:close()
return data
end
return def
end
readfile = 读入文件
function 写出文件(path, data)
创建目录(path)
local file = io.open(path, 'wb')
if file then
file:write(data)
file:close()
return true
end
return false
end
writefile = 写出文件
function 判断文件(path)
if not path then
return
end
local file = io.open(path, 'rb')
if file then
file:close()
return true
end
end
checkfile = 判断文件
function 取表数量(t)
local n = 0
if type(t) == 'table' then
for k, v in pairs(t) do
n = n + 1
end
end
return n
end
function printuv(fn)
local i = 1
while true do
local k, v = debug.getupvalue(fn, i)
if k then
_G.print(i, k, v)
else
break
end
i = i + 1
end
end
function setfenv(fn, env)
local i = 1
while true do
local name = debug.getupvalue(fn, i)
if name == '_ENV' then
debug.upvaluejoin(
fn,
i,
(function()
return env
end),
1
)
break
elseif not name then
break
end
i = i + 1
end
return fn
end
function getfenv(fn)
local i = 1
while true do
local name, val = debug.getupvalue(fn, i)
if name == '_ENV' then
return val
elseif not name then
break
end
i = i + 1
end
end
function print(root)
if root then
local cache = {[root] = 'self'} --防止死循环
local function _dump(t, name, layer)
local temp, out = {}, {}
if next(t) then
table.insert(out, '{')
for k, v in pairs(t) do
if cache[v] then
table.insert(out, string.format(' %s={%s}', k, cache[v]))
elseif type(v) == 'table' then
local new_key
if type(k) == 'string' then
new_key = string.format('%s.%s', name, k)
else
new_key = string.format('%s[%s]', name, k)
end
cache[v] = new_key
table.insert(out, string.format(' %s=%s', k, _dump(v, new_key, layer + 1)))
else
if type(v) == 'string' then
table.insert(out, string.format(' %s=%s,', k, v))
else
table.insert(out, string.format(' %s=%s,', k, v))
end
end
end
table.insert(out, '};')
else
table.insert(out, '{}')
end
return table.concat(out, '\n' .. string.rep(' ', layer))
end
--_G.print(root)
_G.print(_dump(root, 'self', 0))
else
_G.print(nil)
end
end
local print = _G.print
return _ENV
-- @Author: GGELUA
-- @Date: 2021-09-17 08:26:43
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-07 02:50:39
require 'SDL.精灵'
local GGE动画 = class('GGE动画')
function GGE动画:GGE动画(t, maxf, width, height, fps)
if type(t) == 'table' then --载入器
assert(type(t.取精灵) == 'function', '没有取精灵函数')
assert(type(t.帧数) == 'number', '没有指定帧数')
self.资源 = t
self.FPS = t.帧率 or (1.0 / 8)
self.帧数 = t.帧数
self.宽度 = t.宽度
self.高度 = t.高度
elseif ggetype(t) == 'SDL纹理' then
assert(type(maxf) == 'number', '没有指定帧数')
assert(type(width) == 'number', '没有指定宽度')
assert(type(height) == 'number', '没有指定高度')
self.FPS = fps or (1.0 / 8)
self.帧数 = maxf
self.宽度 = width
self.高度 = height
local x, y = 0, 0
for i = 1, maxf do
self:添加帧(require 'SDL.精灵'(t, x, y, width, height))
x = x + width
if x + width > t:取宽度() then
x = 0
y = y + height
end
end
end
self.当前帧 = 0
self._mode = 0 --1循环2往返
self._delta = 1 --递增值
self._list = {}
self._load = {} --协程加载中
self._dt = 0
-- self._hx = 0
-- self._hy = 0
end
function GGE动画:复制()
local r = GGE动画()
for k, v in pairs(self) do
if type(v) ~= 'table' then
r[k] = v
end
end
r.资源 = self.资源
for i, v in ipairs(self._list) do
r._list[i] = v:复制()
end
return r
end
function GGE动画:更新(dt)
if not self.是否播放 then
return
end
self._dt = self._dt + dt
if self._dt >= self.FPS then
self._dt = self._dt - self.FPS
local i = self.当前帧 + self._delta
if i > self.帧数 then
if self._mode & 1 == 1 then --循环
if self._mode & 2 == 2 then --往返
self._delta = -self._delta
else
self.当前帧 = 0
end
else
self:暂停()
end
elseif i < 1 then
if self._mode & 1 == 1 then --循环
self._delta = 1
else
self:暂停()
end
end
if self.是否播放 then
self:置当前帧(self.当前帧 + self._delta)
else
return true
end
end
end
function GGE动画:显示(x, y)
if not y and ggetype(x) == 'GGE坐标' then
x, y = x:unpack()
end
if self._hx then
x, y = x - self._hx, y - self._hy
end
if self._spr then
local r = self._rect
if r then
引擎:置区域(x - r.x, y - r.y, r.w, r.h)
end
self._spr:显示(x, y)
if r then
引擎:置区域()
end
end
end
function GGE动画:播放(循环)
self.是否播放 = true
self.是否暂停 = false
if 循环 ~= nil then
self:置循环(循环)
end
local i = self.当前帧 + self._delta
if i > self.帧数 then
if self._mode & 2 == 2 then --往返
self._delta = -1
else
self._delta = 1
self:置当前帧(1)
end
elseif i < 1 then
self._delta = 1
end
return self
end
local function _停止事件(self)
if self.停止事件 then
if type(self.停止事件) == 'function' then
self.停止事件(self)
elseif type(self.停止事件) == 'thread' then
if coroutine.status(self.停止事件) == 'suspended' then
coroutine.xpcall(self.停止事件)
end
end
end
end
function GGE动画:停止()
if not self.是否播放 then
return
end
self:置首帧()
self.是否播放 = false
_停止事件(self)
return self
end
function GGE动画:暂停()
if not self.是否播放 then
return
end
self.是否播放 = false
self.是否暂停 = true
_停止事件(self)
return self
end
function GGE动画:恢复()
self.是否播放 = true
self.是否暂停 = false
return self
end
function GGE动画:置往返(往返)
self._mode = 往返 and (self._mode | 2) or (self._mode & ~2)
return self
end
function GGE动画:置循环(循环)
self._mode = 循环 and (self._mode | 1) or (self._mode & ~1)
return self
end
function GGE动画:置帧率(v)
assert(type(v) == 'number', '数据错误')
self.FPS = v
return self
end
function GGE动画:取帧率()
return self.FPS
end
function GGE动画:取宽高()
return self.宽度, self.高度
end
function GGE动画:置首帧()
self._dt = 0
self._delta = 1
self:置当前帧(1)
return self
end
function GGE动画:置尾帧()
self._dt = 0
self._delta = 1
self:置当前帧(self.帧数)
return self
end
--协程载入
local function _协程取精灵(self, i)
self._load[i] = true
local r = self.资源:取精灵(i)
if self._load[i] and ggetype(r) == 'SDL精灵' then
self._list[i] = r
-- if self.资源.释放 and #self._list==self.帧数 then
-- self.资源 = nil
-- end
self._load[i] = nil
end
end
function GGE动画:置当前帧(i)
if self.当前帧 ~= i and i > 0 and i <= self.帧数 then
if not self._list[i] and self.资源 then
if self.资源.协程 then
if not self._load[i] then
coroutine.xpcall(_协程取精灵, self, i)
end
else
local r = self.资源:取精灵(i)
if ggetype(r) == 'SDL精灵' then
self._list[i] = r
end
end
-- if self.资源.释放 and #self._list==self.帧数 then
-- self.资源 = nil
-- end
end
if self._list[i] then
self.当前帧 = i
self._spr = self._list[i]
if self._r or self._g or self._b then
self._spr:置颜色(self._r, self._g, self._b)
end
if self._a then
self._spr:置透明(self._a)
end
if self._hl then
self._spr:置高亮(self._hl)
end
if type(self.帧事件) == 'function' then
self.帧事件(self, i, self.帧数)
end
end
end
return self
end
function GGE动画:添加帧(v)
if ggetype(v) == 'SDL精灵' then
table.insert(self._list, v)
elseif ggetype(v) == 'SDL纹理' then
table.insert(self._list, require 'SDL.精灵'(v))
else
error('不支持')
end
self.帧数 = #self._list
return self
end
function GGE动画:删除帧(i)
table.remove(self._list, i)
return self
end
function GGE动画:取精灵(i)
return i and self._list[i] or self._spr
end
function GGE动画:清空()
self._dt = 0
self.当前帧 = 0
self._list = {}
self._load = {}
self._spr = nil
return self
end
function GGE动画:置颜色(r, g, b, a)
for k, v in pairs(self._list) do
v:置颜色(r, g, b, a)
end
self._a = a
self._r = r
self._g = g
self._b = b
return self
end
function GGE动画:置透明(a)
for k, v in pairs(self._list) do
v:置透明(a)
end
self._a = a
return self
end
function GGE动画:置高亮(r, g, b, a)
for k, v in pairs(self._list) do
v:置高亮(r, g, b, a)
end
self._hl = r
return self
end
function GGE动画:取高亮()
return self._spr and self._spr:取高亮()
end
function GGE动画:检查点(x, y)
return self._spr and self._spr:检查点(x, y)
end
function GGE动画:取透明(x, y)
return self._spr and self._spr:取透明(x, y)
end
function GGE动画:检查透明(x, y)
return self._spr and self._spr:取透明(x, y) > 0
end
function GGE动画:置中心(x, y)
self._hx = x or self._hx or 0
self._hy = y or self._hy or 0
return self
end
function GGE动画:取中心()
return self._hx, self._hy
end
function GGE动画:取矩形()
if self._spr then
return self._spr:取矩形()
end
return require('SDL.矩形')()
end
function GGE动画:置区域(x, y, w, h)
self._rect = require('GGE.矩形')(x, y, w, h)
return self
end
return GGE动画
-- @Author : GGELUA
-- @Date : 2021-09-17 08:26:43
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-07 03:04:35
local GGE坐标 = class 'GGE坐标'
GGE坐标.x = 0
GGE坐标.y = 0
function GGE坐标:GGE坐标(x, y)
if type(x) == 'table' then
self.x = x.x or x[1] or 0
self.y = x.y or x[2] or 0
else
self.x = tonumber(x)
self.y = tonumber(y)
end
end
function GGE坐标:ceil()
self.x = math.ceil(self.x)
self.y = math.ceil(self.y)
return self
end
function GGE坐标:floor()
self.x = math.floor(self.x)
self.y = math.floor(self.y)
return self
end
function GGE坐标:unpack()
return self.x, self.y
end
function GGE坐标:pack(x, y)
if type(x) == 'number' and type(y) == 'number' then
self.x = x
self.y = y
elseif ggetype(x) == 'GGE坐标' then
self.x = x.x
self.y = x.y
end
return self:floor()
end
function GGE坐标:四舍五入()
self.x = self.x < 0 and self.x - 0.5 or self.x + 0.5
self.y = self.y < 0 and self.y - 0.5 or self.y + 0.5
return self:floor()
end
function GGE坐标:复制(x, y)
local r = GGE坐标(self.x, self.y)
return x and r:增加(x, y) or r
end
function GGE坐标:随机加(x, x1, y, y1)
local x = math.random(x, x1)
local y = math.random(y or x, y1 or x1)
self:增加(x, y)
return self
end
function GGE坐标:增加(x, y)
self.x = self.x + (x or 0)
self.y = self.y + (y or 0)
return self
end
function GGE坐标:随机(x, x1, y, y1)
self.x = math.random(x, x1)
self.y = math.random(y or x, y1 or x1)
return self
end
--取两点距离
function GGE坐标:取距离(x, y)
if not y and ggetype(x) == 'GGE坐标' then
x, y = x:unpack()
end
x = self.x - x
y = self.y - y
return math.sqrt((x ^ 2) + (y ^ 2)) --平方根
end
--取两点弧度
local math_pi2 = math.pi * 2
function GGE坐标:取弧度(_x, _y)
if not _y and ggetype(_x) == 'GGE坐标' then
_x, _y = _x:unpack()
end
local x, y = self.x, self.y
if _y == y and _x == x then
return 0
elseif _y >= y and _x <= x then
return math.pi - math.abs(math.atan((_y - y) / (_x - x)))
elseif _y <= y and _x >= x then
return math_pi2 - math.abs(math.atan((_y - y) / (_x - x)))
elseif _y <= y and _x <= x then
return math.atan((_y - y) / (_x - x)) + math.pi
elseif _y >= y and _x >= x then
return math.atan((_y - y) / (_x - x))
end
end
function GGE坐标:取角度(x, y) --math.rad
return math.deg(self:取弧度(x, y))
end
function GGE坐标:取地图位置(w, h) --图块宽高
return GGE坐标(math.ceil(self.x / w), math.ceil(self.y / h))
end
function GGE坐标:取距离坐标(r, a) --距离,弧度
-- if ggetype(a)=='GGE坐标' then
-- a = self:取弧度(a)
-- end
local x, y = 0, 0
x = r * math.cos(a) + self.x
y = r * math.sin(a) + self.y
return GGE坐标(x, y):四舍五入()
end
function GGE坐标:取移动坐标(r, x, y) --距离,目标点
local a = self:取弧度(x, y)
return self:取距离坐标(r, a)
end
function GGE坐标:移动(r, x, y) --距离,目标点
local a = self:取弧度(x, y)
self.x = r * math.cos(a) + self.x
self.y = r * math.sin(a) + self.y
return self:四舍五入()
end
--宽度2 = 宽度//2
function GGE坐标:取地图偏移(w, h) --地图宽高
local _x, _y = 0, 0
local x, y = self.x, self.y
if w > 引擎.宽度 then --地图小于窗口
if x > 引擎.宽度2 and x < w - 引擎.宽度2 then
_x = -(x - 引擎.宽度2)
elseif x <= 引擎.宽度2 then
_x = 0
elseif x >= w - 引擎.宽度2 then
_x = -(w - 引擎.宽度)
end
end
if h > 引擎.高度 then
if y > 引擎.高度2 and y < h - 引擎.高度2 then
_y = -(y - 引擎.高度2)
elseif y <= 引擎.高度2 then
_y = 0
elseif y >= h - 引擎.高度2 then
_y = -(h - 引擎.高度)
end
end
return GGE坐标(_x, _y)
end
function GGE坐标:画线(x, y, r, g, b, a)
if ggetype(x) == 'GGE坐标' then
color = y
x, y = x:unpack()
end
引擎:置颜色(r, g, b, a)
引擎:画线(self.x, self.y, x, y)
return self
end
function GGE坐标:显示(r, g, b, a)
local angle = 360 / 20
引擎:置颜色(255, 0, 0, 255)
for i = 0, 20 - 1 do
local pxy = self:取距离坐标(3, math.rad(i * angle))
--rad角度转弧度
local pxy1 = self:取距离坐标(3, math.rad((i + 1) * angle))
引擎:画线(pxy.x, pxy.y, pxy1.x, pxy1.y)
end
return self
end
--==============================================================================
--元方法(重载)
--==============================================================================
--等于 ==
function GGE坐标.__eq(a, b)
return a.x == b.x and a.y == b.y
end
--小于 <
function GGE坐标.__lt(a, b)
return a.x < b.x and a.y < b.y
end
--小于等于 <=
function GGE坐标.__le(a, b)
return a.x <= b.x and a.y <= b.y
end
--相加 +
function GGE坐标.__add(a, b)
if ggetype(a) == 'GGE坐标' and ggetype(b) == 'GGE坐标' then
return GGE坐标(a.x + b.x, a.y + b.y)
elseif type(a) == 'number' then
return GGE坐标(a + b.x, a + b.y)
elseif type(b) == 'number' then
return GGE坐标(a.x + b, a.y + b)
end
end
--相减 -
function GGE坐标.__sub(a, b)
if ggetype(a) == 'GGE坐标' and ggetype(b) == 'GGE坐标' then
return GGE坐标(a.x - b.x, a.y - b.y)
elseif type(a) == 'number' then
return GGE坐标(a - b.x, a - b.y)
elseif type(b) == 'number' then
return GGE坐标(a.x - b, a.y - b)
end
end
--相乘 *
function GGE坐标.__mul(a, b)
if ggetype(a) == 'GGE坐标' and ggetype(b) == 'GGE坐标' then
return GGE坐标(a.x * b.x, a.y * b.y)
elseif type(a) == 'number' then
return GGE坐标(a * b.x, a * b.y)
elseif type(b) == 'number' then
return GGE坐标(a.x * b, a.y * b)
end
end
--相除 /
function GGE坐标.__div(a, b)
if ggetype(a) == 'GGE坐标' and ggetype(b) == 'GGE坐标' then
return GGE坐标(a.x / b.x, a.y / b.y)
elseif type(a) == 'number' then
return GGE坐标(a / b.x, a / b.y)
elseif type(b) == 'number' then
return GGE坐标(a.x / b, a.y / b)
end
end
--整除 //
function GGE坐标.__idiv(a, b)
if ggetype(a) == 'GGE坐标' and ggetype(b) == 'GGE坐标' then
return GGE坐标(a.x // b.x, a.y // b.y)
elseif type(a) == 'number' then
return GGE坐标(a // b.x, a // b.y)
elseif type(b) == 'number' then
return GGE坐标(a.x // b, a.y // b)
end
end
function GGE坐标.__tostring(self)
return string.format('GGE.坐标(%s,%s)', self.x, self.y)
end
--__mod %
--__pow ^
--__unm -
--__band &
--__bor |
--__bxor ~
--__bnot ~
--__shl <<
--__shr >>
--__concat ..
--__len #
--__index table[key]
--__newindex table[key] = value
--__call func(args)
--__gc
--__close
--__mode
--__name
return GGE坐标
-- @Author: GGELUA
-- @Date: 2021-09-17 08:26:43
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-18 15:46:35
local SDL = require 'SDL'
local _objmeta = {
检查点 = function(self, x, y)
if self.rect then
return self.rect:检查点(x, y)
end
end,
置透明 = function(self, a)
self.o:置透明(a)
end,
取坐标 = function(self)
return self.o:取坐标()
end,
更新 = function(self, dt)
if self.o.更新 then
self.o:更新(dt)
end
end,
显示 = function(self, x, y)
if self.b then --闪烁
self.b = self.b + 1
if self.b > 60 then
self.b = 0
end
end
if not self.b or self.b > 30 then
self.o:显示(self.x + x, y)
if self.rect then
self.rect:置坐标(self.o:取坐标())
--self.rect:显示()
end
end
end
}
local _obj = function(t, x, o)
local self = setmetatable({}, {__index = _objmeta})
self.x = x
self.o = o --obj
if t.m or t.url then
self.cb = t.m or t.url
self.rect = require('SDL.矩形')(0, 0, o.宽度, o.高度)
end
if t.b then --闪烁
self.b = 0
end
return self
end
--==============================================================================
local _colors = { --RGBWYK
[0x52] = 0xFF0000,
[0x47] = 0x00FF00,
[0x42] = 0x0000FF,
[0x57] = 0xFFFFFF,
[0x59] = 0xFFFF00,
[0x4B] = 0x000000
}
local function _insert(t) --比table.insert 快
local i = #t + 1
return function(data)
if data ~= nil then
t[i] = data
i = i + 1
end
end
end
local function _Parser(str) --解析结构
local style_c, style_b, style_u, style_F, style_m --颜色,下划线,闪烁,字体,回调
local datas = {}
local indata = _insert(datas)
local codes = {}
local incode = _insert(codes)
local u8char = utf8.char
local unpack = table.unpack
local iter = utf8.codes(str)
local p, code
while true do
p, code = iter(str, p)
if not p then
break
end
if code == 0x23 then --#?
p, code = iter(str, p)
if not p then
break
end
if #codes >= 1 and code ~= 0x23 and code ~= 0x72 and not style_m then --结束
indata {c = style_c, b = style_b, u = style_u, F = style_F, s = u8char(unpack(codes))}
codes = {}
incode = _insert(codes)
end
--样式解析
if code == 0x23 then --##
incode(code)
elseif code == 0x62 then --#bXXXX#b 闪烁
style_b = not style_b
elseif code == 0x63 then --#cFFFFFF 指定16进制颜色
style_c = tonumber(str:sub(p + 1, p + 6), 16)
if style_c then
p = p + 6
end
elseif _colors[code] then --RGBWYK颜色
style_c = _colors[code]
elseif code == 0x6D then --#m(XXXX)XXXX#m 回调
if style_m then
local m, s = string.match(u8char(unpack(codes)), '%((.+)%)(.*)')
indata {c = style_c, b = style_b, u = style_u, F = style_F, m = m, s = s}
codes = {}
incode = _insert(codes)
end
style_m = not style_m
elseif code == 0x6E then --#n 结束
style_c = nil
elseif code == 0x75 then --#uXXXX#u 下划线
style_u = not style_u
elseif code == 0x72 then --#r 换行
indata {c = style_c, b = style_b, u = style_u, F = style_F, r = true, s = u8char(unpack(codes))}
codes = {}
incode = _insert(codes)
elseif code == 0x46 then --#FXXX14: 字体开始
style_F = true
elseif code >= 0x30 and code <= 0x39 then --#0 - #999 表情
local num = {code}
local p_ = p
for i = 2, 3 do
p_, code = iter(str, p_)
if not code then
break
elseif code >= 0x30 and code <= 0x39 then
p = p_
num[i] = code
end
end
indata {s = tonumber(u8char(unpack(num)))}
end
elseif style_F == true and code == 0x3A then --: 字体结束
local name, size = string.match(u8char(unpack(codes)), '([^%d]+)(%d*)')
style_F = {name, tonumber(size)}
codes = {}
incode = _insert(codes)
else --内容
incode(code)
end
end
if #codes > 0 then --结束
indata {c = style_c, b = style_b, u = style_u, F = style_F, s = u8char(unpack(codes))}
end
return datas
end
--==============================================================================
--按宽度分折
local function _split(str, width, font)
for i, c in utf8.codes(str) do
local w = font:取宽度(utf8.char(c))
if w > width then
return str:sub(1, i - 1), str:sub(i)
else
width = width - w
end
end
return '', str
end
--适应宽度,生成x坐标
local function _Adjust(self)
local width = self.宽度
local fonts = self._文字表
local emote = self._精灵表
local font = fonts.默认
local fh = font:取高度()
local ret = {}
local x = 0
line = {w = 0, h = fh}
for _, v in ipairs(self._解析后) do
if type(v.s) == 'string' then --文本
--字体
if type(v.F) == 'table' then
local file, size = v.F[1], v.F[2]
if fonts[file] then
font = fonts[file]
end
font:置大小(size)
fh = size
if not line.eh or fh > line.eh then --当没有表情时
line.h = fh
end
end
--超链接
local str = v.s
if str:find('<url>') then
str = str:match('<url>(.+)</url>')
v.s = str
v.url = str
if str:find('<show>') then
local a, b = str:match('<show>(.+)</show>(.*)')
if a and b then
str = a
v.s = str
v.url = b
end
end
end
--颜色
if v.c then
font:置颜色(v.c >> 16 & 0xFF, v.c >> 8 & 0xFF, v.c & 0xFF, 255)
else
font:置颜色(255, 255, 255, 255)
end
--下划线
if v.u or v.url then
font:置样式(SDL.TTF_STYLE_UNDERLINE)
else
font:置样式(font:取样式() & ~SDL.TTF_STYLE_UNDERLINE)
end
local w, h = font:取宽高(str)
if x == 0 and w > 0 and font:取宽度(utf8.char(utf8.codepoint(str, 1))) > width then
print('宽度过小')
elseif x + w > width then --大于就换行
::loop::
local a, b = _split(str, width - x, font)
if a ~= '' then
w, h = font:取宽高(a)
table.insert(line, _obj(v, x, font:取精灵(a):置中心(0, h)))
x = x + w
end
line.w = x
table.insert(ret, line)
x = 0
line = {w = 0, h = fh}
--换行
w, h = font:取宽高(b)
if w > width then --循环换行
str = b
goto loop
else
table.insert(line, _obj(v, x, font:取精灵(b):置中心(0, h)))
x = x + w
if v.r or x == width then
line.w = x
table.insert(ret, line)
x = 0
line = {w = 0, h = fh}
end
end
else
if w > 0 then
table.insert(line, _obj(v, x, font:取精灵(str):置中心(0, h)))
x = x + w
end
if v.r or x == width then
line.w = x
table.insert(ret, line)
x = 0
line = {w = 0, h = fh}
end
end
elseif emote[v.s] then --表情
local e = emote[v.s]
if e then
local w, h = e:取宽高()
if x + w > width then --大于就换行
line.w = x
table.insert(ret, line) --换行
x = 0
line = {w = 0, h = fh}
end
if x + w <= width then
table.insert(line, _obj(v, x, e:复制()))
x = x + w
end
if h > line.h then
line.h = h
line.eh = h
end
if v.r or x == width then
line.w = x
table.insert(ret, line)
x = 0
line = {w = 0, h = fh}
end
else --表情不存在,以文本显示
end
end
end
line.w = x
table.insert(ret, line)
for i, v in ipairs(ret) do
v.eh = nil
end
return ret
end
--==================================================================
local GGE文本 = class('GGE文本')
function GGE文本:GGE文本(w, h)
self.行间距 = 2
self.宽度 = w or 400
self.高度 = h or 200
self._文字表 = {}
self._精灵表 = {}
self._数据表 = {} --适应宽度后的数据
end
function GGE文本:置文字(f, ...)
if ggetype(f) == 'SDL文字' then
self._文字表.默认 = f
else
self._文字表.默认 = require('SDL.文字')(f, ...)
end
return self
end
function GGE文本:取文字(f)
return self._文字表[f or '默认']
end
function GGE文本:添加文字(name, font) --宋体,SDL文字
self._文字表[name] = font
if not self._文字表.默认 then
self._文字表.默认 = font
end
return self
end
function GGE文本:添加精灵(k, v)
if type(v) == 'table' and v.取宽高 and v.显示 and v.复制 then
self._精灵表[k] = v
end
return self
end
function GGE文本:取行数()
return #self._数据表
end
function GGE文本:清空()
self._数据表 = {}
return self
end
function GGE文本:置文本(s, ...)
if not self._文字表.默认 then
return 0, 0
end
if select('#', ...) > 0 then
s = s:format(...)
end
self:清空()
s = s:gsub('\r\n', '#r'):gsub('\r', '#r'):gsub('\n', '#r')
self._解析后 = _Parser(s)
for _, v in ipairs(_Adjust(self)) do
table.insert(self._数据表, v)
end
local w, h, y = 0, 0, 0
for _, v in ipairs(self._数据表) do
if v.w > w then
w = v.w
end
h = h + v.h + self.行间距
y = y + v.h
v.y = y
y = y + self.行间距
end
return w, h - self.行间距 --返回当前区域内容最大宽高
end
function GGE文本:置透明(a)
for _, line in ipairs(self._数据表) do
for _, v in ipairs(line) do
v:置透明(a)
end
end
return self
end
function GGE文本:置宽度(v)
if self.宽度 ~= v then
self.宽度 = v
self:清空()
for _, v in ipairs(_Adjust(self)) do
table.insert(self._数据表, v)
end
end
local w, h, y = 0, 0, 0
for _, v in ipairs(self._数据表) do
if v.w > w then
w = v.w
end
h = h + v.h + self.行间距
y = y + v.h
v.y = y
y = y + self.行间距
end
return w, h - self.行间距 --返回当前区域内容最大宽高
end
function GGE文本:更新(dt)
for _, line in ipairs(self._数据表) do
for _, v in ipairs(line) do
v:更新(dt)
end
end
end
function GGE文本:显示(x, y)
if not y and ggetype(x) == 'GGE坐标' then
x, y = x:unpack()
end
if self.hx then--中心
x,y = x-self.hx,y-self.hy
end
for _, line in ipairs(self._数据表) do
for _, v in ipairs(line) do
v:显示(x, y + line.y)
end
end
end
function GGE文本:置中心(x,y)
self.hx = x
self.hy = y
return self
end
function GGE文本:检查回调(x, y)
for _, line in ipairs(self._数据表) do
for _, v in ipairs(line) do
if v:检查点(x, y) then
return v.cb, v
end
end
end
end
return GGE文本
-- @Author : GGELUA
-- @Date : 2021-10-30 13:05:32
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-07 02:58:28
local cprint = require('cprint')
local _isdebug = require('ggelua').isdebug
local lcolor = {
INFO = '\x1b[47;30mINFO\x1b[0m',
WARN = '\x1b[43;30mWARN\x1b[0m',
ERROR = '\x1b[41;30mERROR\x1b[0m'
}
local GGE日志 = class('GGE日志')
function GGE日志:GGE日志(file, logger)
self.logger = logger or 'GGELUA'
self.SQL = require('LIB.SQLITE3')(file or 'log.db3')
local r = self.SQL:取值("select count(*) from sqlite_master where name='log';")
if r == 0 then
self.SQL:执行 [[
CREATE TABLE "log" (
"date" integer NOT NULL,
"logger" TEXT,
"level" integer NOT NULL,
"message" TEXT NOT NULL,
"exception" TEXT
);
]]
end
end
function GGE日志:LOG(level, msg, ...)
if select('#', ...) > 0 then
msg = msg:format(...)
end
local time = os.time()
cprint(string.format('[%s] [%s] [%s] %s', os.date('%X', time), self.logger, lcolor[level] or level, tostring(msg)))
local r =
self.SQL:执行(
"insert into log(date,logger,level,message) values('%d','%s','%s','%s')",
time,
self.logger,
level,
msg
)
end
function GGE日志:INFO(msg, ...)
self:LOG('INFO', msg, ...)
end
function GGE日志:WARN(msg, ...)
self:LOG('WARN', msg, ...)
end
function GGE日志:ERROR(msg, ...)
self:LOG('ERROR', msg, ...)
end
function GGE日志:DEBUG(msg, ...)
if _isdebug then
self:LOG('DEBUG', msg, ...)
end
end
return GGE日志
-- @Author: baidwwy
-- @Date: 2021-02-11 11:49:09
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-07 02:58:09
local GGE矩形 = class 'GGE矩形'
function GGE矩形:GGE矩形(x, y, w, h)
self.x = x or 0
self.y = y or 0
self.w = w or 0
self.h = h or 0
end
function GGE矩形:__eq(t)
local a, b = self, t
return (a.x == b.x) and (a.y == b.y) and (a.w == b.w) and (a.h == b.h)
end
function GGE矩形:复制()
return GGE矩形(self.x, self.y, self.w, self.h)
end
function GGE矩形:显示(x, y)
if self.r then
引擎:置颜色(self.r, self.g, self.b)
end
if not y and ggetype(x) == 'GGE坐标' then
x, y = x:unpack()
end
if x and y then
end
end
function GGE矩形:置颜色(r, g, b)
self.r, self.g, self.b = r, g, b
return self
end
function GGE矩形:置中心(x, y)
self._hx = x
self._hy = y
return self
end
function GGE矩形:取中心()
return self._hx, self._hy
end
function GGE矩形:置宽高(w, h)
self.w = w or 0
self.h = h or 0
return self
end
function GGE矩形:取宽高()
return self.w, self.h
end
function GGE矩形:置坐标(x, y)
self.x = x or 0
self.y = y or 0
return self
end
function GGE矩形:取坐标()
return self.x, self.y
end
function GGE矩形:清空()
self.x = 0
self.y = 0
self.w = 0
self.h = 0
end
function GGE矩形:检查点(x, y)
if not y and ggetype(x) == 'GGE坐标' then
x, y = x:unpack()
end
local _x, _y = self.x, self.y
local _w, _h = self.w, self.h
if self._hx then
_x = _x - self._hx
end
if self._hy then
_y = _y - self._hy
end
return (x >= _x) and (x < _x + _w) and (y >= _y) and (y < _y + _h)
end
function GGE矩形:检查交集(t)
end
function GGE矩形:取交集(t)
local r = GGE矩形()
return r
end
function GGE矩形:取并集(t)
local r = GGE矩形()
return r
end
return GGE矩形
-- @Author : GGELUA
-- @Date : 2021-09-01 21:04:09
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-07 03:02:28
local _ENV = require('SDL')
local c_isyieldable = coroutine.isyieldable --lua5.3
local c_runing = coroutine.running
local c_yield = coroutine.yield
local GGE线程 = class 'GGE线程'
function GGE线程:GGE线程(code, name, ms)
self._list = {}
self._th = CreateThread(code, name or tostring(self), ms or 10, self._list)
end
function GGE线程:取名称()
return self._th:GetThreadName()
end
function GGE线程:ID()
return self._th:GetThreadID()
end
function GGE线程:__index(k, super) --调用方法
if GGE线程[k] then
return
end
local co = c_runing()
if co and c_isyieldable() then --如果有协程,则有返回值
return function(self, ...)
self._list[co] = {k, ...}
return c_yield()
end
end
return function(self, ...)
table.insert(self._list, {k, ...})
end
end
return GGE线程
-- @Author : GGELUA
-- @Date : 2021-09-01 21:04:09
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-07 03:04:28
--==================================================================================
--将多个对象添加到一起显示
--==================================================================================
local GGE组合 = class('GGE组合')
function GGE组合:GGE组合(...)
self._list = {...}
for i, v in ipairs(self._list) do
assert(type(v) == 'table', '不是表')
assert(type(v.显示) == 'function', '没有显示方法')
end
end
function GGE组合:更新(dt)
for i, v in ipairs(self._list) do
if type(v.更新) == 'function' then
v:更新(dt)
end
end
end
function GGE组合:显示(x, y)
for i, v in ipairs(self._list) do
v:显示(x, y)
end
end
function GGE组合:添加(t)
if type(t) == 'table' then
if ggetype(t) == 'SDL纹理' then
table.insert(self._list, require('SDL.精灵')(t))
elseif ggetype(t) == 'SDL精灵' then
table.insert(self._list, t)
end
end
end
function GGE组合:清空()
self._list = {}
end
function GGE组合:取纹理()
end
return GGE组合
-- @Author : GGELUA
-- @Date : 2021-10-30 13:05:32
-- @Last Modified by: baidwwy
-- @Last Modified time: 2022-01-05 05:07:45
local GGE资源包 = class('GGE资源包')
function GGE资源包:初始化(file, psd)
self.file = file
local db = require('lib.sqlite3')(file, psd)
if db then
local r = db:取值("select count(*) from sqlite_master where name='file';")
if r == 0 then
db:执行 [[
CREATE TABLE "main"."file" (
"path" TEXT,
"md5" TEXT,
PRIMARY KEY ("path")
);
CREATE UNIQUE INDEX "main"."spath"
ON "file" ("path" ASC);
CREATE TABLE "main"."data" (
"type" INTEGER DEFAULT 0,
"md5" TEXT,
"time" INTEGER,
"size" INTEGER,
"dsize" INTEGER,
"data" BLOB,
PRIMARY KEY ("md5")
);
CREATE UNIQUE INDEX "main"."smd5"
ON "data" ("md5" ASC);
]]
end
self._db = db
else
error('资源包打开失败。')
end
end
function GGE资源包:是否存在(path)
return self._db:取行数("select count(*) from file where path = '%s'; ", path) ~= 0
end
function GGE资源包:取数据(path)
local t = self._db:查询一行("SELECT data FROM data WHERE md5 = (SELECT md5 FROM file WHERE path = '%s');", path)
return t and t.data
end
function GGE资源包:写数据(path, data)
end
--======================================================================================================
local _ENV = require('SDL')
local GGE资源 = class 'GGE资源'
function GGE资源:初始化()
self._res = {''}
end
function GGE资源:添加资源包(file, psd, idx)
if type(file) == 'string' then
local s, pack = pcall(GGE资源包, file, psd)
if not s then
error(file)
end
table.insert(self._res, idx or #self._res+1, pack)
end
return self
end
function GGE资源:删除资源包(file)
for i, v in ipairs(self._res) do
if v.file == file then
table.remove(self._res, i)
return true
end
end
end
function GGE资源:添加路径(path, idx)
if type(path) == 'string' then
table.insert(self._res, idx or #self._res+1, path)
end
return self
end
function GGE资源:删除路径(path)
for i, v in ipairs(self._res) do
if v == path then
table.remove(self._res, i)
return true
end
end
end
function GGE资源:是否存在(path, ...)
if select('#', ...) > 0 then
path = path:format(...)
end
for i, v in ipairs(self._res) do
if type(v) == 'string' then
local path = v ~= '' and v .. '/' .. path or path
local file = SDL.RWFromFile(path, 'rb')
if file then
file:RWclose()
return path
end
elseif v:是否存在(path) then
return v, v.file
end
end
-- --绝对路径 用io.open?
-- local file = SDL.RWFromFile(path, 'rb')
-- if file then
-- file:RWclose()
-- return path
-- end
return false
end
function GGE资源:取数据(path, ...)
if select('#', ...) > 0 then
path = path:format(...)
end
local r = self:是否存在(path)
if r then
if type(r) == 'string' then
return SDL.LoadFile(r)
end
return r:取数据(path) --pack
end
return nil
end
function GGE资源:取纹理(...)
local data = self:取数据(...)
if data then
local rw = require('SDL.读写')(data, #data)
return require('SDL.纹理')(rw)
end
end
function GGE资源:取精灵(...)
local tex = self:取纹理(...)
if tex then
return require('SDL.精灵')(tex)
end
end
function GGE资源:取图像(...)
local data = self:取数据(...)
if data then
local rw = require('SDL.读写')(data, #data)
return require('SDL.图像')(rw)
end
end
-- function GGE资源:取动画(file)
-- return require("SDL.纹理")(file)
-- end
function GGE资源:取音乐(...)
local path = self:是否存在(...)
if path then
return require('SDL.音乐')(path)
end
end
function GGE资源:取音效(...)
local data = self:取数据(...)
if data then
local rw = require('SDL.读写')(data, #data)
return require('SDL.音效')(rw)
end
end
function GGE资源:取文字(...)
local data = self:取数据(...)
if data then
local rw = require('SDL.读写')(data, #data)
return require('SDL.文字')(rw)
end
end
return GGE资源
-- @Author : GGELUA
-- @Date : 2021-09-17 08:26:43
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-08 11:57:22
local adler32 = require('zlib').adler32
local m_pack = require('cmsgpack').pack
local m_unpack = require('cmsgpack.safe').unpack
local c_isyieldable = coroutine.isyieldable
local c_runing = coroutine.running
local c_yield = coroutine.yield
local c_resume = coroutine.resume
local c_create = coroutine.create
local t_unpack = table.unpack
local PackAgent = require('HPSocket.PackAgent')
local RPCAgent = class('RPCAgent', PackAgent)
local _REG = setmetatable({}, {__mode = 'k'})
local _CBK = setmetatable({}, {__mode = 'k'})
function RPCAgent:RPCAgent()
PackAgent.PackAgent(self) --初始化父类
local reg = {}
_REG[self] = reg --private
_CBK[self] = {} --private
return setmetatable(
{},
{
__newindex = function(t, k, v)
if type(v) == 'function' then
reg[k] = v
reg[adler32(k)] = v
end
end,
__index = reg
}
)
end
function RPCAgent:__index(k) --调用方法
local co, main = c_runing()
local funp = type(k) == 'string' and adler32(k) or k
if co and not main and c_isyieldable() then --如果有协程,则有返回值
return function(self, id, ...)
if id then
local cop = adler32(tostring(co))
_CBK[self][cop] = co
self._hp:Send(id, m_pack {funp, cop, ...})
return c_yield()
end
end
end
return function(self, id, ...)
if id then
self._hp:Send(id, m_pack {funp, 0, ...})
end
end
end
function RPCAgent:发送(id, ...)
return self._hp:Send(id, m_pack {...})
end
local function cofunc(self, id, cop, func, ...)
self._hp:Send(id, m_pack {0, cop, func(self, id, ...)})
end
function RPCAgent:_接收事件(id, data)
if rawget(self, '接收事件') then
self:接收事件(id, data)
return
end
local t = m_unpack(data)
if type(t) == 'table' then
local funp, cop = t[1], t[2]
if funp == 0 then --返回
local co = _CBK[self][cop]
if co then
_CBK[self][cop] = nil
coroutine.xpcall(co, t_unpack(t, 3))
end
else
local func = _REG[self][funp]
if func then
if cop == 0 then --没有返回
func(self, id, t_unpack(t, 3))
else
local r = coroutine.xpcall(cofunc, self, id, cop, func, t_unpack(t, 3))
if r == coroutine.FALSE then
self._hp:Send(id, m_pack {0, cop, nil})
end
end
elseif rawget(self, 'RPC事件') then --未注册的函数
func = self.RPC事件
if cop == 0 then --没有返回
func(self, id, funp, t_unpack(t, 3))
else
local r = coroutine.xpcall(cofunc, self, id, cop, func, funp, t_unpack(t, 3))
if r == coroutine.FALSE then
self._hp:Send(id, m_pack {0, cop, nil})
end
end
elseif co ~= 0 then
self._hp:Send(id, m_pack {0, cop, nil})
end
end
end
end
return RPCAgent
-- @Author : GGELUA
-- @Date : 2021-09-17 08:26:43
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-08 12:04:56
local adler32 = require('zlib').adler32
local m_pack = require('cmsgpack').pack
local m_unpack = require('cmsgpack.safe').unpack
local c_isyieldable = coroutine.isyieldable --lua5.3
local c_runing = coroutine.running
local c_yield = coroutine.yield
local c_resume = coroutine.resume
local c_create = coroutine.create
local t_unpack = table.unpack
local next = next
local PackClient = require('HPSocket.PackClient')
local RPCClient = class('RPCClient', PackClient)
local _REG = setmetatable({}, {__mode = 'k'})
local _CBK = setmetatable({}, {__mode = 'k'})
function RPCClient:RPCClient(mcall)
if mcall and 引擎 then --用主线程回调数据
self._mdata = {}
self._mreg =
引擎:注册事件 {
更新事件 = function()
if next(self._mdata) then
for _, v in ipairs(self._mdata) do
self:_接收事件(v, true)
end
self._mdata = {}
end
end
}
end
PackClient.PackClient(self) --初始化父类
local reg = {}
_REG[self] = reg --private 注册表
_CBK[self] = {} --private 回调表
return setmetatable(
{},
{
__newindex = function(t, k, v)
if type(v) == 'function' then
reg[k] = v
reg[adler32(k)] = v
end
end,
__index = reg
}
)
end
function RPCClient:__index(k) --调用方法
local co, main = c_runing()
local funp = type(k) == 'string' and adler32(k) or k
if co and not main and c_isyieldable() then --如果有协程,则有返回值
return function(self, ...)
local cp = adler32(tostring(co))
_CBK[self][cp] = co --TODO:超时
self._hp:Send(m_pack {funp, cp, ...})
return c_yield()
end
end
return function(self, ...)
self._hp:Send(m_pack {funp, 0, ...})
end
end
function RPCClient:发送(...)
return self._hp:Send(m_pack {...})
end
local function cofunc(self, cop, func, ...)
self._hp:Send(m_pack {0, cop, func(self, ...)})
end
function RPCClient:_接收事件(data, mc)
if rawget(self, '接收事件') then
self:接收事件(data)
return
end
if rawget(self, '_mdata') and not mc then
table.insert(self._mdata, data)
return
end
local t = m_unpack(data)
if type(t) == 'table' then
local funp, cop = t[1], t[2]
if funp == 0 then --返回
local co = _CBK[self][cop]
if co then
_CBK[self][cop] = nil
coroutine.xpcall(co, t_unpack(t, 3))
end
else
local func = _REG[self][funp]
if func then
if cop == 0 then --没有返回
func(self, t_unpack(t, 3))
else
local r = coroutine.xpcall(cofunc, self, cop, func, t_unpack(t, 3))
if r == coroutine.FALSE then
self._hp:Send(m_pack {0, cop, nil})
end
end
elseif rawget(self, 'RPC事件') then --未注册的函数
func = self.RPC事件
if cop == 0 then --没有返回
func(self, funp, t_unpack(t, 3))
else
local r = coroutine.xpcall(cofunc, self, cop, func, funp, t_unpack(t, 3))
if r == coroutine.FALSE then
self._hp:Send(m_pack {0, cop, nil})
end
end
elseif cop ~= 0 then
self._hp:Send(m_pack {0, cop, nil})
end
end
end
end
return RPCClient
-- @Author : GGELUA
-- @Date : 2021-09-17 08:26:43
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-08 12:04:37
local adler32 = require('zlib').adler32
local m_pack = require('cmsgpack').pack
local m_unpack = require('cmsgpack.safe').unpack
local c_isyieldable = coroutine.isyieldable
local c_runing = coroutine.running
local c_yield = coroutine.yield
local c_resume = coroutine.resume
local c_create = coroutine.create
local t_unpack = table.unpack
local PackServer = require('HPSocket.PackServer')
local RPCServer = class('RPCServer', PackServer)
local _REG = setmetatable({}, {__mode = 'k'}) --接收函数
local _CBK = setmetatable({}, {__mode = 'k'}) --等待返回的协程
local _PAS = setmetatable({}, {__mode = 'k'}) --验证连接
function RPCServer:RPCServer()
PackServer.PackServer(self) --初始化父类
local reg = {}
_REG[self] = reg --private
_CBK[self] = {} --private
_PAS[self] = {}
return setmetatable(
{},
{
__newindex = function(t, k, v)
if type(v) == 'function' then
reg[k] = v
reg[adler32(k)] = v
end
end,
__index = reg
}
)
end
function RPCServer:__index(k) --调用方法
local co, main = c_runing()
local funp = type(k) == 'string' and adler32(k) or k
if co and not main and c_isyieldable() then --如果有协程,则有返回值
return function(self, id, ...)
if id then
local cop = adler32(tostring(co))
_CBK[self][cop] = co
self._hp:Send(id, m_pack {funp, cop, ...})
return c_yield()
end
end
end
return function(self, id, ...)
if id then
self._hp:Send(id, m_pack {funp, 0, ...})
end
end
end
function RPCServer:发送(id, ...)
return self._hp:Send(id, m_pack {...})
end
function RPCServer:_连接事件(id, ip, port)
_PAS[self][id] = true
if self.连接事件 then
local r = ggexpcall(self.连接事件, self, id, ip, port)
_PAS[self][id] = r ~= false
end
end
local function cofunc(self, id, cop, func, ...)
self._hp:Send(id, m_pack {0, cop, func(self, id, ...)})
end
function RPCServer:_接收事件(id, data)
if rawget(self, '接收事件') then
self:接收事件(id, data)
return
end
local t = m_unpack(data)
if type(t) ~= 'table' then
return
end
if _PAS[self][id] then
local funp, cop = t[1], t[2]
if funp == 0 then --返回
local co = _CBK[self][cop]
if co then
_CBK[self][cop] = nil
coroutine.xpcall(co, t_unpack(t, 3))
end
else
local func = _REG[self][funp]
if func then
if cop == 0 then --没有返回
func(self, id, t_unpack(t, 3))
else
local r = coroutine.xpcall(cofunc, self, id, cop, func, t_unpack(t, 3))
if r == coroutine.FALSE then
self._hp:Send(id, m_pack {0, cop, nil})
end
end
elseif rawget(self, 'RPC事件') then --未注册的函数
func = self.RPC事件
if cop == 0 then --没有返回
func(self, id, funp, t_unpack(t, 3))
else
local r = coroutine.xpcall(cofunc, self, id, cop, func, funp, t_unpack(t, 3))
if r == coroutine.FALSE then
self._hp:Send(id, m_pack {0, cop, nil})
end
end
elseif cop ~= 0 then
self._hp:Send(id, m_pack {0, cop, nil})
end
end
elseif rawget(self, '验证事件') then
local funp, cop = t[1], t[2]
if funp == 261030967 then --adler32('验证')
local r = self:验证事件(id, t_unpack(t, 3))
self._hp:Send(id, m_pack {0, cop, r})
if r then
_PAS[self][id] = true
else
self:断开(id)
end
end
end
end
return RPCServer
-- @Author: baidwwy
-- @Date: 2021-07-10 16:32:33
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-17 01:16:48
local SDL = require 'SDL'
local GUI = class('GUI')
package.loaded.GUI = GUI
local GUI控件 = require 'GUI.控件'
require 'GUI.输入'
require 'GUI.按钮'
require 'GUI.窗口'
require 'GUI.文本'
require 'GUI.网格'
require 'GUI.列表'
require 'GUI.标签'
require 'GUI.滑块'
require 'GUI.进度'
require 'GUI.组合'
function GUI:初始化(窗口, 文字)
self._文字 = 文字
self._win = 窗口
self._界面 = {}
self._root = self
self._popup = {}
self._tip = {}
self._modal = {}
self._msg = {}
self._mcb =
self._win:注册事件 {
键盘事件 = function(...)
if not self._msg.键盘 then
self._msg.键盘 = {}
end
table.insert(self._msg.键盘, select(select('#', ...), ...))
end,
输入事件 = function(...)
if not self._msg.输入 then
self._msg.输入 = {}
end
table.insert(self._msg.输入, select(select('#', ...), ...))
end,
输入法事件 = function(...)
if not self._msg.输入法 then
self._msg.输入法 = {}
end
table.insert(self._msg.输入法, select(select('#', ...), ...))
end,
鼠标事件 = function(...)
if not self._msg.鼠标 then
self._msg.鼠标 = {}
end
table.insert(self._msg.鼠标, select(select('#', ...), ...))
end,
用户事件 = function(...)
if not self._msg.用户 then
self._msg.用户 = {}
end
table.insert(self._msg.用户, select(select('#', ...), ...))
end
-- 窗口事件 = function(...)
-- table.insert(self._msg.窗口, select(select('#', ...), ...))
-- end
}
end
function GUI:更新(dt, x, y)
if self._鼠标 and self._鼠标.消息事件 then
self._鼠标:消息事件(self._msg)
end
if #self._tip > 0 then --提示
if self._msg.鼠标 then
for i, v in ipairs(self._msg.鼠标) do
if v.type == SDL.MOUSE_MOTION then --鼠标移动时清空
self._tip = {}
break
end
end
end
for _, v in ipairs(self._tip) do
v:_更新(dt, x, y)
end
end
if #self._popup > 0 then --弹出
for i, v in ipairs(self._popup) do
if not v.是否可见 then
table.remove(self._popup, i)
break
end
end
if self._msg.鼠标 then
local pop = self._popup[#self._popup]
for i, v in ipairs(self._msg.鼠标) do
if v.type == SDL.MOUSE_UP then --非碰撞按下时关闭
if not pop:检查点(v.x, v.y) and pop.自动关闭 ~= false then
v.x = -9999
v.y = -9999
pop:置可见(false)
break
end
end
end
end
--控件更新会截获鼠标消息,所以放在系统后面
for i = #self._popup, 1, -1 do
local v = self._popup[i]
v:_更新(dt, x, y)
v:_消息事件(self._msg)
end
end
if #self._modal > 0 then --模态
for i = #self._modal, 1, -1 do
local v = self._modal[i]
v:_更新(dt, x, y)
v:_消息事件(self._msg)
self:清空消息()
end
for i, v in ipairs(self._modal) do
if not v.是否可见 then
table.remove(self._modal, i)
break
end
end
end
--从最后显示的控件开始发消息
for i = #self._界面, 1, -1 do
local v = self._界面[i]
if v.是否可见 then
v:_消息事件(self._msg)
end
end
self._msg = {}
for _, v in ipairs(self._界面) do
if v.是否可见 then
v:_更新(dt, x, y)
end
end
if self._鼠标 and self._鼠标.更新 then
self._鼠标:更新(dt, x, y)
--self._鼠标:消息事件(self._msg)
end
end
function GUI:显示(x, y)
for _, v in ipairs(self._界面) do
if v.是否可见 then
if v._显示 then
v:_显示(x, y)
end
end
end
for _, v in ipairs(self._modal) do
v:_显示(x, y)
end
for _, v in ipairs(self._popup) do
v:_显示(x, y)
end
if self._鼠标 and self._鼠标.显示 then
self._鼠标:显示(x, y)
end
for _, v in ipairs(self._tip) do
if v.是否可见 then
v:_显示(x, y)
end
end
end
function GUI:创建模态窗口(...)
return GUI控件.创建模态窗口(self, ...)
end
--弹出列表,弹出右键等等(当鼠标非碰撞点击时关闭,或者置可见false)
function GUI:创建弹出窗口(...)
return GUI控件.创建弹出窗口(self, ...)
end
function GUI:创建弹出控件(...)
return GUI控件.创建弹出控件(self, ...)
end
--鼠标停留 (当鼠标移动关闭)
function GUI:创建提示控件(...)
return GUI控件.创建提示控件(self, ...)
end
function GUI:创建鼠标()
self._鼠标 = GUI控件('鼠标', 0, 0, self._win.宽度, self._win.高度, self)
return self._鼠标
end
function GUI:创建界面(名称)
assert(not self[名称], 名称 .. ':已存在')
self[名称] = GUI控件(名称, 0, 0, self._win.宽度, self._win.高度, self)
table.insert(self._界面, self[名称])
return self[名称]
end
function GUI:重新初始化(名称)
local 控件 = self[名称]
if 控件 then
控件:重新初始化()
end
end
function GUI:释放界面(名称)
local 控件 = self[名称]
if 控件 then
控件:释放()
for i, v in ipairs(self._界面) do
if v == 控件 then
table.remove(self._界面, i)
break
end
end
--释放引用(控件)
self[名称] = nil
end
end
function GUI:释放引用(v)
--释放require
for k, v1 in pairs(package.loaded) do
if v == v1 then
package.loaded[k] = nil
break
end
end
--释放全局
for k, v1 in pairs(_G) do
if v == v1 then
_G[k] = nil
break
end
end
end
--模态
function GUI:清空消息()
if self._msg.鼠标 then
local t = self._msg.鼠标
for _, v in ipairs(t) do
v.x = -9999
v.y = -9999
end
self._msg = {鼠标 = t}
else
self._msg = {}
end
end
function GUI:取输入焦点()
return self._输入焦点
end
function GUI:置默认输入(v)
self._defipt = v
end
function GUI:取默认输入()
return self._defipt
end
return GUI
-- @Author: baidwwy
-- @Date: 2021-07-10 16:32:33
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-17 09:09:02
local SDL = require 'SDL'
local function _刷新焦点(self, x, y)
local i, item = self:检查项目(x, y)
if item then
self.焦点行 = i
return i, item
else
self.焦点行 = 0
end
end
local function _滚动(self)
local py = self._py
for i, v in ipairs(self.子控件) do
--列表之外不可见,以减少draw call
local yy = py + v.y
v.是否可见 = yy + v.高度 > 0 and yy < self.高度
v:置中心(0, py)
end
_刷新焦点(self, self._win:取鼠标坐标())
end
local function _刷新列表(self)
local hy, py = 0, self._py
for i, v in ipairs(self.子控件) do
v._i = i
v.行号 = i
v:置坐标(v.px, hy + v.py)
local yy = py + v.y
v.是否可见 = yy + v.高度 > 0 and yy < self.高度
v:置中心(0, py)
hy = hy + v.高度 + self.行间距
end
hy = hy - self.行间距
if hy > self.高度 then --可以滚动的最大值
self._max = hy - self.高度
else
self._max = 0
end
if self._max ~= 0 and self._auto then --自动滚动
self._py = -self._max
_滚动(self)
end
self:置选中(self.选中行)
_刷新焦点(self, self._win:取鼠标坐标())
end
local GUI控件 = require('GUI.控件')
local GUI列表 = class('GUI列表', GUI控件)
function GUI列表:初始化()
self._py = 0 --滚动值
self._max = 0 --滚动最大值
self.行间距 = 0
self.选中行 = 0
self.焦点行 = 0
self.文字 = self:取根控件()._文字:复制():置颜色(0, 0, 0, 255)
self.行高度 = self.文字:取高度() + 1
self.选中精灵 = require('SDL.精灵')(0, 0, 0, self.宽度, 0):置颜色(0, 0, 240, 128)
self.焦点精灵 = require('SDL.精灵')(0, 0, 0, self.宽度, 0):置颜色(255, 255, 0, 128)
end
function GUI列表:_更新(dt)
GUI控件._更新(self, dt)
if self.选中精灵 and self.选中精灵.更新 then
self.选中精灵:更新(dt)
end
if self.焦点精灵 and self.焦点精灵.更新 then
self.焦点精灵:更新(dt)
end
if self._ref then
self._ref = nil
_刷新列表(self)
if self._max ~= 0 and self._auto then --自动滚动
self._py = -self._max
_滚动(self)
end
end
end
function GUI列表:_显示(...)
local _x, _y = self:取坐标()
self._win:置区域(_x, _y, self.宽度, self.高度)
if self.选中精灵 and self.选中行 > 0 and self.子控件[self.选中行] then
local item = self.子控件[self.选中行]
local x, y = item:取中心()
self.选中精灵:置中心(-item.x, -(item.y + y))
self.选中精灵:置区域(0, 0, item.宽度, item.高度)
self.选中精灵:显示(_x, _y)
end
if self.焦点精灵 and self.焦点行 > 0 and self.子控件[self.焦点行] then
local item = self.子控件[self.焦点行]
local x, y = item:取中心()
self.焦点精灵:置中心(-item.x, -(item.y + y))
self.焦点精灵:置区域(0, 0, item.宽度, item.高度)
self.焦点精灵:显示(_x, _y)
end
self._win:置区域()
GUI控件._显示(self, ...)
end
function GUI列表:清空()
self._py = 0 --滚动值
self._max = 0 --滚动最大值
self.选中行 = 0
self.焦点行 = 0
self.子控件 = {}
end
function GUI列表:添加(...)
return self:插入(#self.子控件 + 1, ...)
end
local _列项 = class('GUI列项', GUI控件) --继承一下,防止控件接收掉消息
function GUI列表:插入(i, 文本, x, y, w, h)
local 列项 = _列项(文本, 0, 0, w or self.宽度, (h or self.行高度), self)
列项.px = x or 0
列项.py = y or 0
if 文本 then
列项:置精灵(self.文字:取精灵(文本))
end
if type(self.子显示) == 'function' then
列项.显示 = function(this, x, y)
self:子显示(x, y, this._i)
end
end
local 置高度 = 列项.置高度
列项.置高度 = function(this, v)
置高度(this, v)
self._ref = true
end
table.insert(self.子控件, i, 列项)
self._ref = true
return 列项
end
function GUI列表:删除(i)
if self.子控件[i] then
table.remove(self.子控件, i)
self._ref = true
end
end
function GUI列表:删除选中()
local i = self.选中行
if self.子控件[i] then
table.remove(self.子控件, i)
self._ref = true
end
end
function GUI列表:自动删除(v)
self._del = v
return self
end
function GUI列表:定位(i)
end
function GUI列表:自动滚动(v)
self._auto = v
return self
end
function GUI列表:置高度(h)
GUI控件.置高度(self, h)
self._ref = true
return self
end
function GUI列表:置宽度(w)
GUI控件.置宽度(self, w)
for i, v in ipairs(self.子控件) do
v:置宽度(w)
end
--self._ref = true
return self
end
function GUI列表:置宽高(w,h)
GUI控件.置宽高(self, w,h)
for i, v in ipairs(self.子控件) do
v:置宽度(w)
end
self._ref = true
return self
end
function GUI列表:取项目(i)
if i < 0 then
i = #self.子控件 + i + 1
end
return self.子控件[i]
end
function GUI列表:遍历项目()
local 子控件 = {}
for i, v in ipairs(self.子控件) do
子控件[i] = v
end
return next, 子控件
end
function GUI列表:置文字(v)
self.文字 = v
self.行高度 = self.文字:取高度('A')
return self
end
function GUI列表:置颜色(...)
self.文字:置颜色(...)
return self
end
function GUI列表:置项目颜色(i, ...)
if self.子控件[i] and self.子控件[i]:取精灵() then
self.子控件[i]:取精灵():置颜色(...)
end
return self
end
function GUI列表:置文本(i, v)
if self.子控件[i] then
self.子控件[i].名称 = v
self.子控件[i]:置精灵(v and self.文字:取精灵(v))
end
return self
end
function GUI列表:取文本(i)
return self.子控件[i] and self.子控件[i].名称
end
function GUI列表:取行数()
return #self.子控件
end
function GUI列表:置选中(i)
if self.子控件[i] then
self.选中行 = i
else
self.选中行 = 0
end
end
function GUI列表:取选中()
if self.选中行 then
return self.子控件[self.选中行]
end
end
function GUI列表:检查项目(x, y)
for i, item in ipairs(self.子控件) do
if item.是否可见 and item:检查点(x, y) then
return i, item
end
end
end
function GUI列表:向上滚动()
if self._py < 0 then
self._py = self._py + self.高度
if self._py > 0 then
self._py = 0
end
_滚动(self)
return true
end
end
function GUI列表:向下滚动()
if math.abs(self._py) < self._max then
self._py = self._py - self.高度
if math.abs(self._py) > self._max then
self._py = -self._max
end
_滚动(self)
return self._py ~= -self._max
end
end
function GUI列表:滚动到底()
self._py = -self._max
_滚动(self)
end
function GUI列表:是否到底()
return self._py == -self._max
end
function GUI列表:绑定滑块(obj)
self.滑块 = obj
if obj then
local 置位置 = obj.置位置
obj.置位置 = function(this, v)
置位置(this, v)
self._py = -math.floor(this.位置 / this.最大值 * self._max)
if self._py == 0 then
置位置(this, 0)
end
_滚动(self)
return self._py ~= 0
end
end
return obj
end
function GUI列表:_消息事件(msg)
if not self.是否可见 then
return
end
GUI控件._消息事件(self, msg)
if not msg.鼠标 then
return
end
for _, v in ipairs(msg.鼠标) do
if v.type == SDL.MOUSE_DOWN then
if self:检查点(v.x, v.y) then
v.typed, v.type = v.type, nil
v.control = self
if not self.是否禁止 then
local i, item = self:检查项目(v.x, v.y)
if item then
self._curdown = i
if v.button == SDL.BUTTON_LEFT then
self.选中行 = i
if rawget(self, '左键按下') then
local x, y = item:取坐标()
self:发送消息('左键按下', x, y, i, item, msg)
end
elseif v.button == SDL.BUTTON_RIGHT then
if rawget(self, '右键按下') then
local x, y = item:取坐标()
self:发送消息('右键按下', x, y, i, item, msg)
end
end
end
end
end
elseif v.type == SDL.MOUSE_UP then
if self:检查点(v.x, v.y) then
v.typed, v.type = v.type, nil
v.control = self
if not self.是否禁止 then
local i, item = self:检查项目(v.x, v.y)
if item and self._curdown == i then
if v.button == SDL.BUTTON_LEFT then
local x, y = item:取坐标()
if ggetype(self) == 'GUI树形列表' then
if item.收展 then --有按钮
item.收展:置选中(not item.是否展开)
elseif item.是否节点 then
item.是否展开 = not item.是否展开
item.父控件._ref = true
end
item:发送消息('左键弹起', x, y, i, item, msg)
end
if rawget(self, '左键弹起') then
self:发送消息('左键弹起', x, y, i, item, msg)
end
if v.clicks == 2 and rawget(self, '左键双击') then
self:发送消息('左键双击', x, y, i, item, msg)
end
elseif v.button == SDL.BUTTON_RIGHT then
if rawget(self, '右键弹起') then
local x, y = item:取坐标()
self:发送消息('右键弹起', x, y, i, item, msg)
end
end
end
end
end
elseif v.type == SDL.MOUSE_MOTION then
if self:检查点(v.x, v.y) then
v.typed, v.type = v.type, nil
v.control = self
local i, item = _刷新焦点(self, v.x, v.y)
if item then
local x, y = item:取坐标()
self:发送消息('获得鼠标', x, y, i, item, msg)
end
else
self.焦点行 = 0
end
elseif v.type == SDL.MOUSE_WHEEL then
local x, y = SDL._wins[v.windowID]:取鼠标坐标()
if self:检查点(x, y) and self._max > 0 then
v.typed, v.type = v.type, nil
v.control = self
if not self.是否禁止 then
local py = self._py + v.y * (self.高度 / 2)
if py > 0 then
py = 0
end
if math.abs(py) > self._max then
py = -self._max
end
if self.滑块 then
self.滑块:置位置(math.floor(math.abs(py) / self._max * self.滑块.最大值))
else
self._py = math.floor(py)
_滚动(self)
end
self:发送消息('鼠标滚轮', py == -self._max)
end
end
end
end
end
function GUI控件:创建列表(name, x, y, w, h)
assert(not self[name], name .. ':此列表已存在,不能重复创建.')
self[name] = GUI列表(name, x, y, w, h, self)
table.insert(self.子控件, self[name])
return self[name]
end
--====================================================================
local function _刷新树(root, node)
for _, v in ipairs(node) do
table.insert(root.子控件, v)
if v.是否展开 then --递归子项
if v._node then
_刷新树(root, v._node)
end
end
end
end
local _节点 = class('树节点', GUI控件)
function _节点:初始化(t, x, y, w, h, f)
self.是否展开 = false
self._lay = 1
self.px = x or 0
self.py = y or 0
self:置精灵(f.文字:取精灵(t))
end
function _节点:添加(name, x, y)
local r = _节点(name, self._lay * self.父控件.缩进宽度 + (x or 0), y, w or self.宽度, (h or self.父控件.行高度), self.父控件)
r.父节点 = self
r._lay = self._lay + 1
if not self._node then
self._node = {}
end
self.是否节点 = true
table.insert(self._node, r)
self.父控件._ref = true
return r
end
function _节点:删除(name)
if not self._node then
return
end
for i, v in ipairs(self._node) do
if v.名称 == name then
table.remove(self._node, i)
self.父控件._ref = true
return
end
end
end
function _节点:清空()
if not self._node then
return
end
self._node = {}
self.父控件._ref = true
end
function _节点:取项目(name)
if not self._node then
return
end
for i, v in ipairs(self._node) do
if v.名称 == name then
self.父控件._ref = true
return v
end
end
end
function _节点:遍历项目()
if not self._node then
return next, {}
end
self.父控件._ref = true
return next, self._node
end
function _节点:创建收展按钮(x, y, w, h)
local 收展 = self:创建多选按钮('收展', x, y, w, h)
收展.检查透明 = 收展.检查点
function 收展.选中事件(_, b)
self.是否展开 = b
self.父控件._ref = true
end
if self:取精灵() then
self:取精灵():置中心(-收展.宽度, 0)
end
return 收展
end
--====================================================================
local GUI树形列表 = class('GUI树形列表', GUI列表)
function GUI树形列表:初始化()
self._node = {}
self.缩进宽度 = 15
end
function GUI树形列表:添加(t, x, y)
local r = _节点(t, x, y, (w or self.宽度), (h or self.行高度), self)
table.insert(self._node, r)
self._ref = true
return r
end
function GUI树形列表:_更新(...)
if self._ref then
self.子控件 = {} --不使用清空
_刷新树(self, self._node) --把节点添加到列表
_刷新列表(self) --列表项目坐标刷新
self._ref = nil --和GUI列表变量同名,可能会出现问题
end
GUI列表._更新(self, ...)
end
function GUI树形列表:清空()
self._node = {}
GUI列表.清空(self)
self._ref = true
end
function GUI树形列表:取项目(name)
for i, v in ipairs(self._node) do
if v.名称 == name then
self._ref = true
return v
end
end
end
function GUI树形列表:遍历项目()
self._ref = true
return next, self._node
end
function GUI控件:创建树形列表(name, x, y, w, h)
assert(not self[name], name .. ':此树形列表已存在,不能重复创建.')
self[name] = GUI树形列表(name, x, y, w, h, self)
table.insert(self.子控件, self[name])
return self[name]
end
--====================================================================
local GUI多列列表 = class('GUI多列列表', GUI列表)
function GUI多列列表:初始化()
self._info = {}
self._color = ''
end
function GUI多列列表:添加列(x, y, w, h)
local t = {x = x, y = y, w = w, h = h}
table.insert(self._info, t)
return t
end
function GUI多列列表:置颜色(r, g, b, a)
self._color = string.format('#c%02X%02X%02X', r, g, b)
end
function GUI多列列表:添加(...)
local data = {...}
local = GUI列表.添加(self)
self[#self + 1] =
for i, v in ipairs(self._info) do
local = :创建控件(i, v.x, v.y, v.w or 50, v.h or .高度)
if data[i] then
.文本 = self._color .. tostring(data[i])
:创建文本(.文本, 0, 0, .宽度, .高度):置文本(.文本)
end
end
return :置可见(true, true)
end
function GUI控件:创建多列列表(name, x, y, w, h)
assert(not self[name], name .. ':此多列列表已存在,不能重复创建.')
self[name] = GUI多列列表(name, x, y, w, h, self)
table.insert(self.子控件, self[name])
return self[name]
end
return GUI列表
-- @Author: baidwwy
-- @Date: 2021-08-14 12:39:47
-- @Last Modified by : baidwwy
-- @Last Modified time : 2022-02-11 12:57:59
local SDL = require 'SDL'
local GUI控件 = require('GUI.控件')
local GUI按钮 = class('GUI按钮', GUI控件)
function GUI按钮:初始化(_, x, y, w, h)
self._rbtn = 1 --用来读
self.宽度 = w or 0
self.高度 = h or 0
local spr = {}
self._btnspr =
setmetatable(
{},
{
__index = spr,
__newindex = function(t, k, v) --控件变量 _spr
assert(type(v) == 'table', '对象错误')
assert(v.显示, '对象错误')
if k == self._rbtn then
self._curspr = v
end
if v.宽度 > self.宽度 or v.高度 > self.高度 then
self:置宽高(v.宽度, v.高度)
end
--rawset(t, k, v)
spr[k] = v
end
}
)
end
-- function GUI按钮:__index(k)
-- if k=='_btn' then
-- return self._rbtn
-- end
-- end
function GUI按钮:__newindex(k, v)
if k == '_btn' then --用来写
rawset(self, '_curspr', self._btnspr[v] or self._btnspr[1])
rawset(self, '_rbtn', v)
return
end
rawset(self, k, v)
end
function GUI按钮:_更新(dt)
GUI控件._更新(self, dt)
if self._curspr and self._curspr.更新 then
self._curspr:更新(dt)
end
end
function GUI按钮:_显示(...)
local _x, _y = self:取坐标()
self._win:置区域(_x, _y, self.宽度, self.高度)
if self._curspr then
self._curspr:显示(_x, _y)
end
self._win:置区域()
GUI控件._显示(self, ...)
end
function GUI按钮:置禁止精灵(v)
self._btnspr[0] = v
return self
end
function GUI按钮:置正常精灵(v)
self._btnspr[1] = v
return self
end
function GUI按钮:置按下精灵(v)
self._btnspr[2] = v
return self
end
function GUI按钮:置经过精灵(v)
self._btnspr[3] = v
return self
end
function GUI按钮:检查点(x, y)
return self._curspr and self._curspr:检查点(x, y)
end
function GUI按钮:检查透明(x, y)
if gge.platform == 'Android' or gge.platform == 'iOS' then
return self._curspr and self._curspr:检查点(x, y)
end
return self._curspr and self._curspr:取透明(x, y) ~= 0
end
function GUI按钮:置可见(v, s)
GUI控件.置可见(self, v, s)
if gge.platform == 'Windows' and v and not self.是否禁止 and self._win:取鼠标焦点() then
local _, x, y = self._win:取鼠标状态()
if self:检查透明(x, y) then
self._btn = 3
else
self._btn = 1
end
end
return self
end
function GUI按钮:置禁止(v)
self.是否禁止 = v == true
if self.是否禁止 then
self._btn = 0
else
self._btn = 1
end
return self
end
local _state = {禁止 = 0, 正常 = 1, 按下 = 2, 经过 = 3, [0] = '禁止', '正常', '按下', '经过'}
function GUI按钮:取状态()
return _state[self._rbtn]
end
function GUI按钮:置状态(v)
if _state[v] then
self._btn = _state[v]
end
end
function GUI按钮:_消息事件(msg)
if not self.是否可见 then
return
end
GUI控件._消息事件(self, msg)
if not msg.鼠标 then
return
end
for _, v in ipairs(msg.鼠标) do
if v.type == SDL.MOUSE_DOWN then
if v.button == SDL.BUTTON_LEFT or v.button == SDL.BUTTON_RIGHT then
if self:检查透明(v.x, v.y) then
v.typed, v.type = v.type, nil
v.control = self
if not self.是否禁止 then
self._btn = 2
msg.按钮按下 = self
local x, y = self:取坐标()
if v.button == SDL.BUTTON_LEFT then
self:发送消息('左键按下', x, y, msg)
elseif v.button == SDL.BUTTON_RIGHT then
self:发送消息('右键按下', x, y, msg)
end
end
end
end
elseif v.type == SDL.MOUSE_UP then
if v.button == SDL.BUTTON_LEFT or v.button == SDL.BUTTON_RIGHT then
if self:检查透明(v.x, v.y) then
if self._rbtn == 2 then
v.typed, v.type = v.type, nil
v.control = self
if not self.是否禁止 then
self._btn = 3
local x, y = self:取坐标()
if v.button == SDL.BUTTON_LEFT then
if self:发送消息('左键弹起', x, y, msg) ~= false then --阻止选中
msg.按钮弹起 = self --已经按下
end
elseif v.button == SDL.BUTTON_RIGHT then
self:发送消息('右键弹起', x, y, msg)
end
end
else
msg.鼠标弹起 = self --没有按下
end
elseif self._rbtn == 2 then
self._btn = 1
end
end
elseif v.type == SDL.MOUSE_MOTION then
if gge.platform == 'Windows' and v.state == 0 then
if self:检查透明(v.x, v.y) then
self.鼠标焦点 = true
local x, y = self:取坐标()
self:发送消息('获得鼠标', x, y, msg)
v.x = -9999
v.y = -9999
if not self.是否禁止 and self._rbtn == 1 then
self._btn = 3
msg.按钮经过 = self
end
elseif self._rbtn == 3 then
self._btn = 1
msg.按钮经过 = false
self:发送消息('失去鼠标', v.x, v.y, msg)
self.鼠标焦点 = false
end
end
end
end
end
function GUI控件:创建按钮(name, x, y, w, h)
assert(not self[name], name .. ':此按钮已存在,不能重复创建.')
self[name] = GUI按钮(name, x, y, w, h, self)
table.insert(self.子控件, self[name])
return self[name]
end
--======================================================================
local GUI多选按钮 = class('GUI多选按钮', GUI按钮)
function GUI多选按钮:初始化()
self.是否选中 = false
local spr1 = {}
self._btnspr1 =
setmetatable(
{},
{
__index = spr1,
__newindex = function(t, k, v)
assert(type(v) == 'table', '对象错误')
assert(v.显示, '对象错误')
if not self.是否选中 and k == self._rbtn then
self._curspr = v
end
if v.宽度 > self.宽度 or v.高度 > self.高度 then
self:置宽高(v.宽度, v.高度)
end
--rawset(t, k, v)
spr1[k] = v
end
}
)
local spr2 = {}
self._btnspr2 =
setmetatable(
{},
{
__index = spr2,
__newindex = function(t, k, v)
assert(type(v) == 'table', '对象错误')
assert(v.显示, '对象错误')
if self.是否选中 and k == self._rbtn then
self._curspr = v
end
if v.宽度 > self.宽度 or v.高度 > self.高度 then
self:置宽高(v.宽度, v.高度)
end
--rawset(t, k, v)
spr2[k] = v
end
}
)
self._btnspr = self._btnspr1
end
GUI多选按钮.__newindex = GUI按钮.__newindex
function GUI多选按钮:置禁止精灵(v)
self._btnspr1[0] = v
return self
end
function GUI多选按钮:置正常精灵(v)
self._btnspr1[1] = v
return self
end
function GUI多选按钮:置按下精灵(v)
self._btnspr1[2] = v
return self
end
function GUI多选按钮:置经过精灵(v)
self._btnspr1[3] = v
return self
end
function GUI多选按钮:置选中禁止精灵(v)
self._btnspr2[0] = v
return self
end
function GUI多选按钮:置选中正常精灵(v)
self._btnspr2[1] = v
return self
end
function GUI多选按钮:置选中按下精灵(v)
self._btnspr2[2] = v
return self
end
function GUI多选按钮:置选中经过精灵(v)
self._btnspr2[3] = v
return self
end
function GUI多选按钮:置选中(v)
self.是否选中 = v == true
self._btnspr = v and self._btnspr2 or self._btnspr1
self._curspr = self._btnspr[self._rbtn] or self._btnspr[1]
if self.是否实例 and self.是否可见 and not self._lock then
self._lock = true --防止循环
self:发送消息('选中事件', self.是否选中)
self._lock = nil
end
return self
end
function GUI多选按钮:_消息事件(msg)
GUI按钮._消息事件(self, msg)
if msg.按钮弹起 == self then
msg.按钮选中 = self
self:置选中(not self.是否选中)
end
end
function GUI控件:创建多选按钮(name, x, y, w, h)
assert(not self[name], name .. ':此按钮已存在,不能重复创建.')
self[name] = GUI多选按钮(name, x, y, w, h, self)
table.insert(self.子控件, self[name])
return self[name]
end
--======================================================================
local GUI单选按钮 = class('GUI单选按钮', GUI多选按钮)
GUI单选按钮.__newindex = GUI按钮.__newindex
function GUI单选按钮:置选中(v)
if v == true then
for _, v in ipairs(self.父控件.子控件) do
if v ~= self and ggetype(v) == 'GUI单选按钮' then
GUI多选按钮.置选中(v, false)
end
end
GUI多选按钮.置选中(self, true)
end
return self
end
function GUI控件:创建单选按钮(name, x, y, w, h)
assert(not self[name], name .. ':此按钮已存在,不能重复创建.')
self[name] = GUI单选按钮(name, x, y, w, h, self)
table.insert(self.子控件, self[name])
return self[name]
end
-- @Author: baidwwy
-- @Date: 2021-08-03 06:12:47
-- @Last Modified by: baidwwy
-- @Last Modified time: 2022-01-07 06:17:54
local SDL = require 'SDL'
local GUI控件 = class('GUI控件')
function GUI控件:初始化(name, x, y, w, h, f)
self.名称 = name
self.x = math.floor(tonumber(x) or 0)
self.y = math.floor(tonumber(y) or 0)
self.宽度 = math.abs(math.floor(tonumber(w) or 0))
self.高度 = math.abs(math.floor(tonumber(h) or 0))
self.父控件 = assert(f, '父控件')
--self._root = self:取根控件()
self._win = self:取根控件()._win
self.子控件 = {} --FIXME 优化其它类的引用
self.是否可见 = false
--self.是否禁止 = false
--self.是否实例 = false --是否已经加载
self.矩形 = require('SDL.矩形')(0, 0, self.宽度, self.高度)
self.矩形:置颜色(255, 0, 0)
--self.矩形:置坐标(self:取坐标())
end
function GUI控件:_更新(...)
if rawget(self, '更新') then
self:更新(...)
end
if self._spr and self._spr.更新 then
self._spr:更新(...)
end
for _, v in ipairs(self.子控件) do
if v.是否可见 then
v:_更新(...)
end
end
end
function GUI控件:_显示(x, y)
local _x, _y = self:取坐标() --坐标是相对的,每次获取,TODO:移动才修改
self.矩形:置坐标(_x, _y)
if rawget(self, '后显示') then
self:后显示(_x, _y)
end
if self._win:置区域(_x, _y, self.宽度, self.高度) then
if self._spr then
self._spr:显示(_x, _y)
end
if rawget(self, '显示') then
self:显示(_x, _y, x, y)
end
for _, v in ipairs(self.子控件) do
if v.是否可见 then
v:_显示(x, y)
end
end
if gge.isdebug and self._win:取按键状态(SDL.KEY_F1) then
self.矩形:显示()
end
self._win:置区域()
end
if rawget(self, '前显示') then
self:前显示(_x, _y)
end
end
function GUI控件:_后显示(x, y, mx, my)
self.矩形:置坐标(x, y)
if gge.isdebug and self._win:取按键状态(SDL.KEY_F1) then
self.矩形:显示()
end
if rawget(self, '后显示') then
self:后显示(x, y, mx, my)
end
if self._spr then
self._spr:显示(x, y)
end
end
function GUI控件:_前显示(x, y, mx, my)
if rawget(self, '显示') then
self:显示(x, y, mx, my)
end
for _, v in ipairs(self.子控件) do
if v.是否可见 then
v:_显示(mx, my)
end
end
if rawget(self, '前显示') then
self:前显示(x, y, mx, my)
end
end
function GUI控件:_子控件消息(msg)
for i = #self.子控件, 1, -1 do
local v = self.子控件[i]
if v.是否可见 then
v:_消息事件(msg)
end
end
end
function GUI控件:_消息事件(msg)
if self.是否禁止 or not self.是否可见 then
return
end
self:_子控件消息(msg)
if msg.键盘 then
for _, v in ipairs(msg.键盘) do
if self:发送消息('键盘事件', table.unpack(v)) then
v[2] = nil
end
end
end
if not msg.鼠标 then
return
end
for _, v in ipairs(msg.鼠标) do
if self:发送消息('鼠标事件', table.unpack(v)) then
--v[2] = nil
end
end
local tp = ggetype(self)
if tp == 'GUI控件' or tp == 'GUI弹出控件' then
for _, v in ipairs(msg.鼠标) do
if v.type == SDL.MOUSE_DOWN then
if self:检查点(v.x, v.y) then
if v.button == SDL.BUTTON_LEFT then
self._ldown = v.x .. v.y
self:发送消息('左键按下', v.x, v.y, msg)
elseif v.button == SDL.BUTTON_RIGHT then
self._rdown = v.x .. v.y
self:发送消息('右键按下', v.x, v.y, msg)
end
if self:检查透明(v.x, v.y) then --窗口下的控件 穿透
v.typed, v.type = v.type, nil
v.control = self
end
end
elseif v.type == SDL.MOUSE_UP then
if self:检查点(v.x, v.y) then
if v.button == SDL.BUTTON_LEFT then
if self._ldown == v.x .. v.y then
self:发送消息('左键弹起', v.x, v.y, msg)
end
elseif v.button == SDL.BUTTON_RIGHT then
if self._rdown then
self:发送消息('右键弹起', v.x, v.y, msg)
end
end
if self:检查透明(v.x, v.y) then --窗口下的控件 穿透
v.typed, v.type = v.type, nil
v.control = self
end
end
self._ldown = nil
self._rdown = nil
elseif v.type == SDL.MOUSE_MOTION then
if v.state == 0 and self:检查点(v.x, v.y) then
self:发送消息('获得鼠标', v.x, v.y, msg)
if self:检查透明(v.x, v.y) then
v.x = -9998
v.y = -9999
--v.control = self
end
end
-- elseif v.type==SDL.MOUSE_WHEEL then
-- print(self.父控件 and self.父控件.名称,self.名称)
end
end
self:发送消息('消息事件', msg)
if self:发送消息('消息结束', msg) then
self:清空消息(msg)
end
end
end
function GUI控件:置精灵(v, wh)
if type(v) == 'table' and type(v.显示) == 'function' then
self._spr = v
if wh or self.宽度 == 0 or self.高度 == 0 then
self.宽度 = v.宽度
self.高度 = v.高度
if type(v.取矩形) == 'function' then
self.矩形 = v:取矩形():复制()
else
self.矩形 = require('SDL.矩形')(0, 0, self.宽度, self.高度)
end
end
else
self._spr = nil
end
return self
end
function GUI控件:取精灵()
return self._spr
end
function GUI控件:取父控件()
return self.父控件
end
function GUI控件:取根控件()
if not self.父控件.取根控件 then
return self.父控件
end
return self.父控件:取根控件()
end
function GUI控件:取窗口()
if not self.父控件.取窗口 then
return self.父控件
end
return self.父控件:取窗口()
end
function GUI控件:绝对可见()
if self.是否可见 then
return true
end
if self.父控件.绝对可见 then
return self.父控件:绝对可见()
end
end
function GUI控件:置坐标(x, y) --坐标是相对于父的
self.x = x or 0
self.y = y or 0
self.矩形:置坐标(self:取坐标())
return self
end
function GUI控件:取坐标()
local x, y = self.x, self.y
if x < 0 then --如果坐标为负数,则值相对于 宽高 - 坐标
if self.父控件 and self.父控件.宽度 then
x = x + self.父控件.宽度
end
end
if y < 0 then
if self.父控件 and self.父控件.高度 then
y = y + self.父控件.高度
end
end
if self._hx and self._hy then
x = x + self._hx --中心
y = y + self._hy
end
if self.父控件 and self.父控件.取坐标 then
local px, py = self.父控件:取坐标()
return x + px, y + py
end
return x, y
end
function GUI控件:置中心(x, y)
self._hx = math.floor(x) or 0
self._hy = math.floor(y) or 0
self.矩形:置坐标(self:取坐标())
return self
end
function GUI控件:取中心()
return self._hx, self._hy
end
function GUI控件:置宽高(w, h)
self.宽度 = w
self.高度 = h
self.矩形:置宽高(w, h)
return self
end
function GUI控件:取宽高()
return self.宽度, self.高度
end
function GUI控件:取坐标宽高()
local x, y = self:取坐标()
return x, y, self.宽度, self.高度
end
function GUI控件:置宽度(w)
self.宽度 = w
self.矩形:置宽高(w, self.高度)
return self
end
function GUI控件:置高度(h)
self.高度 = h
self.矩形:置宽高(self.宽度, h)
return self
end
function GUI控件:遍历控件()
local 子控件 = {}
for i, v in ipairs(self.子控件) do
子控件[i] = v
end
return next, 子控件
end
function GUI控件:置检查区域(x, y, w, h)
self.矩形:置中心(-x, -y)
self.矩形:置宽高(w, h)
return self
end
function GUI控件:检查点(x, y)
if self.父控件.检查点 then
return self.父控件:检查点(x, y) and self.矩形:检查点(x, y)
end
return self.矩形:检查点(x, y)
end
function GUI控件:检查透明(x, y)
if self._spr and type(self._spr.取透明) == 'function' then
return self._spr:取透明(x, y) > 0
end
return false
end
function GUI控件:置可见(val, sub)
if val and self.是否实例 and self.是否禁止 then
return self
end
if self._lock then
self.是否可见 = val == true
return
end
self._lock = true
if self:发送消息('可见事件', val) == false then
return self
end
self.是否可见 = val == true
if not self.是否实例 and val then
if rawget(self, '初始化') then
ggexpcall(self.初始化, self)
end
self.是否实例 = true
end
if sub then
for _, v in ipairs(self.子控件) do
v:置可见(val, sub)
end
end
self._lock = nil
return self
end
function GUI控件:重新初始化()
if self.是否实例 then
if rawget(self, '初始化') then
ggexpcall(self.初始化, self)
end
end
for _, v in ipairs(self.子控件) do
v:重新初始化()
end
end
function GUI控件:置禁止(v)
self.是否禁止 = v == true
return self
end
function GUI控件:发送消息(name, ...)
local fun = rawget(self, name)
if type(fun) == 'function' then
return coroutine.xpcall(fun, self, ...)
end
end
function GUI控件:释放()
for i, v in ipairs(self.子控件) do
v:释放()
self[v.名称] = nil
--释放引用(v)
end
self.子控件 = {}
end
function GUI控件:清空消息(msg)
if msg.鼠标 then
for _, v in ipairs(msg.鼠标) do
v.x = -9999
v.y = -9999
end
end
end
function GUI控件:删除控件(name)
if name then
local 控件 = self[name]
if 控件 then
for i, v in ipairs(self.子控件) do
if v == 控件 then
table.remove(self.子控件, i)
break
end
end
self[name] = nil
end
else
for i, v in ipairs(self.子控件) do
self[v.名称] = nil
end
self.子控件 = {}
end
end
function GUI控件:取子控件数量()
return #self.子控件
end
function GUI控件:创建控件(name, x, y, w, h)
assert(not self[name], name .. ':此控件已存在,不能重复创建.')
self[name] = GUI控件(name, x, y, w, h, self)
table.insert(self.子控件, self[name])
return self[name]
end
--===========================================================================
local GUI弹出控件 = class('GUI弹出控件', GUI控件)
function GUI弹出控件:置可见(b, s)
if not self.是否可见 then
table.insert(self:取根控件()._popup, self)
end
GUI控件.置可见(self, b, s or not self.是否实例)
return self
end
function GUI控件:创建弹出控件(name, x, y, w, h)
return GUI弹出控件(name, x, y, w, h, self)
end
--===========================================================================
local GUI提示控件 = class('GUI提示控件', GUI控件)
function GUI提示控件:置可见(b, s)
local _tip = self:取根控件()._tip
if b then
if not _tip[self] then
table.insert(_tip, self)
_tip[self] = self
end
else
_tip[self] = nil
end
GUI控件.置可见(self, b, s or not self.是否实例)
return self
end
function GUI控件:创建提示控件(name, x, y, w, h)
return GUI提示控件(name, x, y, w, h, self)
end
return GUI控件
-- @Author: baidwwy
-- @Date: 2021-07-10 16:32:33
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-17 00:37:58
local SDL = require 'SDL'
local GUI控件 = require('GUI.控件')
local GGE文本 = require('GGE.文本')
local GUI文本 = class('GUI文本', GUI控件, GGE文本)
function GUI文本:初始化()
self._py = 0
self._max = 0
GGE文本.GGE文本(self, self.宽度, self.高度)
self:置文字(self:取根控件()._文字:复制())
end
function GUI文本:_更新(...)
GUI控件._更新(self, ...)
GGE文本.更新(self, ...)
end
function GUI文本:_显示(...)
GUI控件._显示(self, ...)
local _x, _y = self:取坐标()
self._win:置区域(_x, _y, self.宽度, self.高度)
GGE文本.显示(self, _x, _y + self._py)
self._win:置区域()
--self.矩形:显示()
end
function GUI文本:置文本(...)
self._py = 0
local w, h = GGE文本.置文本(self, ...)
self._max = h - self.高度
if self._max < 0 then
self._max = 0
end
return w, h
end
function GUI文本:置宽度(...)
local w, h = GGE文本.置宽度(self, ...)
self._max = h - self.高度
if self._max < 0 then
self._max = 0
end
GUI控件.置宽度(self, ...)
return w, h
end
function GUI文本:绑定滑块(obj)
self.滑块 = obj
if obj then
local 置位置 = obj.置位置
obj.置位置 = function(this, v)
置位置(this, v)
self._py = -math.floor(this.位置 / this.最大值 * self._max)
if self._py == 0 then
置位置(this, 0)
end
return self._py ~= 0
end
end
return obj
end
function GUI文本:_消息事件(msg)
if not self.是否可见 or self.是否禁止 or not msg.鼠标 then
return
end
for _, v in ipairs(msg.鼠标) do
if v.type == SDL.MOUSE_DOWN then
if self:检查点(v.x, v.y) then
local cb = self:检查回调(v.x, v.y)
if cb then
if v.button == SDL.BUTTON_LEFT then
self._lcb = cb
if rawget(self, '左键按下') then
v.typed, v.type = v.type, nil
v.control = self
self:发送消息('左键按下', cb, msg)
end
elseif v.button == SDL.BUTTON_RIGHT then
self._rcb = cb
if rawget(self, '右键按下') then
v.typed, v.type = v.type, nil
v.control = self
self:发送消息('右键按下', cb, msg)
end
end
end
end
elseif v.type == SDL.MOUSE_UP then
if self:检查点(v.x, v.y) then
local cb = self:检查回调(v.x, v.y)
if cb then
if v.button == SDL.BUTTON_LEFT and rawget(self, '左键弹起') then
if cb == self._lcb then
v.typed, v.type = v.type, nil
v.control = self
self:发送消息('左键弹起', cb, msg)
end
elseif v.button == SDL.BUTTON_RIGHT and rawget(self, '右键弹起') then
if cb == self._rcb then
v.typed, v.type = v.type, nil
v.control = self
self:发送消息('右键弹起', cb, msg)
end
end
end
self._lcb = nil
self._rcb = nil
end
elseif v.type == SDL.MOUSE_MOTION then
if self:检查点(v.x, v.y) and v.state == 0 then
local cb = self:检查回调(v.x, v.y)
if cb then
v.typed, v.type = v.type, nil
v.control = self
self._focus = true
self:发送消息('获得鼠标', v.x, v.y, cb, msg)
elseif self._focus then
self._focus = nil
self:发送消息('失去鼠标', v.x, v.y, msg)
end
end
elseif v.type == SDL.MOUSE_WHEEL then
local x, y = SDL._wins[v.windowID]:取鼠标坐标()
if self:检查点(x, y) and self._max > 0 then
v.typed, v.type = v.type, nil
v.control = self
local py = self._py + v.y * (self.高度 / 2)
if py > 0 then
py = 0
end
if math.abs(py) > self._max then
py = -self._max
end
if self.滑块 then
self.滑块:置位置(math.floor(math.abs(py) / self._max * self.滑块.最大值))
else
self._py = math.floor(py)
end
self:发送消息('鼠标滚轮', py == -self._max)
end
end
end
end
function GUI控件:创建文本(name, x, y, w, h)
assert(not self[name], name .. ':此文本已存在,不能重复创建.')
self[name] = GUI文本(name, x, y, w, h, self)
table.insert(self.子控件, self[name])
return self[name]
end
return GUI文本
-- @Author: baidwwy
-- @Date: 2021-08-18 13:24:54
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-12 09:30:58
local SDL = require 'SDL'
local GUI控件 = require('GUI.控件')
local GUI标签 = class('GUI标签', GUI控件)
function GUI标签:初始化()
self._rect = {}
end
function GUI标签:置可见(...)
GUI控件.置可见(self, ...)
for _, b in ipairs(self.子控件) do
if ggetype(b) == 'GUI单选按钮' and b.是否选中 then
for k, v in pairs(self._rect) do
v:置可见(k == b)
end
break
end
end
end
function GUI标签:创建区域(btn, x, y, w, h)
local name = btn.名称 .. '区域'
assert(not self[name], name .. ':此控件已存在,不能重复创建.')
local r = GUI控件(name, x, y, w, h, self)
table.insert(self.子控件, 1, r) --插到按钮前
local 置选中 = btn.置选中
btn.置选中 = function(this, v) --替换按钮选中事件
if v then
for k, v in pairs(self._rect) do
v:置可见(k == btn)
end
置选中(this, v)
end
end
self._rect[btn] = r
self[name] = r
return r
end
function GUI控件:创建标签(name, x, y, w, h)
assert(not self[name], name .. ':此标签已存在,不能重复创建.')
self[name] = GUI标签(name, x, y, w, h, self)
table.insert(self.子控件, self[name])
return self[name]
end
return GUI标签
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
-- @Author : GGELUA
-- @Date : 2021-09-17 08:26:43
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-11-25 08:55:05
local string = string
local _ENV = require 'ghpsocket.hpsocket'
function 取版本()
local v = GetHPSocketVersion()
return string.format('%d.%d.%d.%d', v >> 24, v >> 16 & 255, v >> 8 & 255, v & 255)
end
function 取主机地址(host)
return GetIPAddress(host)
end
function 枚举主机地址(host)
return EnumHostIPAddresses(host)
end
SS_STARTING = '正在启动'
SS_STARTED = '已经启动'
SS_STOPPING = '正在停止'
SS_STOPPED = '已经停止'
SO_UNKNOWN = '未知'
SO_ACCEPT = '接受'
SO_CONNECT = '连接'
SO_SEND = '发送'
SO_RECEIVE = '接收'
SO_CLOSE = '关闭'
return _ENV
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
-- @Author : GGELUA
-- @Date : 2021-09-01 21:04:09
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-11 22:09:04
local im = require"gimgui"
local IM控件 = require 'IMGUI.控件'
local IM列表 = class('IM列表',IM控件)
function IM列表:初始化()
self[1] = true
end
function IM列表:更新()
end
return IM列表
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
-- @Author : GGELUA
-- @Date : 2021-09-01 21:04:09
-- @Last Modified by: baidwwy
-- @Last Modified time: 2021-12-11 17:24:13
local im = require 'gimgui'
local IM控件 = require 'IMGUI.控件'
local IM提示 = class('IM提示', IM控件)
function IM提示:初始化()
end
function IM提示:更新()
im.BeginTooltip()
IM控件.更新(self)
im.EndTooltip()
end
function IM控件:创建提示(name, ...)
self[name] = IM提示(name, ...)
table.insert(self._子控件, self[name])
return self[name]
end
return IM提示
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册