Posted 23 January 2014 - 10:46 PM
Vertical Scrolling Utility (now also an API…)
In answering a question, I decided to write a utility to allow for the vertical scrolling of text to display on a monitor, computer or turtle (thanks to xbsktball10x for the idea). I dusted off a few routines I had developed for some user interfaces in other programs, and added the refreshDisplay() function and scrollPrint() function to finish it all up. The code is in the spoiler below. The same code (as an API) is in the second spoiler.
Vertical Scroll Program
--[[
Vertical Scrolling Text
by Surferpup
]]
--[[
TO DO
Finish Color Aspects
More Error Checking
Convert to API
]]
function setOutput(_device)
local result,width,height = pcall(function () return _device.getSize() end)
if not result then
print "setOutput: The output device specified is not a monitor or terminal"
error()
end
return _device,width,height
end
function setMaxWidth(_textArray)
local maxWidth = 0
for i = 1,#_textArray do
if (maxWidth < #(_textArray[i])) then
maxWidth = #(_textArray[i])
end
end
return maxWidth
end
function setScale(_maxWidth,_device)
if not (pcall(function () _device.setTextScale(5) end)) then
return false
else
local scale = 5
local function checkScale()
local thisWidth,temp
thisWidth,temp = _device.getSize()
return (_maxWidth > thisWidth)
end
while checkScale() and scale >= 1 do
scale = scale - 0.5
_device.setTextScale(scale)
end
return true,_device.getSize()
end
end
function refreshDisplay(_startY,_startIndex,_text,_device,_width,_height)
if not (_width and _height) then
_width, _height = _device.getSize()
end
for y = _startY,1,-1 do
centerPrint(_text[_startIndex],_width,y,_device)
_startIndex = _startIndex-1
if _startIndex < 1 then break end
end
end
function centerPrint(_text,_width,_yPosition,_output,_highlight,_highlightBackGroundColor,_highlightTextColor,_defaultBackgroundColor,_defaultTextColor)
_text = _text or ""
_output = _output or term
if not _width then
_width,_ = _output.getSize()
end
_yPosition = _yPosition or 1
_highlight = _highlight or 0
if not _output.isColor() then
_highlightBackgroundColor = colors.white
_highlightTextColor = colors.black
_defaultBackgroundColor = colors.black
_defaultTextColor= colors.white
else
_highlightBackgroundColor = _highlightBackgroundColor or colors.white
_highlightTextColor = _highlightTextColor or colors.black
_defaultBackgroundColor = _defaultBackgroundColor or colors.black
_defaultTextColor= _defaultTextColor or colors.white
end
local xPosition = math.floor(_width/2) - (#_text/2)
if xPosition < 1 then
xPosition=1
end
_output.setCursorPos(xPosition,_yPosition)
if _highlight == true then
_output.setBackgroundColor(_highlightBackgroundColor)
_output.setTextColor(_highlightTextColor)
else
_output.setBackgroundColor(_defaultBackgroundColor)
_output.setTextColor(_defaultTextColor)
end
_output.write(_text)
_output.setBackgroundColor(_defaultBackgroundColor)
_output.setTextColor(_defaultTextColor)
end
function scrollPrint(_textArray, -- the text table of strings to print
_startingVerticalPosition, -- the y-position to begin on the monitor
_maximumVerticalPosition, -- the maximum y-position to go to
_sleepInterval, -- delay between printed lines
_outputDevice) -- the output device (term or monitor peripheral)
_textArray = _textArray or {" ";}
_outputDevice = _outputDevice or term
_outputDevice,_,_ = setOutput(_outputDevice)
_sleepInterval = _sleepInterval or 1
local maxWidth = setMaxWidth(_textArray)
local result,width,height = setScale(maxWidth,_outputDevice)
if not result then
width,height = _outputDevice.getSize()
end
_startingVerticalPostition = _startingVerticalPostition or 1
_maximumVerticalPosition = _maximumVerticalPosition or height
if _startingVerticalPosition > height then
_startingVerticalPosition = math.floor(height/2)
end
if _maximumVerticalPosition &gt; height then
_maximumVerticalPosition = height
end
for i = 1,#_textArray do
if _startingVerticalPosition >=_maximumVerticalPosition then
_startingVerticalPosition = _maximumVerticalPosition
else
_startingVerticalPosition=_startingVerticalPosition+1
end
for j = 1,_startingVerticalPosition do
_outputDevice.setCursorPos(1,j)
_outputDevice.write(string.rep(" ",width))
end
refreshDisplay(_startingVerticalPosition,i,_textArray,_outputDevice,2)
sleep(_sleepInterval)
end
end
--Main Program Code Block begins here
-- HERE IS THE LONG TABLE OF STRINGS:
local myDemoTable = {
"This is a vertical scrolling example.";
"";
"The text that is printing is taken from the table of strings";
"the name of witch is passed as the first argument to the";
"scrollPrint() function.";
" ";
"The fourth argument to the scroll print function is the";
"sleep interval, which determines how long the program will pause";
"between printed lines of text.";
"";
"The final argument to the scrollPrint function is the output device.";
"This can be an attached or wired monitor, or the term of the";
"computer or turtle. The program will test to make sure an";
"allowed device is given for this argument.";
"";
"There are defaults for all arguments.";
"";
"The text defaults to a single entry table of one blank string.";
"";
"The starting vertical position defaults to 1 if not supplied,";
"or 1/2 the height of the output device if a value greater than";
"the output device height is given. Also, if the starting vertical";
"position is greater than the maximum vertical position,";
"the starting vertical position will be set to equal the maximum";
"vertical position.";
"";
"The maximum vertical position defaults to the output device";
"height if not supplied, or the output device height if the";
"maximum vertical position is greater than the height.";
" ";
"The sleep interval defaults to 1 second.";
"";
"The output device defaults to term if not supplied.";
" ";
"There is error checking which will stop the program if";
"a device other than a computer, terminal or monitor";
"is specified.";
"";
"Only the portions of the monitor or terminal that require";
"updating are updated. This means that any text or graphics";
"you place below the maximum vertical position will be left alone";
"by this program.";
"";
"The utility auto scales monitors to the best of its ability (obviously";
"auto-scaling does not apply to term devices on computers or turtles).";
"When auto-scaling, the utility will search all of the text strings in the";
"supplied table, and it will determine the maximum length required";
"to print the table strings. It will select the smallest scale";
"from 0.5-5.0 which will allow the longest string to print.";
"If there is a string that is too long to print even at the";
"smallest scale, it will left-justify the string and print what it can.";
"";
"All text is centered horizontally. A later update may give options on this.";
"";
"For now, the program does not handle color, although if you inspect";
"the code, you will note that I am contemplating adding a color and";
"a highlighting feature.";
"";
"Play around with it, see if it is useful for you.";
" ";
"---";
"";
"Best regards,";
" ";
"Surferpup";
}
scrollPrint(myDemoTable,5,20,1.6,peripheral.wrap("top"))
print ("Done")
API
--[[
Vertical Scrolling Text
by Surferpup
]]
--[[
TO DO
Finish Color Aspects
More Error Checking
]]
local function setOutput(_device)
local result,width,height = pcall(function () return _device.getSize() end)
if not result then
print "setOutput: The output device specified is not a monitor or terminal"
error()
end
return _device,width,height
end
local function setMaxWidth(_textArray)
local maxWidth = 0
for i = 1,#_textArray do
if (maxWidth < #(_textArray[i])) then
maxWidth = #(_textArray[i])
end
end
return maxWidth
end
local function setScale(_maxWidth,_device)
if not (pcall(function () _device.setTextScale(5) end)) then
return false
else
local scale = 5
local function checkScale()
local thisWidth,temp
thisWidth,temp = _device.getSize()
return (_maxWidth > thisWidth)
end
while checkScale() and scale >= 1 do
scale = scale - 0.5
_device.setTextScale(scale)
end
return true,_device.getSize()
end
end
local function centerPrint(_text,_width,_yPosition,_output,_highlight,_highlightBackGroundColor,_highlightTextColor,_defaultBackgroundColor,_defaultTextColor)
_text = _text or ""
_output = _output or term
if not _width then
_width,_ = _output.getSize()
end
_yPosition = _yPosition or 1
_highlight = _highlight or false
if not _output.isColor() then
_highlightBackgroundColor = colors.white
_highlightTextColor = colors.black
_defaultBackgroundColor = colors.black
_defaultTextColor= colors.white
else
_highlightBackgroundColor = _highlightBackgroundColor or colors.white
_highlightTextColor = _highlightTextColor or colors.black
_defaultBackgroundColor = _defaultBackgroundColor or colors.black
_defaultTextColor= _defaultTextColor or colors.white
end
local xPosition = math.floor(_width/2) - (#_text/2)
if xPosition < 1 then
xPosition=1
end
_output.setCursorPos(xPosition,_yPosition)
if _highlight == true then
_output.setBackgroundColor(_highlightBackgroundColor)
_output.setTextColor(_highlightTextColor)
else
_output.setBackgroundColor(_defaultBackgroundColor)
_output.setTextColor(_defaultTextColor)
end
_output.write(_text)
end
local function refreshDisplay(_startY,_startIndex,_text,_device,_width,_height)
if not (_width and _height) then
_width,_heigh = _device.getSize()
end
for y = _startY,1,-1 do
centerPrint(_text[_startIndex],_width,y,_device)
_startIndex = _startIndex-1
if _startIndex < 1 then break end
end
end
-- User-accessible Function
function scrollPrint(_textArray, -- the text table of strings to print
_startingVerticalPosition, -- the y-position to begin on the monitor
_maximumVerticalPosition, -- the maximum y-position to go to
_sleepInterval, -- delay between printed lines
_outputDevice) -- the output device (term or monitor peripheral)
_textArray = _textArray or {" ";}
_outputDevice = _outputDevice or term
_outputDevice,_,_ = setOutput(_outputDevice)
_sleepInterval = _sleepInterval or 1
local maxWidth = setMaxWidth(_textArray)
local result,width,height = setScale(maxWidth,_outputDevice)
if not result then
width,height = _outputDevice.getSize()
end
_startingVerticalPostition = _startingVerticalPostition or 1
_maximumVerticalPosition = _maximumVerticalPosition or height
if _startingVerticalPosition > height then
_startingVerticalPosition = math.floor(height/2)
end
if _maximumVerticalPosition > height then
_maximumVerticalPosition = height
end
for i = 1,#_textArray do
if _startingVerticalPosition>=_maximumVerticalPosition then
_startingVerticalPosition = _maximumVerticalPosition
else
_startingVerticalPosition=_startingVerticalPosition+1
end
for j = 1,_startingVerticalPosition do
_outputDevice.setCursorPos(1,j)
_outputDevice.write(string.rep(" ",width))
end
refreshDisplay(_startingVerticalPosition,i,_textArray,_outputDevice)
sleep(_sleepInterval)
end
end
The code is about 125 lines long, and I included myDemoTable table of strings which adds about 70 lines. The main function that drives the utility is the scrollPrint() function. It takes the following arguments:
- _textArray, – the table of strings to print
- _startingVerticalPosition – the y-position to begin on the monitor
- _maximumVerticalPosition, – the maximum y-position to go to
- _sleepInterval, – delay between printed lines
- _outputDevice) – the output device (term or monitor peripheral)
To use it, insert the functions into your code, create your own table of strings and fill in the main function call. In the example, that call is:
scrollPrint(myDemoTable,5,20,1.7,peripheral.wrap("top"))
In the example, the strings in myDemoTable are vertically scrolled on a 4 wide X 3 high monitor I directly attached to the top of a computer. The first lines starts centered on line 5 of the monitor. It then continues adding lines until it hits line 20 of the monitor. From then on, it prints each new line on line 20 and scrolls the older lines up and out of view (much like a normal terminal display would do). If you want it to start on line 20 and scroll up, change the _startingVerticalPosition to 20. If you want it to use the whole screen, set the _startingVerticalPosition argument to 1 and _maximumVerticalPosition argument to _ (underscore). Ex.
scrollPrint(myDemoTable,1,_,1,peripheral.wrap("top"))
If you want to use the code as an API, simply save off the API version of the code, and call it in your program as follows:
os.loadAPI("VerticalScroll") -- or whatever you saved it as
--Here is a test Text Table
text = {"This is","a test","of the","Vertical Scrolling API."}
-- Here is the call to the driving function
VerticalScroll.scrollPrint(text,7,7,1,term) -- will default to term
-- At end of your program, unload API
os.unloadAPI("VerticalScroll")
I also don't clear the monitor. Instead, I only write over used lines with spaces. I think this allows for a smother display. It also allows for you to have other text (or graphics) on say the bottom half of the monitor while the text scrolls in the top half.
I auto-scale to the largest scale that will fit the width of all of the text strings. If you are using a terminal, autoscale is ignored. If it can't fit text on a line, it left justifies and fits as much as it can.
Let me know if you need help sorting out any of the functions. I sincerely appreciate any feedback you may have. I am always looking for ways to improve. Thanks.
EDIT
- Cleaned up variables in refreshDisplay() function
- Created API version of code
- Turned centerPrint into a local function (thanks Bomb Bloke for answering my question on that)
Edited on 26 January 2014 - 01:27 AM