Logo  

CS351 - Computer Organization

Video Attributes:

  • Reading: man attron

Each character can have one or more attributes associated with it, these include:

Name Description
A_NORMAL Normal display (no highlight)
A_STANDOUT Best highlighting mode of the terminal.
A_UNDERLINE Underlining
A_REVERSE Reverse video
A_BLINK Blinking
A_DIM Half bright
A_BOLD Extra bright or bold
A_PROTECT Protected mode
A_INVIS Invisible or blank mode
A_ALTCHARSET Alternate character set
A_ITALIC Italics

Attributes can be turned on or off using:

int attron(int attrs);

  • Turns on the attributes given by attrs

int attroff(int attrs);

  • Turns off the attributes given by attrs

int attrset(int attrs);

  • Set attributes to attrs explicitly.

    Example: Turn on bold and underlining

attrset(A_BOLD | A_UNDERLINE);
printw("Highlighted and underlined");
// Back to normal:
attrset(A_NORMAL);

Attributes can be applied directly to a character when using addch() or mvaddch(), ex:

// Adds an x to the screen that is both bold and underlined.
addch('x' | A_BOLD | A_UNDERLINE);

An aside about the binary OR operator

The Binary OR operator or single vertical bar (|) logically ORs all the binary bits both the left and right operands together, the result being where each bit in the result is a 1 (i.e. set) if the same bit in either the left or right operand has the same bit set to a 1 and will be 0 (zero) if neither the left or right operand has that bit set.

Example:

  153 | 77 == 221   (decimal)

  10011001  (153 in binary)
| 01001101  ( 77 in binary)
──────────
  11011101  (221 in binary)

For the purposes of curses programming (and in many other C programming circumstances,) it is enough to think of the binary OR operator as being addition (in fact, + is sometimes used as the OR operation in Boolean algebra,) and often addition could be used in lieu of binary OR. In our case we want to add one or more attributes to a character, so we use the binary OR operator when doing so.

The alternate character-set

  • Reading: man addch

In curses we can use some semi-graphical characters, known as the Alternate Character Set (ACS) characters. Such characters can only be added to the screen using the *addch() functions or by setting the A_ALTCHARSET attribute before . The characters are referred to by their ACS name, a table of which is shown here.

ACS
Name
Rendered
character
Description
ACS_BTEE bottom tee
ACS_BULLET · bullet
ACS_CKBOARD checker board (stipple)
ACS_DARROW v arrow pointing down
ACS_DEGREE ° degree symbol
ACS_DIAMOND diamond
ACS_GEQUAL greater-than-or-equal-to
ACS_HLINE horizontal line
ACS_LANTERN lantern symbol
ACS_LARROW < arrow pointing left
ACS_LEQUAL less-than-or-equal-to
ACS_LLCORNER lower left-hand corner
ACS_LRCORNER lower right-hand corner
ACS_LTEE left tee
ACS_NEQUAL not-equal
ACS_PI π greek pi
ACS_PLMINUS ± plus/minus
ACS_PLUS plus
ACS_RARROW > arrow pointing right
ACS_RTEE right tee
ACS_STERLING £ pound-sterling symbol
ACS_TTEE top tee
ACS_UARROW ^ arrow pointing up
ACS_ULCORNER upper left-hand corner
ACS_URCORNER upper right-hand corner
ACS_VLINE vertical line

Example:

// This:
move(0,0);
addch(ACS_ULCORNER); addch(ACS_HLINE); addch(ACS_TTEE);  addch(ACS_HLINE); addch(ACS_URCORNER);
move(1,0);
addch(ACS_VLINE);    addch(' ');       addch(ACS_VLINE); addch(' ');       addch(ACS_VLINE);
move(2,0);
addch(ACS_LTEE);     addch(ACS_HLINE); addch(ACS_PLUS);  addch(ACS_HLINE); addch(ACS_RTEE);
move(3,0);
addch(ACS_VLINE);    addch(' ');       addch(ACS_VLINE); addch(' ');       addch(ACS_VLINE);
move(4,0);
addch(ACS_LLCORNER); addch(ACS_HLINE); addch(ACS_BTEE);  addch(ACS_HLINE); addch(ACS_LRCORNER);
// Would render this:
┌─┬─┐
│ │ │
├─┼─┤
│ │ │
└─┴─┘

