@@ -25,15 +25,10 @@ using ftxui::Screen;
2525
2626class Text : public Node {
2727 public:
28- explicit Text (std::string_view text) : glyphs_(Utf8ToGlyphs(text)) {}
29-
30- void ComputeRequirement () override {
28+ explicit Text (std::string_view text) : glyphs_(Utf8ToGlyphs(text)) {
3129 int max_width = 0 ;
3230 int current_width = 0 ;
3331 int lines_count = 1 ;
34- has_selection_ = false ;
35- selection_rows_.clear ();
36- lines_offsets_.clear ();
3732 lines_offsets_.push_back (0 );
3833
3934 for (size_t i = 0 ; i < glyphs_.size (); ++i) {
@@ -53,12 +48,18 @@ class Text : public Node {
5348 requirement_.min_y = lines_count;
5449 }
5550
51+ void ComputeRequirement () override {
52+ // The requirement was computed once in the constructor. This hook still
53+ // runs before every frame; use it to clear the selection, which Select()
54+ // re-populates while a selection is active.
55+ selection_rows_.clear ();
56+ }
57+
5658 void Select (Selection& selection) override {
5759 if (Box::Intersection (selection.GetBox (), box_).IsEmpty ()) {
5860 return ;
5961 }
6062
61- has_selection_ = true ;
6263 selection_rows_.assign (lines_offsets_.size () - 1 , {-1 , -1 });
6364
6465 for (size_t i = 0 ; i < lines_offsets_.size () - 1 ; ++i) {
@@ -92,43 +93,42 @@ class Text : public Node {
9293 }
9394
9495 void Render (Screen& screen) override {
95- int x = box_.x_min ;
96- int y = box_.y_min ;
97- size_t line = 0 ;
98-
99- if (y > box_.y_max ) {
96+ const auto visible_box = Box::Intersection (screen.stencil , box_);
97+ if (visible_box.IsEmpty ()) {
10098 return ;
10199 }
102100
103- for (const auto & cell : glyphs_) {
104- if (cell == " \n " ) {
105- y++;
106- x = box_.x_min ;
107- line++;
108- if (y > box_.y_max ) {
109- return ;
101+ int y = visible_box.y_min ;
102+
103+ const size_t first_line = visible_box.y_min - box_.y_min ;
104+ const size_t last_line = std::min<size_t >(
105+ visible_box.y_max - box_.y_min + 1 , lines_offsets_.size () - 1 );
106+
107+ for (size_t line = first_line; line < last_line; ++line, ++y) {
108+ int x = box_.x_min ;
109+
110+ for (auto glyph = glyphs_.begin () + lines_offsets_[line];
111+ glyph != glyphs_.end () && *glyph != " \n " ; ++glyph, ++x) {
112+ if (x > box_.x_max ) {
113+ break ;
110114 }
111- continue ;
112- }
113115
114- if (x <= box_. x_max ) {
115- screen. CellAt (x, y). character = cell ;
116+ auto & cell = screen. CellAt (x, y);
117+ cell. character = *glyph ;
116118
117- if (has_selection_ && line < selection_rows_.size ()) {
119+ if (line < selection_rows_.size ()) {
118120 const auto & [sel_start, sel_end] = selection_rows_[line];
119121 if (sel_start != -1 && x >= sel_start && x <= sel_end) {
120- screen.GetSelectionStyle ()(screen. CellAt (x, y) );
122+ screen.GetSelectionStyle ()(cell );
121123 }
122124 }
123125 }
124- x++;
125126 }
126127 }
127128
128129 private:
129130 std::vector<std::string> glyphs_;
130131 std::vector<int > lines_offsets_;
131- bool has_selection_ = false ;
132132 std::vector<std::pair<int , int >> selection_rows_;
133133};
134134
0 commit comments