1. Общее описание.
Проект движка универсального меню для малоразмерных текстовых дисплеев (индикаторов).
Малоразмерные текстовые дисплеи (например 20×4 или 40×8 – 8 строк по 40 символов в строке) до сих пор активно применяются во встаиваемых системах. Особенностью данного дисплея, ввиду его малого размера, является невозможность организации классических тестовых окон как было в DOS. В тоже время достаточно актуальна задача организации всевозможных меню на этом дисплее. Известные мне реализации малофункциональны, громоздки, в них нет четкого разделения описания меню и кода (движка меню). Поэтому возникла идея создания универсального движка. Принцип движка основан на листах. Каждое меню – текстовый лист произвольных размеров. Для упрощения ширину листа можно принять равной ширине дисплея. В произвольных местах листа могут быть вставлены пункты меню – переменные, которые можно просмотреть и/или изменить. Переменные могут быть двоичные, числовые, тестовые, выбор из списка или выбор подменю – другого листа. Лист – обычный тестовый массив, с включенной в него разметкой. Разметка простая, по типу printf. Разметка полностью определяет тип переменной, можно ли её изменять, пределы изменения, а также разбивает массив на строки символами конца строки. В конце листа, также в тестовом виде, размещаются индексы адресов переменных, строки выбора в порядке их указания в разметке (также как в prinf). Таким образом лист состоит из нескольких элементов – строк меню, которые будут выводится, ссылок на переменные и элементы выбора из списка. Элементы листа разделяются специальным разделителем, который не может использоваться для вывода на экран. Таким разделителем может быть, например символ точка с запятой “;”. Индексы используются потому, что вписать адрес в лист сразу не представляется возможным, т.к. адреса переменных становятся известны как минимум на этапе компиляции, а не написания программы. Кроме того, писать адреса напрямую очень неудобно и чревато ошибками. Поэтому все адреса сводятся в массив указателей, а в листе в тестовом виде указан индекс указателя в этом массиве. По моему досточно удобно.
Клавиатура состоит из 6-ти клавиш. 4 клавиши навигации вверх/вниз, влево/вправо и 2 клавиши действия – “ввод/выбор” и “отмена”. Навигация выполняется либо по пунктам меню, либо при их отсутсвии производится прокрутка листа на экране (если число строк в листе больше числа строк на экране). При выборе переменной её можно редактировать клавишами вверх/вниз поразрядно или выбором из списка. Нажатие “ввод” применяет изменения, “отмена” возвращает назад. Опционально возможен вызов функции для применения изменений. Индикация выбранного пункта меню осуществляется в соотвествии с возможностями устройства отображения. Это или инверсия или мигание, или просто курсор.
Требования к дисплею можно обобщить. Он должен поддерживать команды:
- очистка clrstr();
- установка позиции для ввода setpos(столбец, строка);
- установка позиции курсора setcur(столбец, строка);
- ввод в режиме поверх имеющегося текста putc(символ);
Аппаратную прокрутку (скроллинг) большинство многострочных индикаторов поддерживают весьма своеобразно, поэтому можно считать что её нет и можно выполнить только программно. Выделение части теста инверсией в большинстве ндикаторов возможно только программно и связано с перезагрузкой знакогенератора, поэтому оставим только курсор.
2. Работа движка.
Работа движка состоит из следующих этапов:
- Интерпретация листа – функция ParseList.
На входе: адрес листа, адрес массива описаний, адрес массива опций выбора. На выходе: заполненный массив описаний, заполненный массив опций выбора.
Интерпретатор получает в качестве входных значений адрес предыдущего листа (или NULL – если главное меню и предыдущего листа нет) и адрес листа для разбора. В процессе разбора интерпретатор выполняет следующие действия:- Заполняет массив структур описаний переменных:
адрес;
код типа;
можно ли редактировать;
начальный индекс в массиве опций выбора;
нижний предел;
верхний предел;
позиция вывода на экран (строка и столбец);
длина (сколько символов занимает);
адрес функции для изменения переменной (или NULL);
Массив статический, рассчитан не некоторое максимально возможное количество переменных в одном меню. - Заполняет массив опций выбора. Массив также статический, рассчитан на некоторое суммарное максимально возможное количество опций выбора в одном меню и длину каждой опции.
- Заполняет массив структур описаний переменных:
- Сбор листа в многострочном буфере – функция RenderList.
На входе: адрес буфера, адрес массива описаний, адрес массива опций выбора. На выходе: заполненный буфер.
Буфер статический, представляет собой массив максимально возможного количества строк максимально возможной длины. Собирает меню. Выводит строку с разметкой, делая пропуски в местах переменных. Проходит по массиву структур и для каждого типа переменной вызывает свою функцию для её перевода в тестовый вид. - Вывод меню из буфера на дисплей – функция ShowList.
На входе: адрес буфера, номер начальной строки. На выходе: заполненный дисплей. Пользуется функцией putc(). -
Основной цикл.
Выполняется либо периодическим вызовом, либо вызовом по нажатию клавиш. При вызове по нажатию клавиш, теряется возможность обновления информации на дисплее, если значение переменной меняется.