mdview2: статус-бар в отдельный модуль, упростить alloc_set_storage
- mdview2_status.c: вынести статус-бар/меню/спиннер из ядра - mdview2.c: убрать retry-цикл в alloc_set_storage (fail-fast вместо ложной устойчивости — при нехватке EMM под индекс контент тоже не влезет) - mdview2.h: дополнить экспортами статус-модуля - mdview2_md.c / mdview2_raw.c: зачистка после расщепления - mdview/mdview.c: переименовать scroll_* → md_scroll_* (симметрия) - docs/fast_ram.md, docs/turboc.txt: добавить справочные доки - examples/mdview2/README.MD, READMEBG.MD: обновить описание Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* mdview2_status.c — статус-бар (строка 0), нижнее меню (строка 31) и спиннер.
|
||||
*
|
||||
* Хром бара АТОМИЗИРОВАН — обновляется по частям, без перерисовки всего бара:
|
||||
* prerender_status() — фон + разделители │ + "MDVIEW" + имя файла (1 раз);
|
||||
* status_encoding() — только поле кодировки (col 37), по F8;
|
||||
* render_md_status_numbers() — числа MD: диапазон строк + % (при скролле);
|
||||
* render_raw_status_numbers()— числа RAW: метка режима + % по байтам;
|
||||
* render_full_status() — encoding + numbers (MD), при смене набора/режима;
|
||||
* render_menu() — строка меню, по смене режима/готовности;
|
||||
* spinner_tick/show — индикатор занятости во время загрузки.
|
||||
* Оба *_status_numbers() самоочищаются по геометрии разделителей (DIV1_X/DIV2_X
|
||||
* в mdview2.h) — фикс. хром не перерисовывается. RAW-позицию даёт raw_pct()
|
||||
* из mdview2_raw.c (raw_top там приватен).
|
||||
*
|
||||
* Раскладка строки 0:
|
||||
* 0 1..6 8 10.. 37..43 45 46..70 71 72..79
|
||||
* . MDVIEW spinner filename encod. │ L a-b / total │ pct%
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h> /* dec8/dec16, cputs */
|
||||
#include <conio.h> /* textattr/gotoxy/wrchar/COLOR */
|
||||
#include <bios/text.h> /* bios_fillcharattr/bios_write_until */
|
||||
#include "mdview2.h"
|
||||
|
||||
/* ---- Спиннер (слот SPINNER_COL в баре) --------------------------- */
|
||||
static const char spinner_chars[4] = { '|', '/', '-', '\\' };
|
||||
static uint8_t spinner_phase = 0;
|
||||
static uint8_t spinner_active = 0;
|
||||
|
||||
/* Продвигает спиннер на один кадр (если включён). */
|
||||
void spinner_tick(void)
|
||||
{
|
||||
if (!spinner_active) return;
|
||||
wrchar(SPINNER_COL, 0, spinner_chars[spinner_phase & 3], ATTR_BAR_SPINNER);
|
||||
spinner_phase++;
|
||||
}
|
||||
|
||||
/* Вкл/выкл спиннер; при выключении гасит его позицию. */
|
||||
void spinner_show(uint8_t on)
|
||||
{
|
||||
spinner_active = on;
|
||||
if (!on) wrchar(SPINNER_COL, 0, ' ', ATTR_BAR);
|
||||
}
|
||||
|
||||
/* ---- Вычисления для чисел статус-бара ----------------------------- */
|
||||
|
||||
/* Число строк, готовых к показу. Во время загрузки последняя эмитированная
|
||||
* строка ещё в g_cells (не зафлашена), поэтому доступны [0..n_lines-2]. */
|
||||
uint16_t drawable_lines(void)
|
||||
{
|
||||
if (g_loading)
|
||||
return (n_lines >= 1) ? (uint16_t)(n_lines - 1) : 0;
|
||||
return n_lines;
|
||||
}
|
||||
|
||||
|
||||
/* ---- Атомарные части статус-бара ---------------------------------- */
|
||||
|
||||
/* Фиксированный хром бара — рисуется ОДИН раз при старте: фон, два
|
||||
* разделителя │, метка "MDVIEW" и имя файла (они не меняются за сессию). */
|
||||
void prerender_status(void)
|
||||
{
|
||||
fill_row(0, ATTR_BAR);
|
||||
wrchar(DIV1_X, 0, 0xB3, ATTR_BAR); /* │ */
|
||||
wrchar(DIV2_X, 0, 0xB3, ATTR_BAR); /* │ */
|
||||
put_str_attr(1, 0, "MDVIEW", ATTR_BAR);
|
||||
put_str_attr(10, 0, filename, ATTR_BAR);
|
||||
}
|
||||
|
||||
/* Поле текущей кодировки (col 37, 7 ячеек). Меняется только по F8. */
|
||||
void status_encoding(void)
|
||||
{
|
||||
textattr(ATTR_BAR);
|
||||
gotoxy(37, 0);
|
||||
bios_write_until(enc_name(g_encoding), 7, 0);
|
||||
}
|
||||
|
||||
/* Числовая часть (MD): "L a-b / total" между разделителями + "pct%" справа.
|
||||
* Перезаписывает ТОЛЬКО области между/после разделителей, сами │ и фикс.
|
||||
* хром не трогает. */
|
||||
void render_md_status_numbers(void)
|
||||
{
|
||||
uint16_t total = drawable_lines();
|
||||
uint16_t last = top_line + VIEW_H;
|
||||
if (last > total)
|
||||
last = total;
|
||||
|
||||
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);
|
||||
cputs("L ");
|
||||
dec16(top_line + 1);
|
||||
cputs("-");
|
||||
dec16(last);
|
||||
cputs(" / ");
|
||||
dec16(total);
|
||||
if (g_loading) cputs("..."); /* ещё грузится */
|
||||
|
||||
}
|
||||
|
||||
/* Полное обновление переменной части (MD): кодировка + числа. */
|
||||
void render_full_status(void)
|
||||
{
|
||||
status_encoding();
|
||||
render_md_status_numbers();
|
||||
}
|
||||
|
||||
void render_percent_progress(uint8_t pct) {
|
||||
gotoxy(DIV2_X + 1, 0);
|
||||
bios_fillcharattr(' ', ATTR_BAR, SCREEN_W - DIV2_X - 1); /* очистить [DIV2_X+1 .. конец] */
|
||||
gotoxy(DIV2_X + 2, 0);
|
||||
dec8(pct);
|
||||
cputs("%");
|
||||
}
|
||||
|
||||
#if WITH_RAW
|
||||
/* RAW-вариант числовой части бара (peer к render_md_status_numbers): метка
|
||||
* режима между разделителями + процент справа. Сам очищает свои области (та же
|
||||
* геометрия DIVn_X), атомарен — не требует общего fill всего бара. Позиция
|
||||
* берётся готовым числом из raw_pct() (raw_top приватен mdview2_raw.c). */
|
||||
void render_raw_status(void)
|
||||
{
|
||||
// uint8_t pct = raw_pct();
|
||||
textattr(ATTR_BAR);
|
||||
gotoxy(DIV1_X + 1, 0);
|
||||
bios_writeattr_until(g_view == VIEW_RAW_WRAP ? " RAW wrap" : " RAW pan",
|
||||
DIV2_X - DIV1_X - 1, ATTR_BAR, 0); /* метка + пад до DIV2_X-1 */
|
||||
}
|
||||
#endif /* WITH_RAW */
|
||||
|
||||
/* ---- Нижнее меню (строка 31) -------------------------------------- */
|
||||
|
||||
void render_menu(void)
|
||||
{
|
||||
/* Блок i = колонка i*8 (8 шириной): 2 поз. НОМЕР клавиши без 'F' (стиль
|
||||
* ATTR_MENU_K, ведущий «чёрный» пробел кроме F10) + 6 поз. ТЕКСТ-функция
|
||||
* (ATTR_MENU_T) сразу за номером. Номера рисуем для ВСЕХ 10 клавиш; текст —
|
||||
* только у задействованных и доступных сейчас. */
|
||||
fill_row(MENU_ROW, ATTR_MENU_T);
|
||||
|
||||
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);
|
||||
}
|
||||
put_str_attr(9 * 8, MENU_ROW, "10", ATTR_MENU_K); /* F10 */
|
||||
|
||||
put_str_attr(0 * 8 + 2, MENU_ROW, "Help", ATTR_MENU_T);
|
||||
#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 */
|
||||
put_str_attr(2 * 8 + 2, MENU_ROW,
|
||||
(g_view == VIEW_RAW_WRAP) ? "UnWrap" : "Wrap", ATTR_MENU_T);
|
||||
#endif
|
||||
if (g_f8_enabled) /* смена кодировки сейчас возможна */
|
||||
put_str_attr(7 * 8 + 2, MENU_ROW, "CodePg", ATTR_MENU_T);
|
||||
put_str_attr(9 * 8 + 2, MENU_ROW, "Exit", ATTR_MENU_T);
|
||||
}
|
||||
Reference in New Issue
Block a user