From d1c2a7126a04dde110792552497b9beabbdee5f2 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 20 Feb 2013 22:51:34 +0100 Subject: [PATCH] terminal: Generalize character-screen code This patch moves the further reusable parts of the terminal into public header files. It also slightly tweaks the color table to give all colors a similar brightness level. --- .../char_cell_array_character_screen.h | 389 ++++++++++++++++ gems/include/terminal/font_face.h | 36 ++ gems/src/server/terminal/main.cc | 426 ++---------------- 3 files changed, 455 insertions(+), 396 deletions(-) create mode 100644 gems/include/terminal/char_cell_array_character_screen.h create mode 100644 gems/include/terminal/font_face.h diff --git a/gems/include/terminal/char_cell_array_character_screen.h b/gems/include/terminal/char_cell_array_character_screen.h new file mode 100644 index 0000000000..dc69e2ec94 --- /dev/null +++ b/gems/include/terminal/char_cell_array_character_screen.h @@ -0,0 +1,389 @@ +/* + * \brief Char-cell-array-based implementation of a character screen + * \author Norman Feske + * \date 2013-01-20 + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _TERMINAL__CHAR_CELL_ARRAY_CHARACTER_SCREEN_H_ +#define _TERMINAL__CHAR_CELL_ARRAY_CHARACTER_SCREEN_H_ + +/* terminal includes */ +#include +#include + +struct Char_cell +{ + unsigned char attr; + unsigned char ascii; + unsigned char color; + + enum { ATTR_COLIDX_MASK = 0x07, + ATTR_CURSOR = 0x10, + ATTR_INVERSE = 0x20, + ATTR_HIGHLIGHT = 0x40 }; + + enum { COLOR_MASK = 0x3f }; /* 111111 */ + + Char_cell() : attr(0), ascii(0), color(0) { } + + Char_cell(unsigned char c, Font_face f, + int colidx, bool inv, bool highlight) + : + attr(f.attr_bits() | (inv ? ATTR_INVERSE : 0) + | (highlight ? ATTR_HIGHLIGHT : 0)), + ascii(c), + color(colidx & COLOR_MASK) + { } + + Font_face font_face() const + { + return Font_face((Font_face::Type)(attr & Font_face::attr_mask())); + } + + int colidx_fg() const { return color & ATTR_COLIDX_MASK; } + int colidx_bg() const { return (color >> 3) & ATTR_COLIDX_MASK; } + bool inverse() const { return attr & ATTR_INVERSE; } + bool highlight() const { return attr & ATTR_HIGHLIGHT; } + + void set_cursor() { attr |= ATTR_CURSOR; } + void clear_cursor() { attr &= ~ATTR_CURSOR; } + + bool has_cursor() const { return attr & ATTR_CURSOR; } +}; + + +class Char_cell_array_character_screen : public Terminal::Character_screen +{ + private: + + enum Cursor_visibility { CURSOR_INVISIBLE, + CURSOR_VISIBLE, + CURSOR_VERY_VISIBLE }; + + Cell_array &_char_cell_array; + Terminal::Boundary _boundary; + Terminal::Position _cursor_pos; + /** + * Color index contains the fg color in the first 3 bits + * and the bg color in the second 3 bits (0bbbbfff). + */ + int _color_index; + bool _inverse; + bool _highlight; + Cursor_visibility _cursor_visibility; + int _region_start; + int _region_end; + int _tab_size; + + enum { DEFAULT_COLOR_INDEX_BG = 0, DEFAULT_COLOR_INDEX = 7, DEFAULT_TAB_SIZE = 8 }; + + struct Cursor_guard + { + Char_cell_array_character_screen &cs; + + Terminal::Position old_cursor_pos; + + Cursor_guard(Char_cell_array_character_screen &cs) + : + cs(cs), old_cursor_pos(cs._cursor_pos) + { + /* temporarily remove cursor */ + cs._char_cell_array.cursor(old_cursor_pos, false); + } + + ~Cursor_guard() + { + /* restore original cursor */ + cs._char_cell_array.cursor(old_cursor_pos, true); + + /* if cursor position changed, move cursor */ + Terminal::Position &new_cursor_pos = cs._cursor_pos; + if (old_cursor_pos != new_cursor_pos) { + + cs._char_cell_array.cursor(old_cursor_pos, false, true); + cs._char_cell_array.cursor(new_cursor_pos, true, true); + } + } + }; + + public: + + Char_cell_array_character_screen(Cell_array &char_cell_array) + : + _char_cell_array(char_cell_array), + _boundary(_char_cell_array.num_cols(), _char_cell_array.num_lines()), + _color_index(DEFAULT_COLOR_INDEX), + _inverse(false), + _highlight(false), + _cursor_visibility(CURSOR_VISIBLE), + _region_start(0), + _region_end(_boundary.height - 1), + _tab_size(DEFAULT_TAB_SIZE) + { } + + + void _line_feed() + { + Cursor_guard guard(*this); + + _cursor_pos.y++; + + if (_cursor_pos.y > _region_end) { + _char_cell_array.scroll_up(_region_start, _region_end); + _cursor_pos.y = _region_end; + } + } + + void _carriage_return() + { + Cursor_guard guard(*this); + + _cursor_pos.x = 0; + } + + + /******************************** + ** Character_screen interface ** + ********************************/ + + Terminal::Position cursor_pos() const { return _cursor_pos; } + + void output(Terminal::Character c) + { + if (c.ascii() > 0x10) { + Cursor_guard guard(*this); + _char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y, + Char_cell(c.ascii(), Font_face::REGULAR, + _color_index, _inverse, _highlight)); + _cursor_pos.x++; + } + + switch (c.ascii()) { + + case '\r': /* 13 */ + _carriage_return(); + break; + + case '\n': /* 10 */ + _line_feed(); + _carriage_return(); + break; + + case 8: /* backspace */ + { + Cursor_guard guard(*this); + + if (_cursor_pos.x > 0) + _cursor_pos.x--; + + break; + } + + case 9: /* tab */ + { + Cursor_guard guard(*this); + _cursor_pos.x += _tab_size - (_cursor_pos.x % _tab_size); + break; + } + + default: + break; + } + + if (_cursor_pos.x >= _boundary.width) { + _carriage_return(); + _line_feed(); + } + } + + void civis() + { + _cursor_visibility = CURSOR_INVISIBLE; + } + + void cnorm() + { + _cursor_visibility = CURSOR_VISIBLE; + } + + void cvvis() + { + _cursor_visibility = CURSOR_VERY_VISIBLE; + } + + void cpr() + { + PDBG("not implemented"); + } + + void csr(int start, int end) + { + /* the arguments are specified use coordinate origin (1, 1) */ + start--; + end--; + + _region_start = Genode::max(start, 0); + _region_end = Genode::min(end, _boundary.height - 1); + + /* preserve invariant of region size >= 0 */ + _region_end = Genode::max(_region_end, _region_start); + } + + void cuf(int dx) + { + Cursor_guard guard(*this); + + _cursor_pos.x += dx; + _cursor_pos.x = Genode::min(_boundary.width - 1, _cursor_pos.x); + } + + void cup(int y, int x) + { + Cursor_guard guard(*this); + + /* top-left cursor position is reported as (1, 1) */ + x--; + y--; + + using namespace Genode; + x = max(0, min(x, _boundary.width - 1)); + y = max(0, min(y, _boundary.height - 1)); + + _cursor_pos = Terminal::Position(x, y); + } + + void cuu1() { PWRN("not implemented"); } + void dch(int) { PDBG("not implemented"); } + + void dl(int num_lines) + { + /* delete number of lines */ + for (int i = 0; i < num_lines; i++) + _char_cell_array.scroll_up(_cursor_pos.y, _region_end); + } + + void ech(int v) + { + Cursor_guard guard(*this); + + for (int i = 0; i < v; i++, _cursor_pos.x++) + _char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y, + Char_cell(' ', Font_face::REGULAR, + _color_index, _inverse, _highlight)); + } + + void ed() + { + /* clear to end of screen */ + _char_cell_array.clear(_cursor_pos.y, _boundary.height - 1); + } + + void el() + { + /* clear to end of line */ + for (int x = _cursor_pos.x; x < _boundary.width; x++) + _char_cell_array.set_cell(x, _cursor_pos.y, Char_cell()); + } + + void el1() { PDBG("not implemented"); } + + void home() + { + Cursor_guard guard(*this); + + _cursor_pos = Terminal::Position(0, 0); + } + + void hpa(int x) + { + Cursor_guard guard(*this); + + _cursor_pos.x = x; + _cursor_pos.x = Genode::min(_boundary.width - 1, _cursor_pos.x); + } + + void hts() { PDBG("not implemented"); } + void ich(int) { PDBG("not implemented"); } + + void il(int value) + { + Cursor_guard guard(*this); + + if (_cursor_pos.y > _region_end) + return; + + _char_cell_array.cursor(_cursor_pos, false); + + for (int i = 0; i < value; i++) + _char_cell_array.scroll_down(_cursor_pos.y, _region_end); + + _char_cell_array.cursor(_cursor_pos, true); + } + + void oc() { PDBG("not implemented"); } + + void op() + { + _color_index = DEFAULT_COLOR_INDEX | (DEFAULT_COLOR_INDEX_BG << 3); + } + + void rc() { PDBG("not implemented"); } + void ri() { PDBG("not implemented"); } + void ris() { PDBG("not implemented"); } + void rmam() { PDBG("not implemented"); } + void rmir() { PDBG("not implemented"); } + + void setab(int value) + { + //_inverse = (value != 0); + _color_index &= ~0x38; /* clear 111000 */ + _color_index |= (((value == 9) ? DEFAULT_COLOR_INDEX_BG : value) << 3); + } + + void setaf(int value) + { + _color_index &= ~0x7; /* clear 000111 */ + _color_index |= (value == 9) ? DEFAULT_COLOR_INDEX : value; + } + + void sgr(int value) + { + _highlight = (value & 0x1) != 0; + _inverse = (value & 0x2) != 0; + + /* sgr 0 is the command to reset all attributes, including color */ + if (value == 0) + _color_index = DEFAULT_COLOR_INDEX | (DEFAULT_COLOR_INDEX_BG << 3); + } + + void sgr0() + { + sgr(0); + } + + void sc() { PDBG("not implemented"); } + void smam() { PDBG("not implemented"); } + void smir() { PDBG("not implemented"); } + void tbc() { PDBG("not implemented"); } + void u6(int, int) { PDBG("not implemented"); } + void u7() { PDBG("not implemented"); } + void u8() { PDBG("not implemented"); } + void u9() { PDBG("not implemented"); } + + void vpa(int y) + { + Cursor_guard guard(*this); + + _cursor_pos.y = y; + _cursor_pos.y = Genode::min(_boundary.height - 1, _cursor_pos.y); + } +}; + +#endif /* _TERMINAL__CHAR_CELL_ARRAY_CHARACTER_SCREEN_H_ */ diff --git a/gems/include/terminal/font_face.h b/gems/include/terminal/font_face.h new file mode 100644 index 0000000000..b20d3bd34f --- /dev/null +++ b/gems/include/terminal/font_face.h @@ -0,0 +1,36 @@ +/* + * \brief Interface for font styles + * \author Norman Feske + * \date 2013-01-20 + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _TERMINAL__FONT_FACE_H_ +#define _TERMINAL__FONT_FACE_H_ + +class Font_face +{ + public: + + enum Type { REGULAR, ITALIC, BOLD, BOLD_ITALIC }; + + private: + + Type _type; + + public: + + Font_face(Type type) : _type(type) { } + + static unsigned char attr_mask() { return 3; } + + unsigned char attr_bits() const { return _type & attr_mask(); } +}; + +#endif /* _TERMINAL__FONT_FACE_H_ */ diff --git a/gems/src/server/terminal/main.cc b/gems/src/server/terminal/main.cc index d17a0c3138..6b1a572fa5 100644 --- a/gems/src/server/terminal/main.cc +++ b/gems/src/server/terminal/main.cc @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include /* nitpicker graphic back end */ @@ -68,6 +68,28 @@ inline Pixel_rgb565 mix(Pixel_rgb565 p1, Pixel_rgb565 p2, int alpha) static Color color_palette[2*8]; +static Color foreground_color(Char_cell const &cell) +{ + Color col = color_palette[cell.colidx_fg() + (cell.highlight() ? 8 : 0)]; + + if (cell.inverse()) + col = Color(col.r/2, col.g/2, col.b/2); + + return col; +} + + +static Color background_color(Char_cell const &cell) +{ + Color col = color_palette[cell.colidx_bg() + (cell.highlight() ? 8 : 0)]; + + if (cell.inverse()) + return Color((col.r + 255)/2, (col.g + 255)/2, (col.b + 255)/2); + + return col; +} + + class Font_family { private: @@ -76,8 +98,6 @@ class Font_family public: - enum Face { REGULAR, ITALIC, BOLD, BOLD_ITALIC }; - Font_family(Font const ®ular /* ...to be extended */ ) : _regular(regular) { } @@ -86,399 +106,13 @@ class Font_family * * For now, we do not support font faces other than regular. */ - Font const *font(Face) const { return &_regular; } + Font const *font(Font_face) const { return &_regular; } unsigned cell_width() const { return _regular.str_w("m"); } unsigned cell_height() const { return _regular.str_h("m"); } }; -struct Char_cell -{ - unsigned char attr; - unsigned char ascii; - unsigned char color; - - enum { ATTR_COLIDX_MASK = 0x07, - ATTR_CURSOR = 0x10, - ATTR_INVERSE = 0x20, - ATTR_HIGHLIGHT = 0x40 }; - - enum { COLOR_MASK = 0x3f }; /* 111111 */ - - Char_cell() : attr(0), ascii(0), color(0) { } - - Char_cell(unsigned char c, Font_family::Face f, - int colidx, bool inv, bool highlight) - : - attr(f | (inv ? ATTR_INVERSE : 0) - | (highlight ? ATTR_HIGHLIGHT : 0)), - ascii(c), - color(colidx & COLOR_MASK) - { } - - Font_family::Face font_face() const { return (Font_family::Face)(attr & 0x3); } - - int colidx_fg() const { return color & ATTR_COLIDX_MASK; } - int colidx_bg() const { return (color >> 3) & ATTR_COLIDX_MASK; } - bool inverse() const { return attr & ATTR_INVERSE; } - bool highlight() const { return attr & ATTR_HIGHLIGHT; } - - Color fg_color() const - { - Color col = color_palette[colidx_fg() + (highlight() ? 8 : 0)]; - - if (inverse()) - col = Color(col.r/2, col.g/2, col.b/2); - - return col; - } - - Color bg_color() const - { - Color col = color_palette[colidx_bg() + (highlight() ? 8 : 0)]; - - if (inverse()) - return Color((col.r + 255)/2, (col.g + 255)/2, (col.b + 255)/2); - - return col; - } - - void set_cursor() { attr |= ATTR_CURSOR; } - void clear_cursor() { attr &= ~ATTR_CURSOR; } - - bool has_cursor() const { return attr & ATTR_CURSOR; } -}; - - -class Char_cell_array_character_screen : public Terminal::Character_screen -{ - private: - - enum Cursor_visibility { CURSOR_INVISIBLE, - CURSOR_VISIBLE, - CURSOR_VERY_VISIBLE }; - - Cell_array &_char_cell_array; - Terminal::Boundary _boundary; - Terminal::Position _cursor_pos; - /** - * Color index contains the fg color in the first 3 bits - * and the bg color in the second 3 bits (0bbbbfff). - */ - int _color_index; - bool _inverse; - bool _highlight; - Cursor_visibility _cursor_visibility; - int _region_start; - int _region_end; - int _tab_size; - - enum { DEFAULT_COLOR_INDEX_BG = 0, DEFAULT_COLOR_INDEX = 7, DEFAULT_TAB_SIZE = 8 }; - - struct Cursor_guard - { - Char_cell_array_character_screen &cs; - - Terminal::Position old_cursor_pos; - - Cursor_guard(Char_cell_array_character_screen &cs) - : - cs(cs), old_cursor_pos(cs._cursor_pos) - { - /* temporarily remove cursor */ - cs._char_cell_array.cursor(old_cursor_pos, false); - } - - ~Cursor_guard() - { - /* restore original cursor */ - cs._char_cell_array.cursor(old_cursor_pos, true); - - /* if cursor position changed, move cursor */ - Terminal::Position &new_cursor_pos = cs._cursor_pos; - if (old_cursor_pos != new_cursor_pos) { - - cs._char_cell_array.cursor(old_cursor_pos, false, true); - cs._char_cell_array.cursor(new_cursor_pos, true, true); - } - } - }; - - public: - - Char_cell_array_character_screen(Cell_array &char_cell_array) - : - _char_cell_array(char_cell_array), - _boundary(_char_cell_array.num_cols(), _char_cell_array.num_lines()), - _color_index(DEFAULT_COLOR_INDEX), - _inverse(false), - _highlight(false), - _cursor_visibility(CURSOR_VISIBLE), - _region_start(0), - _region_end(_boundary.height - 1), - _tab_size(DEFAULT_TAB_SIZE) - { } - - - void _line_feed() - { - Cursor_guard guard(*this); - - _cursor_pos.y++; - - if (_cursor_pos.y > _region_end) { - _char_cell_array.scroll_up(_region_start, _region_end); - _cursor_pos.y = _region_end; - } - } - - void _carriage_return() - { - Cursor_guard guard(*this); - - _cursor_pos.x = 0; - } - - - /******************************** - ** Character_screen interface ** - ********************************/ - - Terminal::Position cursor_pos() const { return _cursor_pos; } - - void output(Terminal::Character c) - { - if (c.ascii() > 0x10) { - Cursor_guard guard(*this); - _char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y, - Char_cell(c.ascii(), Font_family::REGULAR, - _color_index, _inverse, _highlight)); - _cursor_pos.x++; - } - - switch (c.ascii()) { - - case '\r': /* 13 */ - _carriage_return(); - break; - - case '\n': /* 10 */ - _line_feed(); - _carriage_return(); - break; - - case 8: /* backspace */ - { - Cursor_guard guard(*this); - - if (_cursor_pos.x > 0) - _cursor_pos.x--; - - break; - } - - case 9: /* tab */ - { - Cursor_guard guard(*this); - _cursor_pos.x += _tab_size - (_cursor_pos.x % _tab_size); - break; - } - - default: - break; - } - - if (_cursor_pos.x >= _boundary.width) { - _carriage_return(); - _line_feed(); - } - } - - void civis() - { - _cursor_visibility = CURSOR_INVISIBLE; - } - - void cnorm() - { - _cursor_visibility = CURSOR_VISIBLE; - } - - void cvvis() - { - _cursor_visibility = CURSOR_VERY_VISIBLE; - } - - void cpr() - { - PDBG("not implemented"); - } - - void csr(int start, int end) - { - /* the arguments are specified use coordinate origin (1, 1) */ - start--; - end--; - - _region_start = Genode::max(start, 0); - _region_end = Genode::min(end, _boundary.height - 1); - - /* preserve invariant of region size >= 0 */ - _region_end = Genode::max(_region_end, _region_start); - } - - void cuf(int dx) - { - Cursor_guard guard(*this); - - _cursor_pos.x += dx; - _cursor_pos.x = Genode::min(_boundary.width - 1, _cursor_pos.x); - } - - void cup(int y, int x) - { - Cursor_guard guard(*this); - - /* top-left cursor position is reported as (1, 1) */ - x--; - y--; - - using namespace Genode; - x = max(0, min(x, _boundary.width - 1)); - y = max(0, min(y, _boundary.height - 1)); - - _cursor_pos = Terminal::Position(x, y); - } - - void cuu1() { PWRN("not implemented"); } - void dch(int) { PDBG("not implemented"); } - - void dl(int num_lines) - { - /* delete number of lines */ - for (int i = 0; i < num_lines; i++) - _char_cell_array.scroll_up(_cursor_pos.y, _region_end); - } - - void ech(int v) - { - Cursor_guard guard(*this); - - for (int i = 0; i < v; i++, _cursor_pos.x++) - _char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y, - Char_cell(' ', Font_family::REGULAR, - _color_index, _inverse, _highlight)); - } - - void ed() - { - /* clear to end of screen */ - _char_cell_array.clear(_cursor_pos.y, _boundary.height - 1); - } - - void el() - { - /* clear to end of line */ - for (int x = _cursor_pos.x; x < _boundary.width; x++) - _char_cell_array.set_cell(x, _cursor_pos.y, Char_cell()); - } - - void el1() { PDBG("not implemented"); } - - void home() - { - Cursor_guard guard(*this); - - _cursor_pos = Terminal::Position(0, 0); - } - - void hpa(int x) - { - Cursor_guard guard(*this); - - _cursor_pos.x = x; - _cursor_pos.x = Genode::min(_boundary.width - 1, _cursor_pos.x); - } - - void hts() { PDBG("not implemented"); } - void ich(int) { PDBG("not implemented"); } - - void il(int value) - { - Cursor_guard guard(*this); - - if (_cursor_pos.y > _region_end) - return; - - _char_cell_array.cursor(_cursor_pos, false); - - for (int i = 0; i < value; i++) - _char_cell_array.scroll_down(_cursor_pos.y, _region_end); - - _char_cell_array.cursor(_cursor_pos, true); - } - - void oc() { PDBG("not implemented"); } - - void op() - { - _color_index = DEFAULT_COLOR_INDEX | (DEFAULT_COLOR_INDEX_BG << 3); - } - - void rc() { PDBG("not implemented"); } - void ri() { PDBG("not implemented"); } - void ris() { PDBG("not implemented"); } - void rmam() { PDBG("not implemented"); } - void rmir() { PDBG("not implemented"); } - - void setab(int value) - { - //_inverse = (value != 0); - _color_index &= ~0x38; /* clear 111000 */ - _color_index |= (((value == 9) ? DEFAULT_COLOR_INDEX_BG : value) << 3); - } - - void setaf(int value) - { - _color_index &= ~0x7; /* clear 000111 */ - _color_index |= (value == 9) ? DEFAULT_COLOR_INDEX : value; - } - - void sgr(int value) - { - _highlight = (value & 0x1) != 0; - _inverse = (value & 0x2) != 0; - - /* sgr 0 is the command to reset all attributes, including color */ - if (value == 0) - _color_index = DEFAULT_COLOR_INDEX | (DEFAULT_COLOR_INDEX_BG << 3); - } - - void sgr0() - { - sgr(0); - } - - void sc() { PDBG("not implemented"); } - void smam() { PDBG("not implemented"); } - void smir() { PDBG("not implemented"); } - void tbc() { PDBG("not implemented"); } - void u6(int, int) { PDBG("not implemented"); } - void u7() { PDBG("not implemented"); } - void u8() { PDBG("not implemented"); } - void u9() { PDBG("not implemented"); } - - void vpa(int y) - { - Cursor_guard guard(*this); - - _cursor_pos.y = y; - _cursor_pos.y = Genode::min(_boundary.height - 1, _cursor_pos.y); - } -}; - - template inline void draw_glyph(Color fg_color, Color bg_color, @@ -536,7 +170,7 @@ static void convert_char_array_to_pixels(Cell_array *cell_array, unsigned fb_height, Font_family const &font_family) { - Font const ®ular_font = *font_family.font(Font_family::REGULAR); + Font const ®ular_font = *font_family.font(Font_face::REGULAR); unsigned glyph_height = regular_font.img_h, glyph_step_x = regular_font.wtab['m']; @@ -564,8 +198,8 @@ static void convert_char_array_to_pixels(Cell_array *cell_array, if (x + glyph_width >= fb_width) break; - Color fg_color = cell.fg_color(); - Color bg_color = cell.bg_color(); + Color fg_color = foreground_color(cell); + Color bg_color = background_color(cell); if (cell.has_cursor()) { fg_color = Color( 63, 63, 63); @@ -887,10 +521,10 @@ int main(int, char **) /* initialize color palette */ color_palette[0] = Color( 0, 0, 0); /* black */ - color_palette[1] = Color(255, 0, 0); /* red */ - color_palette[2] = Color( 0, 255, 0); /* green */ + color_palette[1] = Color(255, 128, 128); /* red */ + color_palette[2] = Color(128, 255, 128); /* green */ color_palette[3] = Color(255, 255, 0); /* yellow */ - color_palette[4] = Color( 0, 0, 255); /* blue */ + color_palette[4] = Color(128, 128, 255); /* blue */ color_palette[5] = Color(255, 0, 255); /* magenta */ color_palette[6] = Color( 0, 255, 255); /* cyan */ color_palette[7] = Color(255, 255, 255); /* white */