/* * 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 #include /* dec8/dec16, cputs */ #include /* textattr/gotoxy/wrchar/COLOR */ #include #include /* 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(DIV1_X - 10, 0); bios_write_until(enc_name(g_encoding), 8, 0); } static uint16_t local_total = UINT_MAX; static uint16_t local_last = UINT_MAX; static uint8_t local_loading = UCHAR_MAX; static uint8_t local_pct = UCHAR_MAX; /* Числовая часть (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; 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 + 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); cputs("-"); dec16(last); cputs(" / "); dec16(total); if (g_loading) cputs("..."); /* ещё грузится */ } } /* Полное обновление переменной части (MD): кодировка + числа. */ void render_full_status(void) { local_loading = UCHAR_MAX; status_encoding(); render_md_status_numbers(); } void render_percent_progress(uint8_t pct) { 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): метка * режима между разделителями + процент справа. Сам очищает свои области (та же * геометрия 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 */ #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) { /* Блок i = колонка i*8 (8 шириной): 2 поз. НОМЕР клавиши без 'F' (стиль * ATTR_MENU_K, ведущий «чёрный» пробел кроме F10) + 6 поз. ТЕКСТ-функция * (ATTR_MENU_T) сразу за номером. Номера рисуем для ВСЕХ 10 клавиш; текст — * только у задействованных и доступных сейчас. */ char num[3]; fill_row(MENU_ROW, ATTR_MENU_T); 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 (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); put_str_attr(9 * 8 + 2, MENU_ROW, "Exit", ATTR_MENU_T); }