From 858f748e7a6ac833a5e8c4870ccd30a6cb0aecce Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Fri, 26 Jun 2026 11:07:07 +0300 Subject: [PATCH] =?UTF-8?q?mdview2=20RAW:=20=D1=87=D0=B8=D0=BD=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B4=D1=83=D0=B1=D0=BB=D0=B8=D0=BA=D0=B0=D1=82=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B8=20=D0=BF=D1=80=D0=B8=20?= =?UTF-8?q?=D1=81=D0=BA=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=20=D1=83=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D1=86=D0=B0=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit В RAW-режиме offset ряда под экраном (raw_bot) велся инкрементально в предположении, что экран всегда полон контентом. После Wrap → конец файла → Unwrap контент кончается в середине экрана, raw_bot рассинхронизировался (raw_scroll_up1 делал raw_bot = raw_prev(raw_bot)), и guard raw_bot >= file_size в scroll-down ложно проходил → дубликат последней строки внизу. Фикс: убран хрупкий raw_bot. raw_scroll_down1 проходит VIEW_H рядов от raw_top и скроллит вниз только если контент реально уходит за нижний край (иначе внизу была бы пустая строка). Кнопка «вниз» теперь работает лишь когда под экраном есть контент; иначе доступна только «вверх». Co-Authored-By: Claude Opus 4.8 --- examples/mdview2/mdview2_raw.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/mdview2/mdview2_raw.c b/examples/mdview2/mdview2_raw.c index 9d742f5..3b087e8 100644 --- a/examples/mdview2/mdview2_raw.c +++ b/examples/mdview2/mdview2_raw.c @@ -20,7 +20,6 @@ #if WITH_RAW /* весь модуль — опционален (mdview_conf.h); при 0 пустой объектник */ static uint32_t raw_top = 0; /* байт-offset верхней строки экрана */ -static uint32_t raw_bot = 0; /* offset ряда сразу ПОД экраном (для прокрутки) */ static uint16_t raw_hpan = 0; /* гориз. сдвиг (только HSCROLL) */ #define HPAN_STEP 8u @@ -190,12 +189,13 @@ void raw_draw(void) uint32_t off = raw_top; for (uint8_t r = 0; r < VIEW_H; r++) off = raw_draw_one(off, (uint8_t)(VIEW_TOP_ROW + r)); - raw_bot = off; /* offset первого ряда НИЖЕ экрана */ } /* Прокрутка на одну строку: аппаратный scroll окна документа + отрисовка - * ОДНОЙ новой строки (как в MD-режиме). raw_bot — offset ряда сразу под - * экраном, ведётся инкрементально. */ + * ОДНОЙ новой строки (как в MD-режиме). Смещение нижнего ряда вычисляется + * проходом VIEW_H рядов от raw_top — без отдельного инкрементального счётчика, + * который рассинхронизировался, когда контент кончается в середине экрана + * (короче окна после wrap→unwrap у конца файла). */ static uint32_t raw_next(uint32_t off) { return (g_view == VIEW_RAW_WRAP) ? raw_next_wrap(off) : raw_next_line(off); @@ -207,9 +207,19 @@ static uint32_t raw_prev(uint32_t off) static void raw_scroll_down1(void) { - if (raw_bot >= file_size) return; /* уже внизу */ + /* Скроллим вниз ТОЛЬКО если контент уходит за нижний край. Проходим VIEW_H + * рядов от raw_top: если контент кончился раньше (экран не полон) — внизу + * была бы пустая строка, не скроллим; если ровно по нижний ряд (off==EOF) — + * ниже пусто, тоже не скроллим. Иначе off = ряд сразу под экраном. */ + uint32_t off = raw_top; + for (uint8_t r = 0; r < VIEW_H; r++) { + if (off >= file_size) return; /* экран не заполнен контентом */ + off = raw_next(off); + } + if (off >= file_size) return; /* контент ровно по экран, ниже пусто */ + scroll(0, VIEW_TOP_ROW, SCREEN_W, VIEW_H, 1, 0); /* содержимое вверх */ - raw_bot = raw_draw_one(raw_bot, (uint8_t)(VIEW_TOP_ROW + VIEW_H - 1)); + raw_draw_one(off, (uint8_t)(VIEW_TOP_ROW + VIEW_H - 1)); /* новый нижний ряд */ raw_top = raw_next(raw_top); } static void raw_scroll_up1(void) @@ -218,7 +228,6 @@ static void raw_scroll_up1(void) uint32_t nt = raw_prev(raw_top); scroll(0, VIEW_TOP_ROW, SCREEN_W, VIEW_H, 2, 0); /* содержимое вниз */ (void)raw_draw_one(nt, VIEW_TOP_ROW); - raw_bot = raw_prev(raw_bot); raw_top = nt; }