@@ -2264,9 +2264,21 @@ class TextSelection {
22642264};
22652265
22662266class OutputPane : public Widget {
2267+ private:
2268+ struct VisibleRow {
2269+ std::u32string_view text;
2270+ SDL_Point coord;
2271+ SDL_Color color;
2272+ };
2273+
2274+ struct VisibleRowsCache {
2275+ std::vector<VisibleRow> rows;
2276+ bool rebuild { true };
2277+ };
22672278public:
22682279 // Use deque to hold a stable reference.
22692280 std::deque<TextEntry> entries;
2281+ VisibleRowsCache visible_rows_cache;
22702282 Prompt prompt;
22712283 Scrollbar scrollbar;
22722284 // Scrollbar could be made optional.
@@ -2346,7 +2358,7 @@ class OutputPane : public Widget {
23462358 });
23472359
23482360 scrollbar.connect <SDL_UserEvent>(InternalEventType::value_changed, [this ](SDL_UserEvent& e) {
2349- scroll_offset = SignalEmitter::copy_data1_from_userevent<int >(e, 0 );
2361+ set_scroll_offset_from_scrollbar ( SignalEmitter::copy_data1_from_userevent<int >(e, 0 ) );
23502362 });
23512363 }
23522364
@@ -2475,12 +2487,20 @@ class OutputPane : public Widget {
24752487 scrollbar.set_content_size (1 );
24762488 text_selection.reset ();
24772489 emit_text_selection_changed ();
2490+ visible_rows_cache.rebuild = true ;
24782491 }
24792492
24802493 void set_scroll_offset (int v)
24812494 {
24822495 scroll_offset = v;
24832496 scrollbar.scroll_to (v);
2497+ visible_rows_cache.rebuild = true ;
2498+ }
2499+
2500+ void set_scroll_offset_from_scrollbar (int v)
2501+ {
2502+ scroll_offset = v;
2503+ visible_rows_cache.rebuild = true ;
24842504 }
24852505
24862506 void begin_text_selection (const SDL_Point p)
@@ -2519,22 +2539,23 @@ class OutputPane : public Widget {
25192539
25202540 void scroll (ScrollAction sa)
25212541 {
2542+ int v = 0 ;
25222543 switch (sa) {
25232544 case ScrollAction::up:
2524- scroll_offset + = 1 ;
2545+ v = 1 ;
25252546 break ;
25262547 case ScrollAction::down:
2527- scroll_offset -= 1 ;
2548+ v = - 1 ;
25282549 break ;
25292550 case ScrollAction::page_up:
2530- scroll_offset + = rows () / 2 ;
2551+ v = rows () / 2 ;
25312552 break ;
25322553 case ScrollAction::page_down:
2533- scroll_offset -= rows () / 2 ;
2554+ v = - rows () / 2 ;
25342555 break ;
25352556 }
25362557
2537- set_scroll_offset (std::min (std::max (0 , scroll_offset), num_rows - 1 ));
2558+ set_scroll_offset (std::min (std::max (0 , v + scroll_offset), num_rows - 1 ));
25382559 }
25392560
25402561 void resize (const SDL_Rect& rect) override
@@ -2551,6 +2572,8 @@ class OutputPane : public Widget {
25512572 wrap_text (e);
25522573 }
25532574
2575+ visible_rows_cache.rebuild = true ;
2576+
25542577 context.props .set (property::RT_OUTPUT_COLUMNS, columns ());
25552578 context.props .set (property::RT_OUTPUT_ROWS, rows ());
25562579 }
@@ -2604,6 +2627,7 @@ class OutputPane : public Widget {
26042627 entry.wrap_text (font->char_width , content_rect.w );
26052628 num_rows += entry.size ;
26062629 scrollbar.set_content_size (num_rows + prompt.entry .size );
2630+ visible_rows_cache.rebuild = true ;
26072631 }
26082632
26092633 /*
@@ -2709,6 +2733,7 @@ class OutputPane : public Widget {
27092733 }
27102734#endif
27112735
2736+
27122737 void render () override
27132738 {
27142739 // SDL_RenderSetScale(renderer(), 1.2, 1.2);
@@ -2721,20 +2746,31 @@ class OutputPane : public Widget {
27212746 // SDL_SetTextureColorMod(font->texture, 0, 128, 0);
27222747
27232748 render_prompt_and_output ();
2749+
27242750 // SDL_SetTextureColorMod(font->texture, 255, 255, 255);
27252751 prompt.render_cursor (scroll_offset);
27262752 sdl_console::SDL_RenderSetViewport (renderer (), &parent->frame );
27272753 scrollbar.render ();
27282754 // SDL_RenderSetScale(renderer(), 1.0, 1.0);
27292755 }
27302756
2731- void render_prompt_and_output ()
2757+ void build_visible_prompt_and_output_rows ()
27322758 {
2759+ visible_rows_cache.rows .clear ();
2760+ visible_rows_cache.rebuild = false ;
2761+
27332762 const int max_row = rows () + scroll_offset;
27342763 int ypos = content_rect.h ; // Start from the bottom
2735- int row_counter = scroll_offset ;
2764+ int row_counter = 0 ;
27362765
2737- render_entry (prompt.entry , ypos, row_counter, max_row);
2766+ std::vector<VisibleRow> rows;
2767+
2768+ auto append_visible_rows = [this , &ypos, &row_counter, max_row](auto && entry) {
2769+ auto more = get_visible_entry_rows (entry, ypos, row_counter, max_row);
2770+ std::ranges::move (more, std::back_inserter (visible_rows_cache.rows ));
2771+ };
2772+
2773+ append_visible_rows (prompt.entry );
27382774
27392775 if (entries.empty ()) {
27402776 return ;
@@ -2744,14 +2780,15 @@ class OutputPane : public Widget {
27442780 if (row_counter > max_row) {
27452781 break ;
27462782 }
2747- render_entry (entry, ypos, row_counter, max_row);
2783+
2784+ append_visible_rows (entry);
27482785 }
27492786 }
27502787
27512788 // FIXME: Position and rows to render calculations should be done elsewhere.
2752- void render_entry (TextEntry& entry, int & ypos, int & row_counter, int max_row)
2789+ std::vector<VisibleRow> get_visible_entry_rows (TextEntry& entry, int & ypos, int & row_counter, int max_row)
27532790 {
2754- auto scoped_color = font-> set_color (entry. color_opt ) ;
2791+ std::vector<VisibleRow> vrows ;
27552792
27562793 for (auto & row : entry.fragments () | std::views::reverse) {
27572794 row_counter++;
@@ -2765,6 +2802,24 @@ class OutputPane : public Widget {
27652802
27662803 ypos -= font->line_height_with_spacing ();
27672804 row.coord .y = ypos;
2805+
2806+ vrows.push_back ({
2807+ row.text ,
2808+ { row.coord .x , ypos },
2809+ entry.color_opt .value_or (SDL_Color{255 ,255 ,255 ,255 })
2810+ });
2811+ }
2812+ return vrows;
2813+ }
2814+
2815+ void render_prompt_and_output ()
2816+ {
2817+ if (visible_rows_cache.rebuild ) {
2818+ build_visible_prompt_and_output_rows ();
2819+ }
2820+
2821+ for (const auto & row : visible_rows_cache.rows ) {
2822+ font->set_color (row.color );
27682823 font->render (row.text , row.coord .x , row.coord .y );
27692824 }
27702825 }
@@ -3170,15 +3225,15 @@ class SDLConsole_impl : public std::enable_shared_from_this<SDLConsole_impl> {
31703225 handle_tasks ();
31713226
31723227 static auto last_tick = SDL_GetTicks64 ();
3173- constexpr Uint32 shown_min_frame_time = 1000 / 20 ; // 20 fps;
3174- constexpr Uint32 minimized_min_frame_time = 1000 ;
3228+ constexpr Uint32 shown_rate = 1000 / 20 ; // 20 fps;
3229+ constexpr Uint32 minimized_rate = 1000 ;
31753230
31763231 auto current_tick = SDL_GetTicks64 ();
31773232 if (main_window.is_shown )
31783233 {
3179- auto min_frame_time = main_window.is_minimized ? minimized_min_frame_time : shown_min_frame_time ;
3234+ auto rate = main_window.is_minimized ? minimized_rate : shown_rate ;
31803235
3181- if (current_tick - last_tick >= min_frame_time ) {
3236+ if (current_tick - last_tick >= rate ) {
31823237 render_frame ();
31833238 last_tick = current_tick;
31843239 }
0 commit comments