Merge pull request #47 from bell07/master

mail, calculator and a lot of adjustments
This commit is contained in:
Gerold55 2017-12-11 09:30:12 -05:00 committed by GitHub
commit e76cf38f1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 527 additions and 119 deletions

40
API.md
View File

@ -21,26 +21,26 @@
- `laptop.os_get(pos)` - Get an OS object. Usefull in on_construct or on_punch to initialize or do anything with OS
Needed in on_receive_fields to be able to call os:receive_fields(fields, sender) for interactive apps
Needed in on_receive_fields to be able to call mtos:receive_fields(fields, sender) for interactive apps
- `laptop.after_place_node` / `laptop.after_dig_node` - (optional) can be used directly for node definition. Move laptop apps data to ItemStack if digged and restored back if placed again. So you can take along your laptop. Note: you need to set `stack_max = 1` because the data can be stored per stack only, not per item.
## Operating system calls
Usable from node functions, from apps or outsite
`local os = laptop.os_get(pos)` - Get the Operating system object. pos is the node position
`local mtos = laptop.os_get(pos)` - Get the Operating system object. pos is the node position
- `os:power_on(new_node_name)` - Activate the app "launcher" and if given swap node to new_node_name
- `os:resume(new_node_name)` - Restore the last running app after power_off. if given swap node to new_node_name
- `os:power_off(new_node_name)` - Remove the formspec and if given swap node to new_node_name
- `os:swap_node(new_node_name)`- Swap the node only without any changes on OS
- `os:set_infotext(infotext)` - Set the mouseover infotext for laptop node
- `os:save()` - Store all app-data to nodemeta. Called mostly internally so no explicit call necessary
- `os:get_app(appname)`- Get the app instance
- `os:set_app(appname)` - Start/Enable/navigate to appname. If no appname given the launcher is called
- `os:receive_fields(fields, sender)` - Should be called from node.on_receive_fields to get the apps interactive
- `os:get_theme(theme)`- Get theme data current or requested (theme parameter is optional)
- `os:set_theme(theme)`- Activate theme
- `mtos:power_on(new_node_name)` - Activate the app "launcher" and if given swap node to new_node_name
- `mtos:resume(new_node_name)` - Restore the last running app after power_off. if given swap node to new_node_name
- `mtos:power_off(new_node_name)` - Remove the formspec and if given swap node to new_node_name
- `mtos:swap_node(new_node_name)`- Swap the node only without any changes on OS
- `mtos:set_infotext(infotext)` - Set the mouseover infotext for laptop node
- `mtos:save()` - Store all app-data to nodemeta. Called mostly internally so no explicit call necessary
- `mtos:get_app(appname)`- Get the app instance
- `mtos:set_app(appname)` - Start/Enable/navigate to appname. If no appname given the launcher is called
- `mtos:receive_fields(fields, sender)` - Should be called from node.on_receive_fields to get the apps interactive
- `mtos:get_theme(theme)`- Get theme data current or requested (theme parameter is optional)
- `mtos:set_theme(theme)`- Activate theme
## App Definition
@ -50,14 +50,14 @@ Usable from node functions, from apps or outsite
- `app_info` - Short app info visible in launcher tooltip
- `fullscreen` - (boolean) Do not add app-background and window buttons
- `view` - (boolean) The definition is a view. That means the app/view is not visible in launcher
- `formspec_func(app, os)` - Function, should return the app formspec (mandatory) During definition the "app" and the "os" are available
- `appwindow_formspec_func(launcher_app, app, os)`- Only custom launcher app: App background / Window decorations and buttons
- `receive_fields_func(app, os, fields, sender)` Function for input processing. The "app" and the "os" are available inside the call
- `formspec_func(app, mtos)` - Function, should return the app formspec (mandatory) During definition the "app" and the "mtos" are available
- `appwindow_formspec_func(launcher_app, app, mtos)`- Only custom launcher app: App background / Window decorations and buttons
- `receive_fields_func(app, mtos, fields, sender)` Function for input processing. The "app" and the "mtos" are available inside the call
`laptop.register_view(internal_shortname, { definitiontable })` - add a new app or view
same as register_app, but the view flag is set. app_name and app_icon not necessary
## App Object
`local app = os:get_app(appname)` - Give the app object internal_shortname, connected to given os. Not necessary in formspec_func or receive_fields_func because given trough interface
`local app = mtos:get_app(appname)` - Give the app object internal_shortname, connected to given mtos. Not necessary in formspec_func or receive_fields_func because given trough interface
- `data = app:get_storage_ref(appname)` - Returns a "persitant" data table from nodemeta (=hdd). The data in this table is not lost between formspec_func, receive_fields_func, apps-switch or on/off. Appname is optional to get data from other app
- `data = app:get_cloud_storage_ref(appname)` - Returns a persistant table from modmeta (=internet)
- `app:back_app() - Go back to previous app/view
@ -72,3 +72,9 @@ Definitiontable:
- `exit_button` Exit button image
- `major_button` Major (highlighted) button image
- `minor_button` Minor button image
- `textcolor` Default text color for buttons and labels. For buttons the major_textcolor and minor_textcolor supported
## Theme methods
`function laptop.get_theme(theme_name)`
- `theme:get_button(area, prefix, code, text)` get a themed [prefix]_button in area 'x,y;w,h' with code an text
- `theme:get_label(pos, text)` get a themed label text starting at pos 'x,y'

133
apps/calculator_app.lua Normal file
View File

@ -0,0 +1,133 @@
laptop.register_app("calculator", {
app_name = "Calculator",
app_icon = "laptop_calculator.png",
app_info = "Calculate things",
formspec_func = function(app, mtos)
local data = app:get_storage_ref()
if not data.tab then
data.tab = {}
end
if not data.tab[1] then
table.insert(data.tab, {})
end
local formspec = "tablecolumns[" ..
"text,align=right,padding=1.5,width=10;".. -- first value
"text,align=right,padding=1.5;".. -- operator
"text,align=right,padding=1.5,width=10]".. -- last value
"table[3.9,0.8;7,2;tab;"
for idx,entry in ipairs(data.tab) do
if idx > 1 then
formspec = formspec..','
end
formspec = formspec..(entry.var1 or "")..","..(entry.operator or "")..","..(entry.var2 or "0")
end
formspec = formspec .. ";"..#data.tab.."]"..
mtos.theme:get_button('4,3;1,1', "minor", 'number', '1') ..
mtos.theme:get_button('5,3;1,1', "minor", 'number', '2') ..
mtos.theme:get_button('6,3;1,1', "minor", 'number', '3') ..
mtos.theme:get_button('4,4;1,1', "minor", 'number', '4') ..
mtos.theme:get_button('5,4;1,1', "minor", 'number', '5') ..
mtos.theme:get_button('6,4;1,1', "minor", 'number', '6') ..
mtos.theme:get_button('4,5;1,1', "minor", 'number', '7') ..
mtos.theme:get_button('5,5;1,1', "minor", 'number', '8') ..
mtos.theme:get_button('6,5;1,1', "minor", 'number', '9') ..
mtos.theme:get_button('4,6;1,1', "minor", 'number', '0') ..
mtos.theme:get_button('5,6;1,1', "minor", 'number', '.') ..
mtos.theme:get_button('8,3;1,1', "minor", 'operator', '+') ..
mtos.theme:get_button('8,4;1,1', "minor", 'operator', '-') ..
mtos.theme:get_button('8,5;1,1', "minor", 'operator', '/') ..
mtos.theme:get_button('8,6;1,1', "minor", 'operator', '*') ..
mtos.theme:get_button('9,6;2,1', "minor", 'operator', '=') ..
mtos.theme:get_button('9,3;2,1', "minor", 'del_char', 'DEL-1') ..
mtos.theme:get_button('9,4;2,1', "minor", 'del_line', 'DEL-L') ..
mtos.theme:get_button('9,5;2,1', "minor", 'del_all', 'DEL-A')
return formspec
end,
receive_fields_func = function(app, mtos, fields, sender)
local data = app:get_storage_ref()
local entry = data.tab[#data.tab]
if fields.number then
-- simple number entry
entry.var2 = (entry.var2 or "")..minetest.strip_colors(fields.number)
elseif fields.del_char then
-- delete char
if entry.var2 and entry.var2 ~= "" then
-- remove char from current number
entry.var2 = entry.var2:sub(1, -2)
if entry.var2 == "" then
entry.var2 = nil
end
else
-- get previous number
if #data.tab > 1 then
-- go back to previous line if exists
table.remove(data.tab, #data.tab)
else
-- get from left site if first entry
entry.var2 = entry.var1
entry.operator = nil
entry.var1 = nil
end
end
elseif fields.del_line then
-- just delete full number if exists
if entry.var2 and entry.var2 ~= "" then
entry.var2 = nil
else
-- go back to previous line and delete the full number if exists
table.remove(data.tab, #data.tab)
if #data.tab > 0 then
entry = data.tab[#data.tab]
entry.var2 = nil
end
end
elseif fields.del_all then
data.tab = nil
elseif fields.operator then
fields.operator = minetest.strip_colors(fields.operator)
local entry = data.tab[#data.tab]
-- no previous operator
if not entry.operator then
if fields.operator == '=' then
table.insert(data.tab, {}) -- add empty line
elseif entry.var2 and entry.var2 ~= "" then
-- move to the left
entry.var1 = entry.var2
entry.operator = fields.operator
entry.var2 = nil
end
-- process previous operator
else
local result
if entry.operator == '+' then
result = tonumber(entry.var1) + tonumber(entry.var2)
elseif entry.operator == '-' then
result = tonumber(entry.var1) - tonumber(entry.var2)
elseif entry.operator == '/' then
result = tonumber(entry.var1) / tonumber(entry.var2)
elseif entry.operator == '*' then
result = tonumber(entry.var1) * tonumber(entry.var2)
elseif entry.operator == '=' then
result = tonumber(entry.var2)
end
if not result then
result = 0
end
if fields.operator == '=' then
table.insert(data.tab, {var2 = tostring(result)})
else
table.insert(data.tab, {var1 = tostring(result), operator = fields.operator})
end
end
end
end
})

View File

@ -2,13 +2,13 @@
laptop.register_app("launcher", {
-- app_name = "Main launcher", -- not in launcher list
fullscreen = true,
formspec_func = function(launcher_app, os)
formspec_func = function(launcher_app, mtos)
local c_row_count = 4
local i = 0
local out = "size[15,10]"
if os.theme.launcher_bg then
out = out..'background[15,10;0,0;'..os.theme.launcher_bg..';true]'
if mtos.theme.launcher_bg then
out = out..'background[15,10;0,0;'..mtos.theme.launcher_bg..';true]'
end
local appslist_sorted = {}
for name, def in pairs(laptop.apps) do
@ -20,34 +20,35 @@ laptop.register_app("launcher", {
for i, e in ipairs(appslist_sorted) do
local x = math.floor((i-1) / c_row_count)*2 + 1
local y = ((i-1) % c_row_count)*2 + 1
out = out .. 'image_button['..x..','..y..';1,1;'..os.theme.app_button..'^'..(e.def.app_icon or 'logo.png')..';'..e.name..';]'..
out = out .. 'image_button['..x..','..y..';1,1;'..mtos.theme.app_button..'^'..(e.def.app_icon or 'logo.png')..';'..e.name..';]'..
'label['..(x-0.3)..','..(y+1)..';'..e.def.app_name..']'..
'tooltip['..e.name..';'..(e.def.app_info or e.name)..']' --;<bgcolor>;<fontcolor>]'
end
out = out..mtos.theme:get_button("11,9.8;4,0.7", "major", "os_clock", os.date("%c"))
return out
end,
appwindow_formspec_func = function(launcher_app, app, os)
appwindow_formspec_func = function(launcher_app, app, mtos)
local formspec = 'size[15,10]'
if os.theme.app_bg then
formspec = formspec..'background[0,0;15,10;'..os.theme.app_bg..';true]'
if mtos.theme.app_bg then
formspec = formspec..'background[0,0;15,10;'..mtos.theme.app_bg..';true]'
end
if #os.appdata.os.stack > 0 then
formspec = formspec..'image_button[-0.29,-0.31;1.09,0.61;'..os.theme.back_button..';os_back;<]' --TODO: if stack exists
if #mtos.appdata.os.stack > 0 then
formspec = formspec..'image_button[-0.29,-0.31;1.09,0.61;'..mtos.theme.back_button..';os_back;<]'
end
if app.app_info then
if #os.appdata.os.stack > 0 then
if #mtos.appdata.os.stack > 0 then
formspec = formspec.."label[0.8,-0.29;"..app.app_info.."]"
else
formspec = formspec.."label[-0.1,-0.29;"..app.app_info.."]"
end
end
formspec = formspec..'image_button[14.2,-0.31;1.09,0.61;'..os.theme.exit_button..';os_exit;X]'
formspec = formspec..'image_button[14.2,-0.31;1.09,0.61;'..mtos.theme.exit_button..';os_exit;X]'
return formspec
end,
receive_fields_func = function(launcher_app, os, fields, sender)
receive_fields_func = function(launcher_app, mtos, fields, sender)
for name, descr in pairs(fields) do
if laptop.apps[name] then
os:set_app(name)
mtos:set_app(name)
break
end
end

View File

@ -12,15 +12,15 @@ laptop.register_app("launcher_settings", {
app_icon = "laptop_setting_wrench.png",
app_info = "Change the computer's settings.",
formspec_func = function(app, os)
formspec_func = function(app, mtos)
local settings_data = app:get_storage_ref()
-- Change background setting
local current_theme_name = settings_data.selected_theme or os:get_theme().name or "default"
local current_theme = os:get_theme(current_theme_name)
local current_theme_name = settings_data.selected_theme or mtos:get_theme().name or "default"
local current_theme = mtos:get_theme(current_theme_name)
local current_idx
local formspec = "label[0,0.5;Select theme]"
local formspec = mtos.theme:get_label('0,0.5', "Select theme")
local formspec = formspec.."textlist[0,1;5,2;sel_theme;"
for i, theme in ipairs(themes_tab) do
@ -41,12 +41,12 @@ laptop.register_app("launcher_settings", {
formspec = formspec.."image[5.5,1;5,3.75;"..current_theme.launcher_bg.."]"
end
formspec = formspec..'image_button[-0.14,3;3,1;'..current_theme.major_button..';theme_apply;Apply]'
formspec = formspec .. mtos.theme:get_button('0,3.2;2.5,0.6', 'major', 'theme_apply', 'Apply', 'Apply theme')
return formspec
end,
receive_fields_func = function(app, os, fields, sender)
receive_fields_func = function(app, mtos, fields, sender)
local settings_data = app:get_storage_ref()
if fields.sel_theme then
@ -56,9 +56,8 @@ laptop.register_app("launcher_settings", {
end
if fields.theme_apply and settings_data.selected_theme then
os:set_theme(settings_data.selected_theme)
mtos:set_theme(settings_data.selected_theme)
settings_data.selected_theme = nil
app:exit_app()
end
end
})

249
apps/mail_app.lua Normal file
View File

@ -0,0 +1,249 @@
-- based on https://github.com/cheapie/mail
laptop.register_app("mail", {
app_name = "Mail",
app_icon = "laptop_email_letter.png",
app_info = "Write mails to other players",
formspec_func = function(app, mtos)
local cloud = app:get_cloud_storage_ref("mail")
if not mtos.appdata.os.last_player then
mtos:set_app() -- no player. Back to launcher
return false
end
if not cloud[mtos.appdata.os.last_player] then
mtos:set_app("mail:newplayer")
return false
end
local account = cloud[mtos.appdata.os.last_player]
account.selected_box = account.selected_box or "inbox"
account.selected_index = nil -- will be new determinated by selectedmessage
local box = account[account.selected_box] -- inbox or outbox
local formspec =
"label[4,-0.31;Welcome "..mtos.appdata.os.last_player.."]"..
"tablecolumns[" ..
"image,align=center,1=laptop_mail.png,2=laptop_mail_read.png;".. --icon column
"color;".. -- subject and date color
"text;".. -- subject
"text,padding=1.5;".. -- sender
"text,padding=1.5,align=right]".. -- date
"table[0,0.5;7.5,8.2;message;"
if box and box[1] then
for idx,message in ipairs(box) do
if idx > 1 then
formspec = formspec..','
end
-- set read/unread status
if account.selected_box == "sentbox" then
formspec = formspec .. "1,#88FF88," -- unread
elseif not message.is_read then
formspec = formspec .. "1,#FF8888," -- unread
else
formspec = formspec .. "2,#FFFFFF," -- read
end
-- set subject
if not message.subject or message.subject == "" then
formspec = formspec .. "(No subject),"
elseif string.len(message.subject) > 30 then
formspec = formspec .. minetest.formspec_escape(string.sub(message.subject,1,27)) .. "...,"
else
formspec = formspec .. minetest.formspec_escape(message.subject) .. ","
end
-- set sender or receiver
if account.selected_box == "inbox" then
formspec = formspec..minetest.formspec_escape(message.sender or "") .."," -- body
else
formspec = formspec..minetest.formspec_escape(message.receiver or "") .."," -- body
end
-- set date
formspec = formspec .. os.date("%c", message.time) -- timestamp
-- handle marked line
if account.selectedmessage and
message.sender == account.selectedmessage.sender and
message.subject == account.selectedmessage.subject and
message.time == account.selectedmessage.time and
message.body == account.selectedmessage.body then
account.selected_index = idx
end
end
formspec = formspec .. ";"..(account.selected_index or "").."]"
else
formspec = formspec .. ",,No mail :(]"
end
-- toggle inbox/sentbox
if account.selected_box == "inbox" then
formspec = formspec .. mtos.theme:get_button('0,9;1.5,1', 'minor', 'switch_sentbox', 'Sentbox', 'Show sent messages')
else
formspec = formspec .. mtos.theme:get_button('0,9;1.5,1', 'minor', 'switch_inbox', 'Inbox', 'Show received messages')
end
formspec = formspec .. "image_button[1.7,9;1,1;"..mtos.theme.minor_button.."^laptop_email_new.png;new;]tooltip[new;New message]"
if account.newmessage then
formspec = formspec .. "image_button[2.7,9;1,1;"..mtos.theme.minor_button.."^laptop_email_edit.png;continue;]tooltip[continue;Continue last message]"
end
if account.selectedmessage then
formspec = formspec ..
"image_button[3.7,9;1,1;"..mtos.theme.minor_button.."^laptop_email_reply.png;reply;]tooltip[reply;Reply]"..
"image_button[4.7,9;1,1;"..mtos.theme.minor_button.."^laptop_email_forward.png;forward;]tooltip[forward;Forward]"..
"image_button[5.7,9;1,1;"..mtos.theme.minor_button.."^laptop_email_trash.png;delete;]tooltip[delete;Delete]"
if account.selected_box == "inbox" then
if not account.selectedmessage.is_read then
formspec = formspec .. "image_button[6.7,9;1,1;"..mtos.theme.minor_button.."^laptop_mail_read.png;markread;]tooltip[markread;Mark message as read]"
else
formspec = formspec .. "image_button[6.7,9;1,1;"..mtos.theme.minor_button.."^laptop_mail.png;markunread;]tooltip[markunread;Mark message as unread]"
end
end
if account.selected_box == "inbox" then
formspec = formspec .. mtos.theme:get_label('8,0.5', "From: "..(account.selectedmessage.sender or ""))
else
formspec = formspec .. mtos.theme:get_label('8,0.5', "To: "..(account.selectedmessage.receiver or ""))
end
formspec = formspec .. mtos.theme:get_label('8,1', "Subject: "..(account.selectedmessage.subject or ""))..
"background[8,1.55;6.92,7.3;gui_formbg.png]"..
"textarea[8.25,1.5;7,8.35;body;;"..(minetest.formspec_escape(account.selectedmessage.body) or "").."]"
end
return formspec
end,
receive_fields_func = function(app, mtos, fields, sender)
if sender:get_player_name() ~= mtos.appdata.os.last_player then
mtos:set_app() -- wrong player. Back to launcher
return
end
local cloud = app:get_cloud_storage_ref("mail")
local account = cloud[mtos.appdata.os.last_player]
if not account then
mtos:set_app() -- wrong player. Back to launcher
return
end
account.selected_box = account.selected_box or "inbox"
local box = account[account.selected_box] -- inbox or outbox
-- Set read status if 2 seconds selected
if account.selected_index and account.selectedmessage and account.selected_box == "inbox" and
account.selected_timestamp and (os.time() - account.selected_timestamp) > 1 then
account.selectedmessage.is_read = true
end
-- process input
if fields.message then
local event = minetest.explode_table_event(fields.message)
account.selectedmessage = box[event.row]
if account.selectedmessage then
account.selected_index = event.row
account.selected_timestamp = os.time()
else
account.selected_index = nil
end
elseif fields.new then
account.newmessage = {}
mtos:set_app("mail:compose")
elseif fields.continue then
mtos:set_app("mail:compose")
elseif fields.switch_sentbox then
account.selected_box = "sentbox"
account.selectedmessage = nil
elseif fields.switch_inbox then
account.selected_box = "inbox"
account.selectedmessage = nil
elseif account.selected_index then
if fields.delete then
table.remove(box, account.selected_index)
account.selectedmessage = nil
elseif fields.reply then
account.newmessage = {}
account.newmessage.receiver = account.selectedmessage.sender
account.newmessage.subject = "Re: "..(account.selectedmessage.subject or "")
account.newmessage.body = "Type your reply here."..string.char(10)..string.char(10).."--Original message follows--"..string.char(10)..(account.selectedmessage.body or "")
mtos:set_app("mail:compose")
elseif fields.forward then
account.newmessage = {}
account.newmessage.subject = "Fw: "..(account.selectedmessage.subject or "")
account.newmessage.body = "Type your reply here."..string.char(10)..string.char(10).."--Original message follows--"..string.char(10)..(account.selectedmessage.body or "")
mtos:set_app("mail:compose")
elseif fields.markread then
account.selectedmessage.is_read = true
elseif fields.markunread then
account.selectedmessage.is_read = false
account.selected_timestamp = nil -- Stop timer
end
end
end
})
laptop.register_view("mail:newplayer", {
formspec_func = function(app, mtos)
return mtos.theme:get_label('1,3', "No mail account for player "..mtos.appdata.os.last_player.. " found. Do you like to create a new account?")..
mtos.theme:get_button('1,4;3,1', 'major', 'create', 'Create account')
end,
receive_fields_func = function(app, mtos, fields, sender)
if sender:get_player_name() ~= mtos.appdata.os.last_player then
mtos:set_app() -- wrong player. Back to launcher
return
end
if fields.create then
local cloud = app:get_cloud_storage_ref("mail")
cloud[mtos.appdata.os.last_player] = {
inbox = {},
sentbox = {}
}
app:back_app()
elseif fields.os_back then
app:exit_app()
end
end
})
-- Write new mail
laptop.register_view("mail:compose", {
formspec_func = function(app, mtos)
local cloud = app:get_cloud_storage_ref("mail")
local account = cloud[mtos.appdata.os.last_player]
account.newmessage = account.newmessage or {}
local message = account.newmessage
local formspec = "background[-0.1,0.4;4.2,2.4;gui_formbg.png]"..
"field[0.25,1;4,1;receiver;To:;%s]field[0.25,2;4,1;subject;Subject:;%s]"..
"background[0,3.05;7.95,3.44;gui_formbg.png]"..
"textarea[0.25,3;8,4;body;;%s]"..
mtos.theme:get_button("0,8;2,1", "major", "send", "Send message")
formspec = string.format(formspec,minetest.formspec_escape(message.receiver or ""),minetest.formspec_escape(message.subject or ""),minetest.formspec_escape(message.body or ""))
if message.receiver and not cloud[message.receiver] then
formspec = formspec..mtos.theme:get_label('2.3,8', "invalid receiver player")
end
return formspec
end,
receive_fields_func = function(app, mtos, fields, sender)
if sender:get_player_name() ~= mtos.appdata.os.last_player then
mtos:set_app() -- wrong player. Back to launcher
return
end
local cloud = app:get_cloud_storage_ref("mail")
local account = cloud[mtos.appdata.os.last_player]
account.newmessage = account.newmessage or {}
local message = account.newmessage
message.receiver = fields.receiver or message.receiver
message.sender = mtos.appdata.os.last_player
message.time = os.time()
message.subject = fields.subject or message.subject
message.body = fields.body or message.body
if fields.send and message.receiver and cloud[message.receiver] then
table.insert(cloud[message.receiver].inbox, message)
table.insert(account.sentbox, table.copy(message))
account.newmessage = nil
app:back_app()
end
end
})

View File

@ -6,7 +6,8 @@ laptop.register_app("stickynote", {
local data = app:get_storage_ref()
data.text = data.text or ""
return "textarea[0.35,0.35;15.08,10.5;text;;"..minetest.formspec_escape(data.text).."]"
return "background[0,0.35;15.2,9.2;gui_formbg.png]"..
"textarea[0.35,0.35;15.08,10.5;text;;"..minetest.formspec_escape(data.text).."]"
end,
receive_fields_func = function(app, os, fields, sender)
if fields.text then

View File

@ -3,36 +3,36 @@ laptop.register_app("demo1", {
app_name = "Demo App",
app_icon = "laptop_setting_wrench.png",
app_info = "The first and simple demo app",
formspec_func = function(app, os)
return 'image_button[5,5;3,1;'..os.theme.major_button..';next;Second screen]'
formspec_func = function(app, mtos)
return mtos.theme:get_button('5,5;3,1', 'major', 'next', 'Second screen')
end,
receive_fields_func = function(app, os, fields, sender)
receive_fields_func = function(app, mtos, fields, sender)
if fields.next then
os:set_app("demo1_view2")
mtos:set_app("demo1_view2")
end
end
})
laptop.register_view("demo1_view2", {
app_info = "Second screen in Demo App 1",
formspec_func = function(app, os)
return "label[1,5;Use the framework buttons to navigate back or cancel]"
formspec_func = function(app, mtos)
return mtos.theme:get_label('1,5', "Use the framework buttons to navigate back or cancel")
end,
receive_fields_func = function(app, os, fields, sender)
receive_fields_func = function(app, mtos, fields, sender)
end
})
laptop.register_app("demo2", {
app_name = "Demo App 2",
formspec_func = function(app, os)
formspec_func = function(app, mtos)
local data = app:get_storage_ref()
data.counter = data.counter or 1
return 'button[3,1;5,1;count;Click: '..data.counter..']'..
'button[3,3;5,1;back;Back to launcher]'
end,
receive_fields_func = function(app, os, fields, sender)
receive_fields_func = function(app, mtos, fields, sender)
if fields.count then
local data = app:get_storage_ref()
data.counter = data.counter + 1

View File

@ -4,12 +4,12 @@ laptop.node_config = {}
local function after_place_node(pos, placer, itemstack, pointed_thing)
local appdata = minetest.deserialize(itemstack:get_meta():get_string("laptop_appdata"))
if appdata then
local os = laptop.os_get(pos)
os.appdata = appdata
os.appdata.launcher = os.appdata.launcher or {}
os.appdata.os = os.appdata.os or {}
os.appdata.os.stack = os.appdata.os.stack or {}
os:save()
local mtos = laptop.os_get(pos)
mtos.appdata = appdata
mtos.appdata.launcher = mtos.appdata.launcher or {}
mtos.appdata.os = mtos.appdata.os or {}
mtos.appdata.os.stack = mtos.appdata.os.stack or {}
mtos:save()
end
end
@ -30,38 +30,38 @@ local function after_dig_node(pos, oldnode, oldmetadata, digger)
end
local function on_construct(pos)
local os = laptop.os_get(pos)
local mtos = laptop.os_get(pos)
local node = minetest.get_node(pos)
local hwdef = laptop.node_config[node.name]
if hwdef.custom_theme then -- initial only
os:set_theme(hwdef.custom_theme)
mtos:set_theme(hwdef.custom_theme)
end
if hwdef.hw_state then
os[hwdef.hw_state](os)
mtos[hwdef.hw_state](mtos)
else
os:power_off()
mtos:power_off()
end
os:set_infotext(hwdef.hw_infotext)
mtos:set_infotext(hwdef.hw_infotext)
end
local function on_punch(pos, node, puncher)
local os = laptop.os_get(pos)
local mtos = laptop.os_get(pos)
local hwdef = laptop.node_config[node.name]
if hwdef.next_node then
local hwdef_next = laptop.node_config[hwdef.next_node]
if hwdef_next.hw_state then
os[hwdef_next.hw_state](os, hwdef.next_node)
mtos[hwdef_next.hw_state](mtos, hwdef.next_node)
else
os:swap_node(hwdef.next_node)
os:save()
mtos:swap_node(hwdef.next_node)
mtos:save()
end
os:set_infotext(hwdef_next.hw_infotext)
mtos:set_infotext(hwdef_next.hw_infotext)
end
end
local function on_receive_fields(pos, formname, fields, sender)
local os = laptop.os_get(pos)
os:receive_fields(fields, sender)
local mtos = laptop.os_get(pos)
mtos:receive_fields(fields, sender)
end
function laptop.register_hardware(name, hwdef)

View File

@ -73,7 +73,7 @@ laptop.register_hardware("laptop:cube", {
description = "CUBE PC",
infotext = "CUBE PC",
sequence = { "off", "on"},
custom_theme = "red",
custom_theme = "Red",
node_defs = {
["on"] = {
hw_state = "power_on",

11
os.lua
View File

@ -58,16 +58,7 @@ end
-- Get given or current theme
function os_class:get_theme(theme)
local theme_sel = theme or self.appdata.os.theme
local ret = table.copy(laptop.themes.default)
if theme_sel and laptop.themes[theme_sel] then
for k,v in pairs(laptop.themes[theme_sel]) do
ret[k] = v
end
ret.name = theme_sel
else
ret.name = "default"
end
return ret
return laptop.get_theme(theme_sel)
end
-- Set current theme

View File

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 264 B

View File

Before

Width:  |  Height:  |  Size: 322 B

After

Width:  |  Height:  |  Size: 322 B

View File

Before

Width:  |  Height:  |  Size: 197 B

After

Width:  |  Height:  |  Size: 197 B

View File

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 317 B

View File

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 294 B

View File

Before

Width:  |  Height:  |  Size: 429 B

After

Width:  |  Height:  |  Size: 429 B

View File

Before

Width:  |  Height:  |  Size: 612 B

After

Width:  |  Height:  |  Size: 612 B

View File

@ -7,6 +7,7 @@ laptop.themes = {
back_button = "laptop_theme_freedom_back_button.png",
exit_button = "laptop_theme_freedom_exit_button.png",
app_button = "laptop_theme_freedom_app_button.png",
textcolor = "#000000",
},
}
@ -25,4 +26,30 @@ for _, file in ipairs(theme_list) do
if file:sub(-10) == '_theme.lua' then
dofile(theme_path..file)
end
end
end
local theme_class = {}
theme_class.__index = theme_class
-- get prepared button textures
function theme_class:get_button(area, prefix, code, text, tooltip)
return'image_button['..area..';'..self[prefix.."_button"]..';'..code..';'.. minetest.colorize(self[prefix.."_textcolor"] or self.textcolor,minetest.formspec_escape(text))..']'..
"tooltip["..code..";"..minetest.formspec_escape(tooltip or text).."]"
end
-- Get themed label
function theme_class:get_label(area, label)
return'label['..area..';'..minetest.colorize(self.textcolor, minetest.formspec_escape(label))..']'
end
function laptop.get_theme(theme_name)
local self = setmetatable(table.copy(laptop.themes.default), theme_class)
if theme_name and laptop.themes[theme_name] then
for k,v in pairs(laptop.themes[theme_name]) do
self[k] = v
end
self.name = theme_name
else
self.name = "default"
end
return self
end

View File

@ -1,9 +1,10 @@
laptop.register_theme("Basic", {
launcher_bg = "laptop_theme_basic_launcher_bg.png",
app_bg = "laptop_theme_basic_app_bg.png",
major_button = "laptop_theme_basic_button.png",
minor_button = "laptop_theme_basic_button.png",
back_button = "blank.png",
exit_button = "blank.png",
app_button = "blank.png",
})
laptop.register_theme("Basic", {
launcher_bg = "laptop_theme_basic_launcher_bg.png",
app_bg = "laptop_theme_basic_app_bg.png",
major_button = "laptop_theme_basic_button.png",
minor_button = "laptop_theme_basic_button.png",
back_button = "blank.png",
exit_button = "blank.png",
app_button = "blank.png",
textcolor = "#FFFFFF",
})

View File

@ -1,9 +1,9 @@
laptop.register_theme("Blue", {
launcher_bg = "laptop_theme_blue_launcher_bg.png",
app_bg = "laptop_theme_blue_app_bg.png",
major_button = "laptop_theme_blue_major_button.png",
minor_button = "laptop_theme_minor_button.png",
back_button = "laptop_theme_blue_back_button.png",
exit_button = "laptop_theme_blue_exit_button.png",
app_button = "laptop_theme_blue_app_button.png",
laptop.register_theme("Blue", {
launcher_bg = "laptop_theme_blue_launcher_bg.png",
app_bg = "laptop_theme_blue_app_bg.png",
major_button = "laptop_theme_blue_major_button.png",
minor_button = "laptop_theme_minor_button.png",
back_button = "laptop_theme_blue_back_button.png",
exit_button = "laptop_theme_blue_exit_button.png",
app_button = "laptop_theme_blue_app_button.png",
})

View File

@ -1,9 +1,9 @@
laptop.register_theme("Cubic", {
launcher_bg = "laptop_theme_cubic_launcher_bg.png",
app_bg = "laptop_theme_cubic_app_bg.png",
major_button = "laptop_theme_cubic_major_button.png",
minor_button = "laptop_theme_minor_button.png",
back_button = "laptop_theme_cubic_back_button.png",
exit_button = "laptop_theme_cubic_exit_button.png",
app_button = "laptop_theme_cubic_app_button.png",
laptop.register_theme("Cubic", {
launcher_bg = "laptop_theme_cubic_launcher_bg.png",
app_bg = "laptop_theme_cubic_app_bg.png",
major_button = "laptop_theme_cubic_major_button.png",
minor_button = "laptop_theme_minor_button.png",
back_button = "laptop_theme_cubic_back_button.png",
exit_button = "laptop_theme_cubic_exit_button.png",
app_button = "laptop_theme_cubic_app_button.png",
})

View File

@ -1,9 +1,9 @@
laptop.register_theme("Magma", {
launcher_bg = "laptop_theme_magma_launcher_bg.png",
app_bg = "laptop_theme_magma_app_bg.png",
major_button = "laptop_theme_magma_major_button.png",
minor_button = "laptop_theme_minor_button.png",
back_button = "laptop_theme_magma_back_button.png",
exit_button = "laptop_theme_magma_exit_button.png",
app_button = "laptop_theme_magma_app_button.png",
laptop.register_theme("Magma", {
launcher_bg = "laptop_theme_magma_launcher_bg.png",
app_bg = "laptop_theme_magma_app_bg.png",
major_button = "laptop_theme_magma_major_button.png",
minor_button = "laptop_theme_minor_button.png",
back_button = "laptop_theme_magma_back_button.png",
exit_button = "laptop_theme_magma_exit_button.png",
app_button = "laptop_theme_magma_app_button.png",
})

View File

@ -1,9 +1,9 @@
laptop.register_theme("Red", {
launcher_bg = "laptop_theme_red_launcher_bg.png",
app_bg = "laptop_theme_red_app_bg.png",
major_button = "laptop_theme_red_major_button.png",
minor_button = "laptop_theme_minor_button.png",
back_button = "laptop_theme_red_back_button.png",
exit_button = "laptop_theme_red_exit_button.png",
app_button = "laptop_theme_red_app_button.png",
laptop.register_theme("Red", {
launcher_bg = "laptop_theme_red_launcher_bg.png",
app_bg = "laptop_theme_red_app_bg.png",
major_button = "laptop_theme_red_major_button.png",
minor_button = "laptop_theme_minor_button.png",
back_button = "laptop_theme_red_back_button.png",
exit_button = "laptop_theme_red_exit_button.png",
app_button = "laptop_theme_red_app_button.png",
})