add table library; fix lineends and tabs; some fixes in widget(table.remove instead of table[n] = nil); a test "every-frame rect render" for gui
This commit is contained in:
parent
79fe7d2ab6
commit
b26085efb4
@ -1,28 +1,25 @@
|
|||||||
|
|
||||||
Basic goals:
|
Basic goals:
|
||||||
1. Layout compiler
|
1. Layout compiler
|
||||||
Three stages of support:
|
Three stages of support:
|
||||||
Absolute positioning and alignment
|
Absolute positioning and alignment
|
||||||
Relative positioning and alignment
|
Relative positioning and alignment
|
||||||
Packing + reflow
|
Packing + reflow
|
||||||
Packing is considerably more complex than the first two but has huge benefits.
|
Packing is considerably more complex than the first two but has huge benefits.
|
||||||
Compilation on existing widgets should be allowed, and parameters should be adjustable via funcpointers
|
Compilation on existing widgets should be allowed, and parameters should be adjustable via funcpointers
|
||||||
(so that tweening is possible)
|
(so that tweening is possible)
|
||||||
2. Event model
|
2. Event model
|
||||||
Click (down+up)
|
Click (down+up)
|
||||||
Slide (down-hold-up)
|
Slide (down-hold-up)
|
||||||
Raw down, raw up
|
Raw down, raw up
|
||||||
Rectangle collision detection
|
Rectangle collision detection
|
||||||
3. Widgets
|
3. Widgets
|
||||||
Button
|
Button
|
||||||
Modal button
|
Modal button
|
||||||
Label text
|
Label text
|
||||||
Paragraph text
|
Paragraph text
|
||||||
Markdown(or similar) text
|
Markdown(or similar) text
|
||||||
Slider
|
Slider
|
||||||
Checkbox
|
Checkbox
|
||||||
Frame + clipping
|
Frame + clipping
|
||||||
Color picker
|
Color picker
|
||||||
|
|
||||||
**************************************Make sure this is a unix-format textfile**************************
|
|
||||||
|
|
4
lua.c
4
lua.c
@ -163,11 +163,13 @@ void icelua_loadbasefuncs(lua_State *L)
|
|||||||
lua_pushcfunction(L, luaopen_base);
|
lua_pushcfunction(L, luaopen_base);
|
||||||
lua_call(L, 0, 0);
|
lua_call(L, 0, 0);
|
||||||
|
|
||||||
// here's the other two
|
// here's the other three
|
||||||
lua_pushcfunction(L, luaopen_string);
|
lua_pushcfunction(L, luaopen_string);
|
||||||
lua_call(L, 0, 0);
|
lua_call(L, 0, 0);
|
||||||
lua_pushcfunction(L, luaopen_math);
|
lua_pushcfunction(L, luaopen_math);
|
||||||
lua_call(L, 0, 0);
|
lua_call(L, 0, 0);
|
||||||
|
lua_pushcfunction(L, luaopen_table);
|
||||||
|
lua_call(L, 0, 0);
|
||||||
|
|
||||||
// overwrite dofile/loadfile.
|
// overwrite dofile/loadfile.
|
||||||
lua_pushcfunction(L, icelua_fn_base_loadfile);
|
lua_pushcfunction(L, icelua_fn_base_loadfile);
|
||||||
|
@ -601,6 +601,7 @@ function client.hook_render()
|
|||||||
if players and players[players.current] then
|
if players and players[players.current] then
|
||||||
players[players.current].show_hud()
|
players[players.current].show_hud()
|
||||||
end
|
end
|
||||||
|
gui_rect_frame_test()
|
||||||
end
|
end
|
||||||
|
|
||||||
client.hook_tick = h_tick_init
|
client.hook_tick = h_tick_init
|
||||||
|
@ -28,29 +28,29 @@ DIR_PKG_MAP = DIR_PKG_MAP or "pkg/maps"
|
|||||||
MAP_DEFAULT = MAP_DEFAULT or DIR_PKG_MAP.."/mesa.vxl"
|
MAP_DEFAULT = MAP_DEFAULT or DIR_PKG_MAP.."/mesa.vxl"
|
||||||
|
|
||||||
LIB_LIST = LIB_LIST or {
|
LIB_LIST = LIB_LIST or {
|
||||||
DIR_PKG_LIB.."/icegui/widgets.lua",
|
DIR_PKG_LIB.."/icegui/widgets.lua",
|
||||||
|
|
||||||
DIR_PKG_LIB.."/lib_bits.lua",
|
DIR_PKG_LIB.."/lib_bits.lua",
|
||||||
DIR_PKG_LIB.."/lib_collect.lua",
|
DIR_PKG_LIB.."/lib_collect.lua",
|
||||||
DIR_PKG_LIB.."/lib_gui.lua",
|
DIR_PKG_LIB.."/lib_gui.lua",
|
||||||
DIR_PKG_LIB.."/lib_map.lua",
|
DIR_PKG_LIB.."/lib_map.lua",
|
||||||
DIR_PKG_LIB.."/lib_namegen.lua",
|
DIR_PKG_LIB.."/lib_namegen.lua",
|
||||||
DIR_PKG_LIB.."/lib_pmf.lua",
|
DIR_PKG_LIB.."/lib_pmf.lua",
|
||||||
DIR_PKG_LIB.."/lib_sdlkey.lua",
|
DIR_PKG_LIB.."/lib_sdlkey.lua",
|
||||||
DIR_PKG_LIB.."/lib_util.lua",
|
DIR_PKG_LIB.."/lib_util.lua",
|
||||||
DIR_PKG_LIB.."/lib_vector.lua",
|
DIR_PKG_LIB.."/lib_vector.lua",
|
||||||
|
|
||||||
DIR_PKG_LIB.."/obj_player.lua",
|
DIR_PKG_LIB.."/obj_player.lua",
|
||||||
DIR_PKG_LIB.."/obj_intent.lua",
|
DIR_PKG_LIB.."/obj_intent.lua",
|
||||||
}
|
}
|
||||||
|
|
||||||
-- load libs
|
-- load libs
|
||||||
local i
|
local i
|
||||||
for i=1,#LIB_LIST do
|
for i=1,#LIB_LIST do
|
||||||
local asdf_qwerty = i
|
local asdf_qwerty = i
|
||||||
i = nil
|
i = nil
|
||||||
dofile(LIB_LIST[asdf_qwerty])
|
dofile(LIB_LIST[asdf_qwerty])
|
||||||
i = asdf_qwerty
|
i = asdf_qwerty
|
||||||
end
|
end
|
||||||
i = nil
|
i = nil
|
||||||
|
|
||||||
@ -93,184 +93,184 @@ WPN_RIFLE = 1
|
|||||||
weapon_models = {}
|
weapon_models = {}
|
||||||
|
|
||||||
weapons = {
|
weapons = {
|
||||||
[WPN_RIFLE] = function (plr)
|
[WPN_RIFLE] = function (plr)
|
||||||
local this = {} this.this = this
|
local this = {} this.this = this
|
||||||
|
|
||||||
this.cfg = {
|
this.cfg = {
|
||||||
dmg = {
|
dmg = {
|
||||||
head = 100,
|
head = 100,
|
||||||
body = 49,
|
body = 49,
|
||||||
legs = 33,
|
legs = 33,
|
||||||
},
|
},
|
||||||
|
|
||||||
ammo_clip = 10,
|
ammo_clip = 10,
|
||||||
ammo_reserve = 50,
|
ammo_reserve = 50,
|
||||||
time_fire = 1/2,
|
time_fire = 1/2,
|
||||||
time_reload = 2.5,
|
time_reload = 2.5,
|
||||||
|
|
||||||
recoil_x = 0.0001,
|
recoil_x = 0.0001,
|
||||||
recoil_y = -0.05,
|
recoil_y = -0.05,
|
||||||
|
|
||||||
name = "Rifle"
|
name = "Rifle"
|
||||||
}
|
}
|
||||||
|
|
||||||
function this.restock()
|
function this.restock()
|
||||||
this.ammo_clip = this.cfg.ammo_clip
|
this.ammo_clip = this.cfg.ammo_clip
|
||||||
this.ammo_reserve = this.cfg.ammo_reserve
|
this.ammo_reserve = this.cfg.ammo_reserve
|
||||||
end
|
end
|
||||||
|
|
||||||
function this.reset()
|
function this.reset()
|
||||||
this.t_fire = nil
|
this.t_fire = nil
|
||||||
this.t_reload = nil
|
this.t_reload = nil
|
||||||
this.reloading = false
|
this.reloading = false
|
||||||
this.restock()
|
this.restock()
|
||||||
end
|
end
|
||||||
|
|
||||||
this.reset()
|
this.reset()
|
||||||
|
|
||||||
local function prv_fire(sec_current)
|
local function prv_fire(sec_current)
|
||||||
local sya = math.sin(plr.angy)
|
local sya = math.sin(plr.angy)
|
||||||
local cya = math.cos(plr.angy)
|
local cya = math.cos(plr.angy)
|
||||||
local sxa = math.sin(plr.angx)
|
local sxa = math.sin(plr.angx)
|
||||||
local cxa = math.cos(plr.angx)
|
local cxa = math.cos(plr.angx)
|
||||||
local fwx,fwy,fwz
|
local fwx,fwy,fwz
|
||||||
fwx,fwy,fwz = sya*cxa, sxa, cya*cxa
|
fwx,fwy,fwz = sya*cxa, sxa, cya*cxa
|
||||||
|
|
||||||
-- perform a trace
|
-- perform a trace
|
||||||
local d,cx1,cy1,cz1,cx2,cy2,cz2
|
local d,cx1,cy1,cz1,cx2,cy2,cz2
|
||||||
d,cx1,cy1,cz1,cx2,cy2,cz2
|
d,cx1,cy1,cz1,cx2,cy2,cz2
|
||||||
= trace_map_ray_dist(plr.x+sya*0.4,plr.y,plr.z+cya*0.4, fwx,fwy,fwz, 127.5)
|
= trace_map_ray_dist(plr.x+sya*0.4,plr.y,plr.z+cya*0.4, fwx,fwy,fwz, 127.5)
|
||||||
d = d or 127.5
|
d = d or 127.5
|
||||||
|
|
||||||
-- see if there's anyone we can kill
|
-- see if there's anyone we can kill
|
||||||
local hurt_idx = nil
|
local hurt_idx = nil
|
||||||
local hurt_part = nil
|
local hurt_part = nil
|
||||||
local hurt_dist = d*d
|
local hurt_dist = d*d
|
||||||
local i,j
|
local i,j
|
||||||
|
|
||||||
for i=1,players.max do
|
for i=1,players.max do
|
||||||
local p = players[i]
|
local p = players[i]
|
||||||
if p and p ~= plr and p.alive then
|
if p and p ~= plr and p.alive then
|
||||||
local dx = p.x-plr.x
|
local dx = p.x-plr.x
|
||||||
local dy = p.y-plr.y+0.1
|
local dy = p.y-plr.y+0.1
|
||||||
local dz = p.z-plr.z
|
local dz = p.z-plr.z
|
||||||
|
|
||||||
for j=1,3 do
|
for j=1,3 do
|
||||||
local dd = dx*dx+dy*dy+dz*dz
|
local dd = dx*dx+dy*dy+dz*dz
|
||||||
|
|
||||||
local dotk = dx*fwx+dy*fwy+dz*fwz
|
local dotk = dx*fwx+dy*fwy+dz*fwz
|
||||||
local dot = math.sqrt(dd-dotk*dotk)
|
local dot = math.sqrt(dd-dotk*dotk)
|
||||||
if dot < 0.55 and dd < hurt_dist then
|
if dot < 0.55 and dd < hurt_dist then
|
||||||
hurt_idx = i
|
hurt_idx = i
|
||||||
hurt_dist = dd
|
hurt_dist = dd
|
||||||
hurt_part = ({"head","body","legs"})[j]
|
hurt_part = ({"head","body","legs"})[j]
|
||||||
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
dy = dy + 1.0
|
dy = dy + 1.0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if hurt_idx then
|
if hurt_idx then
|
||||||
-- TODO: ship this off to the server!
|
-- TODO: ship this off to the server!
|
||||||
players[hurt_idx].gun_damage(
|
players[hurt_idx].gun_damage(
|
||||||
hurt_part, this.cfg.dmg[hurt_part], plr)
|
hurt_part, this.cfg.dmg[hurt_part], plr)
|
||||||
elseif cx2 then
|
elseif cx2 then
|
||||||
-- TODO: block health rather than instant block removal
|
-- TODO: block health rather than instant block removal
|
||||||
map_block_break(cx2,cy2,cz2)
|
map_block_break(cx2,cy2,cz2)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO: fire a tracer
|
-- TODO: fire a tracer
|
||||||
|
|
||||||
-- apply recoil
|
-- apply recoil
|
||||||
-- attempting to emulate classic behaviour provided i have it right
|
-- attempting to emulate classic behaviour provided i have it right
|
||||||
plr.recoil(sec_current, this.cfg.recoil_y, this.cfg.recoil_x)
|
plr.recoil(sec_current, this.cfg.recoil_y, this.cfg.recoil_x)
|
||||||
end
|
end
|
||||||
|
|
||||||
function this.reload()
|
function this.reload()
|
||||||
if this.ammo_clip ~= this.cfg.ammo_clip then
|
if this.ammo_clip ~= this.cfg.ammo_clip then
|
||||||
if this.ammo_reserve ~= 0 then
|
if this.ammo_reserve ~= 0 then
|
||||||
if not this.reloading then
|
if not this.reloading then
|
||||||
this.reloading = true
|
this.reloading = true
|
||||||
plr.zooming = false
|
plr.zooming = false
|
||||||
this.t_reload = nil
|
this.t_reload = nil
|
||||||
end end end
|
end end end
|
||||||
end
|
end
|
||||||
|
|
||||||
function this.click(button, state)
|
function this.click(button, state)
|
||||||
if button == 1 then
|
if button == 1 then
|
||||||
-- LMB
|
-- LMB
|
||||||
if this.ammo_clip > 0 then
|
if this.ammo_clip > 0 then
|
||||||
this.firing = state
|
this.firing = state
|
||||||
else
|
else
|
||||||
this.firing = false
|
this.firing = false
|
||||||
-- TODO: play sound
|
-- TODO: play sound
|
||||||
end
|
end
|
||||||
elseif button == 3 then
|
elseif button == 3 then
|
||||||
-- RMB
|
-- RMB
|
||||||
if state and not this.reloading then
|
if state and not this.reloading then
|
||||||
plr.zooming = not plr.zooming
|
plr.zooming = not plr.zooming
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function this.get_model()
|
function this.get_model()
|
||||||
return weapon_models[WPN_RIFLE]
|
return weapon_models[WPN_RIFLE]
|
||||||
end
|
end
|
||||||
|
|
||||||
function this.draw(px, py, pz, ya, xa, ya2)
|
function this.draw(px, py, pz, ya, xa, ya2)
|
||||||
client.model_render_bone_global(this.get_model(), 0,
|
client.model_render_bone_global(this.get_model(), 0,
|
||||||
px, py, pz, ya, xa, ya2, 3)
|
px, py, pz, ya, xa, ya2, 3)
|
||||||
end
|
end
|
||||||
|
|
||||||
function this.tick(sec_current, sec_delta)
|
function this.tick(sec_current, sec_delta)
|
||||||
if this.reloading then
|
if this.reloading then
|
||||||
if not this.t_reload then
|
if not this.t_reload then
|
||||||
this.t_reload = sec_current + this.cfg.time_reload
|
this.t_reload = sec_current + this.cfg.time_reload
|
||||||
end
|
end
|
||||||
|
|
||||||
if sec_current >= this.t_reload then
|
if sec_current >= this.t_reload then
|
||||||
local adelta = this.cfg.ammo_clip - this.ammo_clip
|
local adelta = this.cfg.ammo_clip - this.ammo_clip
|
||||||
if adelta > this.ammo_reserve then
|
if adelta > this.ammo_reserve then
|
||||||
adelta = this.ammo_reserve
|
adelta = this.ammo_reserve
|
||||||
end
|
end
|
||||||
this.ammo_reserve = this.ammo_reserve - adelta
|
this.ammo_reserve = this.ammo_reserve - adelta
|
||||||
this.ammo_clip = this.ammo_clip + adelta
|
this.ammo_clip = this.ammo_clip + adelta
|
||||||
this.t_reload = nil
|
this.t_reload = nil
|
||||||
this.reloading = false
|
this.reloading = false
|
||||||
plr.arm_rest_right = 0
|
plr.arm_rest_right = 0
|
||||||
else
|
else
|
||||||
local tremain = this.t_reload - sec_current
|
local tremain = this.t_reload - sec_current
|
||||||
local telapsed = this.cfg.time_reload - tremain
|
local telapsed = this.cfg.time_reload - tremain
|
||||||
local roffs = math.min(tremain,telapsed)
|
local roffs = math.min(tremain,telapsed)
|
||||||
roffs = math.min(roffs,0.3)/0.3
|
roffs = math.min(roffs,0.3)/0.3
|
||||||
|
|
||||||
plr.arm_rest_right = roffs
|
plr.arm_rest_right = roffs
|
||||||
end
|
end
|
||||||
elseif this.firing and this.ammo_clip == 0 then
|
elseif this.firing and this.ammo_clip == 0 then
|
||||||
this.firing = false
|
this.firing = false
|
||||||
elseif this.firing and ((not this.t_fire) or sec_current >= this.t_fire) then
|
elseif this.firing and ((not this.t_fire) or sec_current >= this.t_fire) then
|
||||||
prv_fire(sec_current)
|
prv_fire(sec_current)
|
||||||
|
|
||||||
this.t_fire = this.t_fire or sec_current
|
this.t_fire = this.t_fire or sec_current
|
||||||
this.t_fire = this.t_fire + this.cfg.time_fire
|
this.t_fire = this.t_fire + this.cfg.time_fire
|
||||||
if this.t_fire < sec_current then
|
if this.t_fire < sec_current then
|
||||||
this.t_fire = sec_current
|
this.t_fire = sec_current
|
||||||
end
|
end
|
||||||
|
|
||||||
this.ammo_clip = this.ammo_clip - 1
|
this.ammo_clip = this.ammo_clip - 1
|
||||||
|
|
||||||
-- TODO: poll: do we want to require a new click per shot?
|
-- TODO: poll: do we want to require a new click per shot?
|
||||||
end
|
end
|
||||||
|
|
||||||
if this.t_fire and this.t_fire < sec_current then
|
if this.t_fire and this.t_fire < sec_current then
|
||||||
this.t_fire = nil
|
this.t_fire = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return this
|
return this
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
weapons_enabled = {}
|
weapons_enabled = {}
|
||||||
@ -278,50 +278,50 @@ weapons_enabled[WPN_RIFLE] = true
|
|||||||
|
|
||||||
-- teams
|
-- teams
|
||||||
teams = {
|
teams = {
|
||||||
[0] = {
|
[0] = {
|
||||||
name = "Blue Master Race",
|
name = "Blue Master Race",
|
||||||
color_mdl = {16,32,128},
|
color_mdl = {16,32,128},
|
||||||
color_chat = {0,0,255},
|
color_chat = {0,0,255},
|
||||||
},
|
},
|
||||||
[1] = {
|
[1] = {
|
||||||
name = "Green Master Race",
|
name = "Green Master Race",
|
||||||
color_mdl = {16,128,32},
|
color_mdl = {16,128,32},
|
||||||
color_chat = {0,192,0},
|
color_chat = {0,192,0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cpalette_base = {
|
cpalette_base = {
|
||||||
0x7F,0x7F,0x7F,
|
0x7F,0x7F,0x7F,
|
||||||
0xFF,0x00,0x00,
|
0xFF,0x00,0x00,
|
||||||
0xFF,0x7F,0x00,
|
0xFF,0x7F,0x00,
|
||||||
0xFF,0xFF,0x00,
|
0xFF,0xFF,0x00,
|
||||||
0x00,0xFF,0x00,
|
0x00,0xFF,0x00,
|
||||||
0x00,0xFF,0xFF,
|
0x00,0xFF,0xFF,
|
||||||
0x00,0x00,0xFF,
|
0x00,0x00,0xFF,
|
||||||
0xFF,0x00,0xFF,
|
0xFF,0x00,0xFF,
|
||||||
}
|
}
|
||||||
|
|
||||||
cpalette = {}
|
cpalette = {}
|
||||||
do
|
do
|
||||||
local i,j
|
local i,j
|
||||||
for i=0,7 do
|
for i=0,7 do
|
||||||
local r,g,b
|
local r,g,b
|
||||||
r = cpalette_base[i*3+1]
|
r = cpalette_base[i*3+1]
|
||||||
g = cpalette_base[i*3+2]
|
g = cpalette_base[i*3+2]
|
||||||
b = cpalette_base[i*3+3]
|
b = cpalette_base[i*3+3]
|
||||||
for j=0,3 do
|
for j=0,3 do
|
||||||
local cr = math.floor((r*j)/3)
|
local cr = math.floor((r*j)/3)
|
||||||
local cg = math.floor((g*j)/3)
|
local cg = math.floor((g*j)/3)
|
||||||
local cb = math.floor((b*j)/3)
|
local cb = math.floor((b*j)/3)
|
||||||
cpalette[#cpalette+1] = {cr,cg,cb}
|
cpalette[#cpalette+1] = {cr,cg,cb}
|
||||||
end
|
end
|
||||||
for j=1,4 do
|
for j=1,4 do
|
||||||
local cr = r + math.floor(((255-r)*j)/4)
|
local cr = r + math.floor(((255-r)*j)/4)
|
||||||
local cg = g + math.floor(((255-g)*j)/4)
|
local cg = g + math.floor(((255-g)*j)/4)
|
||||||
local cb = b + math.floor(((255-b)*j)/4)
|
local cb = b + math.floor(((255-b)*j)/4)
|
||||||
cpalette[#cpalette+1] = {cr,cg,cb}
|
cpalette[#cpalette+1] = {cr,cg,cb}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
damage_blk = {}
|
damage_blk = {}
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
-- look into actual drawing functionality!~
|
-- look into actual drawing functionality!~
|
||||||
|
-- the client drawing code requires manual memory management:
|
||||||
|
-- we have to allocate a buffer and draw pixels to it
|
||||||
|
-- this code can't deal with that problem...
|
||||||
|
-- lib_gui will have to provide a layer that takes the abstract APIs here and adds drawing functions
|
||||||
|
-- on top. the abstract API can assist by adding a "dirty" flag so that cache management is straightforward.
|
||||||
|
|
||||||
-- sketch listener and collision system:
|
-- sketch listener and collision system:
|
||||||
-- rect and layers detection (derive layers from hierarchy)
|
-- rect and layers detection (derive layers from hierarchy)
|
||||||
@ -11,6 +16,7 @@
|
|||||||
-- 3. iterate through the children, moving them to the positions and sizes desired as specified by the packing mode.
|
-- 3. iterate through the children, moving them to the positions and sizes desired as specified by the packing mode.
|
||||||
|
|
||||||
-- also something to note - when we draw we have to pass a clip rectangle upwards so that scrolling is possible.
|
-- also something to note - when we draw we have to pass a clip rectangle upwards so that scrolling is possible.
|
||||||
|
-- this isn't strictly necessary, but if the possibility is there, use it!
|
||||||
|
|
||||||
local P = {}
|
local P = {}
|
||||||
|
|
||||||
@ -18,106 +24,107 @@ local widget_mt = {}
|
|||||||
function widget_mt.__add(a, b) a.add_child(b) return a end
|
function widget_mt.__add(a, b) a.add_child(b) return a end
|
||||||
function widget_mt.__sub(a, b) a.remove_child(b) return a end
|
function widget_mt.__sub(a, b) a.remove_child(b) return a end
|
||||||
function widget_mt.__tostring(a)
|
function widget_mt.__tostring(a)
|
||||||
return a.x.."x "..a.y.."y "..a.relx().."rx "..a.rely().."ry"
|
return a.x.."x "..a.y.."y "..a.relx().."rx "..a.rely().."ry"
|
||||||
end
|
end
|
||||||
|
|
||||||
function P.widget(options)
|
function P.widget(options)
|
||||||
|
|
||||||
local this = {x = options.x or 0, y = options.y or 0,
|
local this = {x = options.x or 0, y = options.y or 0,
|
||||||
parent = options.parent or nil,
|
parent = options.parent or nil,
|
||||||
children = options.children or {},
|
children = options.children or {},
|
||||||
align_x = options.align_x or 0.5, align_y = options.align_y or 0.5}
|
align_x = options.align_x or 0.5, align_y = options.align_y or 0.5}
|
||||||
|
|
||||||
local width = options.width or 0
|
local width = options.width or 0
|
||||||
local height = options.height or 0
|
local height = options.height or 0
|
||||||
local margin_left = options.margin_left or 0
|
local margin_left = options.margin_left or 0
|
||||||
local margin_right = options.margin_right or 0
|
local margin_right = options.margin_right or 0
|
||||||
local margin_top = options.margin_top or 0
|
local margin_top = options.margin_top or 0
|
||||||
local margin_bottom = options.margin_bottom or 0
|
local margin_bottom = options.margin_bottom or 0
|
||||||
|
|
||||||
-- align 0 = top-left
|
-- align 0 = top-left
|
||||||
-- align 1 = bottom-right
|
-- align 1 = bottom-right
|
||||||
-- align 0.5 = center
|
-- align 0.5 = center
|
||||||
|
|
||||||
function this.width() return width end
|
function this.width() return width end
|
||||||
function this.height() return height end
|
function this.height() return height end
|
||||||
|
|
||||||
function this.margin_left() return margin_left end
|
function this.margin_left() return margin_left end
|
||||||
function this.margin_top() return margin_top end
|
function this.margin_top() return margin_top end
|
||||||
function this.margin_right() return margin_right end
|
function this.margin_right() return margin_right end
|
||||||
function this.margin_bottom() return margin_bottom end
|
function this.margin_bottom() return margin_bottom end
|
||||||
|
|
||||||
function this.min_width() return width end
|
function this.min_width() return width end
|
||||||
function this.min_height() return height end
|
function this.min_height() return height end
|
||||||
|
|
||||||
function this.relx()
|
function this.relx()
|
||||||
local pos = this.x - (this.width() * this.align_x)
|
local pos = this.x - (this.width() * this.align_x)
|
||||||
if this.parent == nil then return pos
|
if this.parent == nil then return pos
|
||||||
else return pos + this.parent.relx() end
|
else return pos + this.parent.relx() end
|
||||||
end
|
end
|
||||||
|
|
||||||
function this.rely()
|
function this.rely()
|
||||||
local pos = this.y - (this.height() * this.align_y)
|
local pos = this.y - (this.height() * this.align_y)
|
||||||
if this.parent == nil then return pos
|
if this.parent == nil then return pos
|
||||||
else return pos + this.parent.rely() end
|
else return pos + this.parent.rely() end
|
||||||
end
|
end
|
||||||
|
|
||||||
function this.l() return this.relx() end
|
function this.l() return this.relx() end
|
||||||
function this.t() return this.rely() end
|
function this.t() return this.rely() end
|
||||||
function this.r() return this.relx() + this.width() end
|
function this.r() return this.relx() + this.width() end
|
||||||
function this.b() return this.rely() + this.bottom() end
|
function this.b() return this.rely() + this.height() end
|
||||||
function this.cx() return this.relx() + this.width() * 0.5 end
|
function this.cx() return this.relx() + this.width() * 0.5 end
|
||||||
function this.cy() return this.rely() + this.height() * 0.5 end
|
function this.cy() return this.rely() + this.height() * 0.5 end
|
||||||
|
|
||||||
function this.inner()
|
function this.inner()
|
||||||
local l = this.l() + this.margin_left()
|
local l = this.l() + this.margin_left()
|
||||||
local t = this.t() + this.margin_top()
|
local t = this.t() + this.margin_top()
|
||||||
local r = this.r() - this.margin_right()
|
local r = this.r() - this.margin_right()
|
||||||
local b = this.b() - this.margin_bottom()
|
local b = this.b() - this.margin_bottom()
|
||||||
return {x=l, y=t, left=l, top=t, right=r, bottom=b,
|
return {x=l, y=t, left=l, top=t, right=r, bottom=b,
|
||||||
width=r-l, height=b-t, cx=l+(r-l)*0.5, cy=t+(b-t)*0.5}
|
width=r-l, height=b-t, cx=l+(r-l)*0.5, cy=t+(b-t)*0.5}
|
||||||
end
|
end
|
||||||
|
|
||||||
function this.detach() if this.parent then this.parent.children[this] = nil; this.parent = nil end end
|
function this.aabb(x, y, w, h)
|
||||||
function this.add_child(child) child.detach(); child.parent = this; this.children[child] = child end
|
return not (this.l()>x or this.r()<x+w or this.t()>y or this.b()<y+h)
|
||||||
function this.remove_child(child) child.detach() end
|
end
|
||||||
function this.remove_all_children() for k,child in pairs(this.children) do this.remove_child(child) end end
|
|
||||||
function this.set_parent(parent) this.detach(); this.parent = parent; parent.children[this] = this end
|
function this.collide(x, y, w, h)
|
||||||
function this.despawn()
|
-- very simple aabb collision for mousing. returns the "first and deepest child".
|
||||||
for k,child in pairs(this.children) do child.despawn() end this.remove_all_children()
|
w = w or 1
|
||||||
end
|
h = h or 1
|
||||||
|
local hit = this.aabb(x, y, w, h)
|
||||||
setmetatable(this, widget_mt)
|
local result = this
|
||||||
|
for k, v in pairs(this.children) do
|
||||||
|
result = v.collide(x, y, w, h) or this
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
function this.detach() if this.parent then table.remove(this.parent.children, this) this.parent = nil end end
|
||||||
|
function this.add_child(child) child.detach(); child.parent = this; this.children[child] = child end
|
||||||
|
function this.remove_child(child) child.detach() end
|
||||||
|
function this.remove_all_children() for k,child in pairs(this.children) do this.remove_child(child) end end
|
||||||
|
function this.set_parent(parent) this.detach(); this.parent = parent; parent.children[this] = this end
|
||||||
|
function this.despawn()
|
||||||
|
for k,child in pairs(this.children) do child.despawn() end this.remove_all_children()
|
||||||
|
end
|
||||||
|
|
||||||
|
setmetatable(this, widget_mt)
|
||||||
|
|
||||||
return this
|
return this
|
||||||
end
|
|
||||||
|
|
||||||
function P.widget_frame(x, y, width, height)
|
|
||||||
local w = widget{x=x, y=y, width=width, height=height}
|
|
||||||
|
|
||||||
-- presumably this is a drawing widget.
|
|
||||||
-- the key distinction between this API and the Flash monstrosity I made is that I can readily mix
|
|
||||||
-- drawing widgets and non-drawing widgets.
|
|
||||||
|
|
||||||
-- so then, if a packer is just another child, that means that it can inherit the size of the parent's inner.
|
|
||||||
-- but what the children "see" reported is what the packer wants to make available.
|
|
||||||
-- bottom-up traversal. Now I'm remembering this part.
|
|
||||||
-- most custom widgets use their reported width and height, and that's that, but packers don't.
|
|
||||||
|
|
||||||
return w
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if _REQUIREDNAME == nil then
|
if _REQUIREDNAME == nil then
|
||||||
widgets = P
|
widgets = P
|
||||||
else
|
else
|
||||||
_G[_REQUIREDNAME] = P
|
_G[_REQUIREDNAME] = P
|
||||||
end
|
end
|
||||||
|
|
||||||
local test = P.widget{x=100, y=100}
|
local test = P.widget{x=100, y=100, width=100, height=100}
|
||||||
print(test)
|
print(test)
|
||||||
local test2 = P.widget{x=100, y=100}
|
local test2 = P.widget{x=100, y=100, width=100, height=100}
|
||||||
print(test2)
|
|
||||||
test2.set_parent(test)
|
test2.set_parent(test)
|
||||||
print(test2)
|
print(test2)
|
||||||
|
print(test.collide(150,150))
|
||||||
|
|
||||||
return P
|
return P
|
@ -105,4 +105,17 @@ function gui_string_edit(str, maxlen, key, modif)
|
|||||||
|
|
||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function gui_rect_frame_test()
|
||||||
|
-- someday this will grow up to be a real rectangle renderer
|
||||||
|
local img = common.img_new(32, 32)
|
||||||
|
for x = 0, 31, 1 do
|
||||||
|
for y = 0, 31, 1 do
|
||||||
|
common.img_pixel_set(img, x, y, 0xFFFF0000)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
client.img_blit(img, 0, 0)
|
||||||
|
common.img_free(img)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user