Namespacing pt. 2

This commit is contained in:
2022-11-22 02:03:45 -05:00
parent b1fa8c6a75
commit 3c5b6ee4bc
485 changed files with 7 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
-- Form for chatcommand /streets
streets.forms.chatcmd = smartfs.create("streets:chatcmd", function(state)
state:load(streets.modpath .. "/forms/cmd_streets.smartfs")
end)

View File

@@ -0,0 +1 @@
return { ["ele"] = { ["streets:chatcmd_version"] = { ["type"] = "label", ["pos"] = { ["y"] = 1, ["x"] = 6.5 }, ["name"] = "streets:chatcmd_version", ["value"] = "Running version: 1.4.4dev" }, ["streets:chatcmd_guibg"] = { ["type"] = "code", ["name"] = "streets:chatcmd_guibg", ["code"] = "bgcolor[#080808BB;true]background[5,5;1,1;gui_formbg.png;true]" }, ["streets:chatcmd_modlist"] = { ["pos"] = { ["y"] = 1, ["x"] = 0 }, ["size"] = { ["h"] = 5, ["w"] = 6 }, ["type"] = "list", ["name"] = "streets:chatcmd_modlist", ["items"] = { "digilines installed: false", "mesecons installed: false", "moreblocks installed: false", "wool installed: true", "technic installed: false", "prefab installed: false", "awards installed: false" } } }, ["size"] = { ["h"] = 6, ["w"] = 10 } }

View File

