cross-platform advanced terminal control
TG allows you to use the terminal sort of like a normal graphical window. If you are familiar with curses, the Linux library, TG does the same thing, but for both Windows and Linux, and with a simplified flow. In fact, the Linux version uses ncurses.
You can:
- Double-buffer the screen (for fast drawing)
- Collect input in a standard way
- Draw to the screen
- Use colors
Building TG is rather simple. On Windows, just add tg.h
and tg.c
to your
project. On Linux, do the same thing, and add the linker option -lncursesw
.
A makefile has been included as an example.
This is a one-line bash script to compile a program with TG (Assuming
you have a program called yourprogram.c
):
gcc -o yourprogram tg.c tg.h yourprogram.c -lncursesw
And then, of course, run it with
sudo chmod +x yourprogram
./yourprogram
First of all, download and include tg.c
and tg.h
. There are two
functions that enter and exit "TG mode" - which is similar to "curses
mode" if you're familar with that.
#include "tg.h"
int main(){
TG(); // Start TG
TGEnd(); // Stop TG
return 0;
}
Congratulations, you have started, and immediately stopped, TG.
Now let's create a program that keeps rendering an "X" in the top right corner until the "q" key is pressed.
#include <stdbool.h>
#include "tg.h"
int main() {
TGContext *tg = TG();
TGCharInfo info;
info.character = 'X';
TGColor whiteRed = TGColorCreate(TG_WHITE, TG_RED);
info.attributes.color = whiteRed.id;
TGCalculateAttrs(&info.attributes);
TGTitle("termRant");
TGSetCursorVisible(false);
bool running = true;
while (running){
TGBufCell(&tg->drawBuffer, 0, 0, info);
TGUpdate();
TGInput input = TGGetInput();
if (!input.empty) {
if (input.eventType == TG_EVENT_KEY && input.event.keyEvent.key == 'q')
running = false;
}
}
TGEnd();
return 0;
}
Let's run through this
TGContext *tg = TG();
TG
returns a TGContext struct pointer. A TGContext can be helpful because it contains
the main drawing buffer. It's a good idea to keep a reference to this.
TGCharInfo info;
info.character = 'X';
Each drawing buffer is made up of these CharInfo objects. They describe the attributes of the text cells they represent. In other words, a TGCharInfo is a text cell's content.
TGColor whiteRed = TGColorCreate(TG_WHITE, TG_RED);
info.attributes.color = whiteRed.id;
TGCalculateAttrs(&info.attributes);
Because of Linux, colors need to be created in pairs. Each pair of colors (foreground,
background) is unique and given an ID. You should create these pairs only once. In most
Linux terminals, you're limited to just a few pairs, so if you create a new TGColor
every time you render a frame, you'll run out pretty quick.
Next, we set the TGCharInfo
structure's color to the color ID we created earlier.
Lastly, we need to calculate the attributes of the TGCharInfo
. This is largely
done for cross-platform reasons. Essentially, we're turning a description of
attributes into actual system attributes with this call.
TGTitle("termRant");
TGSetCursorVisible(false);
Some visual things just to make the experience a little better. Their function should be obvious.
bool running = true;
while (running){
TGBufCell(&tg->drawBuffer, 0, 0, info);
TGUpdate();
TGInput input = TGGetInput();
if (!input.empty) {
if (input.eventType == TG_EVENT_KEY && input.event.keyEvent.key == 'q') running = false;
}
}
This is a simple input loop. Firstly, we set the (0, 0) position of the main draw buffer
to the TGCharInfo
we created earlier, and then update the screen. Lastly, we read some
input from the user, and if that event is a key press, and they pressed the letter "q",
we stop running the loop.
TGEnd();
return 0;
Of course, we need to clean up our mess after we're done. If you forget TGEnd
, your
console may behave unexpectedly. On Linux, use the reset
command to fix this.
The current version of TG lacks lots of ease-of-use features for drawing, planned for the future. That being said, you already have the tools you need to do anything you want, you'll just need to implement your own drawing functionality if you want to easily do things like lines and rectangles.
As for what is already implemented, it is important to understand the cursor system in TG. TG has two types of cursors: the actual cursor (provided by the terminal emulator) and virtual cursors. Each buffer has it's own virtual cursor, which does not display. A buffer's virtual cursor is where new characters are drawn by default. Every time you clear a buffer, the virtual cursor for that buffer is set to (0, 0).
The system cursor DOES display (by default), and to control the system cursor, see the functions TGSetCursorVisible, TGSetCursorPosition and TGGetCursorPosition.
The functions to work with a buffer's virtual cursor are
TGBufCursorMove and TGBufCursorPosition.
These functions modify the curren position of a buffer's virtual cursor.
If you would like to retrieve the current position of a buffer's virtual cursor,
simply access the member variable virtualCursorPosition
Jump to: Color • Buffer • Character Cell • General • Input
Color | Description | Type |
---|---|---|
Colors | A list of colors | Constants |
TGColor | Color struct | Struct |
TGColorCreate | Create a color (pair) | Function |
TGDefaultColor | The terminal's default color | Extern |
TG_COLOR_NAMES | A list of color names | Constant |
Buffer | Description | Type |
---|---|---|
TGBufAddLString | Add char* string | Function |
TGBufAddLStringAttr | Add char* string with certain attributes | Function |
TGBufAddString | Add wchar_t* string | Function |
TGBufAddStringAttr | Add wchar_t* string with certain attributes | Function |
TGBufAttr | Change attributes for a cell | Function |
TGBufCell | Change a cell | Function |
TGBufClear | Clear a buffer | Function |
TGBufCopy | Copy one buffer to another | Function |
TGBufCreate | Create a new buffer | Function |
TGBufCursorMove | Move a buffer's virtual cursor | Function |
TGBufCursorPosition | Set a buffer's virtual cursor position | Function |
TGBuffer | Buffer struct | Struct |
TGBufFree | Clean up a buffer | Function |
TGBufSize | Resize a buffer | Function |
Character Cells | Description | Type |
---|---|---|
TGAttributes | Attributes structure | Struct |
TGCalculateAttrs | Calculate system attributes | Function |
TGCharInfo | Individual character cell structure | Struct |
General | Description | Type |
---|---|---|
COORD | X and Y coordinate structure | Struct |
TG | Init function | Function |
TG_VERSION | Current TG version | Constant |
TG_WINDOWS_MODE | true if running on Windows |
Constant |
TGContext | Mainly used internally | Struct |
TGEnd | Exit TG mode | Function |
TGSetCursorVisible | Set system cursor visibility | Function |
TGTitle | Set terminal title with wchar_t* |
Function |
TGLTitle | Set terminal title with char* |
Function |
TGUpdate | Update the screen | Function |
Input | Description | Type |
---|---|---|
TGGetInput | Get one input record from the buffer | Function |
TGHandleResizeEvent | Make TG system react to resize | Function |
TGInput | An input record | Struct |
TGKeyEvent | Fired for key events | Struct |
TGMouseEvent | Fired for mouse events | Struct |
TGResizeEvent | Fired for resize events | Struct |
- TGBufAddString
- TGBufAddStringAttr
TG supports seven cross-platform colors. They are:
TG_BLACK
TG_RED
TG_GREEN
TG_YELLOW
TG_BLUE
TG_MAGENTA
TG_CYAN
TG_WHITE
They must be used with TGCreateColor
struct
COORD is a structure describing a position in two-dimensional space. It comes from the Windows standard library, and has only X and Y integer values. They are uppercase for compatibility with Windows.
Member | Data Type | Description |
---|---|---|
X | int | X coordinate |
Y | int | Y coordinate |
function
TG Starts it all. TG enters "TG mode" and returns a pointer to the main TGContext
Return Value | Data Type | Description |
---|---|---|
TGContext | TGContext* | The main TG Context |
constant
Can be used to convert a standard color (see Colors) to their English names in all caps. In order, they are:
"BLACK"
"RED"
"GREEN"
"YELLOW"
"BLUE"
"MAGENTA"
"CYAN"
"WHITE"
Therefore, TG_COLOR_NAMES[TG_BLACK]
is "BLACK"
constant
The current version of TG you are using
constant
Helpful boolean to tell if you're using the Windows version of TG or not.
struct
A structure to hold attributes, as listed below
Member | Data Type | Description |
---|---|---|
underlined | bool | Set to true for underlined text |
bold | bool | Set to true for bold text |
color | unsigned int | Color ID |
function
Add a "legacy string" - one byte characters - at the current buffer position
(virtualCursorPosition
) with the current buffer attributes.
Argument | Data Type | Description |
---|---|---|
Buffer | TGBuffer* | The buffer to draw to |
str | char* | String to draw |
function
Add a "legacy string" - one byte characters - at the current buffer position
(virtualCursorPosition
) with the attributes passed to the function.
Argument | Data Type | Description |
---|---|---|
Buffer | TGBuffer* | The buffer to draw to |
str | char* | String to draw |
attributes | TGAttributes | Attributes to use |
function
Add a wide string at the current buffer position
(virtualCursorPosition
) with the current buffer attributes.
Argument | Data Type | Description |
---|---|---|
Buffer | TGBuffer* | The buffer to draw to |
str | wchar_t* | String to draw |
function
Add wide string at the current buffer position
(virtualCursorPosition
) with the attributes passed to the function.
Argument | Data Type | Description |
---|---|---|
Buffer | TGBuffer* | The buffer to draw to |
str | wchar_t* | String to draw |
attributes | TGAttributes | Attributes to use |
function
Set's a buffer's attributes at a specific location
Argument | Data Type | Description |
---|---|---|
Buffer | TGBuffer* | The buffer to draw to |
x | int | X position of cell to update |
y | int | Y position of cell to update |
Attributes | TGAttributes | Attributes to set |
Returns void
function
Rather than just changing the attributes of a cell, this changes all of the
info contained in a TGCharInfo
Argument | Data Type | Description |
---|---|---|
Buffer | TGBuffer* | The buffer to draw to |
x | int | X position of cell to update |
y | int | Y position of cell to update |
CharInfo | TGCharInfo | CharInfo to set |
function
Clear a buffer and set it's virtual cursor position to (0, 0)
Argument | Data Type | Description |
---|---|---|
Buffer | TGBuffer* | The buffer to clear |
function
Duplicate a buffer
Argument | Data Type | Description |
---|---|---|
Buffer | TGBuffer* | The buffer to duplicate |
Return Value | Data Type | Description |
---|---|---|
New Buffer | TGBuffer | Deep copied buffer |
function
Create a new buffer
Argument | Data Type | Description |
---|---|---|
width | int | Width of new buffer |
height | int | Height of new buffer |
Return Value | Data Type | Description |
---|---|---|
New Buffer | TGBuffer | New buffer |
function
Move the cursor left by some amount. Negative values acceptable to go right. Will not loop back around when it reaches the end of the buffer (or the beginning).
Argument | Data Type | Description |
---|---|---|
buffer | TGBuffer* | The buffer to alter |
amount | int | How far left to move the cursor |
function
Set the virtual cursor position of a buffer
Argument | Data Type | Description |
---|---|---|
buffer | TGBuffer* | The buffer to alter |
x | int | X dimension of position |
y | int | Y dimension of position |
struct
A buffer structure holding TGCharInfo
types
Member | Data Type | Description |
---|---|---|
size | COORD | Dimensions of the buffer |
buffer | TGCharInfo* | The actual buffer |
length | unsigned int | Size of buffer in TGCharInfo |
currentAttributes | TGAttributes | Used as a default for new chars |
virtualCursorPosition | COORD | Used as a default for new chars |
function
Free resources allocated to a buffer
Argument | Data Type | Description |
---|---|---|
Buffer | TGBuffer* | The buffer to free |
function
Resize a buffer
Argument | Data Type | Description |
---|---|---|
Buffer | TGBuffer* | The buffer to size |
width | int | New width of the buffer |
height | int | New height of the buffer |
function
Called to convert an attribute "description" into actual system attributes. Must
be called any time you modify a TGAttributes
struct
Argument | Data Type | Description |
---|---|---|
Attributes | TGAttributes* | The attributes to calculate |
struct
An abstract description of a text cell, including color, character, and other attributes
Member | Data Type | Description |
---|---|---|
character | unsigned int | Text content of the cell |
attributes | TGAttributes | Text attributes struct |
struct
Describes a color
Member | Data Type | Description |
---|---|---|
id | unsigned int | Color ID |
foreground | unsigned short | Foreground color ID |
background | unsigned short | Background color ID |
function
Create a color. You should avoid calling this function multiple times for the same color. As noted above (in getting started), Linux terminals limit the amount of pairs you can make. If you make a new pair each time you render a frame, you'll run out very quickly.
Argument | Data Type | Description |
---|---|---|
Foreground | int | Foreground color ID |
Background | int | Background color ID |
Return Value | Data Type | Description |
---|---|---|
Color | TGColor | New color |
struct
In normal operation, there should only be one context. This structure holds the main drawing buffer and some other vital information
Note: typedef WINDOW* HANDLE; on Linux
Member | Data Type | Description |
---|---|---|
screenBufferHandle | HANDLE | stdscr on Linux, CreateConsoleScreenBuffer on Windows |
inputHandle | HANDLE | Nothing on Linux, STD_INPUT_HANDLE on Windows |
drawBuffer | TGBuffer | The main draw buffer |
extern
A TGColor structure describing the console's default colors
function
Exits TG mode
function
Reads input and returns it as a TGInput
record
There are three types of input:
TG_EVENT_KEY
TG_EVENT_MOUSE
TG_EVENT_RESIZE
To determine the type of input, you can read the eventType
attribute. Each
input type has their own input record.
Please note that resize events MUST be sent to TGHandleResizeEvent
Return Value | Data Type | Description |
---|---|---|
Input | TGInput | User input |
function
Resize events aren't handled by TG automatically. When you read a resize
event from TGGetInput
, you must run that same input trough this function
Argument | Data Type | Description |
---|---|---|
Event | TGInput | Event to react to |
struct
Holds information about a user interaction with the terminal. For more information, see TGGetInput
Member | Data Type | Description |
---|---|---|
eventType | short | Which event type was read |
empty | bool | Empty records can be ignored |
event | union | The various event types |
-> keyEvent | TGKeyEvent | The key event |
-> mouseEvent | TGKeyEvent | The mouse event |
-> resizeEvent | TGKeyEvent | The resize event |
struct
Holds information about when a user presses a key
Some keys are considered "special", such as the arrow keys. Here is a list of "special" keys:
TG_KEY_UP
TG_KEY_RIGHT
TG_KEY_DOWN
TG_KEY_LEFT
TG_KEY_BACKSPACE
TG_KEY_TAB
TG_KEY_ESCAPE
TG_KEY_PAGE_UP
TG_KEY_PAGE_DOWN
TG_KEY_END
TG_KEY_HOME
TG_KEY_INSERT
TG_KEY_DELETE
Member | Data Type | Description |
---|---|---|
key | unisgned int | Which key was pressed |
ctrlDown | bool | If ctrl was pressed |
special | bool | If the key is one of the special keys |
struct
Holds information about when the user interacts with the mouse
The supported buttons are:
TG_MOUSE_LEFT
TG_MMB // Middle Mouse Button
TG_MOUSE_RIGHT
And the various actions are:
TG_MOUSE_CLICK
TG_MOUSE_MOVE
Member | Data Type | Description |
---|---|---|
position | COORD | Where the mouse event occurred |
button | unsigned short | Which button was pressed |
action | unsigned short | What the user did |
struct
Holds information about when the user resizes the terminal
NOTE: IF YOU READ THIS EVENT TYPE, IT MUST BE SENT TO TGHandleResizeEvent
Member | Data Type | Description |
---|---|---|
oldSize | COORD | The old size of the terminal |
newSize | COORD | The new size of the terminal |
function
Sets the cursor to be either visible or invisible. Doesn't seem to be permanent on all platforms, so call this once per render to be sure.
Argument | Data Type | Description |
---|---|---|
visible | bool | Visible if value is truthy |
function
Set the title of the console.
Argument | Data Type | Description |
---|---|---|
title | wchar_t* | The new title of the console |
function
Set the title of the console.
Argument | Data Type | Description |
---|---|---|
title | char* | The new title of the console |
function
Update the screen. No drawing will take visual effect until this is called.