View difference between Paste ID: qUqUad3K and DW3LCC3L
SHOW: | | - or go back to the newest paste.
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 ([email protected])
5+
function printUsage()
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:
6+
7-
--   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7+
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.
8+
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.
9+
10-
--   4. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
10+
11-
--   5. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
11+
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.
12+
13
	return
14-
local function printUsage()
14+
15
16
local sName = tArgs[1]
17
if peripheral.getType( sName ) ~= "monitor" then
18
	print( "No monitor named ".. sName )
19
	return
20
end
21
22
local sProgram = tArgs[2]
23
local sPath = shell.resolveProgram( sProgram )
24
if sPath == nil then
25
	print( "No such program: "..sProgram )
26
	return
27
end
28
29
local fMain = function()
30
    shell.run( sPath, table.unpack( tArgs, 3 ) )
31
end 
32
33
 
34
--Spacial table that will transferr all functions call to each and every sub table. Static tables version
35
function createMultitable(...)
36
37
	local tab = {...}
38
	if #tab==1 and tab[1] and type(tab[1])=="table" then tab = tab[1] end
39
	if #tab==0 then error("Expected table of tables or any tables to table. I know it makes no sense.", 2) end
40
41
	local manymeta={ --Anytime index is requested fist table is used as refference. 
42
	["__index"]=function (parent , key)
43
		if tab and tab[1] and tab[1][key] then --If it has value it tested then
44-
local function createMultitable(...)
44+
45
				return function(...)
46
					local ret={}
47
					local tArgs={...}
48
					for i,k in ipairs(tab) do
49
						if k[key] then
50
							if #ret==0 then ret={k[key](unpack(tArgs))} --ret contains returns from first table that returned anything.
51
							else k[key](unpack(tArgs)) end
52
						end
53
					end
54
					return unpack(ret) 
55
				end
56
			else
57
				return tab[1][key]  --If its not a function then its just given out.
58
			end
59
		else
60
			return nil --Of it not exist in first table give nothing
61
		end
62
	end,
63
	["__newindex"]=function (parent, key, value) --If someone wants to add anything to the table
64
		--do nothing.
65
	end,
66
	["__call"]=function (parent, key) --If someone calls table like function give him direct acces to table list.
67
		--if key then tab = key end changing of content disalowed in static mode
68
		return tab
69
	end,
70
	["__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.
71
		return (tab[1] and #tab[1]) or 0
72
	end,
73
	["__metatable"]=false,--No touching the metatable.
74
	--["__type"]="WojbieManyMeta",--Custom type? Not in current version and not sure if wise. Commented out for now.
75
	}
76
77
	local out = {}
78
	for key,fun in pairs(tab[1]) do --create static table of multitable functions using first one as template
79
		out[key] = function(...)
80
			local ret={}
81
			local tArgs={...}
82
			for i,k in ipairs(tab) do
83
				if k[key] then
84
					if #ret==0 then ret={k[key](unpack(tArgs))} --ret contains returns from first table that returned anything.
85
					else k[key](unpack(tArgs)) end
86
				end
87
			end
88
			return unpack(ret) 
89
		end
90
	end
91
	return setmetatable(out,manymeta) --create acctual manymeta table and return it
92
	
93
end
94
 
95
 --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.
96
local tBor={"+","-","|"}--{"#","=","H"}
97
local function createFramedWindow(sSide,nX,nY,sName)
98
	
99
	if (type( sSide ) ~= "table" and type( sSide ) ~= "string") or
100
       type( nX ) ~= "number" or
101
       type( nY ) ~= "number" or
102
	   (sName ~= nil and type( sName ) ~= "string")then
103
        error( "Expected string/object, number, number, [string]", 2 )
104
    end
105
	
106
	local monitor
107
	if type( sSide ) == "table" then monitor = sSide
108
	else monitor = peripheral.wrap(sSide) end
109
	
110
	if not monitor then error( "No monitor detected on side "..sSide, 2 ) end
111
	
112
	local nOffTop,nOffBot,nOffLeft,nOffRight
113
	local nOffTopBot, nOffLeftnXRight
114
	local nMonX,nMonY
115
	local tLines
116
	local win = window.create( monitor, 1, 1, nX, nY, false )
117
	local reposition = win.reposition
118
	
119
	local function redraw()
120
		for i=1,nMonY,1 do
121
			monitor.setCursorPos(1,i)
122
			if i<nOffTop then monitor.blit(tLines.e,tLines.f,tLines.b) --print(i,tLines.e)
123
			elseif i==nOffTop then monitor.blit(tLines.n or tLines.t,tLines.f,tLines.b) --print(i,tLines.n)
124
			elseif i<nOffTopBot then monitor.blit(tLines.m,tLines.f,tLines.b) --print(i,tLines.m)
125
			elseif i==nOffTopBot then monitor.blit(tLines.t,tLines.f,tLines.b) --print(i,tLines.t)
126
			else monitor.blit(tLines.e,tLines.f,tLines.b) end --print(i,tLines.m)
127
		end
128
	end	
129
	
130
	local function build()
131
		if monitor.setTextScale then
132
			local nCX,nCY
133
			for i=5,0.5,-0.5 do
134
				monitor.setTextScale(i)
135
				nCX,nCY = monitor.getSize()
136
				if nCX > nX and nCY > nY then break end
137
			end
138
		end
139
		nMonX,nMonY = monitor.getSize()
140
		
141
		nOffLeft=math.max((nMonX-nX)/2,0)
142
		nOffRight=math.ceil(nOffLeft)
143
		nOffLeft=math.floor(nOffLeft)
144
		nOffTop=math.max((nMonY-nY)/2,0)
145
		nOffBot=math.ceil(nOffTop)
146
		nOffTop=math.floor(nOffTop)
147
		nOffTopBot=nOffTop+nY+1
148
		nOffLeftnXRight = nOffLeft + nX + nOffRight
149
				
150
		tLines = {}
151
		tLines.e = string.rep(" ",nOffLeftnXRight)
152
		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))