@@ -0,0 +1,89 @@
--[[
StreetsMod 1.5 by webdesigner97:
License : CC-BY-SA 3.0 Unported (see license.txt)
Readme : see readme.txt
Forum : http://bit.ly/12cPMeo
Depends : default
]]
streets = {}
-- Kaeza intllib
-- Boilerplate to support localized strings if intllib mod is installed.
if minetest.get_modpath("intllib") then
streets.S = intllib.Getter()
else
streets.S = function(s) return s end
end
-- Create variable and tables
print("Streets: " .. streets.S("Creating variables and tables..."))
streets.version = "1.5"
streets.modpath = minetest.get_modpath("streetsmod")
streets.extendedBy = {}
streets.load = {
start = os.clock(),
fin = 0
}
streets.forms = {}
-- rubenwardy: smartfs
if not minetest.get_modpath("smartfs") then
dofile(streets.modpath .. "/libs/smartfs/smartfs.lua")
end
-- Load forms
dofile(streets.modpath .. "/forms.lua")
-- Check for mods which change this mod's beahaviour
print("Streets: " .. streets.S("Checking installed mods..."))
if minetest.get_modpath("wool") then
streets.extendedBy.wool = true
else
streets.extendedBy.wool = false
end
if minetest.get_modpath("technic") then
streets.extendedBy.technic = true
else
streets.extendedBy.technic = false
end
if minetest.get_modpath("moreblocks") then
streets.extendedBy.moreblocks = true
else
streets.extendedBy.moreblocks = false
end
if minetest.get_modpath("mesecons") then
streets.extendedBy.mesecons = true
else
streets.extendedBy.mesecons = false
end
if minetest.get_modpath("digilines") then
streets.extendedBy.digilines = true
else
streets.extendedBy.digilines = false
end
if minetest.get_modpath("prefab") then
streets.extendedBy.prefab = true
else
streets.extendedBy.prefab = false
end
if minetest.get_modpath("awards") then
streets.extendedBy.awards = true
else
streets.extendedBy.awards = false
end
-- Streets chatcommand
local function round(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
minetest.register_chatcommand("streets",{
description = streets.S("Check version of your installed StreetsMod and find information"),
func = function(name,param)
streets.forms.chatcmd:show(name);
end
})
-- Done
print("Streets: " .. streets.S("Setup completed, have fun with StreetsMod") .. " " .. streets.version .. "!")
streets.load.fin = os.clock()

View File

@@ -0,0 +1,22 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

View File

@@ -0,0 +1,215 @@
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
x64/
build/
[Bb]in/
[Oo]bj/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.Publish.xml
*.pubxml
# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
App_Data/*.mdf
App_Data/*.ldf
#############
## Windows detritus
#############
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac crap
.DS_Store
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist/
build/
eggs/
parts/
var/
sdist/
develop-eggs/
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg

View File

@@ -0,0 +1,88 @@
smartfs
=======
This mod provides a 2nd generation way of creating forms - this means that the modder does not need to worry about complex formspec strings
* Expandable: you can register your own elements to use on the form.
* Easy event handling: use binding to handle events.
* New elements: Includes a toggle button
License: WTFPL
To install this library, place the smartfs.lua file in your mod and then include it (dofile).
There is an init.lua file in the download that shows you how to do this.
#Using Smart Formspec
Smartfs provides 2nd generation Minetest forms to replace clunky formspec strings. Each smartfs form is a container filled with GUI elements. A number of default elements are included with smartfs, but modders can also define their own custom elements. This document describes the basic usage of the smartfs API.
##Installation
Smartfs can be used as a library or a mod.
To use smartfs as a library, copy the smartfs.lua file to your mod folder and add
dofile(minetest.get\_modpath(minetest.get\_current\_modname()).."/smartfs.lua")
to the top of any files that use it.
To use smartfs as a mod, add it to your game's mods folder or to the user mods folder and enable it.
## Creating and showing forms
A form is a rectangular area of the screen upon which all elements are placed. Use the smartfs.create() function to create a new form. This function takes two arguments and returns a form object.
The first argument is a unique string that identifies the form. The second argument is a function that should take a single argument called state which is used to set form properties like size and background color. State also has constructors for all form elements and can be used with state:element_name. Below is a quick example.
myform = smartfs.create("My Form",function(state)
--sets the form's size
-- (width, hieght)
state:size(5,5)
--creates a label and places it on the form
--(x-pos, y-pos, name, text)
state:label(3,3,"label1", "A label!")
end)
Forms can be shown to the player by using the show(target) function. The target argument is the name of the player that will see the form.
myform:show("singleplayer")
Here is a list of steps the library takes.
* You create a new form using smartfs.create().
* The form is registered and stored for later use.
* You show a form to a player using the myform:show()
* The state is created and stored.
* The function in smartfs.create runs and creates the elements.
* The form is displayed to the player.
## Modifying Elements
Elements have functions of the form element:function(args) where you need to have access to the element object.
You can get the element object by assigning a variable to its creation function like so:
local button1 = state:button(0,0, 1,4, "btn1", "A button")
--button1 is now a table representing the button
You can also get the element by using state:get(name). The example below will retrieve a button with the name "btn1":
button1 = state:get("btn1")
--or
state:get("btn1"):onClick(your\_onclick\_function
Both of these methods should be used inside the form creation callback function, the function you pass to smartfs.create, or in event callbacks.
Now that you have located your element you can modify it.
button1:setPos(4,0)
## Inventory Support
Smartfs supports adding a button to Inventory+ or Unified Inventory which will open one of your own custom forms. Use the smartfs.add\_to\_inventory(form, icon, title) function where form is the smartfs form linked to by the button, icon is the button image (only for unified inventory), and title is the button text (only for inventory+).
smartfs.add_to_inventory(form, icon, title)
## Dynamic forms
Dynamic forms allow you to make a form without having to register it before the game finished loading.
local state = smartfs.dynamic("smartfs:dyn_form", name)
state:load(minetest.get_modpath("smartfs").."/example.smartfs")
state:get("btn"):click(function(self,state)
print("Button clicked!")
end)
state:show()
Make sure you call state:show()

View File

@@ -0,0 +1,107 @@
#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.
* smartfs.dynamic( formname, playername ) - creates a dynamic form. Returns state. See example.lua for example. Remember to call state:show()
* smartfs.add\_to\_inventory(form, icon, title) - Adds a form to an installed advanced inventory. Returns true on success.
* smartfs.inventory_mod() - Returns the name of an installed and supported inventory mod that will be used above, or null.
* smartfs.override\_load\_checks() - Allows you to use smartfs.create after the game loads. Not recommended!
##Form
* form:show( playername [, parameters] ) - shows the form to a player. See state.param.
* form.name - the name of the form.
##State
### 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.
* state:close() - closes the form (does not work yet, due to no MT api support).
* state:load( filepath ) - Loads elements from a file.
* state:save( filepath ) - Saves elements to a file.
* state:button( x,y,w,h,name,text [, exit_on_click] ) - create a new button at x,y with name and caption (text)
* ^ optional: exit_on_click - set to true to exit the form when the button is clicked. ( Also see button.setClose() )
* state:toggle( x,y,w,h,name,list ) - create a new toggle button at x,y with name and possible list of values
* state:label( x,y,name,text ) - create a new label at x,y with name and caption (text)
* state:field( x,y,w,h,name,label ) - create a new field at x,y with label
* state:pwdfield( x,y,w,h,name,label ) - create a password field
* state:textarea( x,y,w,h,name,label ) - create a new textarea
* state:image( x,y,w,h,name,imagepath ) - create an image box.
* state:inventory( x,y,w,h,name ) - create an inventory listing (use 'main' as name for the main player inventory)
* state:checkbox( x,y,name,label,selected ) - create a check box.
* state:element( element_type, data ) - Semi-private, create an element with type and data.
### Variables
* state.player - The name of the player.
* state.param - The parameters supplied by form:show.
* state.def - The form definition.
* state.is_inv - Boolean which is true if this form is being shown as an inventory.
##Button
* element:setPosition( x,y ) - change the position
* element:getPosition() - get the current position
* element:setSize( w,h ) - set the size
* element:getSize() - get the size
* 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
* element:getImage() - get the background filename of the button
* element:click( func(self,state) ) - specify a function to run when the button is clicked
##Toggle Button
* element:setPosition( x,y ) - change the position
* element:getPosition() - get the current position
* element:setSize( w,h ) - set the size
* element:getSize() - get the size
* 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) ) - specify a function to run when the value if toggled
##Label
* element:setPosition( x,y ) - change the position
* element:getPosition() - get the current position
* element:setText( text ) - set the caption of the label
* element:getText() - get the caption of the label
##Field and Text Area
* element:setPosition( x,y ) - change the position
* element:getPosition() - get the current position
* element:setSize( w,h ) - set the size
* element:getSize() - get the size
* element:setText( text ) - set the caption of the button
* element:getText() - get the caption of the field
* element:setImage( filename ) - sets the background of the field
* element:getImage() - get the background filename of the field
##List box
* element:onClick( func(self,state,idx) ) - function to run when listbox item idx is clicked
* element:onDoubleClick( func(self,state,idx) ) - function to run when listbox item idx is double clicked
* element:setPosition( x,y ) - set the position
* element:getPosition() - returns {x=x, y=y}
* element:setSize( w,h ) - set the size
* element:getSize() - gets the size {w=w, h=h}
* element:addItem( item ) - appends and item
* element:removeItem( idx ) - remove item
* element:popItem() - removes last item and returns
##Inventory listing
* element:setPosition( x,y ) - set the position
* element:getPosition() - returns {x=x, y=y}
* element:setSize( w,h ) - set the size
* element:getSize() - gets the size {w=w, h=h}
* 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
* element:usePlayer( name ) - use a player inventory other than the current player
* element:getLocation() - returns the inventory location (default: current_player)
* element:setIndex( index ) - set the inventory starting index
* element:getIndex() - returns the inventory starting index
##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

View File

@@ -0,0 +1,2 @@
unified_inventory?
inventory_plus?

View File

@@ -0,0 +1,66 @@
dofile(minetest.get_modpath("smartfs").."/smartfs.lua")
s = smartfs.create("smartfs:form",function(state)
state:size(10,7)
state:label(2,0,"lbl","SmartFS example formspec!")
state:field(7,1,3,1,"txt","Textbox")
state:image(0,0,2,2,"img","default_stone.png")
state:toggle(0,2,3,1,"tg",{"plenty..","of..","custom..","elements"})
state:checkbox(2,1,"c","Easy code",true)
local res = "smartfs.create(\"smartfs:form\",function(state)\n"
res = res .. "\tstate:size(10,7)\n"
res = res .. "\tstate:label(2,0,\"lbl\",\"SmartFS example formspec!\")\n"
res = res .. "\tstate:field(7,1,3,1,\"txt\",\"Textbox\")\n"
res = res .. "\tstate:image(0,0,2,2,\"img\",\"default_stone.png\")\n"
res = res .. "\tstate:toggle(0,2,3,1,\"tg\",{\"plenty..\",\"of..\",\"custom..\",\"elements\"})\n"
res = res .. "\tstate:checkbox(2,1,\"c\",\"Easy code\",true)\n"
res = res .. "end)"
state:textarea(1,3.5,9,4,"ta","Code:"):setText(res)
return true
end)
l = smartfs.create("smartfs:load",function(state)
state:load(minetest.get_modpath("smartfs").."/example.smartfs")
state:get("btn"):click(function(self,state)
print("Button clicked!")
end)
return true
end)
smartfs.add_to_inventory(l,"icon.png","SmartFS")
minetest.register_chatcommand("sfs_s", {
params = "",
description = "SmartFS test formspec 1: basics",
func = function(name, param)
s:show(name)
end,
})
minetest.register_chatcommand("sfs_l", {
params = "",
description = "SmartFS test formspec 2: loading",
func = function(name, param)
l:show(name)
end,
})
minetest.register_chatcommand("sfs_d", {
params = "",
description = "SmartFS test formspec 3: dynamic",
func = function(name, param)
local state = smartfs.dynamic("smartfs:dyn_form", name)
state:load(minetest.get_modpath("smartfs").."/example.smartfs")
state:get("btn"):click(function(self,state)
print("Button clicked!")
end)
state:show()
end,
})
minetest.register_chatcommand("sfs_lc", {
params = "",
description = "SmartFS test formspec 4: smartfs.create error catching",
func = function(name, param)
smartfs.create("asdinas",function() end)
end
})

View File

@@ -0,0 +1 @@
return { ["ele"] = { ["c"] = { ["pos"] = { ["y"] = 1, ["x"] = 1 }, ["label"] = "Check", ["value"] = true, ["type"] = "checkbox", ["name"] = "c" }, ["btn"] = { ["pos"] = { ["y"] = 2, ["x"] = 1 }, ["size"] = { ["h"] = 1, ["w"] = 1 }, ["value"] = "Button", ["type"] = "button", ["name"] = "btn" } }, ["size"] = { ["h"] = 3, ["w"] = 5 } }

View File

@@ -0,0 +1,2 @@
dofile(minetest.get_modpath("smartfs").."/smartfs.lua")
--dofile(minetest.get_modpath("smartfs").."/example.lua")

View File

@@ -0,0 +1,760 @@
---------------------------
-- SmartFS: Smart Formspecs
-- by Rubenwardy
---------------------------
smartfs = {
_fdef = {},
_edef = {},
opened = {},
inv = {}
}
-- the smartfs() function
function smartfs.__call(self, name)
return smartfs._fdef[name]
end
-- Register forms and elements
function smartfs.create(name,onload)
if smartfs._fdef[name] then
error("SmartFS - (Error) Form "..name.." already exists!")
end
if smartfs.loaded and not smartfs._loaded_override then
error("SmartFS - (Error) Forms should be declared while the game loads.")
end
smartfs._fdef[name] = {
_reg = onload,
name = name,
show = smartfs._show_
}
return smartfs._fdef[name]
end
function smartfs.override_load_checks()
smartfs._loaded_override = true
end
minetest.after(0, function()
smartfs.loaded = true
end)
function smartfs.dynamic(name,player)
if not smartfs._dynamic_warned then
smartfs._dynamic_warned = true
print("SmartFS - (Warning) On the fly forms are being used. May cause bad things to happen")
end
local state = smartfs._makeState_({name=name},player,nil,false)
state.show = state._show_
smartfs.opened[player] = state
return state
end
function smartfs.element(name,data)
if smartfs._edef[name] then
error("SmartFS - (Error) Element type "..name.." already exists!")
end
smartfs._edef[name] = data
return smartfs._edef[name]
end
function smartfs.inventory_mod()
if unified_inventory then
return "unified_inventory"
elseif inventory_plus then
return "inventory_plus"
else
return nil
end
end
function smartfs.add_to_inventory(form,icon,title)
if unified_inventory then
unified_inventory.register_button(form.name, {
type = "image",
image = icon,
})
unified_inventory.register_page(form.name, {
get_formspec = function(player, formspec)
local name = player:get_player_name()
local opened = smartfs._show_(form, name, nil, true)
return {formspec = opened:_getFS_(false)}
end
})
return true
elseif inventory_plus then
minetest.register_on_joinplayer(function(player)
inventory_plus.register_button(player, form.name, title)
end)
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "" and fields[form.name] then
local name = player:get_player_name()
local opened = smartfs._show_(form, name, nil, true)
inventory_plus.set_inventory_formspec(player, opened:_getFS_(true))
end
end)
return true
else
return false
end
end
function smartfs._makeState_(form,player,params,is_inv)
return {
_ele = {},
def = form,
player = player,
param = params,
is_inv = is_inv,
get = function(self,name)
return self._ele[name]
end,
close = function(self)
self.closed = true
end,
size = function(self,w,h)
self._size = {w=w,h=h}
end,
_getFS_ = function(self,size)
local res = ""
if self._size and size then
res = "size["..self._size.w..","..self._size.h.."]"
end
for key,val in pairs(self._ele) do
res = res .. val:build()
end
return res
end,
_show_ = function(self)
if self.is_inv then
if unified_inventory then
unified_inventory.set_inventory_formspec(minetest.get_player_by_name(self.player), self.def.name)
elseif inventory_plus then
inventory_plus.set_inventory_formspec(minetest.get_player_by_name(self.player), self:_getFS_(true))
end
else
local res = self:_getFS_(true)
minetest.show_formspec(player,form.name,res)
end
end,
load = function(self,file)
local file = io.open(file, "r")
if file then
local table = minetest.deserialize(file:read("*all"))
if type(table) == "table" then
if table.size then
self._size = table.size
end
for key,val in pairs(table.ele) do
self:element(val.type,val)
end
return true
end
end
return false
end,
save = function(self,file)
local res = {ele={}}
if self._size then
res.size = self._size
end
for key,val in pairs(self._ele) do
res.ele[key] = val.data
end
local file = io.open(file, "w")
if file then
file:write(minetest.serialize(res))
file:close()
return true
end
return false
end,
button = function(self,x,y,w,h,name,text,exitf)
if exitf == nil then exitf = false end
return self:element("button",{pos={x=x,y=y},size={w=w,h=h},name=name,value=text,closes=exitf})
end,
label = function(self,x,y,name,text)
return self:element("label",{pos={x=x,y=y},name=name,value=text})
end,
toggle = function(self,x,y,w,h,name,list)
return self:element("toggle",{pos={x=x,y=y},size={w=w,h=h},name=name,id=1,list=list})
end,
field = function(self,x,y,w,h,name,label)
return self:element("field",{pos={x=x,y=y},size={w=w,h=h},name=name,value="",label=label})
end,
pwdfield = function(self,x,y,w,h,name,label)
local res = self:element("field",{pos={x=x,y=y},size={w=w,h=h},name=name,value="",label=label})
res:isPassword(true)
return res
end,
textarea = function(self,x,y,w,h,name,label)
local res = self:element("field",{pos={x=x,y=y},size={w=w,h=h},name=name,value="",label=label})
res:isMultiline(true)
return res
end,
image = function(self,x,y,w,h,name,img)
return self:element("image",{pos={x=x,y=y},size={w=w,h=h},name=name,value=img})
end,
checkbox = function(self,x,y,name,label,selected)
return self:element("checkbox",{pos={x=x,y=y},name=name,value=selected,label=label})
end,
listbox = function(self,x,y,w,h,name)
return self:element("list", { pos={x=x,y=y}, size={w=w,h=h}, name=name })
end,
inventory = function(self,x,y,w,h,name)
return self:element("inventory", { pos={x=x,y=y}, size={w=w,h=h}, name=name })
end,
element = function(self,typen,data)
local type = smartfs._edef[typen]
if not type then
error("Element type "..typen.." does not exist!")
end
if self._ele[data.name] then
error("Element "..data.name.." already exists")
end
data.type = typen
local ele = {
name = data.name,
root = self,
data = data,
remove = function(self)
self.root._ele[self.name] = nil
end
}
for key,val in pairs(type) do
ele[key] = val
end
self._ele[data.name] = ele
return self._ele[data.name]
end
}
end
-- Show a formspec to a user
function smartfs._show_(form, player, params, is_inv)
local state = smartfs._makeState_(form, player, params, is_inv)
state.show = state._show_
if form._reg(state)~=false then
if not is_inv then
smartfs.opened[player] = state
state:_show_()
else
smartfs.inv[player] = state
end
end
return state
end
-- Receive fields from formspec
local function _sfs_recieve_(state,name,fields)
if (fields.quit == "true") then
if not state.is_inv then
smartfs.opened[name] = nil
end
return true
end
for key,val in pairs(fields) do
if state._ele[key] then
state._ele[key].data.value = val
end
end
for key,val in pairs(state._ele) do
if val.submit then
if (val:submit(fields)==true) then
return true
end
end
end
if state.closed ~= true then
state:_show_()
else
minetest.show_formspec(name,"","size[5,1]label[0,0;Formspec closing not yet created!]")
if not state.is_inv then
smartfs.opened[name] = nil
end
end
return true
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
local name = player:get_player_name()
if smartfs.opened[name] and not smartfs.opened[name].is_inv then
if smartfs.opened[name].def.name == formname then
local state = smartfs.opened[name]
return _sfs_recieve_(state,name,fields)
else
smartfs.opened[name] = nil
end
elseif smartfs.inv[name] and smartfs.inv[name].is_inv then
local state = smartfs.inv[name]
_sfs_recieve_(state,name,fields)
end
return false
end)
-----------------------------------------------------------------
------------------------- ELEMENTS ----------------------------
-----------------------------------------------------------------
smartfs.element("button",{
build = function(self)
if self.data.img then
return "image_button["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.data.img..
";"..
self.name..
";"..
self.data.value..
"]"
else
if self.data.closes then
return "button_exit["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.name..
";"..
self.data.value..
"]"
else
return "button["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.name..
";"..
self.data.value..
"]"
end
end
end,
submit = function(self,fields,state)
if fields[self.name] and self._click then
self:_click(self.root)
end
if self.data.closes then
return true
end
end,
setPosition = function(self,x,y)
self.data.pos = {x=x,y=y}
end,
getPosition = function(self,x,y)
return self.data.pos
end,
setSize = function(self,w,h)
self.data.size = {w=w,h=h}
end,
getSize = function(self,x,y)
return self.data.size
end,
onClick = function(self,func)
self._click = func
end,
click = function(self,func)
self._click = func
end,
setText = function(self,text)
self.data.value = text
end,
getText = function(self)
return self.data.value
end,
setImage = function(self,image)
self.data.img = image
end,
getImage = function(self)
return self.data.img
end,
setClose = function(self,bool)
self.data.closes = bool
end
})
smartfs.element("toggle",{
build = function(self)
return "button["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.name..
";"..
self.data.list[self.data.id]..
"]"
end,
submit = function(self,fields)
if fields[self.name] then
self.data.id = self.data.id + 1
if self.data.id > #self.data.list then
self.data.id = 1
end
if self._tog then
self:_tog(self.root)
end
end
end,
onToggle = function(self,func)
self._tog = func
end,
setPosition = function(self,x,y)
self.data.pos = {x=x,y=y}
end,
getPosition = function(self,x,y)
return self.data.pos
end,
setSize = function(self,w,h)
self.data.size = {w=w,h=h}
end,
getSize = function(self,x,y)
return self.data.size
end,
setId = function(self,id)
self.data.id = id
end,
getId = function(self)
return self.data.id
end,
getText = function(self)
return self.data.list[self.data.id]
end
})
smartfs.element("label",{
build = function(self)
return "label["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.value..
"]"
end,
setPosition = function(self,x,y)
self.data.pos = {x=x,y=y}
end,
getPosition = function(self,x,y)
return self.data.pos
end,
setText = function(self,text)
self.data.value = text
end,
getText = function(self)
return self.data.value
end
})
smartfs.element("field",{
build = function(self)
if self.data.ml then
return "textarea["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.name..
";"..
self.data.label..
";"..
self.data.value..
"]"
elseif self.data.pwd then
return "pwdfield["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.name..
";"..
self.data.label..
"]"
else
return "field["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.name..
";"..
self.data.label..
";"..
self.data.value..
"]"
end
end,
setPosition = function(self,x,y)
self.data.pos = {x=x,y=y}
end,
getPosition = function(self,x,y)
return self.data.pos
end,
setSize = function(self,w,h)
self.data.size = {w=w,h=h}
end,
getSize = function(self,x,y)
return self.data.size
end,
setText = function(self,text)
self.data.value = text
end,
getText = function(self)
return self.data.value
end,
isPassword = function(self,bool)
self.data.pwd = bool
end,
isMultiline = function(self,bool)
self.data.ml = bool
end
})
smartfs.element("image",{
build = function(self)
return "image["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.data.value..
"]"
end,
setPosition = function(self,x,y)
self.data.pos = {x=x,y=y}
end,
getPosition = function(self,x,y)
return self.data.pos
end,
setSize = function(self,w,h)
self.data.size = {w=w,h=h}
end,
getSize = function(self,x,y)
return self.data.size
end,
setImage = function(self,text)
self.data.value = text
end,
getImage = function(self)
return self.data.value
end
})
smartfs.element("checkbox",{
build = function(self)
if self.data.value then
return "checkbox["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.name..
";"..
self.data.label..
";true]"
else
return "checkbox["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.name..
";"..
self.data.label..
";false]"
end
end,
setPosition = function(self,x,y)
self.data.pos = {x=x,y=y}
end,
getPosition = function(self,x,y)
return self.data.pos
end,
setSize = function(self,w,h)
self.data.size = {w=w,h=h}
end,
getSize = function(self,x,y)
return self.data.size
end,
setText = function(self,text)
self.data.value = text
end,
getText = function(self)
return self.data.value
end
})
smartfs.element("list",{
build = function(self)
local listformspec = "textlist["..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.size.w..","..self.data.size.h..
";"..
self.data.name..
";"
--loop through the list's items and add them to the formspec
if not self.data.items then
self.data.items = {" "}
end
for i,value in ipairs(self.data.items) do
listformspec = listformspec..value..","
end
listformspec = string.sub(listformspec, 0, -2) --removes extra ,
--close out the list items section
listformspec = listformspec..";"
--TODO support selected idx and transparency
--close formspec definition and return formspec
listformspec = listformspec.."]"
return listformspec
end,
submit = function(self,fields)
if fields[self.name] then
local _type = string.sub(fields[self.data.name],1,3)
local index = string.sub(fields[self.data.name],5)
if _type == "CHG" and self._click then
self:_click(self.root, index)
elseif _type == "DCL" and self._doubleClick then
self:_doubleClick(self.root, index)
end
end
end,
onClick = function(self, func)
self._click = func
end,
click = function(self, func)
self._click = func
end,
onDoubleClick = function(self, func)
self._doubleClick = func
end,
doubleclick = function(self, func)
self._doubleClick = func
end,
setPosition = function(self,x,y)
self.data.pos = {x=x,y=y}
end,
getPosition = function(self,x,y)
return self.data.pos
end,
setSize = function(self,w,h)
self.data.size = {w=w,h=h}
end,
getSize = function(self,x,y)
return self.data.size
end,
addItem = function(self, item)
if not self.data.items then
self.data.items = {" "}
end
table.insert(self.data.items, item)
end,
removeItem = function(self,idx)
if not self.data.items then
self.data.items = {" "}
end
table.remove(self.data.items,idx)
end,
popItem = function(self)
if not self.data.items then
self.data.items = {" "}
end
local item = self.data.items[#self.data.items]
table.remove(self.data.items)
return item
end
})
smartfs.element("inventory",{
build = function(self)
return "list["..
(self.data.location or "current_player") ..
";"..
self.name..
";"..
self.data.pos.x..","..self.data.pos.y..
";"..
self.data.size.w..","..self.data.size.h..
";"..
(self.data.index or "") ..
"]"
end,
setPosition = function(self,x,y)
self.data.pos = {x=x,y=y}
end,
getPosition = function(self,x,y)
return self.data.pos
end,
setSize = function(self,w,h)
self.data.size = {w=w,h=h}
end,
getSize = function(self,x,y)
return self.data.size
end,
-- available inventory locations
-- "current_player": Player to whom the menu is shown
-- "player:<name>": Any player
-- "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
end,
getLocation = function(self)
return self.data.location or "current_player"
end,
usePosition = function(self, pos)
self.data.location = string.format("nodemeta:%d,%d,%d", pos.x, pos.y, pos.z)
end,
usePlayer = function(self, name)
self.data.location = "player:" .. name
end,
useDetached = function(self, name)
self.data.location = "detached:" .. name
end,
setIndex = function(self,index)
self.data.index = index
end,
getIndex = function(self)
return self.data.index
end
})
smartfs.element("code",{
build = function(self)
if self._build then
self:_build()
end
return self.data.code
end,
submit = function(self,fields)
if self._sub then
self:_sub(fields)
end
end,
onSubmit = function(self,func)
self._sub = func
end,
onBuild = function(self,func)
self._build = func
end,
setCode = function(self,code)
self.data.code = code
end,
getCode = function(self)
return self.data.code
end
})

View File

@@ -0,0 +1,59 @@
# Translation file GERMAN
Setup completed, have fun with StreetsMod=Setup abgeschlossen, viel Spass mit StreetsMod
Creating variables and tables...=Erstelle Variablen und Tabellen...
Checking installed mods...=Ueberpruefe installierte Mods...
Check version of your installed StreetsMod and find information=Ueberpruefe die installierte StreetsMod Version und weitere Infos
Asphalt=Asphalt
Asphalt stair=Asphalt Treppe
Asphalt slab=Asphalt Platte
Construction fence=Bauzaun
Delineator=Leitpfosten
Emergency Phone=Notrufsaeule
Asphalt with sideline=Asphalt mit Seitenlinie
Asphalt with solid line=Asphalt mit durchgezogener Linie
Asphalt with dashed line=Asphalt mit unterbrochener Linie
Asphalt with sideline (edge)=Asphalt mit Seitenlinie (Ecke)
Asphalt with parking label=Asphalt mit Parkplatzsymbol
Asphalt with arrow=Asphalt mit Richtungspfeil
Simple manhole=Einfacher Gulli
Advanced manhole=Gulli
Pole=Stange
Empty sign=Leeres Schild
Warning sign (lava)=Gefahrenschild Lava
Warning sign (water)=Gefahrenschild Wasser
Warning sign (Construction area)=Gefahrenschild Baustelle
Warning: Careful of lava=Achtung: Lava
Warning: Water nearby=Achtung: Wasser
Warning: Construction area, possible deep excavations=Achtung Baustelle, eventuell tiefe Graeben
Sign workshop - Create signs for your roads!=Schilderworkshop - Baue Schilder fuer deine Strassen!
Available signs:=Verfuegbare Schilder
Needed stuff:=Benoetigt
Put it here:=Rohstoffe
Selected:=Ausgewaehlt
Output:=Ausgabe
Sign workshop=Schilderworkshop
Sign workshop idle=Schilderworkshop bereit
Sign workshop working=Schilderworkshop arbeitet
Please wait %s seconds... = Bitte warte %s Sekunden...
Solid line (yellow)=Durchgezogene Linie (gelb)
Dashed line (yellow)=Unterbrochene Linie (gelb)
Cross (yellow)=Kreuz (gelb)
Outer edge (yellow)=Ecklinie (gelb)
Parking (yellow)=Parkplatzsymbol (gelb)
Arrow (yellow)=Pfeil (gelb)
Sideline (yellow)=Seitenlinie (gelb)
Steel support=Stahlrahmen
Street lamp=Strassenlampe
Concrete wall=Betonwand
Concrete=Beton
Trafficlight=Ampel
Running version=Version
Cheater=Schummler
Cheater!=Schummler!
Off=Aus
Channel=Kanal
green=Gruen
red=Rot
warn=Warnung
off=Aus
U cheater U=Du Schummler Du

View File

@@ -0,0 +1,59 @@
# Translation file for StreetsMod might not be up-to-date.
Setup completed, have fun with StreetsMod=Configuração completa, se divirta com o StreetsMod
Creating variables and tables...=Criando variáveis e tabelas...
Checking installed mods...=Verificando mods instalados...
Check version of your installed StreetsMod and find information=Verifique a versão instalada do StreetsMod e encontre informações
Asphalt=Asfalto
Asphalt stair=Escada de asfalto
Asphalt slab=Placa de asfalto
Construction fence=Cerca de construção
Delineator=Delineador
Emergency Phone=Telefone de Emergência
Asphalt with sideline=Asfalto com linha lateral
Asphalt with solid line=Asfalto com linha contínua
Asphalt with dashed line=Asfalto com linha traçada
Asphalt with sideline (edge)=Asfalto com linha lateral (borda)
Asphalt with parking label=Asfalto com estacionamento
Asphalt with arrow=Asfalto com flecha
Simple manhole=Buraco simples
Advanced manhole=Buraco elaborado
Pole=Poste
Empty sign=Sinal vazio
Warning sign (lava)=Sinal de aviso (lava)
Warning sign (water)=Sinal de aviso (água)
Warning sign (Construction area)=Sinal de aviso (Área de construção)
Warning: Careful of lava=Aviso: Cuidado com a lava
Warning: Water nearby=Aviso: Água nos arredores
Warning: Construction area, possible deep excavations=Aviso: Área de construção, possíveis escavações profundas
Sign workshop - Create signs for your roads!=Oficina de sinais - Crie sinais para suas estradas!
Available signs:=Sinais disponíveis:
Needed stuff:=Materiais necessários:
Put it here:=Coloque aqui:
Selected:=Selecionado:
Output:=Saída:
Sign workshop=Oficina de sinal
Sign workshop idle=Oficina de sinal em espera
Sign workshop working=Oficina de sinal trabalhando
Please wait %s seconds... =Por favor aguarde %s segundos...
Solid line (yellow)=Linha contínua (amarela)
Dashed line (yellow)=Linha traçada (amarela)
Cross (yellow)=Cruzamento (amarelo)
Outer edge (yellow)=Borda externa (amarela)
Parking (yellow)=Estacionamento (amarela)
Arrow (yellow)=Flecha (amarela)
Sideline (yellow)=Linha lateral (amarela)
Steel support=Suporte/apoio de aço
Street lamp=Lâmpada de rua
Concrete wall=Parede de concreto
Concrete=Concreto
Trafficlight=Semáforo
Running version=Versão sendo utilizada
Cheater=Trapaceiro
Cheater!=Trapaceiro!
Off=Desligado
Channel=Canal
green=verde
red=vermelho
warn=aviso
off=desligado
U cheater U=Seu trapaceiro seu

View File

@@ -0,0 +1,59 @@
# Translation file for StreetsMod might not be up-to-date.
Setup completed, have fun with StreetsMod=Configuração completa, se divirta com o StreetsMod
Creating variables and tables...=Criando variáveis e tabelas...
Checking installed mods...=Verificando mods instalados...
Check version of your installed StreetsMod and find information=Verifique a versão instalada do StreetsMod e encontre informações
Asphalt=Asfalto
Asphalt stair=Escada de asfalto
Asphalt slab=Placa de asfalto
Construction fence=Cerca de construção
Delineator=Delineador
Emergency Phone=Telefone de Emergência
Asphalt with sideline=Asfalto com linha lateral
Asphalt with solid line=Asfalto com linha contínua
Asphalt with dashed line=Asfalto com linha traçada
Asphalt with sideline (edge)=Asfalto com linha lateral (borda)
Asphalt with parking label=Asfalto com estacionamento
Asphalt with arrow=Asfalto com flecha
Simple manhole=Buraco simples
Advanced manhole=Buraco elaborado
Pole=Poste
Empty sign=Sinal vazio
Warning sign (lava)=Sinal de aviso (lava)
Warning sign (water)=Sinal de aviso (água)
Warning sign (Construction area)=Sinal de aviso (Área de construção)
Warning: Careful of lava=Aviso: Cuidado com a lava
Warning: Water nearby=Aviso: Água nos arredores
Warning: Construction area, possible deep excavations=Aviso: Área de construção, possíveis escavações profundas
Sign workshop - Create signs for your roads!=Oficina de sinais - Crie sinais para suas estradas!
Available signs:=Sinais disponíveis:
Needed stuff:=Materiais necessários:
Put it here:=Coloque aqui:
Selected:=Selecionado:
Output:=Saída:
Sign workshop=Oficina de sinal
Sign workshop idle=Oficina de sinal em espera
Sign workshop working=Oficina de sinal trabalhando
Please wait %s seconds... =Por favor aguarde %s segundos...
Solid line (yellow)=Linha contínua (amarela)
Dashed line (yellow)=Linha traçada (amarela)
Cross (yellow)=Cruzamento (amarelo)
Outer edge (yellow)=Borda externa (amarela)
Parking (yellow)=Estacionamento (amarela)
Arrow (yellow)=Flecha (amarela)
Sideline (yellow)=Linha lateral (amarela)
Steel support=Suporte/apoio de aço
Street lamp=Lâmpada de rua
Concrete wall=Parede de concreto
Concrete=Concreto
Trafficlight=Semáforo
Running version=Versão sendo utilizada
Cheater=Trapaceiro
Cheater!=Trapaceiro!
Off=Desligado
Channel=Canal
green=verde
red=vermelho
warn=aviso
off=desligado
U cheater U=Seu trapaceiro seu

View File

@@ -0,0 +1,59 @@
# Translation file for StreetsMod might not be up-to-date.
Setup completed, have fun with StreetsMod=
Creating variables and tables...=
Checking installed mods...=
Check version of your installed StreetsMod and find information=
Asphalt=
Asphalt stair=
Asphalt slab=
Construction fence=
Delineator=
Emergency Phone=
Asphalt with sideline=
Asphalt with solid line=
Asphalt with dashed line=
Asphalt with sideline (edge)=
Asphalt with parking label=
Asphalt with arrow=
Simple manhole=
Advanced manhole=
Pole=
Empty sign=
Warning sign (lava)=
Warning sign (water)=
Warning sign (Construction area)=
Warning: Careful of lava=
Warning: Water nearby=
Warning: Construction area, possible deep excavations=
Sign workshop - Create signs for your roads!=
Available signs:=
Needed stuff:=
Put it here:=
Selected:=
Output:=
Sign workshop=
Sign workshop idle=
Sign workshop working=
Please wait %s seconds... =
Solid line (yellow)=
Dashed line (yellow)=
Cross (yellow)=
Outer edge (yellow)=
Parking (yellow)=
Arrow (yellow)=
Sideline (yellow)=
Steel support=
Street lamp=
Concrete wall=
Concrete=
Trafficlight=
Running version=
Cheater=
Cheater!=
Off=
Channel=
green=
red=
warn=
off=
U cheater U=

View File

@@ -0,0 +1,19 @@
MINETEST NODEBOX EDITOR
PARSER 1
NAME test
NODE node1
POSITION 0 0 0
NODEBOX nodebox1 -0.1875 -0.5 0.5 0.1875 0.5 0.75
NODEBOX nodebox2 -0.0625 0.375 0.3125 0.0625 0.4375 0.5
NODEBOX nodebox3 -0.0625 0.0625 0.3125 0.0625 0.125 0.5
NODEBOX nodebox4 -0.0625 -0.25 0.3125 0.0625 -0.1875 0.5
NODEBOX nodebox5 0.0625 0.3125 0.3125 0.125 0.38 0.5
NODEBOX nodebox6 -0.125 0.3125 0.3125 -0.0625 0.375 0.5
NODEBOX nodebox7 0.0625 0 0.3125 0.125 0.0625 0.5
NODEBOX nodebox8 -0.125 0 0.3125 -0.0625 0.0625 0.5
NODEBOX nodebox9 0.0625 -0.3125 0.3125 0.125 -0.25 0.5
NODEBOX nodebox10 -0.125 -0.3125 0.3125 -0.0625 -0.25 0.5
NODEBOX NodeBox11 -0.125 -0.125 0.85 0.125 0.125 0.75
END NODE

View File

@@ -0,0 +1 @@
This is the first loaded mod in this modpack which prepares tables, variables etc.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 761 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB