This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
LBPHacker's profile picture

The Term Api - Controlling The Terminal

Started by LBPHacker, 16 August 2013 - 09:12 AM
LBPHacker #1
Posted 16 August 2013 - 11:12 AM
Hey everyone, LBPHacker here with a tutorial about how graphics work in ComputerCraft.
This tutorial does not explain the events the terminal and the monitors trigger (mouse_click, mouse_scroll, monitor_touch).

About the API

ComputerCraft gives us a nice interface for controlling the terminal (the "GUI" of the computer) in the form of the term API* (a table). You can write text on the terminal using term.write:
term.write("something")

Just like all terminals, the terminal in ComputerCraft has a cursor. When you call term.write, the text appears on the terminal where the cursor is, and the cursor moves to the end of the text. You can move the cursor manually using term.setCursorPos:
term.setCursorPos(1, 1)
1, 1 means "first column, first row of the terminal" (so these arguments are actually positionX and positionY). You can fetch the cursor position using term.getCursorPos:
local cursorX, cursorY = term.getCursorPos()

The terminal usually has 51 columns and 19 rows, though that can be changed in the ComputerCraft configuration file. You can fetch these two variables using term.getSize:
local termWidth, termHeight = term.getSize()

When writing text to the terminal, ComputerCraft uses the current text color and background color of the terminal (white text, black background by default). Those can be set using term.setTextColor and term.setBackgroundColor:
term.setTextColor(colors.orange)
term.setBackgroundColor(colors.blue)
Those functions accept color values from the colors (or colours) API**.

There is a function in the term API which clears the entire screen. Surprisingly, it's called term.clear
term.clear()
This will clear the entire screen, and paints it with the current background color. That means, yes, you could paint the whole screen red like this:
term.setBackgroundColor(colors.red)
term.clear()

The little brother of the above function is a function which works almost the same way, but it clears only one line - the line the cursor is currently on. You could paint the third line of the screen yellow using term.clearLine:
term.setBackgroundColor(colors.yellow)
term.setCursorPos(1, 3) -- the Y position of the cursor is now 3 -> it's on the third line
term.clearLine()

There comes a time when the screen is full of text and you have no more space on it - you have to either clear the terminal or scroll the contents of it upwards by using term.scroll. The latter will free a line at the bottom of the terminal, and you can write the next piece of text there.
term.scroll()
That will scroll everything upwards by one line by default, but you can specify manually how many lines you want to free:
term.scroll(3) -- will free up three lines

Yet another function, which turns on/off the blinking cursor. As you can guess, it's called term.setCursorBlink
term.setCursorBlink(false) -- turns off the blinking cursor

There are both normal and andvanced computer in ComputerCraft, and the difference between them is while the advanced ones can use 16 colors (inspired by the Wool from Vanilla Minecraft) in their terminals, the plain ones can only use black and white. You can check if the terminal you're currently using is advanced or not using term.isColor:
local advanced = term.isColor()

Those are the features of the native term API. There are two more functions, which makes our lives easier, I'll explain them later.

Monitors (peripheral)

When you wrap up a monitor peripheral:
local monitor = peripheral.wrap("left")
you get essentially a new term API you can mess with - with the difference that it's not called term, but the name you assign to it - "monitor", for example. Anything you do with term.* functions can also be done using the monitor.* functions, with the difference that while the term.* functions control the terminal of the computer itself, the monitor.* functions will control the monitor you wrapped up.

One more difference: on monitors, you get a new function, term.setTextScale, which can be used to set the text scale of the monitor:
monitor.setTextScale(2) -- 2 times the size of the normal text
The size can be either 0.5, 1, 2, 3, 4 or 5, if I recall correctly.

About word-wrapping

When using term.write, the .term function isn't going to care of the lenght of the string you give it, it'll just display what fits into the terminal - it doesn't even detect newline characters ( \n ). There are two built-in methods which makes our lives easier again. The first one is write, which does word-wrap, and even scrolls the contents terminal if needed. It returns the number of the lines affected by calling it.
write("First line\nSecond line")
The newline character will move the cursor to the first column and the next line. Note that this function leave there cursor where the cursor is when it displays the last letter of the string you passed it.

And there is print, which uses write to display all arguments you gave it, and it even passes an extra newline character to write. You can easily display two separate lines:
print("First line")
print("Second line")
print("Third line\nForth line")
print([[Fifth line
Sixth line
Seventh line]])

