I am teaching myself C and currently run the latest Fedora.
On a Windows command prompt you can address the screen location. I am led to the believe that a Linux command terminal works, effectively, like characters printed to a piece of paper. i.e. You can't go "up" from where you are.
However, when you install in Linux, there is a progress bar (in text) which doesn't appear to print a new line each time with the increase of progress. Also, take for example raspbi-config in which you can tab/arrow up and down a "menu" and select "OK" and "Cancel" etc.
How does one achieve this? Can this then be used to do simple text graphics applications in Linux like one can do under Windows?
Any help would be appreciated.
Uberlinc.
Coding in C . General non-gui apps which simply "cout" to the stdout. Only found one or two examples which show a progress bar that prints out to the same line, but are not clear to me.
CodePudding user response:
On a basic level, there are two things that enable these kinds of things on a Linux (or other POSIX) terminal: ASCII control characters and ANSI escape codes.
For a simple progress bar, it's enough to know how wide the screen is and to have a way to get back to the beginning of the current terminal line. This can be one by reading the environment variable $COLUMNS
with getenv
and by printing the ASCII control character \r
. A very bare-bones and unbeautified example is
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>
int main() {
// Default screen width
int width = 80;
// Get screenwidth from environment
char const *envwidth = getenv("COLUMNS");
if(envwidth != nullptr) {
std::istringstream(envwidth) >> width;
}
// save some space for numeric display
width -= 10;
for(int i = 1; i < width; i) {
std::cout
<< '\r' // go back to start of line
<< std::string(i, '.') // progress bar
<< std::string(width - i, ' ') // padding
<< "| " << i << '/' << width // numeric display
<< std::flush; // make the progress bar instantly visible
// pretend to work
usleep(100000);
}
}
For more involved terminal "graphics,", there are ANSI escape codes. These allow you to set foreground and background color, move around on the screen at will, and a few other things, by printing special character sequences to stdout. For example,
std::cout << "\x1b[10;20HHello, world." << std::flush;
will print Hello, world.
at position 10, 20 on the screen.
There is also the ncurses
library that provides more high-level terminal UI functionality (windows, dialogs, that sort of thing). They use ANSI escape codes under the hood, but it's normally nicer to use that than to roll your own UI framework.