(c) К.Феськов, г.Абакан. 1996.
Если вы откроете первое издание ZX FORUM, то увидите там программу
Виккера В.В., которая позволяет организовать удобный стрелочный интерфейс. Это
очень удобная программа, но, на данный момент, просто бегающая стрелка мало
кого удовлетворит. Если мы посмотрим на программы Радионова, на мою последнюю
программу, то увидим, что стрелка, попадая на меню, "зажигает" его. Как же
реализовать эту функцию? Я приведу незначительные доработки вышеуказанной
программы, которые позволят реализовать подобный эффект. Хочу упомянуть моего
друга Старкова Павла, который любезно изложил мне смысл алгоритма.
Изменения исходного текста программы коснутся ТОЛЬКО процедуры START,
остальные подпрограммы не изменяются.
Итак, я приведу сначала подпрограммы, а затем расскажу, что нужно для
успешной работы программы.
START LD HL,(CRDS) ; Берем координаты вывода стрелки.
LD A,255 ; Заносим число 255 в номер опции, что говорит о том,
LD (OPC1),A ; что стрелка на опцию не попала.
PUSH IX ; Далее все так, как в программе.
QO CALL SCRBF
CALL FORM
HALT
IN A,(31)
PUSH AF
CALL BFSCR
POP AF
LD C,A
LD E,STEP
LD D,254
LD HL,CRDS+1
BIT 0,C
CALL NZ,PL
BIT 1,C
CALL NZ,MIN
LD D,190
DEC HL
BIT 2,C
CALL NZ,PL
BIT 3,C
CALL NZ,MIN
BIT 4,C
JR NZ,EXIT
CALL COND ; Вызываем процедуру проверки попадания стрелки.
CALL BAR ; Вызываем процедуру закрашивания/стирания опции.
JR QO
COND LD IX,(TABLE) ; В IX заносим адрес данных.
LD A,1 ; Заносим номер первой опции в вспомогательную
LD (OPC),A ; переменную.
LD HL,(CRDS) ; В HL текущие координаты стрелки.
SRL H ; Так как координаты стрелки в пикселях, а программа
SRL H ; работает с знакоместами мы делим координаты на 8.
SRL H
SRL L
SRL L
SRL L
COND1 LD A,(IX+0) ; В A координата X меню.
CP 255 ; Если 255, то данные кончились и стрелка не на опции.
RET Z ; Выход.
LD D,A ; Проверяем попадание по X.
LD A,H
CP D
JR C,PROPOPC ; Если левее опции, пропускаем ее.
LD A,D
LD B,(IX+2) ; В регистре B длина опции в знакоместах.
DEC B
ADD A,B
CP H
JR C,PROPOPC ; Если правее опции, пропускаем ее.
LD A,(IX+1) ; В A координата Y.
CP L
JR NZ,PROPOPC ; Если не совпадает с текущей координатой Y, пропускаем.
LD A,(OPC) ; Если все проверки прошли, значит мы нашли номер опции
RET ; загружаем его в A и выходим.
PROPOPC LD DE,3 ; Переходим к данным следующей опции.
ADD IX,DE
LD A,(OPC) ; Номер текущей опции увеличиваем на 1.
INC A
LD (OPC),A
JR COND1 ; Снова проверяем.
BAR LD L,A ; После выхода из процедуры COND в регистре A номер
; опции или 255, если стрелка не попала.
LD A,(OPC1) ; Поместили в A номер предыдущей опции, сравниваем его
CP L ; с новым и если они равны, то закрашивать не надо.
RET Z ; Выходим.
CP 255 ; Если стрелка ушла с опции, то красить новую не надо,
JR Z,BAR5 ; а надо погасить старую, что и делает BAR5.
PUSH AF
LD A,L ; Заносим новый номер на место старого.
LD (OPC1),A
POP AF
CALL BAR1 ; Стираем старую опцию.
BAR6 LD A,(OPC1) ; В A номер новой опции.
CP 255 ; Если это не опция, то красить не надо.
RET Z ; Выходим.
BAR1 DEC A ; Подготовка к закраске новой опции.
LD H,0
LD L,A
PUSH HL
POP DE
ADD HL,HL
ADD HL,DE
EX DE,HL
LD IX,(TABLE)
ADD IX,DE
BAR3 LD H,(IX+0)
LD L,(IX+1)
CALL FILL ; Процедура FILL закрашивает, либо стирает опцию.
RET
BAR5 LD A,L
LD (OPC1),A
JR BAR6
FILL LD A,L ; Следующие строки выссчитывают адрес опции в атрибутах.
AND 7
RRCA
RRCA
RRCA
ADD A,H
AND #18
RRCA
RRCA
RRCA
OR #58
LD H,A
LD A,(HL) ; Берем байт атрибута.
PUSH AF ; Следующие строки инвертируют опцию меняя местами
AND 7 ; INK и PAPER. BRIGHT не учитывается.
SLA A
SLA A
SLA A
LD D,A
POP AF
AND 56
SRA A
SRA A
SRA A
OR D
LD B,(IX+2) ; В регистре B длина опции в знакоместах.
FILL1 LD (HL),A ; Если опция напечатана на многоцветном фоне, то в цикл
INC HL ; следует включить строки, начиная с "берем байт
DJNZ FILL1 ; атрибута".
RET
START1 LD (TABLE),HL ; Эта отдельная процедура, которая задает координаты
LD A,(HL) ; стрелки так, чтобы она попадала на первую опцию.
ADD A,A
ADD A,A
ADD A,A
LD D,A
INC HL
LD A,(HL)
ADD A,A
ADD A,A
ADD A,A
LD E,A
INC HL
LD A,(HL)
ADD A,A
ADD A,A
ADD A,A
SUB 4
LD D,A
LD (CRDS),DE
RET
TABLE DEFW 0 ; Здесь будет адрес таблицы.
OPC NOP ; Номер новой опции.
OPC1 NOP ; Номер старой опции.
TABLE1 X,Y,L,X1,Y1,L1, ... ,255 ; Данные меню.
Для успешной работы требуется:
Составьте таблицу описания опций меню в таком порядке - сначала координата
X, затем Y, затем длина опции в знакоместах. X и Y задаются в знакоместах.
Как практически использовать процедуру:
PROGRAM LD HL,TEXT ; Печатаем текст меню.
CALL PRINT
LD HL,TABLE1 ; В HL адрес таблицы данных меню.
CALL START1 ; Заносим его в переменную TABLE и центрируем стрелку.
L1 CALL START ; Вызов процедуры стрелки.
LD A,(OPC1) ; В A помещаем номер опции, на которой до нажатия
; выстрела стояла стрелка.
CP 255 ; Если в A 255, то стрелка на меню не попала и мы вновь
JR Z,L1 ; рисуем стрелку (можно реагировать по другому).
CP 1 ; Далее проверяем на какой опции стояла стрелка и
CALL Z,PROG1 ; делаем переход на нужную подпрограмму.
CP 2 ; Номер НЕ ЗАВИСИТ от того как напечатаны опции на
JR Z,PROG ; экране, а зависит от составленной таблицы.
и т.д.
После нажатия выстрела опция остается гореть, но это не всегда приемлемо.
Для принудительного гашения опции, после команды CALL START надо подать
команду CALL BAR6.
Не редкость такая ситуация, когда нам не надо зажигать опцию, но необходимо
знать, попала ли стрелка туда, куда нам надо. Для этого:
PROGRAM LD HL,TABLE1 ; В HL адрес таблицы, которая состоит только из кода 255
CALL START1
CALL START ; Вызываем подпрограмму стрелки.
LD HL,TABLE2 ; В HL адрес настоящей таблицы описания.
LD (TABLE),HL ; Заносим его в переменную.
CALL COND ; Ищем номер опции. После выхода номер будет в A, а не
CP 255 ; в переменной OPC1!!!
JR Z,PROGRAM ; Далее обрабатываем номер как угодно.
CP 1
CALL Z,PROG
и т.д.
TABLE1 DEFB 255 ; Пустая таблица.
TABLE2 X,Y,L,255 ; Настоящая таблица.
На этом позвольте закончить свое повествование. Рад, если кому-то эта
информация поможет.