View difference between Paste ID: nu1b3bRy and aMavDp1e
SHOW: | | - or go back to the newest paste.
1
local sideNames = rs.getSides()
2
local sensorSides = {}
3
local sideSelection, targetSelection, targetOffset, detailOffset = 1, 1, 1, 1
4
local detailLines, targetNameMenuTable
5
local graphing, graphSide, graphTarget, graphMatch, graphInstance = false
6
7
os.loadAPI("ocs/apis/graph")
8
os.loadAPI("ocs/apis/sensor")
9
10
local function checkSensors()
11
	for _,side in ipairs(sideNames) do
12
		if peripheral.getType(side) == "sensor" then
13
			sensorSides[side] = true
14
		else
15
			sensorSides[side] = false
16
		end
17
	end
18
end
19
20
local function writeEntry(menuTable, index, cursorPos)
21
	if cursorPos == index then
22
		term.setBackgroundColor(term.isColor() and colors.blue or colors.white)
23
		term.setTextColor(term.isColor() and colors.white or colors.black)
24
		term.write(string.sub(menuTable[index], 1, 16))
25
		term.setBackgroundColor(colors.black)
26
		term.setTextColor(colors.white)
27
	else
28
		term.write(string.sub(menuTable[index], 1, 16))
29
	end
30
end
31
32
local function toLines(currTable, linesTable, trackingTable, depth)
33
	for k,v in pairs(currTable) do
34
		if type(v) == "table" then
35
			table.insert(linesTable, string.rep(" ", depth)..tostring(k)..":")
36
			if trackingTable[v] then
37
				table.insert(linesTable, string.rep(" ", depth + 1).."<Cyclic Reference: "..trackingTable[v]..">")
38
			else
39
				trackingTable[v] = #linesTable
40
				toLines(v, linesTable, trackingTable, depth + 1)
41
			end
42
		else
43
			table.insert(linesTable, string.rep(" ", depth)..tostring(k).."> "..tostring(v))
44
		end
45
	end
46
end
47
48
local function drawDividerDown(startY)
49
	local w, h = term.getSize()
50
	for i=startY, h do
51
		term.setCursorPos(17, i)
52
		term.write("|")
53
	end
54
end
55
56
local function redraw()
57
	w, h = term.getSize()
58
	--pre-fetch sensor targets and detailed target information.
59
	local targetNames = nil
60
	detailLines = {}
61
	checkSensors()
62
	if sensorSides[sideNames[sideSelection]] then
63
		targetNames = sensor.call(sideNames[sideSelection], "getSensorName") and sensor.call(sideNames[sideSelection], "getTargets")
64
		targetNameMenuTable = {}
65
		if targetNames then
66
			for k,v in pairs(targetNames) do
67
				table.insert(targetNameMenuTable, k)
68
			end
69
			table.sort(targetNameMenuTable)
70
			if #targetNameMenuTable > 0 then
71
				toLines(sensor.call(sideNames[sideSelection], "getTargetDetails", targetNameMenuTable[targetSelection]), detailLines, {}, 0)
72
			end
73
		end
74
	end
75
	--now draw the screen.
76
	term.clear()
77
	term.setCursorPos(1, 1)
78
	term.write("=Sensor Info Viewer="..string.rep("=", w - 20))
79
	term.setCursorPos(1, 2)
80
	for n,side in ipairs(sideNames) do
81
		if n == sideSelection then
82
			term.setBackgroundColor(term.isColor() and colors.blue or colors.white)
83
			term.setTextColor(term.isColor() and colors.white or colors.black)
84
			term.write(side)
85
			term.setBackgroundColor(colors.black)
86
			term.setTextColor(colors.white)
87
			term.write(" ")
88
		else
89
			term.write(side.." ")
90
		end
91
	end
92
	term.setCursorPos(1, 3)
93
	term.write("-Targets--------+-Info-"..string.rep("-", w - 23))
94
95
	if targetNames then
96
		--make sure we have valid targets, even if we have a valid sensor.
97
		if #targetNameMenuTable > 0 then
98
			term.setCursorPos(1, 4)
99
			if targetOffset > 1 then
100
				term.write("/\\")
101
			else
102
				writeEntry(targetNameMenuTable, 1, targetSelection)	
103
			end
104
			--h-5 to leave room for top and bottom entries.
