1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! This module contains utilities that does not fit into any other module.

use crate::states::CanvasClickThroughState;
use anyhow::{bail, Error};
use serde::Serialize;
use std::collections::HashMap;
use tauri::{AppHandle, Emitter, Manager, Runtime};

/// Mapping from widget IDs to corresponding data.
pub(crate) type IdMap<T> = HashMap<String, T>;

/// Toast kind of the "show-toast" event.
#[derive(Serialize, Clone)]
#[serde(rename_all = "lowercase")]
enum ToastKind {
    Success,
}

/// Payload of the "show-toast" event.
#[derive(Serialize, Clone)]
struct ShowToastPayload {
    kind: ToastKind,
    message: String,
}

/// Toggle the click-through state of the canvas window.
///
/// This will toggle whether the canvas window ignores cursor events and update the
/// state accordingly. If the canvas is toggled to not click-through, it will try to
/// regain focus automatically. The function will fail if:
///
/// - The canvas window is not found.
/// - Fails to set the canvas to ignore/unignore cursor events.
pub(crate) fn toggle_click_through_state<R: Runtime>(
    app_handle: &AppHandle<R>,
) -> Result<(), Error> {
    let canvas = match app_handle.get_webview_window("canvas") {
        Some(canvas) => canvas,
        None => bail!("Canvas window not found"),
    };

    let click_through_state = &app_handle.state::<CanvasClickThroughState<R>>();
    let mut click_through = click_through_state.0.lock().unwrap();
    let prev_can_click_through = click_through.yes();

    // Try to toggle the click through state
    canvas.set_ignore_cursor_events(!prev_can_click_through)?;
    click_through.toggle();

    // If the canvas is previously click-through, meaning that it is now set to not
    // click-through, try to regain focus to avoid flickering on the first click
    if prev_can_click_through {
        let _ = canvas.set_focus(); // Consume any error because this is not critical
    }

    // Try to let canvas show the toast message
    let _ = app_handle.emit_to(
        "canvas",
        "show-toast",
        ShowToastPayload {
            kind: ToastKind::Success,
            message: format!(
                "Canvas {}.",
                if prev_can_click_through { "floated" } else { "sunk" }
            ),
        },
    );
    Ok(())
}