use std::collections::HashMap;
use std::sync::Arc;
use crate::event_loop::SurfaceState;
use crate::render::Canvas;
use crate::types::{ Color, Rect };
use crate::widget::Element;
use super::{ build_draw_ctx, commit_draw_ctx, compute_damage, layout_and_draw, DrawCtx };
use super::chrome::{ draw_fallback_banner, draw_titlebar };
pub( crate ) fn fit_canvas( slot: &mut Option<Canvas>, pw: u32, ph: u32, scale: f32, create: impl FnOnce() -> Canvas ) -> &mut Canvas
{
let canvas = slot.get_or_insert_with( ||
{
let mut c = create();
c.set_dpi_scale( scale );
if let Some( reg ) = crate::theme::build_font_registry()
{
c.set_font_registry( Arc::new( reg ) );
}
c
} );
if canvas.size() != ( pw, ph )
{
canvas.resize( pw, ph );
canvas.set_dpi_scale( scale );
}
canvas
}
pub( crate ) fn paint_detached<Msg: Clone>( canvas: &mut Canvas, view: &Element<Msg>, scroll: &mut HashMap<usize, Canvas>, viewport: &mut HashMap<usize, Canvas> )
{
canvas.clear_clip();
canvas.clear();
let ( pw, ph ) = canvas.size();
let screen_rect = Rect { x: 0.0, y: 0.0, width: pw as f32, height: ph as f32 };
let mut ctx = DrawCtx
{
focused_idx: None,
hovered_idx: None,
pressed_idx: None,
cursor_state: HashMap::new(),
selection_anchor: HashMap::new(),
text_scroll: HashMap::new(),
widget_rects: Vec::new(),
debug_layout: false,
scroll_offsets: HashMap::new(),
scroll_rects: Vec::new(),
scroll_canvases: std::mem::take( scroll ),
viewport_canvases: std::mem::take( viewport ),
viewport_seq: 0,
scroll_navigable_items: HashMap::new(),
scroll_clipped: Vec::new(),
previous_widget_rects: Vec::new(),
accessible_extras: Vec::new(),
live_depth: 0,
origin: ( 0.0, 0.0 ),
blur_regions: Vec::new(),
};
layout_and_draw::<Msg>( view, canvas, screen_rect, &mut ctx, 0 );
*scroll = ctx.scroll_canvases;
*viewport = ctx.viewport_canvases;
}
pub( crate ) fn paint_full<Msg: Clone, S>(
ss: &mut SurfaceState<Msg, S>,
view: &Element<Msg>,
bg: Color,
debug_layout: bool,
precise_damage: bool,
pw: u32,
ph: u32,
scale: f32,
) -> Vec<Rect>
{
let canvas = ss.canvas.as_mut().expect( "canvas prepared" );
canvas.clear_clip();
if bg.a > 0.0 { canvas.fill( bg ); } else { canvas.clear(); }
let ctx = paint_view( ss, view, debug_layout, pw, ph, scale );
let damage = if ss.content_dirty || !precise_damage
{
Vec::new()
} else {
compute_damage(
&ss.frame.widget_rects,
&ctx.widget_rects,
ss.frame.prev_focused,
ss.frame.prev_hovered,
ss.frame.prev_pressed,
ss.focused_idx,
ss.hovered_idx,
ss.gesture.pressed_idx,
pw, ph,
)
};
commit_draw_ctx( &mut ss.frame, ss.focused_idx, ss.hovered_idx, ss.gesture.pressed_idx, ctx );
ss.content_dirty = false;
damage
}
pub( crate ) fn paint_partial<Msg: Clone, S>(
ss: &mut SurfaceState<Msg, S>,
view: &Element<Msg>,
bg: Color,
dirty_rects: Vec<Rect>,
pw: u32,
ph: u32,
scale: f32,
) -> Vec<Rect>
{
let canvas = ss.canvas.as_mut().expect( "canvas prepared" );
canvas.set_clip_rects( &dirty_rects );
if bg.a > 0.0 { canvas.fill( bg ); } else { canvas.clear_rects_transparent( &dirty_rects ); }
let ctx = paint_view( ss, view, false, pw, ph, scale );
if let Some( canvas ) = ss.canvas.as_mut() { canvas.clear_clip(); }
commit_draw_ctx( &mut ss.frame, ss.focused_idx, ss.hovered_idx, ss.gesture.pressed_idx, ctx );
ss.content_dirty = false;
dirty_rects
}
fn paint_view<Msg: Clone, S>(
ss: &mut SurfaceState<Msg, S>,
view: &Element<Msg>,
debug_layout: bool,
pw: u32,
ph: u32,
scale: f32,
) -> DrawCtx<Msg>
{
let canvas = ss.canvas.as_mut().expect( "canvas prepared" );
let sf = scale;
let tb_h = ss.titlebar_height * sf;
let inset = ss.insets;
let osk_h = crate::event_loop::osk::place_osk( &mut ss.osk, pw, ph, sf, inset );
let top = tb_h + inset.top * sf;
let screen_rect = Rect
{
x: inset.left * sf,
y: top,
width: ( pw as f32 - ( inset.left + inset.right ) * sf ).max( 0.0 ),
height: ( ph as f32 - top - osk_h - inset.bottom * sf ).max( 0.0 ),
};
ss.titlebar_close_rect = draw_titlebar( canvas, &ss.titlebar_title, pw, tb_h, sf );
let drawn_focus = ss.focused_idx.filter( |&idx| ss.focus_visible || crate::tree::find_handlers( &ss.frame.widget_rects, idx ).is_some_and( |h| h.is_text_input() ) );
let mut ctx = build_draw_ctx( &mut ss.frame, drawn_focus, ss.hovered_idx, ss.gesture.pressed_idx, debug_layout );
layout_and_draw::<Msg>( view, canvas, screen_rect, &mut ctx, 0 );
if ctx.debug_layout
{
for w in &ctx.widget_rects
{
canvas.stroke_rect( w.rect, Color::rgb( 1.0, 0.0, 0.0 ), 1.5, 0.0 );
}
}
if let Some( panel ) = ss.osk.as_mut() { panel.draw( canvas ); }
if let Some( ref menu ) = ss.context_menu
{
super::draw_context_menu( canvas, menu );
}
draw_fallback_banner( canvas, pw, sf );
ctx
}