Te-ki

CCInventory

Mar 23rd, 2025 (edited)
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 50.66 KB | Gaming | 0 0
  1. -- ccInventory by Teki
  2.  
  3. -- TODO :
  4. -- handle peripheral types : inventory OK, monitor partially, modem
  5. -- HANDLE PERIPHERAL STATES (online / offline / disabled)
  6.  
  7. -- monitors :
  8. -- assign a window (list ?) and draw widget
  9. -- on click switch window ?
  10.  
  11. -- move selected responsibility to item ?
  12. -- move events handling responsibility to item ?
  13.  
  14. --      enhance peripheral drawing (item responsibility ?)
  15.  
  16. -- save crafts
  17. -- trigger crafts
  18. -- enhance tabs handling (widget full responsibility)
  19.  
  20. -- Monitor
  21. term.current().clear()
  22. local sizeX,sizeY = term.current().getSize()
  23. local monitor = window.create(term.current(), 1, 1, sizeX, sizeY, true)
  24. sizeX,sizeY = monitor.getSize()
  25. monitor.setCursorPos(1,sizeY)
  26. monitor.write("Loading...")
  27.  
  28. -- Properties
  29. local eventFired = false
  30. local getItemDetailInterval = 1000
  31. local itemDb = {}
  32.  
  33. local nodes = {}
  34. local items = {}
  35. local crafts = {
  36.     -- Make classes
  37.     -- Craft made of a name, Input(s) and Output(s)
  38.     {
  39.         name = "Craft 1",
  40.         -- Input made of Machine(s)
  41.         inputs = {
  42.             -- Machine made of node.name and MachineSlot(s)
  43.             machines = {
  44.                 {
  45.                     name = "", -- peripheral side
  46.                     -- MachineSlot made of a key, an ItemList and a ListType
  47.                     slots = {-- list of slots used 0 for all
  48.                         key = "all",
  49.                         list = {}, -- list of items = name +? nbt / count
  50.                         listType = "whitelist", -- whitelist / blacklist / disabled
  51.                     }
  52.                 }
  53.             },
  54.         },
  55.         -- Output made of Machine(s)
  56.         outputs = {
  57.             machines = {
  58.                 {
  59.                     side = "", -- peripheral side
  60.                     slots = {0}, -- list of slots used 0 for all
  61.                 }
  62.             },
  63.         }
  64.     }
  65. }
  66.  
  67. -- Widgets
  68. local itemsListWidget
  69. local peripheralsListWidget
  70. local craftsListWidget
  71. local tabsWidget
  72. local sortWidget
  73.  
  74. -- Settings
  75. local sortByName = false
  76. local sortAscending = false
  77.  
  78. -- Methods
  79. local function roundTo(num, n)
  80.     local mult = 10^(n or 0)
  81.     return math.floor(num * mult + 0.5) / mult
  82. end
  83.  
  84. local function drawBar(startX, endX, posY, colorFull, colorEmpty, maxSize, currentSize, label, window)
  85.     label = label .. " " .. currentSize .. "/" .. maxSize
  86.     while ((endX - startX + 1) - #label)/2 >= 1 do
  87.         label = " " .. label .. " "
  88.     end
  89.     local length = (endX - startX + 1)*(currentSize/maxSize)
  90.     for i = startX, endX do
  91.         window.setCursorPos(i, posY)
  92.         if i - startX + 1 <= length then
  93.             window.setBackgroundColor(colorFull)
  94.             window.setTextColor(colorEmpty)
  95.         else
  96.             window.setBackgroundColor(colorEmpty)
  97.             window.setTextColor(colorFull)
  98.         end
  99.         if #label < i - startX + 1 then
  100.             window.write(" ")
  101.         else
  102.             window.write(label:sub(i - startX + 1, i))
  103.         end
  104.     end
  105. end
  106.  
  107. local function indexOf(array, needle)
  108.     for index, value in ipairs(array) do
  109.         if value == needle then
  110.             return index
  111.         end
  112.     end
  113.     return false
  114. end
  115.  
  116. -- Logging
  117. local debug = true
  118.     -- reset file
  119. local logsFile = fs.open("inventory.log", "w")
  120. if debug then
  121.     logsFile.write("")
  122.     logsFile.close()
  123. end
  124.     -- Loging method
  125. local function log(message)
  126.     if debug then
  127.         local logsFile = fs.open("inventory.log", "a")
  128.         logsFile.write(message.."\n")
  129.         logsFile.close()
  130.     end
  131. end
  132.  
  133. -- Sorting Items methods
  134. local function growingQuantity(a, b)
  135.     if a.inventory ~= nil and b.inventory ~= nil then
  136.         return a.inventory.capacity < b.inventory.capacity
  137.     elseif a.count ~= nil and b.count ~= nil then
  138.         return a.count < b.count
  139.     else
  140.         return false
  141.     end
  142. end
  143.  
  144. local function shrinkingQuantity(a, b)
  145.     if a.inventory ~= nil and b.inventory ~= nil then
  146.         return a.inventory.capacity >= b.inventory.capacity
  147.     elseif a.count ~= nil and b.count ~= nil then
  148.         return a.count >= b.count
  149.     else
  150.         return false
  151.     end
  152. end
  153.  
  154. local function growingName(a, b)
  155.     if a.displayName ~= nil and b.displayName ~= nil then
  156.         return a.displayName < b.displayName
  157.     else
  158.         return a.name < b.name
  159.     end
  160. end
  161.  
  162. local function shrinkingName(a, b)
  163.     if a.displayName ~= nil and b.displayName ~= nil then
  164.         return a.displayName > b.displayName
  165.     else
  166.         return a.name > b.name
  167.     end
  168. end
  169.  
  170. local function getSortingMethod()
  171.     if sortByName and sortAscending then
  172.         return growingName
  173.     elseif sortByName and not sortAscending then
  174.         return shrinkingName
  175.     elseif not sortByName and sortAscending then
  176.         return growingQuantity
  177.     elseif not sortByName and not sortAscending then
  178.         return shrinkingQuantity
  179.     end
  180. end
  181.  
  182. -- Peripherals Data
  183. local function peripheralCall(side, functionName, ...)
  184.     local status, retval = pcall(peripheral.call, side, functionName, ...)
  185.     if status then
  186.         return retval
  187.     else
  188.         return nil
  189.     end
  190. end
  191.  
  192. local nodeTypes = {
  193.     "command",
  194.     "computer",
  195.     "drive",
  196.     "modem",
  197.     "monitor",
  198.     "printer",
  199.     "speaker",
  200.     -- Generic Peripherals
  201.     "energy_storage",
  202.     "fluid_storage",
  203.     "inventory"
  204. }
  205. -- Node Object Start
  206. local Node = {}
  207. Node.__index = Node
  208. function Node.new(side)
  209.     local newNode = {}
  210.     setmetatable(newNode, Node)
  211.     newNode.side = side
  212.     newNode.name = side
  213.     newNode.peripheral = peripheral.wrap(side)
  214.     newNode.types = {}
  215.     local types = table.pack(peripheral.getType(side))
  216.     for k,type in pairs(types) do
  217.         if indexOf(nodeTypes, type) then
  218.             table.insert(newNode.types, type)
  219.         end
  220.     end
  221.     return newNode
  222. end
  223. -- Node Object end
  224.  
  225. -- Screen Object Start
  226. local Screen = {}
  227. setmetatable(Screen, Node)
  228. Screen.__index = Screen
  229. function Screen.new(side)
  230.     local newScreen = Node.new(side)
  231.     setmetatable(newScreen, Screen)
  232.     newScreen.ouput = "None"
  233.     return newScreen
  234. end
  235. function Screen:drawNetworkName()
  236.     pcall(function()
  237.         local screen = self.peripheral
  238.         screen.setBackgroundColor(colors.black)
  239.         screen.setTextColor(colors.white)
  240.         local screenSizeX,screenSizeY = screen.getSize()
  241.         screen.clear()
  242.         screen.setCursorPos(1, screenSizeY)
  243.         screen.write(self.side)
  244.     end)
  245. end
  246. function Screen:refreshMonitor()
  247.     pcall(function()
  248.         -- Monitor sizes for textScale = 1:
  249.         -- 1x1 monitor : 7 x 5
  250.         -- 2x2 monitor : 18 x 12 (+7+4 x +5+2)
  251.         -- 3x3 monitor : 29 x 19 (+7+4 x +5+2)
  252.         -- 4x4 monitor : 39 x 26 (+7+3 x +5+2)
  253.         -- 5x5 monitor : 50 x 33 (+7+4 x +5+2)
  254.    
  255.         -- Monitor sizes for textScale = 0.5:
  256.         -- 1x1 monitor : 15 x 10
  257.         -- 2x2 monitor : 36 x 24 (+15+6 x +10+4)
  258.         -- 3x3 monitor : 57 x 38 (+15+6 x +10+4)
  259.         -- 4x4 monitor : 79 x 52 (+15+7 x +10+4)
  260.         -- 5x5 monitor : 100 x 67 (+15+6 x +10+5)
  261.    
  262.         -- add widget setup :
  263.         -- -- width
  264.         -- -- height
  265.         -- -- data type selector : item / node
  266.         -- -- data selector : list / entity
  267.         -- widget size should be selectable (multiples of split screens ? 15 / 2 = 7 + 1 + 7 = widget + border + widget)
  268.         -- widgets types : item data / items list / node data (slots / tanks / RF)
  269.         local screen = self.peripheral
  270.         screen.setBackgroundColor(colors.white)
  271.         screen.setTextColor(colors.black)
  272.         screen.setTextScale(0.5)
  273.         local screenSizeX,screenSizeY = screen.getSize()
  274.         screen.clear()
  275.         if self.output == "Items" then
  276.             screen.setCursorPos(1, 1)
  277.             screen.write("Items")
  278.         elseif self.output == "Nodes" then
  279.             screen.setCursorPos(1, 1)
  280.             screen.write("Nodes")
  281.         else
  282.             screen.setCursorPos(1, 1)
  283.             screen.write("None")
  284.             screen.setCursorPos(1,2)
  285.             screen.write("x:" .. screenSizeX)
  286.             screen.setCursorPos(1,3)
  287.             screen.write("y:" .. screenSizeY)
  288.             screen.setCursorPos(1,4)
  289.             screen.write("scale:" .. screen.getTextScale())
  290.             screen.setCursorPos(1,5)
  291.             screen.write("Items:" .. #items)
  292.             screen.setCursorPos(1,6)
  293.             screen.write("Nodes:" .. #nodes)
  294.         end
  295.     end)
  296. end
  297. -- Screen Object End
  298.  
  299. -- Inventory Object Start
  300. local Inventory = {}
  301. setmetatable(Inventory, Node)
  302. Inventory.__index = Inventory
  303. function Inventory.new(side)
  304.     local newInventory = Node.new(side)
  305.     setmetatable(newInventory, Inventory)
  306.     newInventory.inventoryType = "Output"
  307.     newInventory.inventory = {
  308.         capacity = 0,
  309.         stored = 0,
  310.         items = {},
  311.         epoch = 0
  312.     }
  313.     return newInventory
  314. end
  315. function Inventory:refreshInventory()
  316.     local inventory = {
  317.         capacity = self.inventory.capacity,
  318.         stored = 0,
  319.         items = {},
  320.         epoch = 0
  321.     }
  322.     local itemList
  323.     parallel.waitForAll(
  324.         function()
  325.             inventory.capacity = peripheralCall(self.side, "size") or 0
  326.         end,
  327.         function()
  328.             itemList = peripheralCall(self.side, "list") or {}
  329.         end
  330.     )
  331.    
  332.     local functionsTable = {}
  333.     for i = 1, self.inventory.capacity do
  334.         if itemList[i] == nil then
  335.             inventory.items[i] = nil
  336.         elseif self.inventory.items[i] == nil or self.inventory.items[i].epoch == nil or self.inventory.items[i].epoch < os.epoch("utc") - getItemDetailInterval then
  337.             functionsTable[#functionsTable + 1] = function()
  338.                 if itemDb[itemList[i].name] == nil then
  339.                     local tmp = peripheralCall(self.side, "getItemDetail", i)
  340.                     if tmp ~= nil then
  341.                         itemDb[itemList[i].name] = tmp
  342.                     end
  343.                 end
  344.                 inventory.items[i] = {}
  345.                 for k,v in pairs(itemDb[itemList[i].name]) do
  346.                     inventory.items[i][k] = v
  347.                 end
  348.                 inventory.items[i].count = itemList[i].count
  349.                 inventory.items[i].epoch = os.epoch("utc")
  350.             end
  351.         else
  352.             inventory.items[i] = self.inventory.items[i]
  353.         end
  354.     end
  355.     parallel.waitForAll(unpack(functionsTable))
  356.    
  357.     for i = 1, inventory.capacity do
  358.         if inventory.items[i] ~= nil then
  359.             inventory.stored = inventory.stored + 1
  360.         end
  361.     end
  362.     self.inventory = inventory
  363. end
  364. function Inventory:pushItem(toName, fromSlot)
  365.     return peripheralCall(self.side, "pushItems", toName, fromSlot)
  366. end
  367. -- Inventory Object End
  368.  
  369. -- TurtleInventory Object Start
  370. local TurtleInventory = {}
  371. setmetatable(TurtleInventory, Inventory)
  372. TurtleInventory.__index = TurtleInventory
  373. function TurtleInventory.new(side)
  374.     local newInventory = Inventory.new(side)
  375.     setmetatable(newInventory, TurtleInventory)
  376.     newInventory.peripheral = turtle
  377.     newInventory.types = {"inventory"}
  378.     newInventory.inventoryType = "None"
  379.     newInventory.inventory = {
  380.         capacity = 16,
  381.         stored = 0,
  382.         items = {}
  383.     }
  384.     return newInventory
  385. end
  386. function TurtleInventory:refreshInventory()
  387.     local inventory = {
  388.         capacity = 16,
  389.         stored = 0,
  390.         items = {}
  391.     }
  392.  
  393.     local functionsTable = {}
  394.     for i = 1, self.inventory.capacity do
  395.         if self.inventory[i] == nil or self.inventory[i].epoch < os.epoch("utc") - getItemDetailInterval then
  396.             functionsTable[#functionsTable + 1] = function()
  397.                 local tmp = self.peripheral.getItemDetail(i, true)
  398.                 if tmp ~= nil then
  399.                     inventory.items[i] = tmp
  400.                     inventory.items[i].epoch = os.epoch("utc")
  401.                 else
  402.                     inventory.items[i] = nil
  403.                 end
  404.             end
  405.         end
  406.     end
  407.     parallel.waitForAll(unpack(functionsTable))
  408.  
  409.     for i = 1, self.inventory.capacity do
  410.         if inventory.items[i] ~= nil then
  411.             inventory.stored = inventory.stored + 1
  412.         end
  413.     end
  414.     self.inventory = inventory
  415. end
  416. function TurtleInventory:pushItem(toName, fromSlot)
  417.     return peripheralCall(toName, "pullItems", self.side, fromSlot)
  418. end
  419. -- TurtleInventory Object End
  420.  
  421. -- Craft Object Start
  422. local Craft = {}
  423. Craft.__index = Craft
  424. function Craft.new(name)
  425.     local newCraft = {}
  426.     setmetatable(newCraft, Craft)
  427.     -- Craft made of a name, Input(s) and Output(s)
  428.     newCraft.name = name
  429.     newCraft.inputs = {}
  430.     newCraft.outputs = {}
  431.     return newCraft
  432. end
  433. function Craft:pushItem(toName, fromSlot)
  434.     return peripheralCall(self.side, "pushItems", toName, fromSlot)
  435. end
  436. -- Craft Object End
  437.  
  438. -- wrap turtle inventory
  439. if (turtle) then
  440.     local sides = peripheral.getNames()
  441.     local localName = nil;
  442.     for i in pairs(sides) do
  443.         if (peripheral.getType(sides[i]) == "modem") and not peripheralCall(sides[i], "isWireless")then
  444.             localName = peripheralCall(sides[i], "getNameLocal")
  445.             break
  446.         end
  447.     end
  448.     nodes[#nodes + 1] = TurtleInventory.new(localName)
  449. end
  450.  
  451. local function isRemote(name)
  452.     return string.match(name, '(.*_)')
  453. end
  454.  
  455. local function findPeripherals()
  456.     local sides = peripheral.getNames()
  457.  
  458.     for k in pairs(nodes) do
  459.         local peripheralFound = false
  460.         for k2 in pairs(sides) do
  461.             if nodes[k] ~= nil and nodes[k].side == sides[k2] then
  462.                 table.remove(sides, k2)
  463.                 peripheralFound = true
  464.             end
  465.         end
  466.         if not peripheralFound and string.sub(nodes[k].side, 1, string.len("turtle")) ~= "turtle" then
  467.             -- table.remove(nodes, k)
  468.         end
  469.     end
  470.  
  471.     local index = #nodes + 1
  472.     for i in pairs(sides) do
  473.         local matches = isRemote(sides[i])
  474.  
  475.         if matches then
  476.             local types = table.pack(peripheral.getType(sides[i]))
  477.             local filteredTypes = {}
  478.             for k,type in pairs(types) do
  479.                 if indexOf(nodeTypes, type) then
  480.                     table.insert(filteredTypes, type)
  481.                 end
  482.             end
  483.             if indexOf(filteredTypes, "inventory") then
  484.                 nodes[index] = Inventory.new(sides[i])
  485.             elseif indexOf(filteredTypes, "monitor") then
  486.                 nodes[index] = Screen.new(sides[i])
  487.             else
  488.                 nodes[index] = Node.new(sides[i])
  489.             end
  490.             index = index + 1
  491.         end
  492.     end
  493. end
  494.  
  495. local function refreshInventories()
  496.     -- for i in ipairs(wrapped) do
  497.     local functionsTable = {}
  498.     for i = 1, #nodes do
  499.         if indexOf(nodes[i].types, "inventory") then
  500.             functionsTable[#functionsTable + 1] = function() nodes[i]:refreshInventory() end
  501.         end
  502.     end
  503.     if #functionsTable > 0 then
  504.         parallel.waitForAll(unpack(functionsTable))
  505.     end
  506. end
  507. local function refreshScreens()
  508.     -- for i in ipairs(wrapped) do
  509.     local functionsTable = {}
  510.     for i = 1, #nodes do
  511.         if indexOf(nodes[i].types, "monitor") then
  512.             functionsTable[#functionsTable + 1] = function() nodes[i]:refreshMonitor() end
  513.         end
  514.     end
  515.     if #functionsTable > 0 then
  516.         parallel.waitForAll(unpack(functionsTable))
  517.     end
  518. end
  519.  
  520. -- Items Data
  521.  
  522. local function updateItems()
  523.     for i = 1,#items do
  524.         items[i].tempCount = 0
  525.     end
  526.  
  527.     local itemsListHasChanged = false
  528.     for i = 1, #nodes do
  529.         local node = nodes[i]
  530.         if node ~= nil and node.inventory ~= nil and node.inventoryType ~= nil then -- and wrapped[i].inventoryType == "Output" then
  531.             local inventory = node.inventory
  532.             for ii = 1, inventory.capacity do
  533.                 if inventory.items[ii] ~= nil and inventory.items[ii].name ~= nil then
  534.                     local currentIndex = 0
  535.                     for iii = 1,#items do
  536.                         if items[iii].name == inventory.items[ii].name and items[iii].nbt == inventory.items[ii].nbt then
  537.                             currentIndex = iii
  538.                         end
  539.                     end
  540.                     if currentIndex == 0 then
  541.                         items[#items + 1] = inventory.items[ii]
  542.                         items[#items].tempCount = inventory.items[ii].count
  543.                         itemsListHasChanged = true
  544.                     else
  545.                         if items[currentIndex].displayName == nil and inventory.items[ii].displayName ~= nil then
  546.                             items[currentIndex].displayName = inventory.items[ii].displayName
  547.                             itemsListHasChanged = true
  548.                         end
  549.                         if items[currentIndex].epoch == nil or items[currentIndex].epoch < os.epoch("utc") - getItemDetailInterval then
  550.                             for k,v in pairs(inventory.items[ii]) do
  551.                                 if k ~= "count" then
  552.                                     items[currentIndex][k] = v
  553.                                 end
  554.                             end
  555.                         end
  556.                         items[currentIndex].tempCount = items[currentIndex].tempCount + inventory.items[ii].count
  557.                     end
  558.                 end
  559.             end
  560.         end
  561.     end
  562.  
  563.     for k,item in pairs(items) do
  564.         if item.tempCount ~= item.count then
  565.             item.count = item.tempCount
  566.             itemsListHasChanged = true
  567.         end
  568.         item.tempCount = nil
  569.         if item.count == 0 then
  570.             -- TODO : keep data not delete (property hidden = true/false ?)
  571.             table.remove(items, k)
  572.             itemsListHasChanged = true
  573.         end
  574.     end
  575.  
  576.     if itemsListHasChanged then
  577.         table.sort(items, getSortingMethod())
  578.     end
  579. end
  580.  
  581. -- Draw
  582. -- Widget Object Start
  583. local Widget = {}
  584. Widget.__index = Widget
  585. function Widget.new(window, x, y, label)
  586.     local newWidget = {}
  587.     setmetatable(newWidget, Widget)
  588.     newWidget.window = window
  589.     newWidget.x = x
  590.     newWidget.y = y
  591.     newWidget.width, newWidget.height = window.getSize()
  592.     newWidget.label = label
  593.     newWidget.content = nil
  594.     newWidget.events = {}
  595.     return newWidget
  596. end
  597. function Widget:draw()
  598.     if self.content ~= nil then
  599.         for y = self.y, self.height do
  600.             self.window.setCursorPos(self.x, y)
  601.             self.window.write(self.label)
  602.             -- for x = self.x, self.height do
  603.             -- if self.content[y] ~= nil then
  604.             --     self.window.blit(self.content[y][1], self.content[y][2], self.content[y][3])
  605.             -- end
  606.             -- end
  607.         end
  608.     end
  609. end
  610. function Widget:handleEvents(event, side, xPos, yPos)
  611.     if xPos ~= nil and yPos ~= nil then
  612.         local offsetX, offsetY = self.window.getPosition()
  613.         xPos = xPos - offsetX + 1
  614.         yPos = yPos - offsetY + 1
  615.     end
  616.     -- start from the end of the table
  617.     -- pass an object by reference to keep data ?
  618.     -- if a callback returns stop propagating event ?
  619.     for k,v in pairs(self.events) do
  620.         if v.type == event and (xPos == nil or (xPos > 0 and xPos <= self.width)) and (yPos == nil or (yPos > 0 and yPos <= self.height)) then
  621.             v.callback(self, side, xPos, yPos)
  622.         end
  623.     end
  624. end
  625. -- return Widget
  626. -- Widget Object End
  627.  
  628. -- ListWidget Object Start
  629. local ListWidget = {}
  630. setmetatable(ListWidget, Widget)
  631. ListWidget.__index = ListWidget
  632. function ListWidget.new(window, x, y, label, list)
  633.     local newWidget = Widget.new(window, x, y, label)
  634.     setmetatable(newWidget, ListWidget)
  635.     newWidget.list = list
  636.     newWidget.scrolled = 0
  637.     newWidget.totalLines = 0
  638.     newWidget.currentLine = 1
  639.     newWidget.selected = 0
  640.     newWidget.selectedLines = 0
  641.     newWidget.dragged = false
  642.  
  643.     newWidget.events = {
  644.         {
  645.             -- Scroll buttons
  646.             type = "mouse_click",
  647.             callback = function (self, side, xPos, yPos)
  648.                 if (xPos == self.width) then
  649.                     if (yPos == 1) then
  650.                         if self.scrolled > 0 then
  651.                             self.scrolled = self.scrolled - 1
  652.                         end
  653.                     elseif (yPos == self.height) then
  654.                         if self.totalLines > self.scrolled + self.height then
  655.                             self.scrolled = self.scrolled + 1
  656.                         end
  657.                     else
  658.                         self.scrolled = math.floor((yPos-2) * ((self.totalLines - self.height) / (self.height-3)))
  659.                     end
  660.                 end
  661.             end
  662.         },
  663.         {
  664.             -- Scroll wheel
  665.             type = "mouse_scroll",
  666.             callback = function (self, direction, xPos, yPos)
  667.                 if (self.scrolled + direction < 0) then
  668.                     self.scrolled = 0
  669.                 elseif self.scrolled + direction <= self.totalLines - self.height then
  670.                     self.scrolled = self.scrolled + direction
  671.                 end
  672.             end
  673.         },
  674.         {
  675.             -- Drag buttons + selection mecanism
  676.             type = "mouse_click",
  677.             callback = function (self, side, xPos, yPos)
  678.                 if xPos > 0 and yPos > 0 and xPos <= self.width and yPos <= self.height then
  679.                     -- clicked on selected or selectedLines
  680.                     if (yPos + self.scrolled >= self.selected and yPos + self.scrolled <= self.selected + self.selectedLines) then
  681.                         -- clicked on selected
  682.                         if (yPos + self.scrolled == self.selected) then
  683.                             -- clicked on up arrow of the last line
  684.                             if self.selected > 1 and xPos == 1 then
  685.                                 local temp = self.list[self.selected - 1]
  686.                                 self.list[self.selected - 1] = self.list[self.selected]
  687.                                 self.list[self.selected] = temp
  688.                                 self.selected = self.selected - 1
  689.                             -- clicked on down arrow of any line
  690.                             elseif (self.selected == 1 and xPos == 1) or (self.selected > 1 and self.selected < #self.list and xPos == 2) then
  691.                                 local temp = self.list[self.selected + 1]
  692.                                 self.list[self.selected + 1] = self.list[self.selected]
  693.                                 self.list[self.selected] = temp
  694.                                 self.selected = self.selected + 1
  695.                             end
  696.                         else
  697.                             -- trigger click on item selected content ?
  698.                         end
  699.                     -- clicked in list but not on selected => new selected
  700.                     elseif (yPos + self.scrolled <= self.totalLines and xPos < self.width) then
  701.                         if self.selected ~= 0 then
  702.                             -- clicked after selected
  703.                             if yPos + self.scrolled > self.selected + self.selectedLines then
  704.                                 self.dragged = true
  705.                                 self.selected = yPos + self.scrolled - self.selectedLines
  706.                             -- clicked before selected
  707.                             else
  708.                                 self.dragged = true
  709.                                 self.selected = yPos + self.scrolled
  710.                             end
  711.                         else
  712.                             self.dragged = true
  713.                             self.selected = yPos + self.scrolled
  714.                             if self.scrolled + sizeY <= self.selected + self.selectedLines then
  715.                                 self.scrolled = self.selected + 1 - self.height
  716.                             end
  717.                         end
  718.                     end
  719.                 end
  720.             end
  721.         },
  722.         {
  723.             type = "mouse_up",
  724.             callback = function (self, side, xPos, yPos)
  725.                 -- if not dragged clear selected
  726.                 if not self.dragged then
  727.                     if xPos < self.width and yPos >= 1 and (yPos + self.scrolled == self.selected) then
  728.                         if self.scrolled > #self.list - self.height then
  729.                             self.scrolled = #self.list - self.height
  730.                         end
  731.                         if self.scrolled < 0 then
  732.                             self.scrolled = 0
  733.                         end
  734.                         self.selected = 0
  735.                     end
  736.                 else
  737.                     self.dragged = false
  738.                 end
  739.             end
  740.         },
  741.         {
  742.             type = "mouse_drag",
  743.             callback = function (self, side, xPos, yPos)
  744.                 if (yPos + self.scrolled < self.selected and yPos + self.scrolled >= 1) then
  745.                     local temp = self.list[self.selected - 1]
  746.                     self.list[self.selected - 1] = self.list[self.selected]
  747.                     self.list[self.selected] = temp
  748.                     self.selected = self.selected - 1
  749.                     self.dragged = true
  750.                     if (self.scrolled > 0 and yPos == 1) then
  751.                         self.scrolled = self.scrolled - 1
  752.                     end
  753.                 elseif (yPos + self.scrolled > self.selected and self.selected < #self.list) then
  754.                     local temp = self.list[self.selected + 1]
  755.                     self.list[self.selected + 1] = self.list[self.selected]
  756.                     self.list[self.selected] = temp
  757.                     self.selected = self.selected + 1
  758.                     self.dragged = true
  759.                     if (self.scrolled + sizeY-1 < self.selected + self.selectedLines and yPos == self.height) then
  760.                         self.scrolled = self.scrolled + 1
  761.                     end
  762.                 end
  763.             end
  764.         },
  765.         {
  766.             type = "peripheral",
  767.             callback = function (self, side, xPos, yPos)
  768.                 self:listUpdated(side)
  769.             end
  770.         },
  771.         {
  772.             type = "peripheral_detach",
  773.             callback = function (self, side, xPos, yPos)
  774.                 self:listUpdated(side)
  775.             end
  776.         }
  777.     }
  778.     return newWidget
  779. end
  780. function ListWidget:draw()
  781.     self:drawList()
  782.     if (self.totalLines > self.height) then
  783.         self:drawScrollBar()
  784.         -- Check if last line was empty
  785.         if (self.currentLine - 1 < self.height) then
  786.             self.scrolled = self.scrolled - (self.height - self.currentLine) - 1
  787.         end
  788.     end
  789. end
  790. function ListWidget:drawList()
  791.     self.totalLines = 0
  792.     self.currentLine = 1
  793.     self.selectedLines = 0
  794.  
  795.     for i = 1, #self.list do
  796.         if self.list[i] ~= nil then
  797.             if i > self.scrolled - self.selectedLines and self.currentLine <= self.height then
  798.                 local linesAdded = self:drawItem(self.list[i], self.currentLine, i == self.selected, i == 1, i == #self.list)
  799.                 self.currentLine = self.currentLine + linesAdded
  800.                 if i == self.selected then
  801.                     self.selectedLines = linesAdded - 1
  802.                 end
  803.                 self.totalLines = self.totalLines + linesAdded
  804.             elseif i == self.selected then
  805.                 self.currentLine = i - self.scrolled
  806.                 local linesAdded = self:drawItem(self.list[i], self.currentLine, i == self.selected, i == 1, i == #self.list)
  807.                 self.selectedLines = linesAdded - 1
  808.                 self.currentLine = self.currentLine + linesAdded
  809.                 if self.currentLine < 1 then
  810.                     self.currentLine = 1
  811.                 end
  812.                 self.totalLines = self.totalLines + linesAdded
  813.             else
  814.                 self.totalLines = self.totalLines + 1
  815.             end
  816.         end
  817.     end
  818.     if self.totalLines < self.height then
  819.         for i = self.totalLines + 1, self.height do
  820.             self.window.setCursorPos(1, i)
  821.             self.window.setBackgroundColor(colors.white)
  822.             self.window.clearLine()
  823.         end
  824.     end
  825. end
  826. function ListWidget:drawScrollBar()
  827.     local unit = self.totalLines / self.height
  828.     local scrollBarHeight = math.ceil(self.height / unit)
  829.     if scrollBarHeight > self.height then scrollBarHeight = self.height end
  830.  
  831.     for i = 1, self.height do
  832.         self.window.setBackgroundColor(colors.gray)
  833.         self.window.setTextColor(colors.lightGray)
  834.         -- if (i) >= math.ceil(self.scrolled / unit) and (i) <= math.floor((self.scrolled / unit) + scrollBarHeight) then
  835.         if math.floor(i * unit) >= self.scrolled and math.ceil(i * unit) <= self.scrolled + self.height then
  836.             self.window.setBackgroundColor(colors.lightGray)
  837.             self.window.setTextColor(colors.gray)
  838.         end
  839.         self.window.setCursorPos(sizeX, i)
  840.         if i == 1 then
  841.             self.window.write("\30")
  842.         elseif i == self.height then
  843.             self.window.write("\31")
  844.         else
  845.             self.window.write(" ")
  846.         end
  847.     end
  848. end
  849. function ListWidget:drawItemFirstLine(Y, isSelected, first, last)
  850.     self.window.setCursorPos(1, Y)
  851.     if isSelected then
  852.         -- affiche les fleches pour monter/descendre
  853.         self.window.setBackgroundColor(colors.lightGray)
  854.         self.window.setTextColor(colors.gray)
  855.         self.window.clearLine()
  856.         if first then
  857.             self.window.write("\31")
  858.             self.window.setCursorPos(2, Y)
  859.         elseif last then
  860.             self.window.write("\30")
  861.             self.window.setCursorPos(2, Y)
  862.         else
  863.             self.window.write("\30\31")
  864.             self.window.setCursorPos(3, Y)
  865.         end
  866.         self.window.setTextColor(colors.black)
  867.     else
  868.         self.window.setBackgroundColor(colors.white)
  869.         self.window.setTextColor(colors.black)
  870.         self.window.clearLine()
  871.     end
  872. end
  873. function ListWidget:listUpdated(side)
  874. end
  875. -- return ListWidget
  876. -- ListWidget Object End
  877.  
  878. -- ItemsListWidget Object Start
  879. local itemsWindow = window.create(monitor, 1, 2, sizeX, sizeY-1)
  880. itemsListWidget = ListWidget.new(itemsWindow, 1, 1, "Items", items)
  881. function itemsListWidget:drawItem(item, Y, isSelected, first, last)
  882.     local linesDrawn = 0
  883.     self:drawItemFirstLine(Y, isSelected, first, last)
  884.  
  885.     if item.displayName ~= nil then
  886.         self.window.write(item.displayName)
  887.     else
  888.         self.window.write(item.name)
  889.     end
  890.     self.window.setCursorPos(sizeX - #("" .. item.count), Y)
  891.     self.window.write(item.count)
  892.     Y = Y + 1
  893.     linesDrawn = linesDrawn + 1
  894.  
  895.     if isSelected then
  896.         self.window.setTextColor(colors.gray)
  897.         for k,v in pairs(item) do
  898.             if type(v) ~= type(table) then
  899.                 -- if k ~= "epoch" then
  900.                     self.window.setCursorPos(2, Y)
  901.                     self.window.clearLine()
  902.                     self.window.write(k .. " " .. v)
  903.                     Y = Y + 1
  904.                     linesDrawn = linesDrawn + 1
  905.                 -- end
  906.             else
  907.                 -- count entries in table (tags may be empty)
  908.                 local entriesCount = 0;
  909.                 for kk in pairs(v) do
  910.                     entriesCount = entriesCount + 1
  911.                 end
  912.                 if entriesCount > 0 then
  913.                     self.window.setCursorPos(2, Y)
  914.                     self.window.clearLine()
  915.                     self.window.write(k .. ":")
  916.                     Y = Y + 1
  917.                     linesDrawn = linesDrawn + 1
  918.                     for kk in pairs(v) do
  919.                         self.window.setCursorPos(3, Y)
  920.                         self.window.clearLine()
  921.                         self.window.write(kk)
  922.                         Y = Y + 1
  923.                         linesDrawn = linesDrawn + 1
  924.                     end
  925.                 end
  926.             end
  927.         end
  928.     end
  929.     return linesDrawn
  930. end
  931. -- ItemsListWidget Object end
  932.  
  933. -- PeripheralsListWidget Object Start
  934. local peripheralsWindow = window.create(monitor, 1, 2, sizeX, sizeY-1)
  935. peripheralsListWidget = ListWidget.new(peripheralsWindow, 1, 1, "Peripherals", nodes)
  936. function peripheralsListWidget:drawItem(item, Y, isSelected, first, last)
  937.     local linesDrawn = 0
  938.     self:drawItemFirstLine(Y, isSelected, first, last)
  939.  
  940.     if item.name ~= nil then
  941.         self.window.write(item.name)
  942.     else
  943.         self.window.write(item.side)
  944.     end
  945.     Y = Y + 1
  946.     linesDrawn = linesDrawn + 1
  947.  
  948.     if isSelected then
  949.         if indexOf(item.types, "inventory") then
  950.             local inventoryLinesDrawn = self:drawInventory(item, Y)
  951.             Y = Y + inventoryLinesDrawn
  952.             linesDrawn = linesDrawn + inventoryLinesDrawn
  953.         end
  954.         if indexOf(item.types, "monitor") then
  955.             local monitorLinesDrawn = self:drawMonitor(item, Y)
  956.             Y = Y + monitorLinesDrawn
  957.             linesDrawn = linesDrawn + monitorLinesDrawn
  958.         end
  959.  
  960.         -- draw types
  961.         if #item.types > 0 then
  962.             self.window.setBackgroundColor(colors.black)
  963.             self.window.setTextColor(colors.white)
  964.             self.window.setCursorPos(1, Y)
  965.             self.window.clearLine()
  966.             self.window.write("Types :")
  967.             Y = Y + 1
  968.             linesDrawn = linesDrawn + 1
  969.             for k, type in pairs(item.types) do
  970.                 self.window.setCursorPos(1, Y)
  971.                 self.window.clearLine()
  972.                 self.window.write(" " .. type)
  973.                 Y = Y + 1
  974.                 linesDrawn = linesDrawn + 1
  975.             end
  976.         end
  977.     end
  978.     return linesDrawn
  979. end
  980. function peripheralsListWidget:drawInventory(item, Y)
  981.     local linesDrawn = 0
  982.     self.window.setBackgroundColor(colors.white)
  983.     self.window.setTextColor(colors.black)
  984.     self.window.setCursorPos(1, Y)
  985.     self.window.clearLine()
  986.     self.window.write("Type : Input Output None Configure")
  987.     self.window.setBackgroundColor(colors.black)
  988.     self.window.setTextColor(colors.white)
  989.     if item.inventoryType == "Input" then
  990.         self.window.setCursorPos(8, Y)
  991.         self.window.write("Input")
  992.     elseif item.inventoryType == "Output" then
  993.         self.window.setCursorPos(14, Y)
  994.         self.window.write("Output")
  995.     else
  996.         self.window.setCursorPos(21, Y)
  997.         self.window.write("None")
  998.     end
  999.     Y = Y + 1
  1000.     linesDrawn = linesDrawn + 1
  1001.  
  1002.     drawBar(1, self.width-1, Y, colors.lightGray, colors.gray, item.inventory.capacity, item.inventory.stored, "Inventory", self.window)
  1003.     Y = Y + 1
  1004.     linesDrawn = linesDrawn + 1
  1005.  
  1006.     self.window.setBackgroundColor(colors.lightGray)
  1007.     self.window.setTextColor(colors.gray)
  1008.     for i = 1,item.inventory.capacity do
  1009.         if item.inventory.items[i] ~= nil then
  1010.             self.window.setCursorPos(1, Y)
  1011.             self.window.clearLine()
  1012.             if item.inventory.items[i].displayName ~= nil then
  1013.                 self.window.write(i .. " " .. item.inventory.items[i].displayName .. " " .. item.inventory.items[i].count)
  1014.             else
  1015.                 self.window.write(i .. " " .. item.inventory.items[i].name .. " " .. item.inventory.items[i].count)
  1016.             end
  1017.             Y = Y + 1
  1018.             linesDrawn = linesDrawn + 1
  1019.         end
  1020.     end
  1021.     return linesDrawn
  1022. end
  1023. function peripheralsListWidget:drawMonitor(item, Y)
  1024.     local linesDrawn = 0
  1025.     self.window.setBackgroundColor(colors.white)
  1026.     self.window.setTextColor(colors.black)
  1027.     self.window.setCursorPos(1, Y)
  1028.     self.window.clearLine()
  1029.     self.window.write("Print : Items Nodes None")
  1030.     self.window.setBackgroundColor(colors.black)
  1031.     self.window.setTextColor(colors.white)
  1032.     if item.output == "Items" then
  1033.         self.window.setCursorPos(9, Y)
  1034.         self.window.write("Items")
  1035.     elseif item.output == "Nodes" then
  1036.         self.window.setCursorPos(15, Y)
  1037.         self.window.write("Nodes")
  1038.     else
  1039.         self.window.setCursorPos(21, Y)
  1040.         self.window.write("None")
  1041.     end
  1042.     Y = Y + 1
  1043.     linesDrawn = linesDrawn + 1
  1044.     return linesDrawn
  1045. end
  1046. function peripheralsListWidget:listUpdated(side)
  1047.     if self.list[self.selected] ~= nil and self.list[self.selected].side == side then
  1048.         self.selected = 0
  1049.     end
  1050. end
  1051. table.insert(peripheralsListWidget.events, {
  1052.     type = "mouse_click",
  1053.     callback = function (self, side, xPos, yPos)
  1054.         -- Peripherals settings
  1055.         if self.selected ~= 0 and yPos + self.scrolled == self.selected + 1 then
  1056.             local item = nodes[self.selected]
  1057.             if indexOf(item.types, "inventory") then
  1058.                 if xPos >= 8 and xPos <= 12 then
  1059.                     item.inventoryType = "Input"
  1060.                 elseif xPos >= 14 and xPos <= 19 then
  1061.                     item.inventoryType = "Output"
  1062.                 elseif xPos >= 21 and xPos <= 24 then
  1063.                     item.inventoryType = "None"
  1064.                 end
  1065.             end
  1066.             if indexOf(item.types, "monitor") then
  1067.                 if xPos >= 9 and xPos <= 13 then
  1068.                     item.output = "Items"
  1069.                 elseif xPos >= 15 and xPos <= 19 then
  1070.                     item.output = "Nodes"
  1071.                 elseif xPos >= 21 and xPos <= 24 then
  1072.                     item.output = "None"
  1073.                 end
  1074.             end
  1075.         end
  1076.     end
  1077. })
  1078. -- PeripheralsListWidget Object end
  1079.  
  1080. -- CraftsListWidget Object Start
  1081. local craftsWindow = window.create(monitor, 1, 2, sizeX, sizeY-1)
  1082. craftsListWidget = ListWidget.new(craftsWindow, 1, 1, "Crafts", crafts)
  1083. craftsListWidget.mode = "list"
  1084. function craftsListWidget:drawItem(item, Y, isSelected, first, last)
  1085.     local linesDrawn = 0
  1086.     self:drawItemFirstLine(Y, isSelected, first, last)
  1087.  
  1088.     self.window.write(item.name)
  1089.     self.window.setCursorPos(sizeX - #("Config"), Y)
  1090.     self.window.write("Config")
  1091.     Y = Y + 1
  1092.     linesDrawn = linesDrawn + 1
  1093.  
  1094.     if isSelected then
  1095.         -- Inputs
  1096.         self.window.setTextColor(colors.gray)
  1097.         self.window.setCursorPos(2, Y)
  1098.         self.window.clearLine()
  1099.         self.window.write("Inputs :")
  1100.         Y = Y + 1
  1101.         linesDrawn = linesDrawn + 1
  1102.         if #item.inputs > 0 then
  1103.             for k,v in pairs(item.inputs) do
  1104.                 self.window.setCursorPos(3, Y)
  1105.                 self.window.clearLine()
  1106.                 self.window.write(k .. " " .. v)
  1107.                 Y = Y + 1
  1108.                 linesDrawn = linesDrawn + 1
  1109.             end
  1110.         end
  1111.  
  1112.         -- Outputs
  1113.         self.window.setTextColor(colors.gray)
  1114.         self.window.setCursorPos(2, Y)
  1115.         self.window.clearLine()
  1116.         self.window.write("Outputs :")
  1117.         Y = Y + 1
  1118.         linesDrawn = linesDrawn + 1
  1119.         if #item.outputs > 0 then
  1120.             for k,v in pairs(item.outputs) do
  1121.                 self.window.setCursorPos(3, Y)
  1122.                 self.window.clearLine()
  1123.                 self.window.write(k .. " " .. v)
  1124.                 Y = Y + 1
  1125.                 linesDrawn = linesDrawn + 1
  1126.             end
  1127.         end
  1128.     end
  1129.     return linesDrawn
  1130. end
  1131. function craftsListWidget:draw()
  1132.     if craftsListWidget.mode == "list" then
  1133.         self:drawList()
  1134.         self.totalLines = self.totalLines + 1
  1135.         self.window.setBackgroundColour(colors.gray)
  1136.         self.window.setTextColor(colors.lightGray)
  1137.         self.window.setCursorPos(self.width / 2, self.currentLine)
  1138.         self.window.clearLine()
  1139.         self.window.write("+")
  1140.         self.currentLine = self.currentLine + 1
  1141.         if (self.totalLines > self.height) then
  1142.             self:drawScrollBar()
  1143.             -- Check if last line was empty
  1144.             if (self.currentLine - 1 < self.height) then
  1145.                 self.scrolled = self.scrolled - (self.height - self.currentLine) - 1
  1146.             end
  1147.         end
  1148.     else
  1149.         -- Start Method display Craft Setup
  1150.         self.totalLines = 0
  1151.         self.currentLine = 1
  1152.         self.selectedLines = 0
  1153.    
  1154.         if self.list[self.selected] ~= nil then
  1155.             if self.selected > self.scrolled - self.selectedLines and self.currentLine <= self.height then
  1156.                 local linesAdded = self:drawItem(self.list[self.selected], self.currentLine, self.selected == self.selected, self.selected == 1, self.selected == #self.list)
  1157.                 self.currentLine = self.currentLine + linesAdded
  1158.                 if self.selected == self.selected then
  1159.                     self.selectedLines = linesAdded - 1
  1160.                 end
  1161.                 self.totalLines = self.totalLines + linesAdded
  1162.             elseif self.selected == self.selected then
  1163.                 self.currentLine = self.selected - self.scrolled
  1164.                 local linesAdded = self:drawItem(self.list[self.selected], self.currentLine, self.selected == self.selected, self.selected == 1, self.selected == #self.list)
  1165.                 self.selectedLines = linesAdded - 1
  1166.                 self.currentLine = self.currentLine + linesAdded
  1167.                 if self.currentLine < 1 then
  1168.                     self.currentLine = 1
  1169.                 end
  1170.                 self.totalLines = self.totalLines + linesAdded
  1171.             else
  1172.                 self.totalLines = self.totalLines + 1
  1173.             end
  1174.         end
  1175.         if self.totalLines < self.height then
  1176.             for i = self.totalLines + 1, self.height do
  1177.                 self.window.setCursorPos(1, i)
  1178.                 self.window.setBackgroundColor(colors.white)
  1179.                 self.window.clearLine()
  1180.             end
  1181.         end
  1182.         -- End Method
  1183.     end
  1184. end
  1185. table.insert(craftsListWidget.events, {
  1186.     type = "mouse_click",
  1187.     callback = function (self, side, xPos, yPos)
  1188.         if craftsListWidget.mode == "list" then
  1189.             -- Craft settings
  1190.             local item = nil
  1191.             if self.selected ~= 0 and yPos + self.scrolled == self.selected + 1 then
  1192.                 item = crafts[self.selected]
  1193.             elseif yPos + self.scrolled == self.totalLines then
  1194.                 -- New craft !
  1195.                 crafts[#crafts + 1] = Craft.new("Craft #" .. #crafts + 1)
  1196.                 item = crafts[#crafts]
  1197.             end
  1198.             if item ~= nil then
  1199.                 -- Print craft configuration
  1200.                 -- new widget ? configuration widget ? pre made inputs ?
  1201.             end
  1202.         else
  1203.             -- chaining events to another widget -- abstraction needed ? (généraliser à tous les widgets se relayer l'abonnement aux events ?)
  1204.             -- TODO : créer un widget CraftSetupWidget permettant de créer un Craft et de revenir à la craftListWidget
  1205.             -- Créer un ClickableWidget : créé à partir de coordonnées relatives à l'item affiché contenant un label et un callback !!!
  1206.         end
  1207.     end
  1208. })
  1209. -- CraftsListWidget Object end
  1210.  
  1211. -- TabsWidget Object start
  1212. tabsWidget = Widget.new(monitor, 1, 1, "Tabs")
  1213. tabsWidget.currentTab = itemsListWidget
  1214. tabsWidget.tabsList = {itemsListWidget, peripheralsListWidget, craftsListWidget}
  1215. function tabsWidget:draw()
  1216.     self.window.setBackgroundColor(colors.black)
  1217.     self.window.setTextColor(colors.white)
  1218.     self.window.setCursorPos(6, 1)
  1219.     self.window.clearLine()
  1220.     self.window.write(" ")
  1221.     local X = 1
  1222.     for key, tab in pairs(tabsWidget.tabsList) do
  1223.         if tabsWidget.currentTab == tab then
  1224.             self.window.setBackgroundColour(colors.gray)
  1225.         else
  1226.             self.window.setBackgroundColour(colors.black)
  1227.         end
  1228.         self.window.setCursorPos(X, 1)
  1229.         self.window.write(tab.label)
  1230.         X = X + #tab.label + 1
  1231.     end
  1232. end
  1233. table.insert(tabsWidget.events, {
  1234.     type = "mouse_click",
  1235.     callback = function (self, side, xPos, yPos)
  1236.         -- Tabs
  1237.         if (yPos == 1) then
  1238.             local X = 1
  1239.             for key, tab in pairs(tabsWidget.tabsList) do
  1240.                 if xPos >= X and xPos <= X + #tab.label then
  1241.                     tabsWidget.currentTab = tab
  1242.                     break
  1243.                 else
  1244.                     X = X + #tab.label + 1
  1245.                 end
  1246.             end
  1247.         end
  1248.     end
  1249. })
  1250. -- TabsWidget Object end
  1251.  
  1252. -- SortWidget Object start
  1253. sortWidget = Widget.new(monitor, 1, 1, "SortingButtons")
  1254. sortWidget.needRedraw = true
  1255. function sortWidget:draw()
  1256.     if self.needRedraw then
  1257.         table.sort(tabsWidget.currentTab.list, getSortingMethod())
  1258.         self.needRedraw = false
  1259.     end
  1260.     self.window.setBackgroundColor(colors.black)
  1261.     self.window.setTextColor(colors.white)
  1262.     self.window.setCursorPos(sizeX-1, 1)
  1263.     if sortByName == true then
  1264.         self.window.write("N")
  1265.     else
  1266.         self.window.write("C")
  1267.     end
  1268.     self.window.setCursorPos(sizeX, 1)
  1269.     if sortAscending == true then
  1270.         self.window.write("\30")
  1271.     else
  1272.         self.window.write("\31")
  1273.     end
  1274.     self.window.setBackgroundColor(colors.white)
  1275. end
  1276. table.insert(sortWidget.events, {
  1277.     type = "mouse_click",
  1278.     callback = function (self, side, xPos, yPos)
  1279.         -- Sorting
  1280.         if (xPos == sizeX-1 and yPos == 1) then
  1281.             sortByName = not sortByName
  1282.             self.needRedraw = true
  1283.         elseif (xPos == sizeX and yPos == 1) then
  1284.             sortAscending = not sortAscending
  1285.             self.needRedraw = true
  1286.         end
  1287.     end
  1288. })
  1289. -- SortWidget Object end
  1290.  
  1291. local function drawAll()
  1292.     local elapsed = os.clock()
  1293.     while not eventFired do
  1294.         updateItems()
  1295.         monitor.setVisible(false)
  1296.         -- monitor.clear()
  1297.         tabsWidget:draw()
  1298.         sortWidget:draw()
  1299.         tabsWidget.currentTab:draw()
  1300.  
  1301.         -- Debug List Count
  1302.             monitor.setBackgroundColor(colors.black)
  1303.             monitor.setTextColor(colors.white)
  1304.             monitor.setCursorPos(sizeX - 8 + 1 - 4, 1)
  1305.             monitor.write("    ")
  1306.             monitor.setCursorPos(sizeX - 8 + 1 - 4, 1)
  1307.             monitor.write(tabsWidget.currentTab.totalLines)
  1308.         -- End Debug
  1309.  
  1310.         -- Debug Elapsed Time
  1311.             monitor.setBackgroundColor(colors.black)
  1312.             monitor.setTextColor(colors.white)
  1313.             local elapsedTime = (os.clock() - elapsed)
  1314.             local elapsedTimeString = "" .. roundTo((os.clock() - elapsed) / 0.05, 1)
  1315.             monitor.setCursorPos(sizeX - 3 + 1 - 4, 1)
  1316.             monitor.write("    ")
  1317.             monitor.setCursorPos(sizeX - 3 + 1 - #elapsedTimeString, 1)
  1318.             monitor.write(elapsedTimeString)
  1319.             elapsed = os.clock()
  1320.         -- End Debug
  1321.         monitor.setVisible(true)
  1322.  
  1323.         -- sleep(0)
  1324.         if tonumber(elapsedTime) >= 0.01 then
  1325.             os.queueEvent("")
  1326.             coroutine.yield()
  1327.         else
  1328.             sleep(0)
  1329.         end
  1330.     end
  1331. end
  1332.  
  1333. local function catchEvents()
  1334.  
  1335.     -- EVENTS
  1336.     -- local event, side, xPos, yPos = os.pullEvent(eventType)
  1337.     while not eventFired do
  1338.         local event, side, xPos, yPos = os.pullEvent()
  1339.  
  1340.         while event ~= "monitor_touch" and event ~= "mouse_click" and event ~= "mouse_up" and event ~= "mouse_drag"
  1341.         and event ~= "mouse_scroll" and event ~= "peripheral" and event ~= "peripheral_detach" do
  1342.             event, side, xPos, yPos = os.pullEvent()
  1343.         end
  1344.  
  1345.         if tabsWidget ~= nil then
  1346.             tabsWidget:handleEvents(event, side, xPos, yPos)
  1347.             tabsWidget.currentTab:handleEvents(event, side, xPos, yPos)
  1348.         end
  1349.         if sortWidget ~= nil then
  1350.             sortWidget:handleEvents(event, side, xPos, yPos)
  1351.         end
  1352.  
  1353.         if event == "monitor_touch" then
  1354.             for key, node in pairs(nodes) do
  1355.                 if node.side == side then
  1356.                     node:drawNetworkName()
  1357.                 end
  1358.             end
  1359.         end
  1360.  
  1361.         if event == "peripheral" or event == "peripheral_detach" then
  1362.             findPeripherals()
  1363.             refreshScreens()
  1364.             eventFired = true
  1365.         end
  1366.     end
  1367. end
  1368.  
  1369. local function updateLoop()
  1370.     while not eventFired do
  1371.         refreshInventories()
  1372.         refreshScreens()
  1373.         sleep(0)
  1374.     end
  1375. end
  1376.  
  1377. local function transferLoop()
  1378.     while not eventFired do
  1379.         local movingItemsFunctionsTable = {}
  1380.         for indexMaster = 1, #nodes do
  1381.             if nodes[indexMaster] ~= nil and nodes[indexMaster].inventory ~= nil and nodes[indexMaster].inventoryType ~= nil and nodes[indexMaster].inventoryType == "Input" then
  1382.                 for indexSlotMaster = 1, nodes[indexMaster].inventory.capacity do
  1383.                     if nodes[indexMaster].inventory.items[indexSlotMaster] ~= nil and nodes[indexMaster].inventory.items[indexSlotMaster].count > 0 then
  1384.                         local targetFound = false
  1385.                         for indexSlave = 1, #nodes do
  1386.                             if not targetFound and nodes[indexSlave] ~= nil and nodes[indexSlave].inventory ~= nil and nodes[indexSlave].inventoryType ~= nil and nodes[indexSlave].inventoryType == "Output" then
  1387.                                 for indexSlotSlave = 1, nodes[indexSlave].inventory.capacity do
  1388.                                     if not targetFound and nodes[indexSlave].inventory.items[indexSlotSlave] ~= nil and nodes[indexSlave].inventory.items[indexSlotSlave].count > 0 and nodes[indexSlave].inventory.items[indexSlotSlave].name == nodes[indexMaster].inventory.items[indexSlotMaster].name then
  1389.                                         movingItemsFunctionsTable[#movingItemsFunctionsTable + 1] = function()
  1390.                                             local ret = nodes[indexMaster]:pushItem(nodes[indexSlave].side, indexSlotMaster)
  1391.                                             if ret ~= nil and ret > 0 then
  1392.                                                 nodes[indexMaster].inventory.items[indexSlotMaster].count = nodes[indexMaster].inventory.items[indexSlotMaster].count - ret
  1393.                                             -- else
  1394.                                                 -- handle error (slot is full ? peripheral is off ?)
  1395.                                             end
  1396.                                         end
  1397.                                         targetFound = true
  1398.                                         break
  1399.                                     end
  1400.                                 end
  1401.                             elseif targetFound then
  1402.                                 break
  1403.                             end
  1404.                         end
  1405.                     end
  1406.                 end
  1407.             end
  1408.         end
  1409.  
  1410.         if #movingItemsFunctionsTable > 0 then
  1411.             parallel.waitForAll(unpack(movingItemsFunctionsTable))
  1412.         end
  1413.         sleep(0)
  1414.     end
  1415. end
  1416.  
  1417. -- Loop
  1418. local function main()
  1419.     findPeripherals()
  1420.     refreshScreens()
  1421.     while true do
  1422.         refreshInventories()
  1423.         parallel.waitForAll(catchEvents, drawAll, updateLoop, transferLoop)
  1424.         eventFired = false
  1425.         -- sleep(0)
  1426.     end
  1427. end
  1428.  
  1429. local status, retval = pcall(main)
  1430.  
  1431. monitor.clear()
  1432. monitor.setCursorPos(1, sizeY);
  1433. if not status then
  1434.     printError(retval)
  1435. else
  1436.     print(retval)
  1437. end
Add Comment
Please, Sign In to add comment