@@ -23,6 +23,7 @@ struct Internal {
2323 align_y : alignment:: Vertical ,
2424 bounds : Size ,
2525 min_bounds : Size ,
26+ truncated : bool ,
2627 version : text:: Version ,
2728 hint : bool ,
2829 hint_factor : f32 ,
@@ -93,9 +94,15 @@ impl core::text::Paragraph for Paragraph {
9394 ) ;
9495
9596 buffer. set_wrap ( font_system. raw ( ) , text:: to_wrap ( text. wrapping ) ) ;
96- buffer. set_ellipsize (
97+
98+ // First measure WITHOUT ellipsis and WITHOUT height limit to get natural bounds
99+ // (for truncation detection). The height must be unconstrained so we can detect
100+ // when text would need more vertical space than the bounds allow.
101+ buffer. set_ellipsize ( font_system. raw ( ) , cosmic_text:: Ellipsize :: None ) ;
102+ buffer. set_size (
97103 font_system. raw ( ) ,
98- text:: to_ellipsize ( text. ellipsis , text. bounds . height * hint_factor) ,
104+ Some ( text. bounds . width * hint_factor) ,
105+ None ,
99106 ) ;
100107
101108 buffer. set_text (
@@ -106,8 +113,27 @@ impl core::text::Paragraph for Paragraph {
106113 None ,
107114 ) ;
108115
116+ let ( natural_min_bounds, _) = text:: measure ( & buffer) ;
117+ let natural_min_bounds = natural_min_bounds / hint_factor;
118+
119+ // Now restore height limit and set actual ellipsis, then re-measure
120+ buffer. set_size (
121+ font_system. raw ( ) ,
122+ Some ( text. bounds . width * hint_factor) ,
123+ Some ( text. bounds . height * hint_factor) ,
124+ ) ;
125+ buffer. set_ellipsize (
126+ font_system. raw ( ) ,
127+ text:: to_ellipsize ( text. ellipsis , text. bounds . height * hint_factor) ,
128+ ) ;
129+
109130 let min_bounds = text:: align ( & mut buffer, font_system. raw ( ) , text. align_x ) / hint_factor;
110131
132+ let truncated = text. ellipsis != Ellipsis :: None
133+ && ( natural_min_bounds. width > text. bounds . width
134+ || natural_min_bounds. height >= text. bounds . height
135+ || natural_min_bounds != min_bounds) ;
136+
111137 Self ( Arc :: new ( Internal {
112138 buffer,
113139 hint,
@@ -120,6 +146,7 @@ impl core::text::Paragraph for Paragraph {
120146 ellipsis : text. ellipsis ,
121147 bounds : text. bounds ,
122148 min_bounds,
149+ truncated,
123150 version : font_system. version ( ) ,
124151 letter_spacing : text. letter_spacing ,
125152 } ) )
@@ -210,6 +237,7 @@ impl core::text::Paragraph for Paragraph {
210237 ellipsis : text. ellipsis ,
211238 bounds : text. bounds ,
212239 min_bounds,
240+ truncated : false ,
213241 version : font_system. version ( ) ,
214242 letter_spacing : text. letter_spacing ,
215243 } ) )
@@ -220,17 +248,41 @@ impl core::text::Paragraph for Paragraph {
220248
221249 let mut font_system = text:: font_system ( ) . write ( ) . expect ( "Write font system" ) ;
222250
251+ // Measure without ellipsis and without height limit for truncation detection
252+ paragraph
253+ . buffer
254+ . set_ellipsize ( font_system. raw ( ) , cosmic_text:: Ellipsize :: None ) ;
255+ paragraph. buffer . set_size (
256+ font_system. raw ( ) ,
257+ Some ( new_bounds. width * paragraph. hint_factor ) ,
258+ None ,
259+ ) ;
260+ let ( natural_min_bounds, _) = text:: measure ( & paragraph. buffer ) ;
261+ let natural_min_bounds = natural_min_bounds / paragraph. hint_factor ;
262+
263+ // Restore height limit and re-apply ellipsis
223264 paragraph. buffer . set_size (
224265 font_system. raw ( ) ,
225266 Some ( new_bounds. width * paragraph. hint_factor ) ,
226267 Some ( new_bounds. height * paragraph. hint_factor ) ,
227268 ) ;
269+ paragraph. buffer . set_ellipsize (
270+ font_system. raw ( ) ,
271+ text:: to_ellipsize (
272+ paragraph. ellipsis ,
273+ new_bounds. height * paragraph. hint_factor ,
274+ ) ,
275+ ) ;
228276
229277 let min_bounds = text:: align ( & mut paragraph. buffer , font_system. raw ( ) , paragraph. align_x )
230278 / paragraph. hint_factor ;
231279
232280 paragraph. bounds = new_bounds;
233281 paragraph. min_bounds = min_bounds;
282+ paragraph. truncated = paragraph. ellipsis != Ellipsis :: None
283+ && ( natural_min_bounds. width > new_bounds. width
284+ || natural_min_bounds. height >= new_bounds. height
285+ || natural_min_bounds != min_bounds) ;
234286 }
235287
236288 fn compare ( & self , text : Text < ( ) > ) -> core:: text:: Difference {
@@ -310,6 +362,10 @@ impl core::text::Paragraph for Paragraph {
310362 self . internal ( ) . min_bounds
311363 }
312364
365+ fn is_truncated ( & self ) -> bool {
366+ self . internal ( ) . truncated
367+ }
368+
313369 fn hit_test ( & self , point : Point ) -> Option < Hit > {
314370 let cursor = self
315371 . internal ( )
@@ -547,6 +603,7 @@ impl Default for Internal {
547603 align_y : alignment:: Vertical :: Top ,
548604 bounds : Size :: ZERO ,
549605 min_bounds : Size :: ZERO ,
606+ truncated : false ,
550607 version : text:: Version :: default ( ) ,
551608 hint : false ,
552609 hint_factor : 1.0 ,
0 commit comments