Skip to main content

dais_ui/audience/
mod.rs

1//! Audience window — fullscreen slide display and overlays.
2//!
3//! Composes the audience display + visual aid overlays.
4
5pub mod display;
6pub mod overlays;
7
8use std::sync::{Arc, RwLock};
9
10use dais_core::state::PresentationState;
11use dais_document::cache::PageCache;
12use dais_document::page::RenderSize;
13use dais_document::typst_renderer::TextBoxRenderCache;
14
15use self::display::AudienceDisplay;
16use crate::widgets::TextBoxTextureCache;
17
18/// The audience window.
19pub struct AudienceWindow {
20    display: AudienceDisplay,
21    tb_cache: TextBoxRenderCache,
22    tb_texture_cache: TextBoxTextureCache,
23}
24
25impl AudienceWindow {
26    pub fn new() -> Self {
27        Self {
28            display: AudienceDisplay::new(),
29            tb_cache: TextBoxRenderCache::new(),
30            tb_texture_cache: TextBoxTextureCache::default(),
31        }
32    }
33
34    /// Render the audience window content.
35    pub fn show(
36        &mut self,
37        ctx: &egui::Context,
38        shared_state: &Arc<RwLock<PresentationState>>,
39        cache: &mut PageCache,
40        render_size: RenderSize,
41    ) {
42        let state = shared_state.read().map_or_else(
43            |e| {
44                tracing::error!("Failed to read state for audience window: {e}");
45                PresentationState::new(0, Vec::new())
46            },
47            |s| s.clone(),
48        );
49
50        let audience_page = state.audience_page();
51
52        if let Some(page) = cache.get(audience_page, render_size) {
53            let page = page.clone();
54            self.display.update(ctx, &page, audience_page);
55        }
56
57        // Extract zoom region if active
58        let zoom_region = if state.zoom_active {
59            state.zoom_region.as_ref().map(|r| (r.center, r.factor))
60        } else {
61            None
62        };
63
64        egui::CentralPanel::default().frame(egui::Frame::new().fill(egui::Color32::BLACK)).show(
65            ctx,
66            |ui| {
67                let viewport_rect = ui.max_rect();
68                let image_rect = self.display.show(ui, zoom_region);
69                overlays::draw_overlays(
70                    ui,
71                    viewport_rect,
72                    image_rect,
73                    &state,
74                    &mut self.tb_cache,
75                    &mut self.tb_texture_cache,
76                    true,
77                );
78            },
79        );
80    }
81}
82
83impl Default for AudienceWindow {
84    fn default() -> Self {
85        Self::new()
86    }
87}