os_print_app.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. local printer_range = 10
  2. local function trigger_queue(app, mtos)
  3. -- Check print requirements
  4. if mtos.sysdata.selected_view ~= 'output' or
  5. mtos.sysdata.out_stack_save or
  6. not mtos.sysdata.paper_count or mtos.sysdata.paper_count == 0 or
  7. not mtos.sysdata.dye_count or mtos.sysdata.dye_count == 0 or
  8. not mtos.sysdata.print_queue or
  9. not mtos.sysdata.print_queue[1] then
  10. mtos.sysdata.print_progress = 0
  11. return false
  12. end
  13. -- timer done
  14. if mtos.sysdata.print_progress >= 5 then
  15. mtos.sysdata.print_progress = 0
  16. mtos.sysdata.paper_count = mtos.sysdata.paper_count - 1
  17. mtos.sysdata.dye_count = mtos.sysdata.dye_count - 0.1
  18. mtos.bdev.removable_disk = nil -- force reading
  19. local idata = mtos.bdev:get_removable_disk()
  20. local stack = ItemStack("laptop:printed_paper")
  21. local print_data = mtos.sysdata.print_queue[1]
  22. stack:get_meta():from_table({ fields = print_data})
  23. table.remove(mtos.sysdata.print_queue, 1)
  24. idata:reload(stack)
  25. idata.label = print_data.title
  26. mtos.bdev:sync()
  27. end
  28. local timer = app:get_timer()
  29. if not timer:is_started() then
  30. timer:start(1)
  31. end
  32. return true
  33. end
  34. local function sync_stack_values(mtos)
  35. mtos.sysdata.paper_count = mtos.sysdata.paper_count or 0
  36. mtos.sysdata.dye_count = mtos.sysdata.dye_count or 0
  37. mtos.sysdata.print_progress = mtos.sysdata.print_progress or 0
  38. mtos.bdev.removable_disk = nil -- force reading
  39. local idata = mtos.bdev:get_removable_disk()
  40. -- store old stack values
  41. if mtos.sysdata.selected_view == 'paper' then
  42. if idata.stack then
  43. mtos.sysdata.paper_count = idata.stack:get_count()
  44. else
  45. mtos.sysdata.paper_count = 0
  46. end
  47. elseif mtos.sysdata.selected_view == 'dye' then
  48. if idata.stack then
  49. mtos.sysdata.dye_count = mtos.sysdata.dye_count - math.floor(mtos.sysdata.dye_count) + idata.stack:get_count()
  50. else
  51. mtos.sysdata.dye_count = mtos.sysdata.dye_count - math.floor(mtos.sysdata.dye_count)
  52. end
  53. elseif mtos.sysdata.selected_view == 'output' then
  54. if idata.stack then
  55. mtos.sysdata.out_stack_save = idata.stack:to_string()
  56. else
  57. mtos.sysdata.out_stack_save = nil
  58. end
  59. end
  60. end
  61. laptop.register_app("printer_launcher", {
  62. app_name = "Printer firmware",
  63. view = true, -- to be hidden in "usual" OS
  64. fullscreen = true,
  65. formspec_func = function(launcher_app, mtos)
  66. mtos.sysdata.print_queue = mtos.sysdata.print_queue or {}
  67. mtos.sysdata.selected_view = mtos.sysdata.selected_view or 'output'
  68. sync_stack_values(mtos)
  69. trigger_queue(launcher_app, mtos)
  70. mtos.bdev:sync()
  71. -- inventory fields
  72. local formspec = "size[9,8]"..
  73. "list[current_player;main;0.3,3.85;8,1;]" ..
  74. "list[current_player;main;0.3,5.08;8,3;8]" ..
  75. "listring[nodemeta:"..mtos.pos.x..','..mtos.pos.y..','..mtos.pos.z..";main]" ..
  76. "listring[current_player;main]"..
  77. mtos.theme:get_label('0,0', mtos.hwdef.description, 'titlebar')
  78. -- queue
  79. formspec = formspec .. mtos.theme:get_tableoptions()..
  80. "tablecolumns[" ..
  81. "text;".. -- label
  82. "text;".. -- author
  83. "text]".. -- timestamp
  84. "table[0,0.5;5,2.42;printers;"
  85. for idx, file in ipairs(mtos.sysdata.print_queue) do
  86. if idx > 1 then
  87. formspec = formspec..','
  88. end
  89. formspec = formspec .. minetest.formspec_escape(file.title or "")..','..
  90. (file.author or "")..','..os.date("%c", file.timestamp)
  91. end
  92. formspec = formspec .. ";]"
  93. local out_button = 'minor'
  94. local paper_button = 'minor'
  95. local dye_button = 'minor'
  96. if mtos.sysdata.selected_view == 'paper' then
  97. paper_button = 'major'
  98. formspec = formspec .."background[6.2,0.8;2.5,0.7;"..mtos.theme.contrast_background..']'
  99. elseif mtos.sysdata.selected_view == 'dye' then
  100. dye_button = 'major'
  101. formspec = formspec .."background[6.2,1.5;2.5,0.7;"..mtos.theme.contrast_background..']'
  102. elseif mtos.sysdata.selected_view == 'output' then
  103. out_button = 'major'
  104. formspec = formspec .."background[6.2,2.2;2.5,0.7;"..mtos.theme.contrast_background..']'
  105. end
  106. formspec = formspec .."background[5.2,0.55;1.5,2.45;"..mtos.theme.contrast_background..']'..
  107. mtos.theme:get_label('5.3,0.8', 'Paper: '..mtos.sysdata.paper_count, 'contrast')..
  108. mtos.theme:get_label('5.3,1.3', 'Dye: '..mtos.sysdata.dye_count, 'contrast')..
  109. mtos.theme:get_button('6.8,0.8;1.5,0.7', paper_button, 'view_paper', 'Paper tray', 'Insert paper')..
  110. mtos.theme:get_button('6.8,1.5;1.5,0.7', dye_button, 'view_dye', 'Dye tray', 'Insert black dye')..
  111. mtos.theme:get_button('6.8,2.2;1.5,0.7', out_button, 'view_out', 'Output tray', 'Get printed paper')..
  112. "list[nodemeta:"..mtos.pos.x..','..mtos.pos.y..','..mtos.pos.z..";main;5.4,1.8;1,1;]"..
  113. mtos.theme:get_button('0.3,3;1.5,0.7', 'minor', 'reset', 'Reset', 'Reset printer queue')..
  114. mtos.theme:get_button('2,3;1.5,0.7', 'minor', 'delete', 'Delete', 'Delete job')..
  115. "background[3.7,3.1;"..(mtos.sysdata.print_progress)..",0.5;laptop_theme_red_back_button.png]"
  116. return formspec
  117. end,
  118. appwindow_formspec_func = function(launcher_app, app, mtos)
  119. local formspec = 'size[10,7]'
  120. return formspec
  121. end,
  122. allow_metadata_inventory_put = function(app, mtos, player, listname, index, stack)
  123. if mtos.sysdata.selected_view == 'output' then
  124. -- nothing
  125. elseif mtos.sysdata.selected_view == 'paper' and stack:get_name() == 'default:paper' then
  126. return stack:get_stack_max()
  127. elseif mtos.sysdata.selected_view == 'dye' and stack:get_name() == 'dye:black' then
  128. return stack:get_stack_max()
  129. end
  130. return 0
  131. end,
  132. allow_metadata_inventory_take = function(app, mtos, player, listname, index, stack)
  133. -- removal allways possible
  134. return stack:get_count()
  135. end,
  136. receive_fields_func = function(app, mtos, sender, fields)
  137. sync_stack_values(mtos)
  138. local idata = mtos.bdev:get_removable_disk()
  139. if fields.view_out then
  140. mtos.sysdata.selected_view = 'output'
  141. idata.stack = ItemStack(mtos.sysdata.out_stack_save or "")
  142. elseif fields.view_paper then
  143. mtos.sysdata.selected_view = 'paper'
  144. idata.stack = ItemStack('default:paper')
  145. idata.stack:set_count(mtos.sysdata.paper_count)
  146. elseif fields.view_dye then
  147. mtos.sysdata.selected_view = 'dye'
  148. idata.stack = ItemStack('dye:black')
  149. idata.stack:set_count(math.floor(mtos.sysdata.dye_count))
  150. elseif fields.reset then
  151. mtos.sysdata.print_queue = {}
  152. mtos.sysdata.print_progress = 0
  153. elseif fields.delete then
  154. table.remove(mtos.sysdata.print_queue, 1)
  155. mtos.sysdata.print_progress = 0
  156. end
  157. idata:reload(idata.stack)
  158. trigger_queue(app, mtos)
  159. mtos.bdev:sync()
  160. end,
  161. on_timer = function(app, mtos)
  162. mtos.sysdata.print_progress = mtos.sysdata.print_progress + 1
  163. mtos.bdev.removable_disk = nil -- force reading
  164. return trigger_queue(app, mtos)
  165. end,
  166. })
  167. local function get_printer_info(pos)
  168. local hw_os = laptop.os_get(pos)
  169. local printer
  170. if hw_os then
  171. printer = {
  172. pos = pos,
  173. name = hw_os.hwdef.description,
  174. nodename = hw_os.node.name,
  175. }
  176. if not minetest.registered_items[hw_os.node.name].groups.laptop_printer then
  177. printer.status = 'off'
  178. -- printer.status_color = '#FF0000'
  179. elseif not hw_os.sysram.current_app or hw_os.sysram.current_app == 'os:power_off' then
  180. printer.status = 'disabled'
  181. -- printer.status_color = '#FF0000'
  182. else
  183. printer.status = 'online'
  184. -- printer.status_color = '#00FF00'
  185. end
  186. end
  187. return printer
  188. end
  189. laptop.register_view("printer:app", {
  190. app_info = "Print file",
  191. formspec_func = function(app, mtos)
  192. local store = mtos.bdev:get_app_storage('ram', 'printer:app')
  193. local param = store.param
  194. local sysstore = mtos.bdev:get_app_storage('system', 'printer:app')
  195. sysstore.printers = sysstore.printers or {}
  196. local formspec = mtos.theme:get_label('0.5,1', "Selected Printer:")
  197. if sysstore.selected_printer then
  198. local printer = get_printer_info(sysstore.selected_printer.pos)
  199. if not printer then
  200. printer = sysstore.selected_printer
  201. printer.status = 'removed'
  202. else
  203. sysstore.selected_printer = printer
  204. end
  205. local status_color = mtos.theme["status_"..printer.status.."_textcolor"] or mtos.theme.textcolor
  206. formspec = formspec .. 'item_image[0.5,1.5;1,1;'..printer.nodename..']'..
  207. mtos.theme:get_label('1.5,1.7', minetest.formspec_escape(printer.name)..' '..
  208. minetest.pos_to_string(printer.pos)..' '.. minetest.colorize(status_color, printer.status))
  209. end
  210. formspec = formspec .. mtos.theme:get_tableoptions()..
  211. "tablecolumns[" ..
  212. "text;".. -- Printer name
  213. "text;".. -- Printer position
  214. "color;"..-- Status color
  215. "text]".. -- Printer status
  216. "table[0.5,2.5;6.5,4.2;printers;"
  217. if sysstore.printers[1] then
  218. local sel_idx = ""
  219. for idx, printer in ipairs(sysstore.printers) do
  220. if idx > 1 then
  221. formspec = formspec..','
  222. end
  223. local pos_string = minetest.pos_to_string(printer.pos)
  224. local status_color = mtos.theme["status_"..printer.status.."_textcolor"] or mtos.theme.textcolor
  225. formspec = formspec..minetest.formspec_escape(printer.name)..','..
  226. minetest.formspec_escape(minetest.pos_to_string(printer.pos))..','..
  227. status_color..','..printer.status
  228. if sysstore.selected_printer and vector.distance(printer.pos, sysstore.selected_printer.pos) == 0 then
  229. sel_idx = idx
  230. end
  231. end
  232. formspec = formspec .. ";"..sel_idx.."]"
  233. else
  234. formspec = formspec .. "No printer found :(]"
  235. end
  236. formspec = formspec .. mtos.theme:get_button('2.7,9;2,0.7', 'minor', 'scan', 'Search', 'Scan for printers')
  237. if sysstore.selected_printer and sysstore.selected_printer.status == 'online' then
  238. formspec = formspec .. mtos.theme:get_button('10,9;2,0.7', 'major', 'print', 'Print', 'Print file')
  239. end
  240. param.label = param.label or "<unnamed>"
  241. formspec = formspec .. mtos.theme:get_bgcolor_box("7.15,0.4;7.6,1","contrast")..
  242. mtos.theme:get_label('7.3,0.6','Heading:','contrast').."field[9.7,0.7;5,1;label;;"..minetest.formspec_escape(param.label or "").."]"..
  243. mtos.theme:get_label('9.7,1.7'," by "..(mtos.sysram.current_player or ""))..
  244. mtos.theme:get_tableoptions(false).."tablecolumns[text]table[7.15,2.5;7.6,6.0;preview_bg;]"..
  245. "textarea[7.5,2.5;7.5,7;;"..minetest.colorize(mtos.theme.table_textcolor, (minetest.formspec_escape(param.text) or ""))..";]"
  246. return formspec
  247. end,
  248. receive_fields_func = function(app, mtos, sender, fields)
  249. local store = mtos.bdev:get_app_storage('ram', 'printer:app')
  250. local param = store.param
  251. local sysstore = mtos.bdev:get_app_storage('system', 'printer:app')
  252. sysstore.printers = sysstore.printers or {}
  253. if fields.scan then
  254. sysstore.printers = {}
  255. local nodes = minetest.find_nodes_in_area({x = mtos.pos.x-printer_range, y= mtos.pos.y-printer_range, z = mtos.pos.z-printer_range},
  256. {x = mtos.pos.x+printer_range, y= mtos.pos.y+printer_range, z = mtos.pos.z+printer_range}, {"group:laptop_printer"})
  257. for _, pos in ipairs(nodes) do
  258. local printer = get_printer_info(pos)
  259. if printer then
  260. printer.printer_os = nil -- do not store whole OS
  261. table.insert(sysstore.printers, printer)
  262. end
  263. end
  264. table.sort(sysstore.printers, function(a,b) return vector.distance(a.pos, mtos.pos) < vector.distance(b.pos, mtos.pos) end)
  265. end
  266. if fields.printers then
  267. local event = minetest.explode_table_event(fields.printers)
  268. sysstore.selected_printer = sysstore.printers[event.row] or sysstore.selected_printer
  269. end
  270. if fields.label then
  271. param.label = fields.label
  272. end
  273. if fields.print and sysstore.selected_printer then
  274. local hw_os = laptop.os_get(sysstore.selected_printer.pos)
  275. if hw_os and minetest.registered_items[hw_os.node.name].groups.laptop_printer then
  276. hw_os.sysdata.print_queue = hw_os.sysdata.print_queue or {}
  277. sync_stack_values(hw_os)
  278. table.insert(hw_os.sysdata.print_queue, { title = param.label, text = param.text, author = param.author or sender:get_player_name(), timestamp = param.timestamp or os.time() })
  279. hw_os:set_app() --update page
  280. app:back_app()
  281. end
  282. end
  283. end,
  284. })