mdview2: HEX-режим (F4) — дамп оригинального файла; версия v1.0 (b1)
Новый модуль mdview2_hex.c (WITH_HEX в conf): формат ' 0x012340 │ 16×hex │ 16 print', 30 строк, один атрибут. - Дамп всегда ОРИГИНАЛЬНОГО файла (orig_file_phys), не активного буфера; ряд выровнен на 16 → один bank_read на ряд (не пересекает EMM-страницу), fb()/W3 не используются. - Printable по текущей кодировке: CP866 как есть, CP1251/KOI8 через g_remap, UTF-8 — глиф на позиции лид-байта (continuation → '.') через новый utf_cp_glyph(), выделенный из конвертера enc-модуля. - Навигация: ±16 / ±480 / Home / End; одна строка — аппаратный scroll() + подрисовка одного ряда (как MD/RAW); процент в статусе. - F4 — тумблер HEX ↔ прежний вид; F2 из HEX уводит в MD; позиция при всех переходах через view_pos/view_reanchor (map_off orig ↔ active). - F8 в HEX: hex-колонка неизменна, printable перерисовывается в новой кодировке; позиция не двигается. - Help: версия v1.0 (b1), строка F4. exe 25725 → 27893 (+2168). Проверено в MAME. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
|
||||
PROJ_ROOT := $(abspath $(CURDIR)/../..)
|
||||
EXAMPLE := mdview2
|
||||
EXTRA_SRCS := mdview2_raw.c mdview2_help.c mdview2_table.c mdview2_enc.c mdview2_md.c mdview2_status.c mdview2_index.c
|
||||
EXTRA_SRCS := mdview2_raw.c mdview2_hex.c mdview2_help.c mdview2_table.c mdview2_enc.c mdview2_md.c mdview2_status.c mdview2_index.c
|
||||
MEMORY := small
|
||||
# --max-allocs 100000: агрессивнее аллокация регистров SDCC — минус ~850 байт
|
||||
# кода на всём приложении (замер 2026-07-04) ценой более долгой компиляции.
|
||||
|
||||
@@ -199,6 +199,9 @@ uint8_t g_view = VIEW_MD; /* extern: активный
|
||||
#if WITH_RAW
|
||||
uint8_t g_ready; /* extern: 1 когда первичный документ построен — F2 (RAW) рабочий */
|
||||
static uint8_t g_raw_last = VIEW_RAW_WRAP; /* последний под-режим RAW (возврат по F2) */
|
||||
#if WITH_HEX
|
||||
static uint8_t g_hex_last = VIEW_MD; /* вид, из которого вошли в HEX (возврат по F4) */
|
||||
#endif
|
||||
#endif
|
||||
uint8_t g_loading; /* extern: 1 во время index_lines() */
|
||||
static uint8_t g_first_drawn; /* первый экран уже нарисован */
|
||||
@@ -720,6 +723,12 @@ void progress_tick(void)
|
||||
* не MD-вид (иначе мелькал бы MD). Индекс при этом строится дальше (нужен
|
||||
* для MD-вида). */
|
||||
if (g_view != VIEW_MD) {
|
||||
#if WITH_HEX
|
||||
if (g_view == VIEW_HEX) { /* HEX показывает оригинал — экран уже актуален */
|
||||
spinner_tick();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (!g_first_drawn) {
|
||||
raw_draw();
|
||||
// render_raw_status();
|
||||
@@ -845,18 +854,33 @@ static uint32_t map_off(uint32_t off, uint32_t from, uint32_t to)
|
||||
}
|
||||
|
||||
/* Байт-позиция текущего вида (верх экрана) — единая «валюта» для переноса
|
||||
* позиции между видами/наборами. */
|
||||
* позиции между видами/наборами. Валюта = offset АКТИВНОГО буфера; HEX живёт
|
||||
* в байтах оригинала, для UTF-набора конвертируем через map_off. */
|
||||
static uint32_t view_pos(void)
|
||||
{
|
||||
#if WITH_HEX
|
||||
if (g_view == VIEW_HEX)
|
||||
return (g_active_doc == DOC_UTF8)
|
||||
? map_off(hex_pos(), orig_file_size, file_size)
|
||||
: hex_pos();
|
||||
#endif
|
||||
#if WITH_RAW
|
||||
if (g_view != VIEW_MD) return raw_pos();
|
||||
#endif
|
||||
return seg_off(top_line);
|
||||
}
|
||||
|
||||
/* Поставить текущий вид на байт-позицию off (после doc_switch). */
|
||||
/* Поставить текущий вид на байт-позицию off (активного буфера). */
|
||||
static void view_reanchor(uint32_t off)
|
||||
{
|
||||
#if WITH_HEX
|
||||
if (g_view == VIEW_HEX) {
|
||||
hex_reanchor((g_active_doc == DOC_UTF8)
|
||||
? map_off(off, file_size, orig_file_size)
|
||||
: off);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if WITH_RAW
|
||||
if (g_view != VIEW_MD) { raw_reanchor(off); return; }
|
||||
#endif
|
||||
@@ -893,7 +917,7 @@ static void switch_encoding(uint8_t next)
|
||||
doc_save_live(g_active_doc); /* сохранить текущий (позиция и т.п.) */
|
||||
#if WITH_RAW
|
||||
uint32_t raw_save = raw_pos();
|
||||
if (g_view != VIEW_MD)
|
||||
if (VIEW_IS_RAW(g_view)) /* HEX показывает оригинал — его позиция инвариантна */
|
||||
raw_reanchor(0); /* прогрессивный показ нового буфера — с начала */
|
||||
g_ready = 0;
|
||||
render_menu(); /* идёт индексация — прячем F2 */
|
||||
@@ -911,7 +935,7 @@ static void switch_encoding(uint8_t next)
|
||||
g_utf_failed = 1;
|
||||
doc_load_live(g_active_doc);
|
||||
#if WITH_RAW
|
||||
if (g_view != VIEW_MD)
|
||||
if (VIEW_IS_RAW(g_view))
|
||||
raw_reanchor(raw_save); /* буфер прежний — вернуть позицию RAW */
|
||||
#endif
|
||||
return;
|
||||
@@ -1072,7 +1096,8 @@ int main(int argc, char **argv)
|
||||
show_help();
|
||||
continue;
|
||||
} /* show_help сам перерисует */
|
||||
/* F2 — тумблер RAW ↔ MD (рабочий только после постройки документа). */
|
||||
/* F2 — тумблер RAW ↔ MD (из HEX тоже уводит в MD).
|
||||
* Рабочий только после постройки документа. */
|
||||
if (scan == KEY_F2) {
|
||||
if (!g_ready) continue;
|
||||
if (g_view == VIEW_MD) {
|
||||
@@ -1084,15 +1109,45 @@ int main(int argc, char **argv)
|
||||
render_raw_status();
|
||||
raw_draw();
|
||||
} else {
|
||||
uint32_t off = view_pos(); /* позиция из RAW/HEX */
|
||||
if (VIEW_IS_RAW(g_view))
|
||||
g_raw_last = g_view; /* запомнить под-режим RAW */
|
||||
g_view = VIEW_MD;
|
||||
top_line = line_at_off(raw_pos()); /* позиция из RAW */
|
||||
top_line = line_at_off(off);
|
||||
clamp_top();
|
||||
render_full_status(); render_menu();
|
||||
draw_viewport_from_cache();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#if WITH_HEX
|
||||
/* F4 — тумблер HEX ↔ прежний вид (MD/RAW). */
|
||||
if (scan == KEY_F4) {
|
||||
if (!g_ready) continue;
|
||||
uint32_t off = view_pos(); /* позиция текущего вида */
|
||||
if (g_view == VIEW_HEX) { /* HEX → прежний вид */
|
||||
g_view = g_hex_last;
|
||||
view_reanchor(off);
|
||||
if (g_view == VIEW_MD) {
|
||||
clamp_top();
|
||||
render_full_status(); render_menu();
|
||||
draw_viewport_from_cache();
|
||||
} else {
|
||||
raw_screen_init();
|
||||
status_encoding(); render_menu();
|
||||
render_raw_status(); raw_draw();
|
||||
}
|
||||
} else { /* MD/RAW → HEX */
|
||||
g_hex_last = g_view;
|
||||
g_view = VIEW_HEX;
|
||||
view_reanchor(off); /* active → байты оригинала */
|
||||
hex_screen_init();
|
||||
status_encoding(); render_menu();
|
||||
render_hex_status(); hex_draw();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/* цикл CP866→CP1251→KOI8R→UTF8→CP866; набор дособерётся лениво */
|
||||
if (scan == KEY_F8) {
|
||||
uint8_t next = (g_encoding == ENC_CP866) ? ENC_CP1251 :
|
||||
@@ -1104,6 +1159,14 @@ int main(int argc, char **argv)
|
||||
if (g_abort)
|
||||
exit(0); /* Esc/F10 во время ленивой досборки */
|
||||
/* Перерисовка — по текущему виду (switch_encoding сам не рисует). */
|
||||
#if WITH_HEX
|
||||
if (g_view == VIEW_HEX) {
|
||||
status_encoding();
|
||||
render_hex_status();
|
||||
hex_draw(); /* printable-колонка в новой кодировке */
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#if WITH_RAW
|
||||
if (g_view != VIEW_MD) {
|
||||
status_encoding();
|
||||
@@ -1121,6 +1184,11 @@ int main(int argc, char **argv)
|
||||
/* MD-режим: F1/F8/F10 здесь, навигация — в md_key() (peer к raw_key). */
|
||||
md_key(scan); /* навигация MD (сама рисует+статус); незнакомые игнорит */
|
||||
continue;
|
||||
#if WITH_HEX
|
||||
case VIEW_HEX:
|
||||
hex_key(scan); /* навигация HEX (сама рисует+процент) */
|
||||
continue;
|
||||
#endif
|
||||
#if WITH_RAW
|
||||
case VIEW_RAW_WRAP:
|
||||
case VIEW_RAW_HSCROLL:
|
||||
|
||||
@@ -69,6 +69,8 @@
|
||||
#define VIEW_MD 0 /* markdown с форматированием (по умолчанию) */
|
||||
#define VIEW_RAW_WRAP 1 /* RAW: длинные строки переносятся кратно 80 */
|
||||
#define VIEW_RAW_HSCROLL 2 /* RAW: длинные строки в одну, гориз. скролл */
|
||||
#define VIEW_HEX 3 /* HEX-дамп оригинального файла */
|
||||
#define VIEW_IS_RAW(v) ((v) == VIEW_RAW_WRAP || (v) == VIEW_RAW_HSCROLL)
|
||||
|
||||
/* ---- Кодировки --------------------------------------------------- */
|
||||
/* 8-битные (CP866/CP1251/KOI8R) различаются только ремапом глифов [128-255]
|
||||
@@ -153,6 +155,17 @@ uint8_t raw_key(uint8_t scan); /* навигация RAW; 1 = о
|
||||
void raw_screen_init(void); /* очистка экрана с нужным аттрибутом */
|
||||
void raw_renorm(void); /* выровнять позицию при смене под-режима (F3) */
|
||||
|
||||
/* ================================================================== *
|
||||
* API модуля HEX (mdview2_hex.c) — дамп ОРИГИНАЛЬНОГО файла (F4).
|
||||
* Позиция hex_pos/hex_reanchor — в байтах ОРИГИНАЛА (orig_file_*);
|
||||
* конвертацию в/из активного буфера делает ядро (map_off).
|
||||
* ================================================================== */
|
||||
uint32_t hex_pos(void); /* offset верхнего ряда (кратен 16) */
|
||||
void hex_reanchor(uint32_t orig_off); /* поставить на ряд с байтом orig_off */
|
||||
void hex_draw(void); /* перерисовать область документа */
|
||||
uint8_t hex_key(uint8_t scan); /* навигация HEX; 1 = обработано */
|
||||
void hex_screen_init(void); /* очистка экрана */
|
||||
|
||||
/* ================================================================== *
|
||||
* Запись директории рендер-кэша (одна на видимую строку, РОВНО 8 байт —
|
||||
* cache_dir_get/put адресуют сдвигом idx<<3). Контент — len пар (char,attr).
|
||||
@@ -189,6 +202,7 @@ void prerender_status(void); /* фикс. часть: фон,
|
||||
void status_encoding(void); /* только поле кодировки (col 37) */
|
||||
void render_md_status_numbers(void); /* числа MD: диапазон строк + % */
|
||||
void render_raw_status(void); /* RAW mode: метка режима */
|
||||
void render_hex_status(void); /* HEX mode: метка режима */
|
||||
void render_full_status(void); /* encoding + numbers (MD) */
|
||||
void render_menu(void); /* строка меню (по смене режима/готовности) */
|
||||
uint16_t drawable_lines(void); /* число строк, готовых к показу */
|
||||
@@ -278,5 +292,6 @@ uint8_t detect_encoding(void); /* автоопределени
|
||||
void win_rest_remap(uint8_t row, uint8_t w, uint8_t page, uint16_t off); /* вывод среза с ремапом */
|
||||
void utf_convert_more(uint32_t target); /* инкрементальная конвертация до target байт */
|
||||
uint8_t utf_alloc(void); /* выделить EMM-страницы под UTF-набор; 0 = нет EMM */
|
||||
uint8_t utf_cp_glyph(uint32_t cp); /* кодпойнт → один CP866-глиф ('?' без аналога) */
|
||||
|
||||
#endif /* MDVIEW2_H */
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
#define MDVIEW2_CONF_H
|
||||
|
||||
#define WITH_RAW 1 /* RAW-просмотр исходника (F2): mdview2_raw.c */
|
||||
#define WITH_HEX 0 /* HEX-просмотр (зарезервировано): mdview2_hex.c */
|
||||
#define WITH_HEX 1 /* HEX-дамп оригинального файла (F4): mdview2_hex.c */
|
||||
|
||||
#endif /* MDVIEW2_CONF_H */
|
||||
|
||||
@@ -230,20 +230,24 @@ static const utf_sym_t utf_sym[] = {
|
||||
};
|
||||
#define UTF_SYM_N (uint8_t)(sizeof(utf_sym) / sizeof(utf_sym[0]))
|
||||
|
||||
/* Кодпойнт → CP866-глиф(ы). Кириллица по таблице; спецслучаи (…, BOM) явно;
|
||||
* остальные ходовые символы по таблице utf_sym[]; прочее → '?'. */
|
||||
/* Кодпойнт → ОДИН CP866-глиф: кириллица по таблице, ходовые символы по
|
||||
* utf_sym[], прочее → '?'. Общая для конвертера и HEX-printable (F4). */
|
||||
uint8_t utf_cp_glyph(uint32_t cp)
|
||||
{
|
||||
if (cp < 0x80) return (uint8_t)cp;
|
||||
if (cp >= 0x0400 && cp <= 0x045F) return utf_cyr_to_866[cp - 0x0400];
|
||||
for (uint8_t i = 0; i < UTF_SYM_N; i++)
|
||||
if (utf_sym[i].utf8 == (uint16_t)cp) return utf_sym[i].cp866;
|
||||
return '?';
|
||||
}
|
||||
|
||||
/* Кодпойнт → CP866-глиф(ы) в поток конвертера. Спецслучаи с НЕ-1:1 заменой
|
||||
* (… → "...", BOM → ничего) здесь; остальное через utf_cp_glyph(). */
|
||||
static void conv_emit_cp(uint32_t cp)
|
||||
{
|
||||
if (cp < 0x80) { conv_put((uint8_t)cp); return; }
|
||||
if (cp >= 0x0400 && cp <= 0x045F) { conv_put(utf_cyr_to_866[cp - 0x0400]); return; }
|
||||
if (cp == 0x2026) { conv_put('.'); conv_put('.'); conv_put('.'); return; } /* … → "..." */
|
||||
if (cp == 0xFEFF) return; /* BOM/ZWNBSP — выкинуть */
|
||||
for (uint8_t i = 0; i < UTF_SYM_N; i++)
|
||||
if (utf_sym[i].utf8 == (uint16_t)cp) {
|
||||
conv_put(utf_sym[i].cp866);
|
||||
return;
|
||||
}
|
||||
conv_put('?');
|
||||
conv_put(utf_cp_glyph(cp));
|
||||
}
|
||||
|
||||
/* Последовательное чтение байта ОРИГИНАЛА (utf-8) конвертером. Оригинал лежит
|
||||
|
||||
@@ -73,7 +73,7 @@ void show_help(void)
|
||||
/* Содержимое (20 внутренних строк) */
|
||||
uint8_t r = 0;
|
||||
help_line(r++, "", ATTR_HELP_BG);
|
||||
help_line(r++, " MDView v1.0 (a3) -- Markdown Viewer for Sprinter", ATTR_HELP_HDR);
|
||||
help_line(r++, " MDView v1.0 (b1) -- Markdown Viewer for Sprinter", ATTR_HELP_HDR);
|
||||
help_line(r++, " (c) 2026 \x8F\xA5\xE2\xE0\xAE\xA2 \x80\x2E\x83\x2E",
|
||||
ATTR_HELP_BG);
|
||||
help_line(r++, "", ATTR_HELP_BG);
|
||||
@@ -92,11 +92,11 @@ void show_help(void)
|
||||
help_line(r++, " Encoding and View modes:", ATTR_HELP_HDR);
|
||||
help_line(r++, " F2 RAW Mode", ATTR_HELP_BG);
|
||||
help_line(r++, " F3 Wrap/Unwrap Mode for RAW View", ATTR_HELP_BG);
|
||||
help_line(r++, " F4 HEX Mode (dump of original file)", ATTR_HELP_BG);
|
||||
help_line(r++, " F8 Cycle CP866 / CP1251 / KOI8-R / UTF-8", ATTR_HELP_BG);
|
||||
help_line(r++, " Auto-detected on open; F8 to override", ATTR_HELP_BG);
|
||||
help_line(r++, "", ATTR_HELP_BG);
|
||||
help_line(r++, " File size: up to 256 KB (EMM). Lines: up to 18432.", ATTR_HELP_BG);
|
||||
help_line(r++, "", ATTR_HELP_BG);
|
||||
|
||||
(void)getkey();
|
||||
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* mdview2_hex.c — HEX-дамп ОРИГИНАЛЬНОГО файла (F4).
|
||||
*
|
||||
* Показывает исходные байты файла (orig_file_phys), а не активный буфер:
|
||||
* hex-дамп декодированного UTF-набора был бы искажением. Printable-колонка
|
||||
* интерпретируется ТЕКУЩЕЙ кодировкой: CP866 как есть, CP1251/KOI8 через
|
||||
* g_remap, UTF-8 — глиф на позиции лид-байта (continuation-байты → '.').
|
||||
*
|
||||
* Формат ряда (79 колонок, один атрибут ATTR_TEXT — как RAW):
|
||||
* 0x012340 │ XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX │ 16 символов
|
||||
*
|
||||
* Ряд выровнен на 16 байт и никогда не пересекает границу EMM-страницы
|
||||
* (16 делит 16384 нацело) — один bank_read на ряд, fb()/W3-маппинг не нужны.
|
||||
* Позиция (hex_top) живёт в байтах ОРИГИНАЛА; конвертацию в/из байт-позиции
|
||||
* активного буфера делает ядро (view_pos/view_reanchor через map_off).
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <bios/text.h>
|
||||
#include <sprinter_mem.h> /* bank_read (чтение оригинала по страницам EMM) */
|
||||
#include "mdview2.h"
|
||||
|
||||
#if WITH_HEX /* весь модуль опционален (mdview2_conf.h); при 0 пустой объектник */
|
||||
|
||||
#define HEX_BPR 16u /* байт на ряд */
|
||||
#define HEX_SPAN ((uint32_t)(VIEW_H - 1) * HEX_BPR)
|
||||
|
||||
/* Геометрия ряда (колонки). */
|
||||
#define HX_OFF 1u /* "0x012340" */
|
||||
#define HX_SEP1 10u /* │ */
|
||||
#define HX_DUMP 12u /* пары hex-цифр */
|
||||
#define HX_SEP2 61u /* │ */
|
||||
#define HX_PRINT 63u /* printable */
|
||||
|
||||
static uint32_t hex_top; /* offset верхнего ряда (кратен 16) */
|
||||
|
||||
uint32_t hex_pos(void) { return hex_top; }
|
||||
|
||||
/* Максимальный hex_top: последний ряд файла на нижней строке экрана. */
|
||||
static uint32_t hex_max_top(void)
|
||||
{
|
||||
uint32_t last = (orig_file_size == 0) ? 0
|
||||
: ((orig_file_size - 1u) & ~(uint32_t)(HEX_BPR - 1u));
|
||||
return (last > HEX_SPAN) ? (last - HEX_SPAN) : 0;
|
||||
}
|
||||
|
||||
void hex_reanchor(uint32_t orig_off)
|
||||
{
|
||||
uint32_t mt = hex_max_top();
|
||||
orig_off &= ~(uint32_t)(HEX_BPR - 1u);
|
||||
hex_top = (orig_off > mt) ? mt : orig_off;
|
||||
}
|
||||
|
||||
void hex_screen_init(void)
|
||||
{
|
||||
bios_clearwin(VIEW_TOP_ROW, 0, VIEW_H, SCREEN_W, ATTR_TEXT);
|
||||
}
|
||||
|
||||
/* ---- отрисовка ----------------------------------------------------- */
|
||||
|
||||
static uint8_t hexdig(uint8_t v)
|
||||
{
|
||||
v &= 15u;
|
||||
return (uint8_t)((v < 10u) ? ('0' + v) : ('A' - 10 + v));
|
||||
}
|
||||
|
||||
/* Один байт оригинала (для UTF-lookahead за границей ряда — редкий путь). */
|
||||
static uint8_t fbo(uint32_t off)
|
||||
{
|
||||
uint8_t b;
|
||||
bank_read(orig_file_phys[off >> PAGE_BITS], (uint16_t)(off & PAGE_MASK), &b, 1);
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Printable-глиф для n байт ряда b[] (off — offset b[0] в файле) → out[]. */
|
||||
static void hex_print_cells(const uint8_t *b, uint32_t off, uint8_t n, uint8_t *out)
|
||||
{
|
||||
for (uint8_t i = 0; i < n; i++) {
|
||||
uint8_t c = b[i];
|
||||
uint8_t g;
|
||||
if (c < 0x20u) {
|
||||
g = '.';
|
||||
} else if (c < 0x80u || g_encoding != ENC_UTF8) {
|
||||
g = (uint8_t)((c >= 0x80u && g_remap) ? g_remap[c - 0x80u] : c);
|
||||
} else if ((c & 0xC0u) == 0x80u) {
|
||||
g = '.'; /* continuation-байт */
|
||||
} else {
|
||||
/* Лид-байт: собрать кодпойнт (хвост может выйти за ряд → fbo).
|
||||
* 4-байтовые (за пределами CP866) и битые последовательности → '.'. */
|
||||
uint32_t cp;
|
||||
uint8_t need, ok = 1;
|
||||
if ((c & 0xE0u) == 0xC0u) { cp = (uint32_t)(c & 0x1Fu); need = 1; }
|
||||
else if ((c & 0xF0u) == 0xE0u) { cp = (uint32_t)(c & 0x0Fu); need = 2; }
|
||||
else { out[i] = '.'; continue; }
|
||||
for (uint8_t k = 1; k <= need; k++) {
|
||||
uint32_t p = off + i + k;
|
||||
if (p >= orig_file_size) { ok = 0; break; }
|
||||
uint8_t cb = (uint8_t)((i + k < n) ? b[i + k] : fbo(p));
|
||||
if ((cb & 0xC0u) != 0x80u) { ok = 0; break; }
|
||||
cp = (cp << 6) | (uint32_t)(cb & 0x3Fu);
|
||||
}
|
||||
g = ok ? utf_cp_glyph(cp) : '.';
|
||||
if (g < 0x20u) g = '.'; /* overlong мог дать управляющий */
|
||||
}
|
||||
out[i] = g;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t hex_line[SCREEN_W]; /* собранный ряд (только символы, единый attr) */
|
||||
|
||||
static void hex_draw_row(uint32_t off, uint8_t row)
|
||||
{
|
||||
uint8_t buf[HEX_BPR];
|
||||
uint8_t n = 0;
|
||||
|
||||
memset(hex_line, ' ', SCREEN_W);
|
||||
if (off < orig_file_size) {
|
||||
uint32_t rem = orig_file_size - off;
|
||||
n = (rem >= HEX_BPR) ? (uint8_t)HEX_BPR : (uint8_t)rem;
|
||||
bank_read(orig_file_phys[off >> PAGE_BITS], (uint16_t)(off & PAGE_MASK), buf, n);
|
||||
}
|
||||
if (n) { /* ряды за EOF — пустые */
|
||||
hex_line[HX_OFF] = '0';
|
||||
hex_line[HX_OFF + 1] = 'x';
|
||||
hex_line[HX_OFF + 2] = hexdig((uint8_t)(off >> 20));
|
||||
hex_line[HX_OFF + 3] = hexdig((uint8_t)(off >> 16));
|
||||
hex_line[HX_OFF + 4] = hexdig((uint8_t)(off >> 12));
|
||||
hex_line[HX_OFF + 5] = hexdig((uint8_t)(off >> 8));
|
||||
hex_line[HX_OFF + 6] = hexdig((uint8_t)(off >> 4));
|
||||
hex_line[HX_OFF + 7] = hexdig((uint8_t)off);
|
||||
hex_line[HX_SEP1] = TBL_V;
|
||||
for (uint8_t i = 0; i < n; i++) {
|
||||
uint8_t x = (uint8_t)(HX_DUMP + i * 3u + ((i >= 8u) ? 1u : 0u));
|
||||
hex_line[x] = hexdig((uint8_t)(buf[i] >> 4));
|
||||
hex_line[x + 1] = hexdig(buf[i]);
|
||||
}
|
||||
hex_line[HX_SEP2] = TBL_V;
|
||||
hex_print_cells(buf, off, n, hex_line + HX_PRINT);
|
||||
}
|
||||
bios_set_place(row, 0);
|
||||
bios_write_until((const char *)hex_line, SCREEN_W, 0);
|
||||
}
|
||||
|
||||
void hex_draw(void)
|
||||
{
|
||||
uint32_t off = hex_top;
|
||||
for (uint8_t r = 0; r < VIEW_H; r++) {
|
||||
hex_draw_row(off, (uint8_t)(VIEW_TOP_ROW + r));
|
||||
off += HEX_BPR;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- статус-бар: % по байтам (как calc_raw_pct) --------------------- */
|
||||
|
||||
static uint8_t calc_hex_pct(void)
|
||||
{
|
||||
return pct16((uint16_t)(hex_top >> 8), (uint16_t)(orig_file_size >> 8));
|
||||
}
|
||||
|
||||
/* ---- навигация (вызывается из главного цикла при g_view == VIEW_HEX) */
|
||||
|
||||
uint8_t hex_key(uint8_t scan)
|
||||
{
|
||||
uint32_t mt = hex_max_top();
|
||||
switch (scan) {
|
||||
/* Одна строка — аппаратный скролл окна + подрисовка одного ряда
|
||||
* (как в MD/RAW), без перерисовки всего экрана. */
|
||||
case KEY_DOWN:
|
||||
if (hex_top < mt) {
|
||||
hex_top += HEX_BPR;
|
||||
scroll(0, VIEW_TOP_ROW, SCREEN_W, VIEW_H, 1, 0); /* содержимое вверх */
|
||||
hex_draw_row(hex_top + HEX_SPAN, (uint8_t)(VIEW_TOP_ROW + VIEW_H - 1));
|
||||
}
|
||||
break;
|
||||
case KEY_UP:
|
||||
if (hex_top) {
|
||||
hex_top -= HEX_BPR;
|
||||
scroll(0, VIEW_TOP_ROW, SCREEN_W, VIEW_H, 2, 0); /* содержимое вниз */
|
||||
hex_draw_row(hex_top, VIEW_TOP_ROW);
|
||||
}
|
||||
break;
|
||||
case KEY_PGDN: {
|
||||
uint32_t nt = hex_top + (uint32_t)VIEW_H * HEX_BPR;
|
||||
if (nt > mt) nt = mt;
|
||||
if (nt != hex_top) { hex_top = nt; hex_draw(); }
|
||||
break;
|
||||
}
|
||||
case KEY_PGUP: {
|
||||
uint32_t d = (uint32_t)VIEW_H * HEX_BPR;
|
||||
uint32_t nt = (hex_top >= d) ? hex_top - d : 0;
|
||||
if (nt != hex_top) { hex_top = nt; hex_draw(); }
|
||||
break;
|
||||
}
|
||||
case KEY_HOME:
|
||||
if (hex_top) { hex_top = 0; hex_draw(); }
|
||||
break;
|
||||
case KEY_END:
|
||||
if (hex_top != mt) { hex_top = mt; hex_draw(); }
|
||||
break;
|
||||
default:
|
||||
return 0; /* не наша клавиша */
|
||||
}
|
||||
render_percent_progress(calc_hex_pct());
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* WITH_HEX */
|
||||
@@ -145,6 +145,16 @@ void render_raw_status(void)
|
||||
}
|
||||
#endif /* WITH_RAW */
|
||||
|
||||
#if WITH_HEX
|
||||
/* HEX-вариант числовой части бара (peer к render_raw_status). */
|
||||
void render_hex_status(void)
|
||||
{
|
||||
textattr(ATTR_BAR);
|
||||
gotoxy(DIV1_X + 1, 0);
|
||||
bios_writeattr_until(" HEX", DIV2_X - DIV1_X - 1, ATTR_BAR, 0);
|
||||
}
|
||||
#endif /* WITH_HEX */
|
||||
|
||||
/* ---- Нижнее меню (строка 31) -------------------------------------- */
|
||||
|
||||
void render_menu(void)
|
||||
@@ -168,9 +178,13 @@ void render_menu(void)
|
||||
#if WITH_RAW
|
||||
if (g_ready) /* RAW доступен после постройки документа */
|
||||
put_str_attr(1 * 8 + 2, MENU_ROW, (g_view == VIEW_MD) ? "RAW" : "MD", ATTR_MENU_T);
|
||||
if (g_view != VIEW_MD) /* Wrap/Unwrap — только в RAW */
|
||||
if (VIEW_IS_RAW(g_view)) /* Wrap/Unwrap — только в RAW */
|
||||
put_str_attr(2 * 8 + 2, MENU_ROW,
|
||||
(g_view == VIEW_RAW_WRAP) ? "UnWrap" : "Wrap", ATTR_MENU_T);
|
||||
#endif
|
||||
#if WITH_HEX
|
||||
if (g_ready) /* HEX доступен после постройки документа */
|
||||
put_str_attr(3 * 8 + 2, MENU_ROW, (g_view == VIEW_HEX) ? "Back" : "Hex", ATTR_MENU_T);
|
||||
#endif
|
||||
if (g_f8_enabled) /* смена кодировки сейчас возможна */
|
||||
put_str_attr(7 * 8 + 2, MENU_ROW, "CodePg", ATTR_MENU_T);
|
||||
|
||||
Reference in New Issue
Block a user