use crate::app::{ App, SurfaceTarget };
use crate::platform::{ Platform, Presentation };
use crate::types::{ Color, Rect };
use crate::widget::Element;
use super::AppData;
use super::focus::{ drop_misplaced_focus, follow_focused_id, surface_focused_text_input };
use super::surface::{ SurfaceFocus, SurfaceState };
use crate::draw::{ paint_full, paint_partial };
use crate::draw::damage::compute_interaction_dirty_rects;
pub( crate ) fn draw_frame<A: App, P: Platform>( data: &mut AppData<A, P> ) -> bool
{
let main_view = data.cached_view.as_ref().expect( "view cache populated" );
let overlays = data.cached_overlays.as_ref().expect( "overlays cache populated" );
let main_bg = data.app.background_color();
let main_region = data.app.input_region();
let debug_layout = data.debug_layout;
let platform = &data.platform;
let mut first_commit_now = false;
let mut text_focus_rebuilt: Vec<SurfaceFocus> = Vec::new();
if data.main.configured && data.main.needs_redraw && !data.main.frame_pending
{
if surface_focused_text_input( &data.main )
{
text_focus_rebuilt.push( SurfaceFocus::Main );
}
data.main.needs_redraw = draw_surface(
platform,
&mut data.main,
main_view,
main_bg,
main_region.as_deref(),
None,
debug_layout,
Some( SurfaceFocus::Main ),
);
data.main.last_draw = crate::time::Instant::now();
if !data.first_frame_committed
{
data.first_frame_committed = true;
first_commit_now = true;
}
data.app.on_main_frame_committed();
if std::mem::take( &mut data.main.frame.blur_changed )
{
data.app.on_blur_regions( SurfaceTarget::Main, &data.main.frame.blur_regions );
}
}
for ( _, ss ) in data.secondaries.iter_mut()
{
if !ss.configured || !ss.needs_redraw || ss.frame_pending { continue; }
let view = data.app.secondary_view( ss.physical_width(), ss.physical_height() )
.unwrap_or_else( || crate::spacer().into() );
ss.needs_redraw = draw_surface( platform, ss, &view, main_bg, None, None, debug_layout, None );
ss.frame_pending = false;
ss.last_draw = crate::time::Instant::now();
}
for spec in overlays
{
if let Some( ss ) = data.overlays.get_mut( &spec.id )
{
if !ss.configured || !ss.needs_redraw || ss.frame_pending { continue; }
let focus = SurfaceFocus::Overlay( spec.id );
if surface_focused_text_input( ss )
{
text_focus_rebuilt.push( focus );
}
let bg = Color::rgba( 0.0, 0.0, 0.0, 0.0 );
let opaque = data.app.overlay_opaque_region( spec.id );
ss.needs_redraw = draw_surface(
platform,
ss,
&spec.view,
bg,
spec.input_region.as_deref(),
opaque.as_deref(),
debug_layout,
Some( focus ),
);
ss.last_draw = crate::time::Instant::now();
data.app.on_overlay_frame_committed( spec.id );
if std::mem::take( &mut ss.frame.blur_changed )
{
data.app.on_blur_regions( SurfaceTarget::Overlay( spec.id ), &ss.frame.blur_regions );
}
}
}
for focus in text_focus_rebuilt
{
data.reconcile_text_focus( focus );
}
first_commit_now
}
fn draw_surface<P: Platform, Msg: Clone>(
platform: &P,
ss: &mut SurfaceState<Msg, P::Surface>,
view: &Element<Msg>,
bg: Color,
input_region: Option<&[Rect]>,
opaque_region: Option<&[Rect]>,
debug_layout: bool,
frame: Option<SurfaceFocus>,
) -> bool
{
let scale = ss.scale_factor;
let w = ss.width;
let h = ss.height;
if w == 0 || h == 0 { return false; }
let ( pw, ph ) = ( ss.physical_width(), ss.physical_height() );
let canvas_ready = ss.canvas.as_ref()
.map( |c| c.size() == ( pw, ph ) )
.unwrap_or( false );
let partial_eligible = !ss.content_dirty
&& canvas_ready
&& !ss.frame.widget_rects.is_empty();
let mut partial = None;
if partial_eligible
{
let dirty_rects = compute_interaction_dirty_rects(
&ss.frame.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,
);
if dirty_rects.is_empty() { return false; }
let total: f32 = dirty_rects.iter().map( |r| r.width * r.height ).sum();
if total < pw as f32 * ph as f32 * 0.5 { partial = Some( dirty_rects ); }
}
if !platform.prepare_canvas( &mut ss.platform, &mut ss.canvas, pw, ph, scale ) { return false; }
let damage = match partial
{
Some( dirty_rects ) => paint_partial( ss, view, bg, dirty_rects, pw, ph, scale ),
None =>
{
let precise = platform.precise_damage( &ss.platform );
paint_full( ss, view, bg, debug_layout, precise, pw, ph, scale )
}
};
let focus_moved = follow_focused_id( ss );
drop_misplaced_focus( ss );
if focus_moved { ss.content_dirty = true; }
let presentation = Presentation { damage: &damage, bg, opaque_region, input_region, width: w, height: h, scale, frame };
let Some( canvas ) = ss.canvas.as_mut() else { return focus_moved };
if platform.present( &mut ss.platform, canvas, &presentation )
{
ss.frame_pending = true;
} else {
ss.content_dirty = true;
}
focus_moved
}