Colors:

To use colors on your terminal, your terminal type must be set to a terminal type that can support colors. Typically 'xterm' is the preferred terminal type. This is done by setting your 'term' shell variable:

set term=xterm

To make this permanent, edit your ~/.cshrc file to either add or edit the term variable to make it xterm. (this should already be the case for your CS256 accounts.)

In curses a color has two components, the foreground or text color and the background color. These colors cannot be set individually, they are set in what is called a color pair.

To tell curses to enable colors, use:

int start_color(void);

The default colors available are:

COLOR_BLACK
COLOR_RED
COLOR_GREEN
COLOR_YELLOW
COLOR_BLUE
COLOR_MAGENTA
COLOR_CYAN
COLOR_WHITE

To produce a color pair, we use the function:

int init_pair(short pair, short f, short b);

pair The number for this particular combination of colors.
f The foreground (text) color
b The background color

example:

init_pair(1, COLOR_RED, COLOR_WHITE); // Makes color pair #1 red on white

Note: color pair #0 is a special pair that defaults to the terminals normal foreground and background color.

The following loop will initialize all 8 x 8 combinations of colors

for(int fg=0; fg < 8; fg++)
  for(int bg=0; bg < 8; bg++)
    init_pair( (fg*8 + bg), fg, bg );


To apply a color pair to a character or characters it must be applied as an attribute, which can be done with the attron, attroff and attrset functions or directly on a character via the addch functions. However it must fist be converted to an attribute form, which is done with the COLOR_PAIR() macro function:

COLOR_PAIR(int n);

The COLOR_PAIR() function takes a color pair number and returns that color as an attribute which can be given to functions that take attributes.

Examples:

// Apply color pair 5 to the character 'x':
addch('x' | COLOR_PAIR(5));
// Make red on black the current color for all characters that follow:
// This assumes we setup our color pairs using the fg/bg loop above:
attron(COLOR_PAIR(COLOR_RED*8 + COLOR_BLACK));

color.c

#include <curses.h>
#include <string.h>

int main(void)
{
  int fg, bg;

  initscr();
  start_color();
  // Define all the foreground and background combinations:
  for(fg=0; fg < 8; fg++)
    for(bg=0; bg < 8; bg++)
      init_pair( (fg*8 + bg), fg, bg );

  clear();

  move(2, 20);
  // Draw the background color numbers across the top:
  for(bg=0; bg < 8; bg++) {
    printw("%3d", bg);
  }
  move(3, 19);
  // Draws a line under the top numbers:
  addch(ACS_ULCORNER);
  for(bg=0; bg < 8; bg++) {
    addch(ACS_HLINE);
    addch(ACS_HLINE);
    addch(ACS_HLINE);
  }

  // For every foreground color (one each row):
  for(fg=0; fg < 8; fg++) {
    attrset(A_NORMAL);
    mvprintw(4+fg,16, "%2d ", fg);
    addch(ACS_VLINE);
    // All the background colors for each foreground color (columns):
    for(bg=0; bg < 8; bg++) {
      attrset(COLOR_PAIR(fg*8 + bg));
      addch('x'|A_DIM);
      addch('x');
      addch('x'|A_BOLD);
    }
  }
  attrset(A_NORMAL);

  getch();
  endwin();
  return 0;
}

Setting the visibility of the cursor:

int curs_set(int visibility);

where visibility is on of:

visibility
0 Invisible
1 Normal visibility
2 Very visible

Inspecting characters that are on the screen:

We can read back a character that is on the screen using the inch() or mvinch() functions. Since these functions return encoded data about a character, which includes the character, it's attributes and color, we need to use the Binary AND (&, not to be confused with the address of operator) operator to separate out just the information we want from the function, examples of this are shown below:

chtype inch();

  • Returns character at current cursor position

chtype mvinch(int y, int x);

  • Moves cursor to x,y then returns character at that position.

    Examples:

// Gets the character at 10,10:
char ch = mvinch(10,10) & A_CHARTEXT;
// Gets the Attributes and colors in use at the current cursor position:
char attr = inch() & A_ATTRIBUTES;
char color = inch() & A_COLOR;