Compare commits

...

5 Commits

Author SHA1 Message Date
bell07 580508fa37 Fix showing up complex images
Some complex texture strings contains [ character that needs to be escaped.
Issue found with [halloween](https://github.com/GreenXenith/halloween) preview texture on player tab page button in smart_inventory. The button was dissapeared, after this change visible again.
2018-08-27 20:15:55 +01:00
bell07 72107bc648 Clean up state and add validation 2018-01-26 16:12:27 +00:00
bell07 a115299266 Update API.md
Format header lines
2018-01-26 16:11:35 +00:00
bell07 602245d13a Make "smartfs_name" in nodemeta private 2018-01-26 16:09:35 +00:00
Alexander Weber 99e8809ffd rename inventory's location to invlocation to avoid confusion with state location 2017-11-01 15:09:59 +00:00
2 changed files with 57 additions and 41 deletions

View File

@ -1,5 +1,5 @@
#Full API
##Smartfs
# Full API
## Smartfs
* smartfs( name ) - returns the form regisered with the name 'name'
* smartfs.create( name,function ) - creates a new form and adds elements to it by running the function. Use before Minetest loads. (like minetest.register_node)
* smartfs.element( name, data ) - creates a new element type.
@ -10,21 +10,21 @@
* smartfs.override_load_checks() - Allows you to use smartfs.create after the game loads. Not recommended!
* smartfs.nodemeta_on_receive_fields(nodepos, formname, fields, sender) - on_receive_fields callback can be used in minetest.register_node for nodemeta forms
##Form
## Form
* form:show( playername [, parameters] ) - shows the form to a player. See state.param.
* form.name - the name of the form.
* form:attach_to_node(nodepos, params) - Attach a form to a node meta (usable in register_node's constructor, on_placenode, or dynamically)
##Supported locations
## Supported locations
* unified_inventory or inventory_plus plugins - assigned by smartfs.add_to_inventory() - auto-detection which inventory should be used
* player / show_formspec() - used for form:show(player)
* (main) inventory - assigned by smartfs.set_player_inventory()
* nodemeta - assigned by form:attach_to_node(nodepos, params)
* container - used internally for state:container()
##State
## State
###Methods
### Methods
* state:size( width,height ) - sets the forms width and height.
* state:get( name ) - gets an element by name.
* state:show() - reshows the form to the player.
@ -53,7 +53,7 @@
* state:view(x,y,name) - Add a virtual container (view). element coordinates are ablsolute to the parent view
* state:element( element_type, data ) - Semi-private, create an element with type and data.
###Variables
### Variables
* state.players - Object to handle players connected to the formspec
* state.players:connect(playername) - register player is viewing the formspec (should be used only by framework)
* state.players:disconnect(playername) - remove player from active viewers (should be used only by framework)
@ -65,9 +65,9 @@
* state.location.player - the assigned player ("player" and "inventory" only)
* state.location.pos - the assigned node position ("nodemeta" only)
##State Elements
## State Elements
###All elements / abstract
### All elements / abstract
* element:setPosition( x,y ) - change the position
* element:getPosition() - get the current position
* element:setSize( w,h ) - set the size
@ -80,7 +80,7 @@
* element:setTooltip(text) - set the tooltip for the button
* element:getTooltip() - get the current tooltip
###Button
### Button
* element:setText( text ) - set the caption of the button
* element:getText() - get the caption of the button
* element:setImage( filename ) - sets the background of the button
@ -91,26 +91,26 @@
* element:getClose() - get the current close setting
* element:click( func(self,state,playername) ) - specify a function to run when the button is clicked (equal to onClick)
###Toggle Button
### Toggle Button
* element:getText() - get the text of the toggle option
* element:setId( filename ) - sets the selected id
* element:getId() - get the selected id
* element:onToggle( func(self,state,playername) ) - specify a function to run when the value if toggled
###Label
### Label
* element:setText( text ) - set the caption of the label
* element:getText() - get the caption of the label
###Image and Background
### Image and Background
* element:setImage( image ) - set image
* element:getImage() - get the image
###Checkbox
### Checkbox
* element:setValue( bool ) - set the value
* element:getValue() - get the value
* element:onToggle( func(self,state,playername) ) - specify a function to run when the value if toggled
###Field and Text Area
### Field and Text Area
* element:setText( text ) - set the caption of the button
* element:getText() - get the caption of the field
* element:isPassword() - returns true if the field is a password field
@ -119,7 +119,7 @@
* element:getCloseOnEnter() - Get the field_close_on_enter value
* element:onKeyEnter(func(self, state, playername) - process the Enter key action for this fiels
###List box
### List box
* element:onClick( func(self,state,idx,playername) ) - function to run when listbox item idx is clicked
* element:onDoubleClick( func(self,state,idx,playername) ) - function to run when listbox item idx is double clicked
* element:addItem( item ) - appends and item - returns the index for the item
@ -131,7 +131,7 @@
* element:getSelected() - get selected item (index)
* element:getSelectedItem() - get selected item (value)
###Drop Down list
### Drop Down list
* element:onSelect( func(self,state,field,playername) ) - function to run when dropdown entry selected
* element:addItem( item ) - appends and item
* element:removeItem( idx ) - remove item
@ -142,7 +142,7 @@
* element:getSelected() - get selected item (index)
* element:getSelectedItem() - get selected item (value)
###Inventory listing
### Inventory listing
* element:setLocation( location ) - set a custom inventory location or nil for the default (current_player)
* element:usePosition( position ) - use a node metadata attached inventory of the node at the given positon
* element:useDetached( name ) - use a detached inventory with the given name
@ -151,11 +151,11 @@
* element:setIndex( index ) - set the inventory starting index
* element:getIndex() - returns the inventory starting index
###Custom Code
### Custom Code
* element:onSubmit( func(self) ) - on form submit
* element:onBuild( func(self) ) - run every time form is shown. You can set code from here
* element:setCode( code ) - set the formspec code
* element:getCode( code ) - get the formspec code
###Container/View
### Container/View
* element:getContainerState() - returns the container's sub-state to work with or add container elements

View File

@ -187,7 +187,9 @@ smartfs._ldef.player = {
minetest.after(0, function(state)
if state then
state._show_queued = nil
minetest.show_formspec(state.location.player, state.def.name, state:_buildFormspec_(true))
if (not state.closed) and (not state.obsolete) then
minetest.show_formspec(state.location.player, state.def.name, state:_buildFormspec_(true))
end
end
end, state) -- state given as reference. Maybe additional updates are done in the meantime or the form is obsolete
end
@ -213,6 +215,7 @@ smartfs._ldef.inventory = {
end)
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
smartfs.inv[name].obsolete = true
smartfs.inv[name] = nil
end)
end,
@ -252,6 +255,7 @@ smartfs._ldef.nodemeta = {
local meta = minetest.get_meta(state.location.pos)
meta:set_string("formspec", state:_buildFormspec_(true))
meta:set_string("smartfs_name", state.def.name)
meta:mark_as_private("smartfs_name")
end
end, state)
end
@ -293,9 +297,13 @@ function smartfs.nodemeta_on_receive_fields(nodepos, formname, fields, sender, p
local state
local form = smartfs.get(nodeform)
if not smartfs.opened[opened_id] or -- If opened first time
smartfs.opened[opened_id].def.name ~= nodeform then -- Or form is changed
smartfs.opened[opened_id].def.name ~= nodeform or -- Or form is changed
smartfs.opened[opened_id].obsolete then
local statelocation = smartfs._ldef.nodemeta._make_state_location_(nodepos)
state = smartfs._makeState_(form, params, statelocation)
if smartfs.opened[opened_id] then
smartfs.opened[opened_id].obsolete = true
end
smartfs.opened[opened_id] = state
form.form_setup_callback(state)
else
@ -313,7 +321,7 @@ function smartfs.nodemeta_on_receive_fields(nodepos, formname, fields, sender, p
state:_sfs_on_receive_fields_(name, fields)
-- Reset form if all players disconnected
if sender and not state.players:get_first() then
if sender and not state.players:get_first() and not state.obsolete then
local statelocation = smartfs._ldef.nodemeta._make_state_location_(nodepos)
local resetstate = smartfs._makeState_(form, params, statelocation)
if form.form_setup_callback(resetstate) ~= false then
@ -331,9 +339,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if smartfs.opened[name] and smartfs.opened[name].location.type == "player" then
if smartfs.opened[name].def.name == formname then
local state = smartfs.opened[name]
return state:_sfs_on_receive_fields_(name, fields)
else
smartfs.opened[name] = nil
state:_sfs_on_receive_fields_(name, fields)
-- disconnect player if form closed
if not state.players:get_first() then
smartfs.opened[name].obsolete = true
smartfs.opened[name] = nil
end
end
elseif smartfs.inv[name] and smartfs.inv[name].location.type == "inventory" then
local state = smartfs.inv[name]
@ -359,6 +371,9 @@ function smartfs._show_(form, name, params)
local statelocation = smartfs._ldef.player._make_state_location_(name)
local state = smartfs._makeState_(form, params, statelocation, name)
if form.form_setup_callback(state) ~= false then
if smartfs.opened[name] then -- set maybe previous form to obsolete
smartfs.opened[name].obsolete = true
end
smartfs.opened[name] = state
state:show()
end
@ -375,6 +390,10 @@ function smartfs._attach_to_node_(form, nodepos, params)
local statelocation = smartfs._ldef.nodemeta._make_state_location_(nodepos)
local state = smartfs._makeState_(form, params, statelocation)
if form.form_setup_callback(state) ~= false then
local opened_id = minetest.pos_to_string(nodepos)
if smartfs.opened[opened_id] then -- set maybe previous form to obsolete
smartfs.opened[opened_id].obsolete = true
end
state:show()
end
return state
@ -517,14 +536,11 @@ function smartfs._makeState_(form, params, location, newplayer)
end
end
if not fields.quit and not self.closed then
if not fields.quit and not self.closed and not self.obsolete then
self:show()
else
self.players:disconnect(player)
if self.location.type == "player" then
smartfs.opened[player] = nil
end
if not fields.quit and self.closed then
if not fields.quit and self.closed and not self.obsolete then
--closed by application (without fields.quit). currently not supported, see: https://github.com/minetest/minetest/pull/4675
minetest.show_formspec(player,"","size[5,1]label[0,0;Formspec closing not yet created!]")
end
@ -869,7 +885,7 @@ smartfs.element("button", {
self.data.pos.x..","..self.data.pos.y..";"..
self.data.size.w..","..self.data.size.h..";"
if self.data.image then
specstring = specstring..self.data.image..";"
specstring = specstring..minetest.formspec_escape(self.data.image)..";"
elseif self.data.item then
specstring = specstring..self.data.item..";"
end
@ -1080,7 +1096,7 @@ smartfs.element("image", {
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.data.value..
minetest.formspec_escape(self.data.value)..
"]"
else
return "image["..
@ -1088,7 +1104,7 @@ smartfs.element("image", {
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.data.value..
minetest.formspec_escape(self.data.value)..
"]"
end
end,
@ -1299,7 +1315,7 @@ smartfs.element("inventory", {
end,
build = function(self)
return "list["..
(self.data.location or "current_player") ..
(self.data.invlocation or "current_player") ..
";"..
self.name.. --no namespacing
";"..
@ -1316,20 +1332,20 @@ smartfs.element("inventory", {
-- "nodemeta:<X>,<Y>,<Z>": Any node metadata
-- "detached:<name>": A detached inventory
-- "context" does not apply to smartfs, since there is no node-metadata as context available
setLocation = function(self,location)
self.data.location = location
setLocation = function(self,invlocation)
self.data.invlocation = invlocation
end,
getLocation = function(self)
return self.data.location or "current_player"
return self.data.invlocation or "current_player"
end,
usePosition = function(self, pos)
self.data.location = string.format("nodemeta:%d,%d,%d", pos.x, pos.y, pos.z)
self.data.invlocation = string.format("nodemeta:%d,%d,%d", pos.x, pos.y, pos.z)
end,
usePlayer = function(self, name)
self.data.location = "player:" .. name
self.data.invlocation = "player:" .. name
end,
useDetached = function(self, name)
self.data.location = "detached:" .. name
self.data.invlocation = "detached:" .. name
end,
setIndex = function(self,index)
self.data.index = index