Основной таблицей меню является массив MENU-структур.
Структура MENU определена в twindow.h (см. Главу 6). Этот массив
является входным для каждого процесса выборки из скользящей меню-
строки. Каждый ввод выбранного элемента меню содержит
отображаемое пользователю имя элемента меню и ряд указателей,
описывающих содержание "всплывающего" вертикального меню,
соответствующего указанному пользователю элементу горизонтального
меню. Эти указатели включают в себя указатель на массив имен
элементов "всплывающего" меню и указатель на массив указателей
функций на языке Си. Имена отображаются во "всплывающем" меню, а
функции входят в состав системы, использующей это меню, и
выполняются, когда пользователь отмечает в качестве выбранных
соответствующие имена элементов меню.
Иерархическая система меню состоит из двух уровней. Первый
уровень включает в себя выборку из горизонтального меню и
ограничен лишь шестью элементами вследствие того, что элементы
этого уровня располагаются на одной строке. Любая выборка
элемента на этом уровне приводит к появлению соответствующего
"всплывающего" меню на втором уровне. Размер "всплывающего" меню
ограничен 21 элементами, что соответствует максимальному числу
строк, которое может быть включено в "всплывающее" меню. Каждая
выборка на этом уровне приводит к вызову определенной Си-функции
из закрепленных за элементами меню.
Если вы хотите получить дополнительные уровни в вашем
иерархическом меню, то должны описать дополнительные управляющие
таблицы меню, присвоить им значения и определить рекурсивные
вызовы функций поддержки системы меню. Вследствие того, что
функции поддержки меню реентерабельны, выборка на втором уровне
"всплывающего" меню может привести к появлению нового
горизонтального меню.
Описание иерархии системы меню фактически осуществляет ваша
прикладная программа (или программная система), которая
непосредственно генерирует массивы меню. Пример, представленный
на листинге 10.3 (листинг см. ниже в этой главе), поясняет
процесс формирования массивов. Обсуждение этого примера включает
обсуждение полученного изображения как результата предварительной
генерации массивов меню, а также детальное описание самого
процесса их генерации.
Функции поддержки меню
-----------------------------------------------------------------
Для использования оконных меню в этой главе вы должны
вначале сгенерировать массив MENU, затем массив, на который
ссылается массив MENU, а также написать и оттранслировать
прикладные функции, которые будут выполняться, когда пользователь
выберет конкретный элемент "всплывающего" меню. Затем вы так или
иначе обращаетесь к функции menu_select, которая описана ниже.
void menu_select(char *name, Menu *mn)
Эта функция активизирует меню-процесс, отображая на экране
дисплея горизонтальное скользящее меню-строку и переходя в
состояние ожидания использования пользователем клавиатуры для
выборки из меню. Указатель name является именем заголовка
скользящей меню-строки. Указатель mn содержит адрес массива
структур MENU в вызывающей программе. Этот массив и указатель на
массив MENU определяют иерархию меню для меню-процесса.
После того, как функция menu_select отобразила
горизонтальное меню, пользователь, используя клавиши управления
курсором вправо и влево, может перемещаться по меню. Если
пользователь нажал клавишу <КЛЮЧ> (), то меню-процесс
прерывается, и управление передается в точку вызова функции menu_
select. Если же пользователь нажал клавишу <ВВОД> (), то
осуществляется привязка конкретного "всплывающего" вертикального
меню к текущему элементу горизонтального меню (определяется
текущим положением маркера меню или курсора) и отображение
нужного вертикального меню.
Во время отображения вертикального "всплывающего" меню
пользователь может использовать клавиши передвижения курсора
вправо и влево для выбора других элементов горизонтального
меню-строки. В этом режиме в соответствии с движением курсора в
меню-строке осуществляется последовательное отображение
вертикальных меню, причем перед отображением очередного
вертикального меню предыдущее вертикальное меню уничтожается.
Если пользователь нажмет клавишу <КЛЮЧ> (), то текущее
"всплывающее" меню уничтожается, и процесс возвращается к
обработке скользящего меню-строки аналогично описанному выше.
Пользователь может использовать клавиши перемещения курсора вверх
и вниз для навигации по вертикальному меню и выбора нужного
элемента меню. После того, как нужный элемент выбран, нужно
нажать клавишу <ВВОД> (). Нажатие этой клавиши приведет к
исчезновению как вертикального, так и горизонтального меню и
вызову функции, соответствующей указателю, хранимому в массиве
указателей функций "всплывающего"меню и, в свою очередь,
соответствующего выбранному элементу меню. Выполнение функций
осуществляется путем обычного обращения к ним.
После того как управление от вызванной функции передается в
точку ее вызова, вся система меню восстанавливается на экране
дисплея в том состоянии, которое предшествовало вызову функции,
реализующей идентифицированное пользователем действие, и
меню-процесс продолжается в соответствии с его описанием.
Исходный листинг: tmenu.c
-----------------------------------------------------------------
Листинг 10.1 содержит текст библиотечной функции tmenu.c,
предназначенной для поддержки предварительного описания
меню-процесса.
Листинг 10.1: tmenu.c
/* ------------ tmenu.c ------------ */
#include
#include
#include
#include "keys.h"
#include "twindow.h"
extern int VSG;
WINDOW *open_menu(char *mnm, MENU *mn, int hsel);
int gethmenu(MENU *mn, WINDOW *hmenu, int hsel);
int getvmn(MENU *mn, WINDOW *hmenu, int *hsel, int vsel);
int haccent(MENU *mn, WINDOW *hmenu, int hsel, int vsel);
void dimension(char *sl[], int *ht, int *wd);
void light(MENU *mn, WINDOW *hmenu, int hsel, int d);
/* ------------ Отображение и обработка меню--------- */
void menu_select(char *name, MENU *mn)
{
WINDOW *open_menu();
WINDOW *hmenu;
int sx, sy;
int hsel = 1, vsel;
curr_cursor(&sx, &sy);
cursor(0, 26);
hmenu = open_menu(name, mn, hsel);
while (hsel = gethmenu(mn, hmenu, hsel)) {
vsel = 1;
while (vsel = getvmn(mn, hmenu, &hsel, vsel)) {
delete_window(hmenu);
set_help("", 0, 0);
(*(mn+hsel-1)->func [vsel-1])(hsel, vsel);
hmenu = open_menu(name, mn, hsel);
}
}
delete_window(hmenu);
cursor(sx, sy);
}
/* ----Инициализация горизонтального меню-------*/
static WINDOW *open_menu(char *mnm, MENU *mn, int hsel)
{
int i = 0;
WINDOW *hmenu;
set_help("menu ", 30, 10);
hmenu = establish_window(0, 0, 3, 80);
set_title(hmenu, mnm);
set_colors(hmenu, ALL, BLUE, AQUA, BRIGHT);
set_colors(hmenu, ACCENT, WHITE, BLACK, DIM);
display_window(hmenu);
while ((mn+i)->mname)
wprintf(hmenu, " %-10.10s ", (mn+i++)->mname);
light(mn, hmenu, hsel, 1);
cursor(0, 26);
return hmenu;
}
/* ----Выборка из горизонтальногоь меню------*/
static int gethmenu(MENU *mn, WINDOW *hmenu, int hsel)
{
int sel;
light(mn, hmenu, hsel, 1);
while (TRUE) {
switch (sel = get_char()) {
case FWD:
case BS: hsel = haccent(mn, hmenu, hsel, sel);
break;
case ESC: return 0;
case '\r': return hsel;
default: putchar(BELL);
break;
}
}
}
/* -----Всплывающее вертикальное меню--------*/
static int getvmn(MENU *mn,WINDOW *hmenu,int *hsel,int vsel)
{
WINDOW *vmenu;
int ht = 10, wd = 20;
char **mp;
while (1) {
dimension((mn+*hsel-1)->mselcs, &ht, &wd);
vmenu = establish_window(2+(*hsel-1)*12, 2, ht, wd);
set_colors(vmenu, ALL, BLUE, AQUA, BRIGHT);
set_colors(vmenu, ACCENT, WHITE, BLACK, DIM);
set_border(vmenu, 4);
display_window(vmenu);
mp = (mn+*hsel-1)->mselcs;
while (*mp)
wprintf(vmenu, "\n%s", *mp++);
vsel = get_selection(vmenu, vsel, "");
delete_window(vmenu);
if (vsel == FWD || vsel == BS) {
*hsel = haccent(mn, hmenu, *hsel, vsel);
vsel = 1;
}
else
return vsel;
}
}
/* -----Управление отображением выбранных элементов
горизонтального меню -----*/
static int haccent(MENU *mn,WINDOW *hmenu,int hsel,int sel)
{
switch (sel) {
case FWD:
light(mn, hmenu, hsel ,0);
if ((mn+hsel)->mname)
hsel++;
else
hsel = 1;
light(mn, hmenu, hsel ,1);
break;
case BS:
light(mn, hmenu, hsel ,0);
if (hsel == 1)
while ((mn+hsel)->mname)
hsel++;
else
--hsel;
light(mn, hmenu, hsel ,1);
break;
default:
break;
}
return hsel;
}
/* -----Вычисление высоты и ширины меню-------*/
static void dimension(char *sl[], int *ht, int *wd)
{
unsigned strlen(char *);
*ht = *wd = 0;
while (sl [*ht]) {
*wd = max(*wd, strlen(sl [*ht]));
(*ht)++;
}
*ht += 2;
*wd += 2;
}
/* --------Отображение в соответствии с параметром
accent элемента горизонтального меню ---*/
static void light(MENU *mn, WINDOW *hmenu, int hsel, int d)
{
if (d)
revers_video(hmenu);
wcursor(hmenu, (hsel-1)*12+2, 0);
wprintf(hmenu, (mn+hsel-1)->mname);
normal_video(hmenu);
cursor(0, 26);
}
Описание программы: tmenu.c
-----------------------------------------------------------------
Функция menu_select вызывается для обработки меню,
описанного в массиве структур MENU. Эта функция запоминает
текущее положение системы меню и позицию курсора относительно
координат экрана. Затем вызывается функция open_menu, которая
осуществляет инициализацию и отображение на экране (в его верхней
части) горизонтального меню-строки. Цикл while осуществляет
обработку горизонтального меню-строки до тех пор, пока
пользователь не нажмет клавишу <КЛЮЧ> (). На каждой итерации
цикла вызывается функция getmenu. Если функция getmenu возвращает
значение 0, значит, пользователь нажал клавишу <КЛЮЧ> ().
Если функция getmenu возвращает ненулевое значение, значит,
пользователь произвел выборку одного из элементов горизонтального
меню. Возвращаемое функцией значение специфицирует выбранный
пользователем элемент меню. Следующий цикл while обрабатывает
"всплывающее" вертикальное меню, соответствующее выбранному ранее
элементу горизонтального меню-строки. На каждой операции этого
цикла происходит обращение к функции getvmn, которая осуществляет
обработку "всплывающего" меню. При нажатии пользователем клавиши
<КЛЮЧ> () функция getvmn возвращает значение 0, в противном
случае getvmn возвращает значение, специфицирующее выбранный
пользователем элемент вертикального меню. После этого окно,
выделенное для горизонтального и вертикальных меню, уничтожается,
вызывается функция, реализующая действия, соответствующие
выбранному пользователем элементу вертикального меню. По
завершении работы этой функции open_menu вызывает восстановление
изображения на экране горизонтального меню-строки.
Функция open_menu открывает окно в верхней части экрана на
всю его ширину. Это окно предназначено для горизонтального
меню-строки. Меню выбора функций вашей программы отображается в
этом окне в соответствии с таблицей MENU. Первый из выбранных