Redirection of the terminal

Now there is a problem with all these functions. They work only with the term API, and you can't force them (directly) to work with the monitor API you got by wrapping up a monitor. There is a way though to redirect the terminal of the computer to a monitor. That will alter the term API itself so it will control a monitor, therefore these two useful functions will control the monitor as well. We do that using this:
local monitor = peripheral.wrap("right")
term.redirect(monitor)
Now the term API is essentially the monitor API, and everything that uses it controls the monitor instead of the terminal of the computer. You can restore the term API using this:
term.restore()

Keep in mind that redirection uses a stack to keep track of monitors, which means that if you redirect the term API twice, you have to restore it twice as well. It's like building a tower out of bricks: When you start building, there is nothing where the tower should be - looking from above you see the ground (the original term API). When you place a brick (term.redirect), looking from above you can't see the ground, you can only see the brick (the monitor API you redirected the term to). When you put a second brick on top of the first (term.redirect), you can only see the second brick (the second monitor API). You take the brick on top (term.restore), and now you can see the first brick (the first monitor API) again. Just after taking another brick (term.restore) can you see the ground again (the original term API). Example:
print("This is on the terminal of the computer")
term.redirect(peripheral.wrap("left"))
print("This is on the monitor on the left")
term.redirect(peripheral.wrap("right"))
print("This is on the monitor on the right")
term.restore()
print("This is on the monitor on the left again, not on the computer")
term.restore()
print("This finally is on the computer")

There is a table in the term API which is never affected by redirection. That's the native term API. It's essentially the same as the term API, but it never changes (under you mess it up manually), and always controls the terminal built into the computer. You can call functions in it using the native table itself (term.native.*):
term.native.write("I'm still here")

Footnotes

*the term API on the Wiki
**the colors API on the Wiki

This tutorial is inspired by (and aims to become part of) the Ask-a-Pro Renewal Project.
Engineer #2
Posted 17 August 2013 - 10:16 AM
This is really useful for those who are not familair with the graphics standard Computercraft uses.

I like this tutorial :)/>
General_Led #3
Posted 18 August 2013 - 05:26 PM
How do i get it to write to a monitor?
LBPHacker #4
Posted 18 August 2013 - 05:45 PM
How do i get it to write to a monitor?
Thanks for pointing out that I clumsily forgot the part where you actually wrap up a monitor. If you read it again, you can see, you only have to wrap up a monitor like this:
local monitor = peripheral.wrap("left")
then redirect the terminal to the new "API":
term.redirect(monitor)
Then use the built-in print or write functions, and the end of the program, restore the terminal:
term.restore()
General_Led #5
Posted 18 August 2013 - 06:23 PM
I hope I am not bugging you to much but I am a ultra beginner to all of this as a whole. I am currently trying to write to a monitor and it just isn't doing what I want it to do, most likely because I am doing everything wrong. Could you possibly give a example of what it should look like if I am trying to write something to a monitor such as "hello". Again I am sorry if I am being a pain I only know what I google and read on the forums. Thanks
oeed #6
Posted 19 August 2013 - 12:01 AM
I hope I am not bugging you to much but I am a ultra beginner to all of this as a whole. I am currently trying to write to a monitor and it just isn't doing what I want it to do, most likely because I am doing everything wrong. Could you possibly give a example of what it should look like if I am trying to write something to a monitor such as "hello". Again I am sorry if I am being a pain I only know what I google and read on the forums. Thanks

Try this:


local monitor = peripheral.wrap("left")
term.redirect(monitor)
term.write("hello")
NomNuggetNom #7
Posted 19 August 2013 - 11:00 PM
Thanks a bunch for this tutorial, it was really helpful! I have a follow-up question: What would be the easiest way to display a 1x1 cube of color?
theoriginalbit #8
Posted 20 August 2013 - 02:07 AM
Thanks a bunch for this tutorial, it was really helpful! I have a follow-up question: What would be the easiest way to display a 1x1 cube of color?
Doing the following code will achieve a single red coloured pixel

--# paintutils.drawPixel(x, y, colour)
paintutils.drawPixel(10, 8, colors.red)

As a point of learning, this is how the above API function works

function drawPixel(x,y,colour)
  term.setCursorPos(x,y)
  term.setBackgroundColour(colour)
  write(' ')
end