Advertisement
Wojbie

Monitor Mirror v2.1

Oct 1st, 2015 (edited)
5,301
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.66 KB | None | 0 0
  1. --# Monitor Mirror v2.1 - Program to mirror terminal contents onto monitor.
  2. --# Made By Wojbie
  3. --# http://pastebin.com/DW3LCC3L
  4.  
  5. --   Copyright (c) 2015-2021 Wojbie (wojbie@wojbie.net)
  6. --   Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met:
  7. --   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  8. --   2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  9. --   3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
  10. --   4. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  11. --   5. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
  12. --   NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY.
  13.  
  14. local function printUsage()
  15.     print( "Usage: mirror <name> <program> <arguments>" )
  16.     return
  17. end
  18.  
  19. local tArgs = { ... }
  20. if #tArgs < 2 then
  21.     printUsage()
  22.     return
  23. end
  24.  
  25. local sName = tArgs[1]
  26. if peripheral.getType( sName ) ~= "monitor" then
  27.     print( "No monitor named ".. sName )
  28.     return
  29. end
  30.  
  31. local sProgram = tArgs[2]
  32. local sPath = shell.resolveProgram( sProgram )
  33. if sPath == nil then
  34.     print( "No such program: "..sProgram )
  35.     return
  36. end
  37.  
  38. local fMain = function()
  39.     shell.run( sPath, table.unpack( tArgs, 3 ) )
  40. end
  41.  
  42.  
  43. --Spacial table that will transferr all functions call to each and every sub table. Static tables version
  44. local function createMultitable(...)
  45.  
  46.     local tab = {...}
  47.     if #tab==1 and tab[1] and type(tab[1])=="table" then tab = tab[1] end
  48.     if #tab==0 then error("Expected table of tables or any tables to table. I know it makes no sense.", 2) end
  49.  
  50.     local manymeta={ --Anytime index is requested fist table is used as refference.
  51.     ["__index"]=function (parent , key)
  52.         if tab and tab[1] and tab[1][key] then --If it has value it tested then
  53.             if type(tab[1][key]) =="function" then --If its function then a function that calls all tables in row is made
  54.                 return function(...)
  55.                     local ret={}
  56.                     local tArgs={...}
  57.                     for i,k in ipairs(tab) do
  58.                         if k[key] then
  59.                             if #ret==0 then ret={k[key](unpack(tArgs))} --ret contains returns from first table that returned anything.
  60.                             else k[key](unpack(tArgs)) end
  61.                         end
  62.                     end
  63.                     return unpack(ret)
  64.                 end
  65.             else
  66.                 return tab[1][key]  --If its not a function then its just given out.
  67.             end
  68.         else
  69.             return nil --Of it not exist in first table give nothing
  70.         end
  71.     end,
  72.     ["__newindex"]=function (parent, key, value) --If someone wants to add anything to the table
  73.         --do nothing.
  74.     end,
  75.     ["__call"]=function (parent, key) --If someone calls table like function give him direct acces to table list.
  76.         --if key then tab = key end changing of content disalowed in static mode
  77.         return tab
  78.     end,
  79.     ["__len"]=function (parent, key) --Not sure if it works but this is giving the leanght of first table or 0 if there is no first table.
  80.         return (tab[1] and #tab[1]) or 0
  81.     end,
  82.     ["__metatable"]=false,--No touching the metatable.
  83.     --["__type"]="WojbieManyMeta",--Custom type? Not in current version and not sure if wise. Commented out for now.
  84.     }
  85.  
  86.     local out = {}
  87.     for key,fun in pairs(tab[1]) do --create static table of multitable functions using first one as template
  88.         out[key] = function(...)
  89.             local ret={}
  90.             local tArgs={...}
  91.             for i,k in ipairs(tab) do
  92.                 if k[key] then
  93.                     if #ret==0 then ret={k[key](unpack(tArgs))} --ret contains returns from first table that returned anything.
  94.                     else k[key](unpack(tArgs)) end
  95.                 end
  96.             end
  97.             return unpack(ret)
  98.         end
  99.     end
  100.     return setmetatable(out,manymeta) --create acctual manymeta table and return it
  101.    
  102. end
  103.  
  104.  --Create Window that is inside other terminal object of selected size. If setTextScale is defined it attempts to finds largest possible size for terminal. Its auto centered and not needed part of screen is painter gray and frame is added. If sName is defined its added onto frame if possible.
  105. local tBor={"+","-","|"}--{"#","=","H"}
  106. local function createFramedWindow(sSide,nX,nY,sName)
  107.    
  108.     if (type( sSide ) ~= "table" and type( sSide ) ~= "string") or
  109.        type( nX ) ~= "number" or
  110.        type( nY ) ~= "number" or
  111.        (sName ~= nil and type( sName ) ~= "string")then
  112.         error( "Expected string/object, number, number, [string]", 2 )
  113.     end
  114.    
  115.     local monitor
  116.     if type( sSide ) == "table" then monitor = sSide
  117.     else monitor = peripheral.wrap(sSide) end
  118.    
  119.     if not monitor then error( "No monitor detected on side "..sSide, 2 ) end
  120.    
  121.     local nOffTop,nOffBot,nOffLeft,nOffRight
  122.     local nOffTopBot, nOffLeftnXRight
  123.     local nMonX,nMonY
  124.     local tLines
  125.     local win = window.create( monitor, 1, 1, nX, nY, false )
  126.     local reposition = win.reposition
  127.    
  128.     local function redraw()
  129.         for i=1,nMonY,1 do
  130.             monitor.setCursorPos(1,i)
  131.             if i<nOffTop then monitor.blit(tLines.e,tLines.f,tLines.b) --print(i,tLines.e)
  132.             elseif i==nOffTop then monitor.blit(tLines.n or tLines.t,tLines.f,tLines.b) --print(i,tLines.n)
  133.             elseif i<nOffTopBot then monitor.blit(tLines.m,tLines.f,tLines.b) --print(i,tLines.m)
  134.             elseif i==nOffTopBot then monitor.blit(tLines.t,tLines.f,tLines.b) --print(i,tLines.t)
  135.             else monitor.blit(tLines.e,tLines.f,tLines.b) end --print(i,tLines.m)
  136.         end
  137.     end
  138.    
  139.     local function build()
  140.         if monitor.setTextScale then
  141.             local nCX,nCY
  142.             for i=5,0.5,-0.5 do
  143.                 monitor.setTextScale(i)
  144.                 nCX,nCY = monitor.getSize()
  145.                 if nCX > nX and nCY > nY then break end
  146.             end
  147.         end
  148.         nMonX,nMonY = monitor.getSize()
  149.        
  150.         nOffLeft=math.max((nMonX-nX)/2,0)
  151.         nOffRight=math.ceil(nOffLeft)
  152.         nOffLeft=math.floor(nOffLeft)
  153.         nOffTop=math.max((nMonY-nY)/2,0)
  154.         nOffBot=math.ceil(nOffTop)
  155.         nOffTop=math.floor(nOffTop)
  156.         nOffTopBot=nOffTop+nY+1
  157.         nOffLeftnXRight = nOffLeft + nX + nOffRight
  158.                
  159.         tLines = {}
  160.         tLines.e = string.rep(" ",nOffLeftnXRight)
  161.         tLines.t = string.rep(" ",math.max(0,nOffLeft-1))..(nOffLeft>0 and tBor[1] or "")..string.rep(tBor[2],nX)..(nOffRight>0 and tBor[1] or "")..string.rep(" ",math.max(0,nOffRight-1))
  162.         tLines.m = string.rep(" ",math.max(0,nOffLeft-1))..(nOffLeft>0 and tBor[3] or "")..string.rep(" ",nX)..(nOffRight>0 and tBor[3] or "")..string.rep(" ",math.max(0,nOffRight-1))
  163.         if sName and type(sName)=="string" and #sName<= nX then
  164.             local sName2=string.sub(sName, 1, nX)
  165.             local a=(nX-string.len(sName2))/2
  166.             local b=math.ceil(a)
  167.             a=math.floor(a)
  168.             tLines.n = string.rep(" ",math.max(0,nOffLeft-1))..(nOffLeft>0 and tBor[1] or "")..string.rep(tBor[2],a)..sName2..string.rep(tBor[2],b)..(nOffRight>0 and tBor[1] or "")..string.rep(" ",math.max(0,nOffRight-1))
  169.         end
  170.         tLines.f = string.rep("7",nOffLeftnXRight) --0
  171.         tLines.b = string.rep("8",nOffLeftnXRight) --f
  172.        
  173.         redraw()
  174.         reposition( nOffLeft+1, nOffTop+1, nX, nY ) --window.reposition localized
  175.         win.setVisible( true )
  176.        
  177.     end
  178.  
  179.     build()
  180.     win.redrawBorder = function() return redraw() end
  181.     win.synch = function() return build() end
  182.     win.setName = function(A) sName=(A ~= nil and type( A ) == "string") and A or nil return build() end
  183.     win.resize = function(A,B)
  184.         if  type( A ) ~= "number" or
  185.             type( B ) ~= "number" then
  186.             error( "Expected number, number", 2 )
  187.         end
  188.         nX,nY = A,B
  189.         return build()
  190.     end
  191.     win.localize = function(A,B)
  192.         local x,y = A-nOffLeft,B-nOffTop
  193.         if x>0 and y>0 and x<=nX and y<=nY then
  194.             return x,y
  195.         end
  196.     end  --localizes coordinates for inside of the window.
  197.    
  198.     return win
  199.    
  200.     --if sSide is a monitor object (like multiMon! http://www.computercraft.info/forums2/index.php?/topic/18229-multimon-multiple-monitors-in-computercraft/) use it instead of side.
  201.     --create window on monitor
  202.     --sized nX nY
  203.     --centered on monitor
  204.     --monitor scalled to max text size possible.
  205.     --remove reposition call and store it in local wariable.
  206.     --add synch function that rescales monitor and redraws window. if provided with new nX,nY it will resize too.
  207.  
  208. end
  209.  
  210. local function  mirrorToMonitors(fMain,tSides,sName) --tSides is table with monitor sides to write on. If empty or not defined it will take all possible sides.
  211.     if type( fMain ) ~= "function" or
  212.         (tSides ~= nil and type( tSides ) ~= "table") or
  213.         (sName ~= nil and type( sName ) ~= "string") then
  214.         error( "Expected function, table, [string]", 2 )
  215.     end
  216.    
  217.    
  218.     local parent = term.current()
  219.     local x,y = parent.getSize()
  220.     local tMirrorsSides = {}
  221.     local tMirrors = {}
  222.    
  223.     if not tSides or #tSides == 0 then
  224.         peripheral.find("monitor",function(name,wrap) tMirrorsSides[name] = createFramedWindow(name,x,y,sName) table.insert(tMirrors,tMirrorsSides[name]) end)
  225.     else
  226.         for i,k in pairs(tSides) do
  227.             if peripheral.isPresent(k) and peripheral.getType(k) == "monitor" then
  228.                 tMirrorsSides[k] = createFramedWindow(k,x,y,sName)
  229.                 table.insert(tMirrors,tMirrorsSides[k])
  230.             end
  231.         end
  232.     end
  233.    
  234.     local mirr = createMultitable(tMirrors)
  235.     local mix = createMultitable(parent,mirr)
  236.     term.redirect(mix)
  237.  
  238.     local co = coroutine.create(fMain)
  239.  
  240.     local function resume( ... )
  241.         local ok, param = coroutine.resume( co, ... )
  242.         if not ok then
  243.             printError( param )
  244.         end
  245.         return param
  246.     end
  247.  
  248.     local ok, param = pcall( function()
  249.         local sFilter = resume()
  250.         local TResizeLoop = {}
  251.         while coroutine.status( co ) ~= "dead" do
  252.             local tEvent = { os.pullEventRaw() }
  253.             if tEvent[1] == "term_resize" then
  254.                 mirr.resize(parent.getSize())
  255.             elseif tEvent[1] == "monitor_resize" and tMirrorsSides[tEvent[2]] then
  256.                 if TResizeLoop[tEvent[2]] then
  257.                     TResizeLoop[tEvent[2]] = false
  258.                 else
  259.                     tMirrorsSides[tEvent[2]].synch()
  260.                     TResizeLoop[tEvent[2]] = true
  261.                 end
  262.             end
  263.             if sFilter == nil or tEvent[1] == sFilter or tEvent[1] == "terminate" then
  264.                 sFilter = resume( table.unpack( tEvent ) )
  265.             end
  266.             if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "mouse_click") then
  267.                 if tEvent[1] == "monitor_touch" and tMirrorsSides[tEvent[2]] then
  268.                     tEvent[3],tEvent[4] = tMirrorsSides[tEvent[2]].localize(tEvent[3],tEvent[4])
  269.                     if tEvent[3] then
  270.                         sFilter = resume( "mouse_click", 1, table.unpack( tEvent, 3 ) )
  271.                         if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "mouse_up") then
  272.                             sFilter = resume( "mouse_up", 1, table.unpack( tEvent, 3 ) )
  273.                         end
  274.                     end
  275.                 end
  276.             end
  277.         end
  278.     end )  
  279.    
  280.     term.redirect(parent)
  281.     if not ok then
  282.         printError( param )
  283.     end
  284. end
  285.  
  286. mirrorToMonitors(fMain,{sName},sProgram)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement