@@ -18,7 +18,9 @@ use std::collections::{HashMap, VecDeque};
1818
1919use crate :: bloom:: Bloom ;
2020use crate :: kurbo:: { Affine , Insets , Point , Rect , Shape , Size , Vec2 } ;
21- use crate :: piet:: { FontBuilder , RenderContext , Text , TextLayout , TextLayoutBuilder } ;
21+ use crate :: piet:: {
22+ FontBuilder , PietTextLayout , RenderContext , Text , TextLayout , TextLayoutBuilder ,
23+ } ;
2224use crate :: {
2325 BoxConstraints , Color , Command , Data , Env , Event , EventCtx , InternalEvent , InternalLifeCycle ,
2426 LayoutCtx , LifeCycle , LifeCycleCtx , PaintCtx , Region , Target , TimerToken , UpdateCtx , Widget ,
@@ -45,6 +47,8 @@ pub struct WidgetPod<T, W> {
4547 old_data : Option < T > ,
4648 env : Option < Env > ,
4749 inner : W ,
50+ // stashed layout so we don't recompute this when debugging
51+ debug_widget_text : Option < PietTextLayout > ,
4852}
4953
5054/// Generic state for all widgets in the hierarchy.
@@ -141,6 +145,7 @@ impl<T, W: Widget<T>> WidgetPod<T, W> {
141145 old_data : None ,
142146 env : None ,
143147 inner,
148+ debug_widget_text : None ,
144149 }
145150 }
146151
@@ -316,6 +321,10 @@ impl<T, W: Widget<T>> WidgetPod<T, W> {
316321 window_id,
317322 } ;
318323 child. lifecycle ( & mut child_ctx, & hot_changed_event, data, env) ;
324+ // if hot changes and we're showing widget ids, always repaint
325+ if env. get ( Env :: DEBUG_WIDGET_ID ) {
326+ child_ctx. request_paint ( ) ;
327+ }
319328 return true ;
320329 }
321330 false
@@ -335,25 +344,32 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
335344 /// [`paint`]: trait.Widget.html#tymethod.paint
336345 /// [`paint_with_offset`]: #method.paint_with_offset
337346 pub fn paint ( & mut self , ctx : & mut PaintCtx , data : & T , env : & Env ) {
347+ // we need to do this before we borrow from self
348+ if env. get ( Env :: DEBUG_WIDGET_ID ) {
349+ self . make_widget_id_layout_if_needed ( self . state . id , ctx, env) ;
350+ }
351+
338352 let mut inner_ctx = PaintCtx {
339353 render_ctx : ctx. render_ctx ,
340354 window_id : ctx. window_id ,
341355 z_ops : Vec :: new ( ) ,
342356 region : ctx. region . clone ( ) ,
343357 base_state : & self . state ,
344358 focus_widget : ctx. focus_widget ,
359+ depth : ctx. depth ,
345360 } ;
346361 self . inner . paint ( & mut inner_ctx, data, env) ;
347- ctx. z_ops . append ( & mut inner_ctx. z_ops ) ;
348362
349- if env. get ( Env :: DEBUG_PAINT ) {
363+ let debug_layout = env. get ( Env :: DEBUG_PAINT ) ;
364+ let debug_ids = env. get ( Env :: DEBUG_WIDGET_ID ) && inner_ctx. is_hot ( ) ;
365+
366+ if debug_layout {
350367 self . debug_paint_layout_bounds ( & mut inner_ctx, env) ;
351368 }
352-
353- if env. get ( Env :: DEBUG_WIDGET_ID ) {
369+ if debug_ids {
354370 self . debug_paint_widget_ids ( & mut inner_ctx, env) ;
355371 }
356-
372+ ctx . z_ops . append ( & mut inner_ctx . z_ops ) ;
357373 self . state . invalid = Region :: EMPTY ;
358374 }
359375
@@ -392,30 +408,48 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
392408 } ) ;
393409 }
394410
411+ fn make_widget_id_layout_if_needed ( & mut self , id : WidgetId , ctx : & mut PaintCtx , env : & Env ) {
412+ if self . debug_widget_text . is_none ( ) {
413+ let font = ctx
414+ . text ( )
415+ . new_font_by_name ( env. get ( crate :: theme:: FONT_NAME ) , 10.0 )
416+ . build ( )
417+ . unwrap ( ) ;
418+ let id_string = id. to_raw ( ) . to_string ( ) ;
419+ self . debug_widget_text = ctx
420+ . text ( )
421+ . new_text_layout ( & font, & id_string, f64:: INFINITY )
422+ . build ( )
423+ . ok ( ) ;
424+ }
425+ }
426+
395427 fn debug_paint_widget_ids ( & self , ctx : & mut PaintCtx , env : & Env ) {
396- let font = ctx
397- . text ( )
398- . new_font_by_name ( env. get ( crate :: theme:: FONT_NAME ) , 10.0 )
399- . build ( )
400- . unwrap ( ) ;
401- let id_string = ctx. widget_id ( ) . to_raw ( ) . to_string ( ) ;
402- let text = ctx
403- . text ( )
404- . new_text_layout ( & font, & id_string, f64:: INFINITY )
405- . build ( )
406- . unwrap ( ) ;
407- let text_size = Size :: new ( text. width ( ) , 10.0 ) ;
408- let origin = ctx. size ( ) . to_vec2 ( ) - text_size. to_vec2 ( ) ;
409- let origin = Point :: new ( origin. x . max ( 0.0 ) , origin. y . max ( 0.0 ) ) ;
410-
411- let text_pos = origin + Vec2 :: new ( 0. , 8.0 ) ;
412- ctx. fill ( Rect :: from_origin_size ( origin, text_size) , & Color :: WHITE ) ;
413- ctx. stroke (
414- Rect :: from_origin_size ( origin, text_size) ,
415- & Color :: rgb ( 1.0 , 0. , 0. ) ,
416- 1.0 ,
417- ) ;
418- ctx. draw_text ( & text, text_pos, & Color :: BLACK ) ;
428+ // we clone because we need to move it for paint_with_z_index
429+ let text = self . debug_widget_text . clone ( ) ;
430+ if let Some ( text) = text {
431+ let text_size = Size :: new ( text. width ( ) , 10.0 ) ;
432+ let origin = ctx. size ( ) . to_vec2 ( ) - text_size. to_vec2 ( ) ;
433+ let border_color = env. get_debug_color ( ctx. widget_id ( ) . to_raw ( ) ) ;
434+ self . debug_paint_layout_bounds ( ctx, env) ;
435+
436+ ctx. paint_with_z_index ( ctx. depth ( ) , move |ctx| {
437+ let origin = Point :: new ( origin. x . max ( 0.0 ) , origin. y . max ( 0.0 ) ) ;
438+
439+ let text_pos = origin + Vec2 :: new ( 0. , 8.0 ) ;
440+ let text_rect = Rect :: from_origin_size ( origin, text_size) ;
441+
442+ ctx. fill ( text_rect, & border_color) ;
443+ let ( r, g, b, _) = border_color. as_rgba_u8 ( ) ;
444+ let avg = ( r as u32 + g as u32 + b as u32 ) / 3 ;
445+ let text_color = if avg < 128 {
446+ Color :: WHITE
447+ } else {
448+ Color :: BLACK
449+ } ;
450+ ctx. draw_text ( & text, text_pos, & text_color) ;
451+ } )
452+ }
419453 }
420454
421455 fn debug_paint_layout_bounds ( & self , ctx : & mut PaintCtx , env : & Env ) {
@@ -738,6 +772,7 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
738772
739773 true
740774 }
775+ //NOTE: this is not sent here, but from the special set_hot_state method
741776 LifeCycle :: HotChanged ( _) => false ,
742777 LifeCycle :: FocusChanged ( _) => {
743778 // We are a descendant of a widget that has/had focus.
0 commit comments