mdview2: полировка статус-бара/справки/детекции + libc min/max
- status-bar: dirty-tracking (числа/процент/кодировка перерисовываются только при изменении), поле кодировки сдвинуто к DIV1_X-10 (8 симв.) - md_key: HOME/END не перерисовывают экран, если позиция не меняется - help: версия v1.0(a3), добавлены F2/F3 (RAW/Wrap), компактные секции - enc: детекция по 5 частотным буквам и сэмплу 1КБ; ENC_UNSUPPORTED (UTF16/32) - libc: добавлены min()/max() (naked, <stdlib.h>) + сборка в lib/Makefile Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+90
-33
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <bios/text.h>
|
||||
@@ -269,6 +270,7 @@ static void doc_switch(uint8_t target); /* forward (нужна в progress_tic
|
||||
void put_str_attr(uint8_t x, uint8_t y, const char *s, uint8_t attr)
|
||||
{
|
||||
uint8_t len = (x < SCREEN_W) ? (uint8_t)(SCREEN_W - x) : 0;
|
||||
len = min(len, strlen(s));
|
||||
if (len == 0) return;
|
||||
bios_set_place(y, x);
|
||||
bios_writeattr_until(s, len, attr, 0);
|
||||
@@ -490,7 +492,7 @@ static int alloc_set_storage(void)
|
||||
{
|
||||
uint8_t want;
|
||||
|
||||
want = (uint8_t)(file_pages >> 1 + 1u);
|
||||
want = (uint8_t)((file_pages >> 1) + 1u);
|
||||
if (want > MAX_INDEX_PAGES) want = MAX_INDEX_PAGES;
|
||||
index_blk = mem_alloc_pages(want);
|
||||
if (index_blk == 0) return -5;
|
||||
@@ -499,7 +501,7 @@ static int alloc_set_storage(void)
|
||||
index_phys[i] = mem_get_page(index_blk, i);
|
||||
max_lines = (uint16_t)index_pages * INDEX_RECS_PER_PAGE;
|
||||
|
||||
want = (uint8_t)(file_pages >> 1 + 1u);
|
||||
want = (uint8_t)((file_pages >> 1) + 1u);
|
||||
if (want > MAX_CACHE_DIR_PAGES) want = MAX_CACHE_DIR_PAGES;
|
||||
cache_dir_blk = mem_alloc_pages(want);
|
||||
if (cache_dir_blk == 0) return -6;
|
||||
@@ -616,32 +618,67 @@ static void load_key(uint16_t k)
|
||||
uint16_t maxtop = (dr > VIEW_H) ? (uint16_t)(dr - VIEW_H) : 0;
|
||||
uint16_t nt = top_line;
|
||||
|
||||
if (ascii == 0x1B || scan == KEY_F10) { g_abort = 1; return; } /* Esc/F10 → выход */
|
||||
if (ascii) return; /* прочие ascii игнорируем */
|
||||
if (ascii == 0x1B || scan == KEY_F10) {
|
||||
g_abort = 1;
|
||||
return;
|
||||
} /* Esc/F10 → выход */
|
||||
if (ascii)
|
||||
return; /* прочие ascii игнорируем */
|
||||
|
||||
switch (scan) {
|
||||
case KEY_UP: nt = (top_line >= 1) ? (uint16_t)(top_line - 1) : 0; break;
|
||||
case KEY_DOWN: nt = top_line + 1; break;
|
||||
case KEY_PGUP: nt = (top_line >= VIEW_H) ? (uint16_t)(top_line - VIEW_H) : 0; break;
|
||||
case KEY_PGDN: nt = top_line + VIEW_H; break;
|
||||
case KEY_HOME: top_line = 0; viewport_x = 0; draw_viewport_from_cache(); render_md_status_numbers(); return;
|
||||
case KEY_END: top_line = maxtop; viewport_x = 0; draw_viewport_from_cache(); render_md_status_numbers(); return;
|
||||
case KEY_LEFT: md_scroll_horizon(-(int8_t)HPAN_STEP); render_md_status_numbers(); return;
|
||||
case KEY_RIGHT: md_scroll_horizon(+(int8_t)HPAN_STEP); render_md_status_numbers(); return;
|
||||
case KEY_F1: show_help(); return;
|
||||
case KEY_F8: /* во время сборки крутим ТОЛЬКО 8-бит и только если набор 8-битный
|
||||
case KEY_UP:
|
||||
nt = (top_line >= 1) ? (uint16_t)(top_line - 1) : 0;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
nt = top_line + 1;
|
||||
break;
|
||||
case KEY_PGUP:
|
||||
nt = (top_line >= VIEW_H) ? (uint16_t)(top_line - VIEW_H) : 0;
|
||||
break;
|
||||
case KEY_PGDN:
|
||||
nt = top_line + VIEW_H;
|
||||
break;
|
||||
case KEY_HOME:
|
||||
top_line = 0;
|
||||
viewport_x = 0;
|
||||
draw_viewport_from_cache();
|
||||
render_md_status_numbers();
|
||||
return;
|
||||
case KEY_END:
|
||||
top_line = maxtop;
|
||||
viewport_x = 0;
|
||||
draw_viewport_from_cache();
|
||||
render_md_status_numbers();
|
||||
return;
|
||||
case KEY_LEFT:
|
||||
md_scroll_horizon(-(int8_t)HPAN_STEP);
|
||||
render_md_status_numbers();
|
||||
return;
|
||||
case KEY_RIGHT:
|
||||
md_scroll_horizon(+(int8_t)HPAN_STEP);
|
||||
render_md_status_numbers();
|
||||
return;
|
||||
case KEY_F1:
|
||||
show_help();
|
||||
return;
|
||||
case KEY_F8:
|
||||
/* во время сборки крутим ТОЛЬКО 8-бит и только если набор 8-битный
|
||||
* (ремап на отрисовке; индексация не зависит от кодировки) */
|
||||
if (g_f8_enabled && g_active_doc == DOC_8BIT) {
|
||||
uint8_t nx = (g_encoding == ENC_CP866) ? ENC_CP1251 :
|
||||
(g_encoding == ENC_CP1251) ? ENC_KOI8R : ENC_CP866;
|
||||
set_encoding(nx); g_doc[DOC_8BIT].enc = nx;
|
||||
set_encoding(nx);
|
||||
g_doc[DOC_8BIT].enc = nx;
|
||||
draw_viewport_from_cache();
|
||||
render_full_status();
|
||||
}
|
||||
return;
|
||||
default: return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (nt > maxtop) nt = maxtop;
|
||||
|
||||
if (nt > maxtop)
|
||||
nt = maxtop;
|
||||
if (nt != top_line) {
|
||||
top_line = nt;
|
||||
draw_viewport_from_cache();
|
||||
@@ -676,10 +713,11 @@ void progress_tick(void)
|
||||
g_first_drawn = 1;
|
||||
touched = 1;
|
||||
}
|
||||
if (n_lines >= (uint16_t)(g_last_prog + 20)) {
|
||||
if (n_lines >= (uint16_t)(g_last_prog + 10)) {
|
||||
g_last_prog = n_lines;
|
||||
spinner_tick();
|
||||
if (g_first_drawn) render_md_status_numbers();
|
||||
if (g_first_drawn)
|
||||
render_md_status_numbers();
|
||||
touched = 1;
|
||||
}
|
||||
if (g_first_drawn && kbhit()) {
|
||||
@@ -688,7 +726,8 @@ void progress_tick(void)
|
||||
}
|
||||
/* Отрисовка/WINREST/BIOS могли сбить маппинг W3, на который опирается fb()
|
||||
* при индексации → форсируем ре-маппинг страницы файла на следующем fb(). */
|
||||
if (touched) cur_page = 0xFF;
|
||||
if (touched)
|
||||
cur_page = 0xFF;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
@@ -710,10 +749,12 @@ static int build_doc(uint8_t slot, uint8_t enc, uint8_t visible)
|
||||
{
|
||||
if (slot == DOC_UTF8) {
|
||||
if (!utf_avail) { /* первый вход: выделить страницы */
|
||||
if (!utf_alloc()) return -7; /* выделяет страницы + сбрасывает конвертер */
|
||||
if (!utf_alloc())
|
||||
return -7; /* выделяет страницы + сбрасывает конвертер */
|
||||
utf_avail = 1;
|
||||
}
|
||||
file_blk = utf_blk; file_pages = utf_pages;
|
||||
file_blk = utf_blk;
|
||||
file_pages = utf_pages;
|
||||
memcpy(file_phys, utf_phys, MAX_PAGES);
|
||||
if (g_utf_building) {
|
||||
file_size = 0;
|
||||
@@ -723,18 +764,25 @@ static int build_doc(uint8_t slot, uint8_t enc, uint8_t visible)
|
||||
file_size = utf_size;
|
||||
}
|
||||
} else {
|
||||
file_blk = orig_file_blk; file_pages = orig_file_pages; file_size = orig_file_size;
|
||||
file_blk = orig_file_blk;
|
||||
file_pages = orig_file_pages;
|
||||
file_size = orig_file_size;
|
||||
memcpy(file_phys, orig_file_phys, MAX_PAGES);
|
||||
}
|
||||
cur_page = 0xFF;
|
||||
|
||||
int rc = alloc_set_storage();
|
||||
if (rc < 0) return rc;
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
set_encoding(enc);
|
||||
top_line = 0; viewport_x = 0;
|
||||
top_line = 0;
|
||||
viewport_x = 0;
|
||||
g_active_doc = slot;
|
||||
if (visible) { g_disp_doc = slot; g_first_drawn = 0; }
|
||||
if (visible) {
|
||||
g_disp_doc = slot;
|
||||
g_first_drawn = 0;
|
||||
}
|
||||
|
||||
g_loading = 1;
|
||||
g_last_prog = 0;
|
||||
@@ -743,7 +791,10 @@ static int build_doc(uint8_t slot, uint8_t enc, uint8_t visible)
|
||||
|
||||
/* Зафиксировать конвертацию (на случай обрыва индекса по max_lines до конца
|
||||
* исходника) — иначе g_utf_building остался бы 1 и сломал бы следующую сборку. */
|
||||
if (g_utf_building) { utf_size = file_size; g_utf_building = 0; }
|
||||
if (g_utf_building) {
|
||||
utf_size = file_size;
|
||||
g_utf_building = 0;
|
||||
}
|
||||
|
||||
g_doc[slot].built = 1;
|
||||
doc_save_live(slot);
|
||||
@@ -763,24 +814,30 @@ static void switch_encoding(uint8_t next)
|
||||
uint8_t target = (next == ENC_UTF8) ? DOC_UTF8 : DOC_8BIT;
|
||||
|
||||
if (target == g_active_doc) { /* тот же набор — только ремап */
|
||||
set_encoding(next); g_doc[target].enc = next;
|
||||
set_encoding(next);
|
||||
g_doc[target].enc = next;
|
||||
} else if (g_doc[target].built) { /* набор готов — мгновенный свап */
|
||||
doc_switch(target); g_disp_doc = target;
|
||||
set_encoding(next); g_doc[target].enc = next;
|
||||
doc_switch(target);
|
||||
g_disp_doc = target;
|
||||
set_encoding(next);
|
||||
g_doc[target].enc = next;
|
||||
} else { /* строим набор лениво */
|
||||
doc_save_live(g_active_doc); /* сохранить текущий (позиция и т.п.) */
|
||||
#if WITH_RAW
|
||||
g_ready = 0; render_menu(); /* идёт индексация — прячем F2 */
|
||||
g_ready = 0;
|
||||
render_menu(); /* идёт индексация — прячем F2 */
|
||||
#endif
|
||||
spinner_show(1);
|
||||
int rc = build_doc(target, next, 1); /* visible: прогрессивный показ первого экрана
|
||||
* (progress_tick рисует по текущему виду — MD/RAW) */
|
||||
spinner_show(0);
|
||||
#if WITH_RAW
|
||||
g_ready = 1; render_menu();
|
||||
g_ready = 1;
|
||||
render_menu();
|
||||
#endif
|
||||
if (rc < 0) { /* нет EMM — откат на текущий набор */
|
||||
if (target == DOC_UTF8) g_utf_failed = 1;
|
||||
if (target == DOC_UTF8)
|
||||
g_utf_failed = 1;
|
||||
doc_load_live(g_active_doc);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
#define ENC_CP1251 1
|
||||
#define ENC_KOI8R 2
|
||||
#define ENC_UTF8 3
|
||||
#define ENC_UNSUPPORTED -1 /* UTF16 / UTF32 */
|
||||
#define CONV_MARGIN 4096u /* на сколько байт держать UTF-конвертацию впереди индексатора */
|
||||
|
||||
/* ---- Флаги сегмента индекса (IF_*) — общие для индексатора/кэша/вью ---- */
|
||||
|
||||
@@ -70,12 +70,22 @@ void set_encoding(uint8_t enc)
|
||||
|
||||
/* Самые ходовые строчные русские буквы (о е а и н т с р в л) — их байты
|
||||
* различают 8-битные кодировки по частоте. */
|
||||
static const uint8_t common866 [10] = {0xAE,0xA5,0xA0,0xA8,0xAD,0xE2,0xE1,0xE0,0xA2,0xAB};
|
||||
static const uint8_t common1251[10] = {0xEE,0xE5,0xE0,0xE8,0xED,0xF2,0xF1,0xF0,0xE2,0xEB};
|
||||
static const uint8_t commonkoi [10] = {0xCF,0xC5,0xC1,0xC9,0xCE,0xD4,0xD3,0xD2,0xD7,0xCC};
|
||||
// static const uint8_t common866 [10] = {0xAE,0xA5,0xA0,0xA8,0xAD,0xE2,0xE1,0xE0,0xA2,0xAB};
|
||||
// static const uint8_t common1251[10] = {0xEE,0xE5,0xE0,0xE8,0xED,0xF2,0xF1,0xF0,0xE2,0xEB};
|
||||
// static const uint8_t commonkoi [10] = {0xCF,0xC5,0xC1,0xC9,0xCE,0xD4,0xD3,0xD2,0xD7,0xCC};
|
||||
// static uint8_t in_set10(const uint8_t *s, uint8_t b)
|
||||
// {
|
||||
// for (uint8_t i = 0; i < 10; i++) if (s[i] == b) return 1;
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
/* Проверяем только пять самых популярных символов (о е а и н) */
|
||||
static const uint8_t common866 [5] = {0xAE,0xA5,0xA0,0xA8,0xAD};
|
||||
static const uint8_t common1251[5] = {0xEE,0xE5,0xE0,0xE8,0xED};
|
||||
static const uint8_t commonkoi [5] = {0xCF,0xC5,0xC1,0xC9,0xCE};
|
||||
static uint8_t in_set10(const uint8_t *s, uint8_t b)
|
||||
{
|
||||
for (uint8_t i = 0; i < 10; i++) if (s[i] == b) return 1;
|
||||
for (uint8_t i = 0; i < 5; i++) if (s[i] == b) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -88,7 +98,7 @@ uint8_t detect_encoding(void)
|
||||
return ENC_UTF8;
|
||||
|
||||
uint32_t n = file_size;
|
||||
if (n > 4096u) n = 4096u; /* сэмпл: первые 4 КБ — детекции хватает */
|
||||
if (n > 1024u) n = 1024u; /* сэмпл: первый 1 КБ — детекции хватает */
|
||||
uint8_t utf_ok = 1, has_mb = 0, has_high = 0, cont = 0;
|
||||
uint16_t s866 = 0, s1251 = 0, skoi = 0;
|
||||
|
||||
@@ -102,7 +112,8 @@ uint8_t detect_encoding(void)
|
||||
if (cont) {
|
||||
if ((b & 0xC0) == 0x80) cont--;
|
||||
else { utf_ok = 0; cont = 0; }
|
||||
} else if (b >= 0xC2 && b <= 0xDF) { cont = 1; has_mb = 1; }
|
||||
}
|
||||
else if (b >= 0xC2 && b <= 0xDF) { cont = 1; has_mb = 1; }
|
||||
else if (b >= 0xE0 && b <= 0xEF) { cont = 2; has_mb = 1; }
|
||||
else if (b >= 0xF0 && b <= 0xF4) { cont = 3; has_mb = 1; }
|
||||
else utf_ok = 0; /* битый лид/одиночный континюэйшн */
|
||||
@@ -138,7 +149,10 @@ static uint8_t attr_is_content(uint8_t a)
|
||||
* g_remap (CP1251/KOI8). Без активной таблицы — прямой win_rest. */
|
||||
void win_rest_remap(uint8_t row, uint8_t w, uint8_t page, uint16_t off)
|
||||
{
|
||||
if (!g_remap || w == 0) { win_rest(row, 0, 1, w, page, off); return; }
|
||||
if (!g_remap || w == 0) {
|
||||
win_rest(row, 0, 1, w, page, off);
|
||||
return;
|
||||
}
|
||||
uint8_t buf[SCREEN_W * 2];
|
||||
bank_read(page, off, buf, (uint16_t)w * 2u);
|
||||
for (uint8_t i = 0; i < w; i++) {
|
||||
@@ -225,7 +239,10 @@ static void conv_emit_cp(uint32_t cp)
|
||||
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; }
|
||||
if (utf_sym[i].utf8 == (uint16_t)cp) {
|
||||
conv_put(utf_sym[i].cp866);
|
||||
return;
|
||||
}
|
||||
conv_put('?');
|
||||
}
|
||||
|
||||
@@ -251,7 +268,10 @@ void utf_convert_more(uint32_t target)
|
||||
while (utf_src < n &&
|
||||
(uint32_t)((uint32_t)conv_page * PAGE_SIZE + conv_off) < target) {
|
||||
uint8_t b = (uint8_t)cv_read(utf_src++);
|
||||
if (b < 0x80) { conv_emit_cp(b); continue; }
|
||||
if (b < 0x80) {
|
||||
conv_emit_cp(b);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t cp;
|
||||
uint8_t need;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
/* Геометрия диалога справки (в символьных координатах 80×32). */
|
||||
#define HELP_X 8u /* левая граница рамки */
|
||||
#define HELP_Y 4u /* верхняя граница рамки */
|
||||
#define HELP_Y 3u /* верхняя граница рамки */
|
||||
#define HELP_W 64u /* ширина рамки (включая │) */
|
||||
#define HELP_H 26u /* высота рамки (включая ─) */
|
||||
|
||||
@@ -28,10 +28,13 @@ static void help_line(uint8_t r, const char *s, uint8_t attr)
|
||||
uint8_t x = HELP_X + 1u;
|
||||
uint8_t y = HELP_Y + 1u + r;
|
||||
uint8_t len = (uint8_t)strlen(s);
|
||||
if (len > HELP_W - 2u) len = HELP_W - 2u;
|
||||
|
||||
if (len > HELP_W - 2u)
|
||||
len = HELP_W - 2u;
|
||||
|
||||
bios_set_place(y, x);
|
||||
if (len > 0) bios_writeattr(s, len, attr);
|
||||
if (len > 0)
|
||||
bios_writeattr(s, len, attr);
|
||||
/* place уже продвинут bios_writeattr на len колонок (verified). */
|
||||
if (len < HELP_W - 2u) {
|
||||
bios_fillcharattr(' ', ATTR_HELP_BG, (uint8_t)(HELP_W - 2u - len));
|
||||
@@ -70,24 +73,25 @@ void show_help(void)
|
||||
/* Содержимое (20 внутренних строк) */
|
||||
uint8_t r = 0;
|
||||
help_line(r++, "", ATTR_HELP_BG);
|
||||
help_line(r++, " MDView v0.2 -- Markdown Viewer for Sprinter", ATTR_HELP_HDR);
|
||||
help_line(r++, " (c) 2026 Petrov A.G.", ATTR_HELP_BG);
|
||||
help_line(r++, " MDView v1.0 (a3) -- 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);
|
||||
help_line(r++, " Navigation:", ATTR_HELP_HDR);
|
||||
help_line(r++, " \x18 \x19 Scroll one line up / down", ATTR_HELP_BG);
|
||||
help_line(r++, " PgUp PgDn Scroll one page up / down", ATTR_HELP_BG);
|
||||
help_line(r++, " Home End Jump to beginning / end of document", ATTR_HELP_BG);
|
||||
help_line(r++, " \x1B \x1A Horizontal pan (code blocks/tables)", ATTR_HELP_BG);
|
||||
help_line(r++, " \x1B \x1A Horizontal pan (code blocks/tables/unwrap)", ATTR_HELP_BG);
|
||||
help_line(r++, " Esc F10 Exit", ATTR_HELP_BG);
|
||||
help_line(r++, "", ATTR_HELP_BG);
|
||||
help_line(r++, " Markdown elements:", ATTR_HELP_HDR);
|
||||
help_line(r++, " # ## ### Headings H1-H6", ATTR_HELP_BG);
|
||||
help_line(r++, " **bold** *italic* `code` ~~strike~~", ATTR_HELP_BG);
|
||||
help_line(r++, " > quote ``` ... ``` Fenced code block", ATTR_HELP_BG);
|
||||
help_line(r++, " - * + item 1. 2. Ordered list", ATTR_HELP_BG);
|
||||
help_line(r++, " |----|----| Tables", ATTR_HELP_BG);
|
||||
help_line(r++, " # ## ### Headings H1-H6, **bold**, *italic*,", ATTR_HELP_BG);
|
||||
help_line(r++, " `code`, ``` code ```, ~~strike~~, > quote", ATTR_HELP_BG);
|
||||
help_line(r++, " - * + 1. 2. Ordered list, |----|----| Tables", ATTR_HELP_BG);
|
||||
help_line(r++, "", ATTR_HELP_BG);
|
||||
help_line(r++, " Encoding:", ATTR_HELP_HDR);
|
||||
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++, " 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);
|
||||
|
||||
@@ -187,14 +187,19 @@ uint8_t md_key(uint8_t scan)
|
||||
md_scroll_down(VIEW_H);
|
||||
break;
|
||||
case KEY_HOME:
|
||||
if(top_line != 0 || viewport_x != 0 ) {
|
||||
top_line = 0;
|
||||
viewport_x = 0;
|
||||
draw_viewport_from_cache();
|
||||
}
|
||||
break;
|
||||
case KEY_END:
|
||||
top_line = (n_lines > VIEW_H) ? (uint16_t)(n_lines - VIEW_H) : 0;
|
||||
uint16_t new_top_line = (n_lines > VIEW_H) ? (uint16_t)(n_lines - VIEW_H) : 0;
|
||||
if(top_line != new_top_line || viewport_x != 0 ) {
|
||||
top_line = new_top_line;
|
||||
viewport_x = 0;
|
||||
draw_viewport_from_cache();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h> /* dec8/dec16, cputs */
|
||||
#include <conio.h> /* textattr/gotoxy/wrchar/COLOR */
|
||||
#include <limits.h>
|
||||
#include <bios/text.h> /* bios_fillcharattr/bios_write_until */
|
||||
#include "mdview2.h"
|
||||
|
||||
@@ -32,7 +33,8 @@ static uint8_t spinner_active = 0;
|
||||
/* Продвигает спиннер на один кадр (если включён). */
|
||||
void spinner_tick(void)
|
||||
{
|
||||
if (!spinner_active) return;
|
||||
if (!spinner_active)
|
||||
return;
|
||||
wrchar(SPINNER_COL, 0, spinner_chars[spinner_phase & 3], ATTR_BAR_SPINNER);
|
||||
spinner_phase++;
|
||||
}
|
||||
@@ -73,8 +75,8 @@ void prerender_status(void)
|
||||
void status_encoding(void)
|
||||
{
|
||||
textattr(ATTR_BAR);
|
||||
gotoxy(37, 0);
|
||||
bios_write_until(enc_name(g_encoding), 7, 0);
|
||||
gotoxy(DIV1_X - 10, 0);
|
||||
bios_write_until(enc_name(g_encoding), 8, 0);
|
||||
}
|
||||
|
||||
/* Числовая часть (MD): "L a-b / total" между разделителями + "pct%" справа.
|
||||
@@ -82,14 +84,20 @@ void status_encoding(void)
|
||||
* хром не трогает. */
|
||||
void render_md_status_numbers(void)
|
||||
{
|
||||
static uint16_t local_total = UINT_MAX;
|
||||
static uint16_t local_last = UINT_MAX;
|
||||
static uint8_t local_loading = UCHAR_MAX;
|
||||
|
||||
uint16_t total = drawable_lines();
|
||||
uint16_t last = top_line + VIEW_H;
|
||||
if (last > total)
|
||||
last = total;
|
||||
|
||||
if(local_total != total || local_last != last || local_loading != g_loading) {
|
||||
local_total = total; local_last = last; local_loading = g_loading;
|
||||
textattr(ATTR_BAR);
|
||||
gotoxy(DIV1_X + 1, 0);
|
||||
bios_fillcharattr(' ', ATTR_BAR, DIV2_X - DIV1_X - 1); /* очистить [DIV1_X+1 .. DIV2_X-1] */
|
||||
gotoxy(DIV1_X + 2, 0);
|
||||
bios_fillcharattr(' ', ATTR_BAR, DIV2_X - DIV1_X - 2); /* очистить [DIV1_X+1 .. DIV2_X-1] */
|
||||
gotoxy(DIV1_X + 2, 0);
|
||||
cputs("L ");
|
||||
dec16(top_line + 1);
|
||||
@@ -98,6 +106,7 @@ void render_md_status_numbers(void)
|
||||
cputs(" / ");
|
||||
dec16(total);
|
||||
if (g_loading) cputs("..."); /* ещё грузится */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -109,12 +118,16 @@ void render_full_status(void)
|
||||
}
|
||||
|
||||
void render_percent_progress(uint8_t pct) {
|
||||
gotoxy(DIV2_X + 1, 0);
|
||||
bios_fillcharattr(' ', ATTR_BAR, SCREEN_W - DIV2_X - 1); /* очистить [DIV2_X+1 .. конец] */
|
||||
static uint8_t local_pct = UCHAR_MAX;
|
||||
if (local_pct != pct) {
|
||||
local_pct = pct;
|
||||
gotoxy(DIV2_X + 2, 0);
|
||||
bios_fillcharattr(' ', ATTR_BAR, SCREEN_W - DIV2_X - 2); /* очистить [DIV2_X+1 .. конец] */
|
||||
gotoxy(DIV2_X + 2, 0);
|
||||
dec8(pct);
|
||||
cputs("%");
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_RAW
|
||||
/* RAW-вариант числовой части бара (peer к render_md_status_numbers): метка
|
||||
@@ -141,7 +154,8 @@ void render_menu(void)
|
||||
* только у задействованных и доступных сейчас. */
|
||||
fill_row(MENU_ROW, ATTR_MENU_T);
|
||||
|
||||
char num[3]; num[2] = 0;
|
||||
char num[3];
|
||||
num[2] = 0;
|
||||
for (uint8_t i = 0; i < 9; i++) { /* F1..F9: ' 1'..' 9' */
|
||||
num[0] = ' '; num[1] = (char)('1' + i);
|
||||
put_str_attr((uint8_t)(i * 8), MENU_ROW, num, ATTR_MENU_K);
|
||||
|
||||
@@ -60,6 +60,7 @@ LIBC_C := \
|
||||
libc/stdio/getchar.c \
|
||||
libc/stdio/putchar.c \
|
||||
libc/stdio/puts.c \
|
||||
libc/stdlib/minmax.c \
|
||||
libc/file/file.c \
|
||||
libc/stdio/hex_print.c \
|
||||
libc/stdio/dec_print.c \
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef STDLIB_H
|
||||
#define STDLIB_H
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
int16_t min(int16_t a, int16_t b);
|
||||
int16_t max(int16_t a, int16_t b);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int16_t min(int16_t a, int16_t b) __naked
|
||||
{
|
||||
(void)a; (void)b;
|
||||
__asm
|
||||
ld a, h
|
||||
cp d
|
||||
jr c, min_less
|
||||
jr nz, min_greater
|
||||
ld a, l
|
||||
cp e
|
||||
jr c, min_less
|
||||
min_greater:
|
||||
ret /* DE уже содержит b */
|
||||
min_less:
|
||||
ex de, hl
|
||||
ret
|
||||
__endasm;
|
||||
}
|
||||
|
||||
int16_t max(int16_t a, int16_t b) __naked
|
||||
{
|
||||
(void)a; (void)b;
|
||||
__asm
|
||||
ld a, h
|
||||
cp d
|
||||
jr c, max_less
|
||||
jr nz, max_greater
|
||||
ld a, l
|
||||
cp e
|
||||
jr c, max_less
|
||||
ret /* a >= b, return a in HL */
|
||||
max_less:
|
||||
/* a < b, return b in DE */
|
||||
ret /* DE already contains b */
|
||||
max_greater:
|
||||
/* a > b, return a in HL */
|
||||
ex de, hl
|
||||
ret
|
||||
__endasm;
|
||||
}
|
||||
Reference in New Issue
Block a user