153
		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))
154
		if sName and type(sName)=="string" and #sName<= nX then 
155
			local sName2=string.sub(sName, 1, nX)
156
			local a=(nX-string.len(sName2))/2
157
			local b=math.ceil(a)
158
			a=math.floor(a)
159
			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))
160
		end
161
		tLines.f = string.rep("7",nOffLeftnXRight) --0
162
		tLines.b = string.rep("8",nOffLeftnXRight) --f
163
		
164
		redraw()
165
		reposition( nOffLeft+1, nOffTop+1, nX, nY ) --window.reposition localized
166
		win.setVisible( true )
167
		
168
	end
169
170
	build()
171
	win.redrawBorder = function() return redraw() end
172
	win.synch = function() return build() end
173
	win.setName = function(A) sName=(A ~= nil and type( A ) == "string") and A or nil return build() end
174
	win.resize = function(A,B) 
175
		if 	type( A ) ~= "number" or
176
			type( B ) ~= "number" then
177
			error( "Expected number, number", 2 )
178
		end
179
		nX,nY = A,B
180
		return build() 
181
	end
182
	win.localize = function(A,B)
183
		local x,y = A-nOffLeft,B-nOffTop
184
		if x>0 and y>0 and x<=nX and y<=nY then
185
			return x,y
186
		end
187
	end  --localizes coordinates for inside of the window.
188
	
189
	return win
190
	
191
	--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.
192
	--create window on monitor
193
	--sized nX nY
194
	--centered on monitor
195
	--monitor scalled to max text size possible.
196
	--remove reposition call and store it in local wariable.
197
	--add synch function that rescales monitor and redraws window. if provided with new nX,nY it will resize too.
198
199
end
200
201
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.
202
	if type( fMain ) ~= "function" or
203
		(tSides ~= nil and type( tSides ) ~= "table") or
204
		(sName ~= nil and type( sName ) ~= "string") then
205
		error( "Expected function, table, [string]", 2 )
206
    end
207
	
208
	
209
	local parent = term.current()
210
	local x,y = parent.getSize()
211
	local tMirrorsSides = {}
212
	local tMirrors = {}
213
	
214
	if not tSides or #tSides == 0 then
215
		peripheral.find("monitor",function(name,wrap) tMirrorsSides[name] = createFramedWindow(name,x,y,sName) table.insert(tMirrors,tMirrorsSides[name]) end)
216
	else
217
		for i,k in pairs(tSides) do
218
			if peripheral.isPresent(k) and peripheral.getType(k) == "monitor" then
219
				tMirrorsSides[k] = createFramedWindow(k,x,y,sName)
220
				table.insert(tMirrors,tMirrorsSides[k])
221
			end
222
		end
223
	end
224
	
225
	local mirr = createMultitable(tMirrors)
226
	local mix = createMultitable(parent,mirr)
227
	term.redirect(mix)
228
229
	local co = coroutine.create(fMain)
230
231
	local function resume( ... )
232
		local ok, param = coroutine.resume( co, ... )
233
		if not ok then
234
			printError( param )
235
		end
236
		return param
237
	end
238
239
	local ok, param = pcall( function()
240
		local sFilter = resume()
241
		local TResizeLoop = {}
242
		while coroutine.status( co ) ~= "dead" do
243
			local tEvent = { os.pullEventRaw() }
244
			if tEvent[1] == "term_resize" then
245
				mirr.resize(parent.getSize())
246
			elseif tEvent[1] == "monitor_resize" and tMirrorsSides[tEvent[2]] then
247
				if TResizeLoop[tEvent[2]] then
248
					TResizeLoop[tEvent[2]] = false
249
				else
250
					tMirrorsSides[tEvent[2]].synch()
251
					TResizeLoop[tEvent[2]] = true
252
				end
253
			end
254
			if sFilter == nil or tEvent[1] == sFilter or tEvent[1] == "terminate" then
255
				sFilter = resume( table.unpack( tEvent ) )
256
			end
257
			if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "mouse_click") then
258
				if tEvent[1] == "monitor_touch" and tMirrorsSides[tEvent[2]] then
259
					tEvent[3],tEvent[4] = tMirrorsSides[tEvent[2]].localize(tEvent[3],tEvent[4])
260
					if tEvent[3] then
261
						sFilter = resume( "mouse_click", 1, table.unpack( tEvent, 3 ) )
262
						if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "mouse_up") then
263
							sFilter = resume( "mouse_up", 1, table.unpack( tEvent, 3 ) )
264
						end
265
					end
266
				end
267
			end
268
		end
269
	end )	
270
	
271
	term.redirect(parent)
272
	if not ok then
273
		printError( param )
274
	end
275
end
276
277
mirrorToMonitors(fMain,{sName},sProgram)