diff --git a/firmware/application/apps/ui_text_editor.cpp b/firmware/application/apps/ui_text_editor.cpp index efb9e8e49..db6f0af55 100644 --- a/firmware/application/apps/ui_text_editor.cpp +++ b/firmware/application/apps/ui_text_editor.cpp @@ -72,6 +72,7 @@ void TextViewer::paint(Painter& painter) { paint_state_.first_line = first_line; paint_state_.first_col = first_col; paint_state_.redraw_text = true; + paint_state_.line = UINT32_MAX; // forget old cursor position when overwritten } if (paint_state_.redraw_text) { @@ -221,6 +222,10 @@ void TextViewer::paint_text(Painter& painter, uint32_t line, uint16_t col) { r.top() + (int)i * char_height, clear_width * char_width, char_height}, style().background); + + // if cursor line got overwritten, disable XOR of old cursor when displaying new cursor + if (i == paint_state_.line) + paint_state_.line = UINT32_MAX; } } @@ -228,21 +233,32 @@ void TextViewer::paint_cursor(Painter& painter) { if (!has_focus()) return; - auto draw_cursor = [this, &painter](uint32_t line, uint16_t col, Color c) { - auto r = screen_rect(); - line = line - paint_state_.first_line; - col = col - paint_state_.first_col; - - painter.draw_rectangle( - {(int)col * char_width - 1, - r.top() + (int)line * char_height, - char_width + 1, char_height}, - c); + auto xor_cursor = [this, &painter](int32_t line, uint16_t col) { + int cursor_width = char_width + 1; + int x = (col - paint_state_.first_col) * char_width - 1; + if (x < 0) { // cursor is one pixel narrower when in left column + cursor_width--; + x = 0; + } + int y = screen_rect().top() + (line - paint_state_.first_line) * char_height; + + // Converting one row at a time to reduce buffer size + auto pbuf8 = cursor_.pixel_buffer8; + auto pbuf = cursor_.pixel_buffer; + for (auto col = 0; col < char_height; col++) { + // Annoyingly, read_pixels uses a 24-bit pixel format vs draw_pixels which uses 16-bit + portapack::display.read_pixels({x, y + col, cursor_width, 1}, pbuf8, cursor_width); + for (auto i = 0; i < cursor_width; i++) + pbuf[i] = Color(pbuf8[i].r, pbuf8[i].g, pbuf8[i].b).v ^ 0xFFFF; + portapack::display.draw_pixels({x, y + col, cursor_width, 1}, pbuf, cursor_width); + } }; - // Clear old cursor. CONSIDER: XOR cursor? - draw_cursor(paint_state_.line, paint_state_.col, style().background); - draw_cursor(cursor_.line, cursor_.col, style().foreground); + if (paint_state_.line != UINT32_MAX) // only XOR old cursor if it still appears on the screen + xor_cursor(paint_state_.line, paint_state_.col); + + xor_cursor(cursor_.line, cursor_.col); + paint_state_.line = cursor_.line; paint_state_.col = cursor_.col; } diff --git a/firmware/application/apps/ui_text_editor.hpp b/firmware/application/apps/ui_text_editor.hpp index d543f32d9..7a7bec83b 100644 --- a/firmware/application/apps/ui_text_editor.hpp +++ b/firmware/application/apps/ui_text_editor.hpp @@ -117,6 +117,10 @@ class TextViewer : public Widget { uint32_t line{}; uint16_t col{}; ScrollDirection dir{ScrollDirection::Vertical}; + + // Pixel buffer used for cursor XOR'ing - Max cursor width = Max char width + 1 + ColorRGB888 pixel_buffer8[ui::char_width + 1]{}; + Color pixel_buffer[ui::char_width + 1]{}; } cursor_{}; }; diff --git a/firmware/common/lcd_ili9341.hpp b/firmware/common/lcd_ili9341.hpp index e2f3f0c94..81e502ca7 100644 --- a/firmware/common/lcd_ili9341.hpp +++ b/firmware/common/lcd_ili9341.hpp @@ -100,6 +100,9 @@ class ILI9341 { constexpr ui::Dim height() const { return 320; } constexpr ui::Rect screen_rect() const { return {0, 0, width(), height()}; } + void draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count); + void read_pixels(const ui::Rect r, ui::ColorRGB888* const colors, const size_t count); + private: struct scroll_t { ui::Coord top_area; @@ -109,9 +112,6 @@ class ILI9341 { }; scroll_t scroll_state; - - void draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count); - void read_pixels(const ui::Rect r, ui::ColorRGB888* const colors, const size_t count); }; } /* namespace lcd */