воскресенье, 7 января 2018 г.

Панели оператора СП307 / СП310. Кнопка возращения на предыдущий экран (с использованием макросов).

Если иерархия экранов проекта панели имеет большую глубину, то для упрощения навигации между ними хочется иметь возможность возвращаться на предыдущие экраны.
Для этого можно использовать стандартную функциональную кнопку с выбранной функцией перехода на предыдущий экран при нажатии:

Создание стандартной кнопки 'Назад'

Однако эта кнопка оказывается способна обеспечить переключение только между двумя экранами - текущим и предыдущим.
При переходе на предыдущий экран, текущий экран становится предыдущим и при повторном нажатии кнопки мы возвращаемся туда откуда только что пришли.
Это немного не то, чего обычно ожидаешь от кнопки 'Назад'. Ожидаемое поведение - это воспроизведение последовательности переходов между экранами в обратном порядке. Такую функциональность мы и реализуем с помощью макросов C.

Для того, чтобы хранить историю переходов нам понадобится буфер. Создадим его в Глобальном макросе добавив объявление глобального массива с именем _back_stack:

WORD _back_stack[20];






Количество сохранённых экранов будет определяться количеством элементов массива - будет на единицу меньше его.
Этим буфером мы будем пользоваться как стеком. При переходе на новый экран будем дописывать в него идентификатор этого экрана. А при возврате на предыдущий экран удалять последний дописанный идентификатор.

Нам понадобятся два макроса. Первый, назовём его PushScreenId, будет вызываться при переходе на новый экран и сохранять его идентификатор:

const WORD SCREEN_SAVER = 8; 
WORD current_screen = PSW[1];

if (current_screen == _back_stack[0] || current_screen == SCREEN_SAVER) return;

memmove(_back_stack + 1, _back_stack, sizeof(_back_stack) - sizeof(_back_stack[0]));
_back_stack[0] = current_screen;

В этом макросе мы учли наличие скринсейвера. Если идентификатор нового экрана (переменная current_screen) совпадает с идентификатором экрана скринсейвера (константа SCREEN_SAVER), то мы этот идентификатор в историю переходов не заносим (прерываем выполнение функции).
Этот макрос также будет выполняться при возврате на предыдущий экран. В этом случае на вершине стека окажется идентификатор экрана, на который мы перешли, поэтому его в стек заносить не нужно и мы также прерываем выполнение функции.
Двумя последними строчками мы сдвигаем содержимое стека на одну позицию и кладём на вершину стека идентификатор текущего экрана.
Для вызова этого макроса мы используем функциональную область с выбранной функцией 'Вызов макроса' и условием запуска 'Переход на экран элемента':


Создание функциональной области для вызова PushScreenId

Эту функциональную область нужно сделать глобальной, так как она должна присутствовать на всех экранах.

Второй макрос, который мы назовём JumpBack, будет вызываться при нажатии кнопки 'Назад':

if (_back_stack[1] == 0) return;

memmove(_back_stack, _back_stack + 1, sizeof(_back_stack) - sizeof(_back_stack[0]));
ScreenJump(_back_stack[0]);

В этом макросе мы учли случай, когда в стеке находится только один элемент - значит возвращаться некуда и мы прерываем выполнение функции.
Этот макрос мы привяжем к функции 'Вызов макроса' функциональной кнопки, которую также нужно сделать глобальной.

Создание функциональной кнопки для вызова JumpBack

Добавив для тестирования несколько экранов и кнопок перехода мы получаем демонстрационный проект, который можно скачать по ссылке:

Скриншот демонстрационного проекта














Комментариев нет:

Отправить комментарий