Основы программирования в Linux - Нейл Мэтью
Шрифт:
Интервал:
Закладка:
Применение цвета
В прошлом очень немногие терминалы ввода/вывода поддерживали цвета, поэтому у большей части самых старых версий библиотеки curses не было поддержки цветов. Цвета появились в библиотеке ncurses и других современных реализациях curses. К сожалению, на "неинтеллектуальный экран", первооснову библиотеки curses, повлиял API, и curses используют цвета очень ограниченным способом, отражающим слабые характеристики старых цветных терминалов.
Каждая символьная ячейка на экране может быть записана одним цветом из набора разных цветов на фоне одного цвета из набора различных цветов фона. Например, можно вывести зеленый текст на красном фоне.
Цветовая поддержка в библиотеке curses немного необычна, в том смысле, что цвет символа не определяется независимо от цвета фона. Вы должны задать цвет переднего плана и фона как пару, именуемую, что неудивительно, цветовой парой.
Прежде чем применять цвета в curses, нужно убедиться в том, что текущий терминал поддерживает цвета, и инициализировать подпрограммы управления цветом библиотеки curses. Для этого примените две функции: has_colors и start_color.
#include <curses.h>
bool has_colors(void);
int start_color(void);
Функция has_colors возвращает true, если терминал поддерживает цвета. Далее следует вызвать функцию start_color, которая вернет OK, если цветовая поддержка успешно инициализирована. После вызова start_color и инициализации цветов переменная COLOR_PAIRS принимает значение, равное максимальному количеству цветовых пар, которые может поддерживать терминал. Переменная COLORS определяет максимальное число доступных цветов, которых, как правило, восемь. Внутри компьютера числа от 0 до 63 действуют как уникальные ID для каждого из доступных цветов.
Прежде чем применять цвета как атрибуты, вы должны инициализировать цветовые пары, которые хотите использовать. Делается это с помощью функции init_pair. Обратиться к атрибутам, задающим цвет, можно с помощью функции COLOR_PAIR.
#include <curses.h>
int init_pair(short pair_number, short foreground, short background);
int COLOR_PAIR(int pair_number);
int pair_content(short pair_number, short *foreground, short *background);
В файле curses.h обычно определены некоторые базовые цвета, начинающиеся с префикса COLOR_. Дополнительная функция pair_content позволяет извлечь сведения о ранее определенной цветовой паре.
Для определения цветовой пары номер 1, как красный на зеленом, примените следующую строку:
init_pair(1, COLOR_RED, COLOR_GREEN);
Затем вы сможете получить доступ к этой цветовой паре, применив функцию COLOR_PAIR следующим образом:
wattron(window_ptr, COLOR_PAIR(1));
Она установит вывод в будущем на экран красных символов на зеленом фоне.
Поскольку COLOR_PAIR — это атрибут, вы можете комбинировать его с другими атрибутами. На ПК часто можно добиться на экране цветов повышенной яркости, объединив с помощью поразрядной операции OR атрибут COLOR_PAIR с дополнительным атрибутом A_BOLD:
wattron(window_ptr, COLOR_PAIR(1) | A_BOLD);
Давайте проверим эти функции в примере color.c (упражнение 6.7).
Упражнение 6.7. Цвета1. Сначала проверьте, поддерживает ли цвета терминал, используемый программой. Если да, то инициализируйте отображение цветов:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <curses.h>
int main() {
int i;
initscr();
if (!has_colors()) {
endwin();
fprintf(stderr, "Error — no color support on this terminaln");
exit(1);
}
if (start_color() != OK) {
endwin();
fprintf(stderr, "Error — could not initialize colorsn");
exit(2);
}
2. Теперь можно вывести допустимое количество цветов и цветовые пары. Создайте семь цветовых пар и выведите их по очереди на экран:
clear();
mvprintw(5, 5, "There are %d COLORS, and %d COLOR_PAIRS available", COLORS, COLOR_PAIRS);
refresh();
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_RED, COLOR_GREEN);
init_pair(3, COLOR_GREEN, COLOR_RED);
init_pair(4, COLOR_YELLOW, COLOR_BLUE);
init_pair(5, COLOR_BLACK, COLOR_WHITE);
init_pair(6, COLOR_MAGENTA, COLOR_BLUE);
init_pair(7, COLOR_CYAN, COLOR_WHITE);
for (i = 1; i <= 7; i++) {
attroff(A_BOLD);
attrset(COLOR_PAIR(i));
mvprintw(5 + i, 5, "Color pair %d", i);
attrset(COLOR_PAIR(i) | A_BOLD);
mwprintw(5 + i, 25, "Bold color pair %d", i);
refresh();
sleep(1);
}
endwin();
exit(EXIT_SUCCESS);
}
Выполнение примера приведет к выводу, показанному на рис. 6.7, за вычетом реальных цветов, которые не отображаются на черно-белом снимке экрана.
Рис. 6.7
Как это работает
После проверки того, что экран поддерживает управление цветами, программа инициализирует цветовую обработку и определяет ряд цветовых пар. Далее на экран выводится текст с использованием цветовых пар для того, чтобы продемонстрировать комбинации разных цветов на экране.
Переопределение цветов
Как пережиток, оставшийся от старых неинтеллектуальных терминалов, которые могли отображать очень немного цветов в каждый момент времени, но позволяли настраивать текущую цветовую палитру, в библиотеке curses сохранилась возможность переопределения цветов с помощью функции init_color:
#include <curses.h>
int init_color(short color_number, short red, short green, short blue);
Она позволяет переопределить существующий цвет (в диапазоне от 0 до COLORS) новыми значениями яркости цвета из диапазона от 0 до 1000. Такой подход немного напоминает определение цветовых характеристик в графических файлах формата GIF.
Панели
При написании более сложных программ с использованием curses порой бывает легче построить логический экран и затем позже вывести весь или часть экрана на физический экран. В некоторых случаях лучше иметь логический экран большего размера, чем физический экран и отображать только часть логического экрана в любой конкретный момент времени.
Это нелегко сделать с помощью функций библиотеки curses, с которыми вы познакомились к этому моменту, т.к. все окна должны быть не больше физического экрана. Библиотека curses предоставляет специальную структуру данных, панель (pad), для манипулирования данными логического экрана, которые не умещаются в стандартном окне.
Структура панели похожа на структуру WINDOW, и все функции библиотеки curses, написанные для работы с окнами, можно применять и к панелям. Но у панелей есть и собственные функции для создания и обновления.
Панели создаются во многом так же, как и обычные окна.
#include <curses.h>
WINDOW *newpad(int number_of_lines, int number_of_columns);
Обратите внимание на то, что возвращаемое значение — указатель на структуру типа WINDOW, такое же, как у функции newwin. Удаляются панели, как и окна, функцией delwin.
Но к панелям применяются другие подпрограммы обновления. Поскольку панель не привязана к конкретной точке экрана, вы должны задать область панели, которую хотите поместить на экран, и ее положение на экране. Делайте это с помощью функции prefresh.
#include <сurses.h>
int prefresh(WINDOW *pad_ptr, int pad_row, int pad_column, int screen_row_min, int screen_col_min, int screen_row_max, int screen_соl_max);
Функция выполняет запись области панели, начинающейся в точке (pad_row, pad_column), в область экрана, определенную от (screen_row_min, screen_col_min) до (screen_row_max, screen_col_max).
Есть и дополнительная подпрограмма pnoutrefresh. Она действует так же, как функция wnoutrefresh, обеспечивая более производительное обновление экрана.
Давайте проверим это на практике с помощью программы pad.с (упражнение 6.8).
Упражнение 6.8. Применение панели1. В начале этой программы вы инициализируете структуру панели и затем формируете панель с помощью функции, которая возвращает указатель на нее. Вставьте символы, заполняющие структуру панели (панель на 50 символов шире и выше экрана терминала):
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
int main() {
WINDOW *pad_ptr;
int x, y;
int pad_lines;
int pad_cols;
char disp_char;
initscr();
pad_lines = LINES + 50;
pad_cols = COLS + 50;
pad_ptr = newpad(pad_lines, padcols);
disp_char = 'a';
for (x = 0; x < pad_lines; x++) {
for (у = 0; у < pad_cols; y++) {
mvwaddch(pad_ptr, x, y, disp_char);