105
			for i=1, math.min(h - 5, #targetNameMenuTable - 1) do
106
				term.setCursorPos(1, i + 4)
107
				writeEntry(targetNameMenuTable, targetOffset + i, targetSelection)
108
			end
109
			if #targetNameMenuTable >= h then
110
				term.setCursorPos(1, h)
111
				if #targetNameMenuTable > targetOffset + h - 4 then
112
					term.write("\\/")
113
				else
114
					writeEntry(targetNameMenuTable, #targetNameMenuTable, targetSelection)
115
				end
116
			end
117
118
			--detailed info.
119
			for i=1, math.min(h - 3, #detailLines - ((detailOffset - 1) * (h - 3))) do
120
				term.setCursorPos(17, i + 3)
121
				term.write("|"..string.sub(detailLines[(detailOffset - 1) * (h - 3) + i], 1, w - 17))
122
			end
123
			local currX, currY = term.getCursorPos()
124
			drawDividerDown(currY + 1)
125
		else
126
			term.setCursorPos(1, 4)
127
			term.write("No targets found|")
128
			drawDividerDown(5)
129
		end
130
	else
131
		if peripheral.getType(sideNames[sideSelection]) == "sensor" then
132
			term.setCursorPos(1, 4)
133
			term.write("No sensor card  |")
134
			drawDividerDown(5)
135
		else
136
			term.setCursorPos(1, 4)
137
			term.write("No sensor found |")
138
			drawDividerDown(5)
139
		end
140
	end
141
	term.setCursorPos(1, h)
142
end
143
144
local function findGraphMatch(currTable, target, matchCount, trackingTable)
145
	for k, v in pairs(currTable) do
146
		if type(v) == "table" then
147
			if trackingTable[v] then return false end
148
			trackingTable[v] = true
149
			ret, path, count = findGraphMatch(v, target, matchCount, trackingTable)
150
			if ret and path then
151
				return ret, tostring(k).."-"..path
152
			elseif count then
153
				matchCount = count
154
			end
155
		elseif type(v) == "number" then
156
			matchCount = matchCount + 1
157
			if matchCount == target then return v, tostring(k) end
158
		end
159
	end
160
	return false, nil, matchCount
161
end
162
163
local function createGraph(targetNum)
164
	local monSide = ""
165
	for k, side in ipairs(rs.getSides()) do
166
		if peripheral.getType(side) == "monitor" then
167
			monSide = side
168
			break
169
		end
170
	end
171
	if monSide and targetNum >= 1 and findGraphMatch(sensor.call(graphSide, "getTargetDetails", graphTarget), targetNum, 0, {}) then
172
		graphMatch = targetNum
173
		local val, name = findGraphMatch(sensor.call(graphSide, "getTargetDetails", graphTarget), targetNum, 0, {})
174
		local updateFunc = function() return (findGraphMatch(sensor.call(graphSide, "getTargetDetails", graphTarget), graphMatch, 0, {})) end
175
		graphInst = graph.new(peripheral.wrap(monSide), updateFunc, name)
176
		return graphInst
177
	end
178
end
179
180
while true do
181
	redraw()
182
	local e, p1 = os.pullEvent()
183
	if e == "key" then
184
		local w, h = term.getSize()
185
		if p1 == 203 then
186
			--left, selects previous side
187
			if sideSelection > 1 then
188
				sideSelection = sideSelection - 1
189
				targetSelection = 1
190
				targetOffset = 1
191
				detailOffset = 1
192
				detailLines = nil
193
			end
194
		elseif p1 == 205 then
195
			--right, selects next side
196
			if sideSelection < 6 then
197
				sideSelection = sideSelection + 1
198
				targetSelection = 1
199
				targetOffset = 1
200
				detailOffset = 1
201
				detailLines = nil
202
			end
203
		elseif p1 == 200 then
204
			--up, selects previous target, adjusting offset if necessary.
205
			if targetSelection > 1 then
206
				if targetSelection - targetOffset + 1 == 2 and targetOffset > 1 then
207
					targetOffset = targetOffset - 1
208
				end
209
				targetSelection = targetSelection - 1
210
				detailOffset = 1
211
				detailLines = nil
212
			end
213
		elseif p1 == 208 then
214
			--down, selects next target, adjusting offset if necessary.
215
			if targetNameMenuTable and targetSelection < #targetNameMenuTable then
216
				if targetSelection - targetOffset + 1 == h - 4 and targetSelection ~= #targetNameMenuTable - 1 then
217
					targetOffset = targetOffset + 1
218
				end
219
				targetSelection = targetSelection + 1
220
				detailOffset = 1
221
				detailLines = nil
222
			end
223-
		elseif p1 == 201 then
223+
		elseif p1 == 23 then
224-
			--pgup, moves detail
224+
			--I, moves detail
225
			if detailOffset > 1 then
226
				detailOffset = detailOffset - 1
227
			end
228-
		elseif p1 == 209 then
228+
		elseif p1 == 37 then
229-
			--pgdown, moves detail
229+
			--K, moves detail
230
			local w, h = term.getSize()
231
			if detailLines and detailOffset < math.ceil(#detailLines / (h - 3)) then
232
				detailOffset = detailOffset + 1
233
			end
234
		--and now, since redraw() will eat char events with the change to sensor.call:
235
		elseif p1 == 31 then --s
236
			if detailLines then
237
				local fileHandle = io.open("sensorDetailed-"..sideNames[sideSelection].."-"..targetNameMenuTable[targetSelection], "w")
238
				if fileHandle then
239
					for k, v in ipairs(detailLines) do
240
						fileHandle:write(v.."\n")
241
					end
242
					fileHandle:close()
243
				end
244
			end
245
		elseif p1 == 16 then --q
246
			sleep(0)
247
			return
248
		elseif p1 == 34 then --g
249
			if graph then
250
				graphing = not graphing
251
				if not graphing then
252
					graphSide = nil
253
					graphTarget = nil
254
					graphUpdate = nil
255
				else
256
					graphSide = sideNames[sideSelection]
257
					graphTarget = targetNameMenuTable[targetSelection]
258
					graphInstance = createGraph(1)
259
					graphUpdate = os.startTimer(0.5)
260
				end
261
			end
262
		elseif p1 == 49 then --n
263
			if graphing then
264
				local newGraph = createGraph(graphMatch + 1)
265
				if newGraph then
266
					graphInstance = newGraph
267
					graphUpdate = os.startTimer(0.5)
268
				end
269
			end
270
		elseif p1 == 25 then --p
271
			if graphing then
272
				local newGraph = createGraph(graphMatch - 1)
273
				if newGraph then
274
					graphInstance = newGraph
275
					graphUpdate = os.startTimer(0.5)
276
				end
277
			end
278
		end
279
	elseif e == "timer" then
280
		if p1 == graphUpdate then
281
			graphInstance:draw()
282
			graphUpdate = os.startTimer(0.5)
283
		end
284
	end
285
end