Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve documentation of eframe, especially for wasm32 #3295

Merged
merged 3 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/eframe/src/epi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ pub trait App {
///
/// Can be used from web to interact or other external context.
///
/// You need to implement this if you want to be able to access the application from JS using [`crate::web::backend::AppRunner`].
/// You need to implement this if you want to be able to access the application from JS using [`crate::WebRunner::app_mut`].
///
/// This is needed because downcasting `Box<dyn App>` -> `Box<dyn Any>` to get &`ConcreteApp` is not simple in current rust.
///
Expand Down
13 changes: 10 additions & 3 deletions crates/eframe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
//! #[derive(Clone)]
//! #[wasm_bindgen]
//! pub struct WebHandle {
//! runner: WebRunner,
//! runner: eframe::WebRunner,
//! }
//!
//! # #[cfg(target_arch = "wasm32")]
Expand All @@ -64,7 +64,7 @@
//! eframe::WebLogger::init(log::LevelFilter::Debug).ok();
//!
//! Self {
//! runner: WebRunner::new(),
//! runner: eframe::WebRunner::new(),
//! }
//! }
//!
Expand All @@ -82,6 +82,7 @@
//!
//! // The following are optional:
//!
//! /// Shut down eframe and clean up resources.
//! #[wasm_bindgen]
//! pub fn destroy(&self) {
//! self.runner.destroy();
Expand Down Expand Up @@ -121,6 +122,7 @@
#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
//!

#![warn(missing_docs)] // let's keep eframe well-documented
#![allow(clippy::needless_doctest_main)]

// Re-export all useful libraries:
Expand Down Expand Up @@ -296,23 +298,28 @@ pub fn run_simple_native(
/// The different problems that can occur when trying to run `eframe`.
#[derive(thiserror::Error, Debug)]
pub enum Error {
/// An error from [`winit`].
#[cfg(not(target_arch = "wasm32"))]
#[error("winit error: {0}")]
Winit(#[from] winit::error::OsError),

/// An error from [`glutin`] when using [`glow`].
#[cfg(all(feature = "glow", not(target_arch = "wasm32")))]
#[error("glutin error: {0}")]
Glutin(#[from] glutin::error::Error),

/// An error from [`glutin`] when using [`glow`].
#[cfg(all(feature = "glow", not(target_arch = "wasm32")))]
#[error("Found no glutin configs matching the template: {0:?}. error: {1:?}")]
#[error("Found no glutin configs matching the template: {0:?}. Error: {1:?}")]
NoGlutinConfigs(glutin::config::ConfigTemplate, Box<dyn std::error::Error>),

/// An error from [`wgpu`].
#[cfg(feature = "wgpu")]
#[error("WGPU error: {0}")]
Wgpu(#[from] egui_wgpu::WgpuError),
}

/// Short for `Result<T, eframe::Error>`.
pub type Result<T> = std::result::Result<T, Error>;

// ---------------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions crates/eframe/src/native/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@ use super::epi_integration::{self, EpiIntegration};

// ----------------------------------------------------------------------------

/// The custom even `eframe` uses with the [`winit`] event loop.
#[derive(Debug)]
pub enum UserEvent {
/// A repaint is requested.
RequestRepaint {
/// When to repaint.
when: Instant,

/// What the frame number was when the repaint was _requested_.
frame_nr: u64,
},

/// A request related to [`accesskit`](https://accesskit.dev/).
#[cfg(feature = "accesskit")]
AccessKitActionRequest(accesskit_winit::ActionRequestEvent),
}
Expand Down
8 changes: 4 additions & 4 deletions crates/eframe/src/web/app_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl AppRunner {
egui_ctx.set_os(egui::os::OperatingSystem::from_user_agent(
&super::user_agent().unwrap_or_default(),
));
super::load_memory(&egui_ctx);
super::storage::load_memory(&egui_ctx);

let theme = system_theme.unwrap_or(web_options.default_theme);
egui_ctx.set_visuals(theme.egui_visuals());
Expand Down Expand Up @@ -140,7 +140,7 @@ impl AppRunner {

pub fn save(&mut self) {
if self.app.persist_egui_memory() {
super::save_memory(&self.egui_ctx);
super::storage::save_memory(&self.egui_ctx);
}
if let Some(storage) = self.frame.storage_mut() {
self.app.save(storage);
Expand Down Expand Up @@ -262,11 +262,11 @@ struct LocalStorage {}

impl epi::Storage for LocalStorage {
fn get_string(&self, key: &str) -> Option<String> {
super::local_storage_get(key)
super::storage::local_storage_get(key)
}

fn set_string(&mut self, key: &str, value: String) {
super::local_storage_set(key, &value);
super::storage::local_storage_set(key, &value);
}

fn flush(&mut self) {}
Expand Down
27 changes: 5 additions & 22 deletions crates/eframe/src/web/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ use super::percent_decode;

/// Data gathered between frames.
#[derive(Default)]
pub struct WebInput {
pub(crate) struct WebInput {
/// Required because we don't get a position on touched
pub latest_touch_pos: Option<egui::Pos2>,

/// Required to maintain a stable touch position for multi-touch gestures.
pub latest_touch_pos_id: Option<egui::TouchId>,

/// The raw input to `egui`.
pub raw: egui::RawInput,
}

Expand All @@ -41,10 +42,8 @@ impl WebInput {

// ----------------------------------------------------------------------------

use std::sync::atomic::Ordering::SeqCst;

/// Stores when to do the next repaint.
pub struct NeedRepaint(Mutex<f64>);
pub(crate) struct NeedRepaint(Mutex<f64>);

impl Default for NeedRepaint {
fn default() -> Self {
Expand Down Expand Up @@ -74,30 +73,14 @@ impl NeedRepaint {
}
}

pub struct IsDestroyed(std::sync::atomic::AtomicBool);

impl Default for IsDestroyed {
fn default() -> Self {
Self(false.into())
}
}

impl IsDestroyed {
pub fn fetch(&self) -> bool {
self.0.load(SeqCst)
}

pub fn set_true(&self) {
self.0.store(true, SeqCst);
}
}

// ----------------------------------------------------------------------------

/// The User-Agent of the user's browser.
pub fn user_agent() -> Option<String> {
web_sys::window()?.navigator().user_agent().ok()
}

/// Get the [`epi::Location`] from the browser.
pub fn web_location() -> epi::Location {
let location = web_sys::window().unwrap().location();

Expand Down
10 changes: 5 additions & 5 deletions crates/eframe/src/web/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn paint_if_needed(runner: &mut AppRunner) -> Result<(), JsValue> {
Ok(())
}

pub fn request_animation_frame(runner_ref: WebRunner) -> Result<(), JsValue> {
pub(crate) fn request_animation_frame(runner_ref: WebRunner) -> Result<(), JsValue> {
let window = web_sys::window().unwrap();
let closure = Closure::once(move || paint_and_schedule(&runner_ref));
window.request_animation_frame(closure.as_ref().unchecked_ref())?;
Expand All @@ -39,7 +39,7 @@ pub fn request_animation_frame(runner_ref: WebRunner) -> Result<(), JsValue> {

// ------------------------------------------------------------------------

pub fn install_document_events(runner_ref: &WebRunner) -> Result<(), JsValue> {
pub(crate) fn install_document_events(runner_ref: &WebRunner) -> Result<(), JsValue> {
let document = web_sys::window().unwrap().document().unwrap();

{
Expand Down Expand Up @@ -189,7 +189,7 @@ pub fn install_document_events(runner_ref: &WebRunner) -> Result<(), JsValue> {
Ok(())
}

pub fn install_window_events(runner_ref: &WebRunner) -> Result<(), JsValue> {
pub(crate) fn install_window_events(runner_ref: &WebRunner) -> Result<(), JsValue> {
let window = web_sys::window().unwrap();

// Save-on-close
Expand All @@ -211,7 +211,7 @@ pub fn install_window_events(runner_ref: &WebRunner) -> Result<(), JsValue> {
Ok(())
}

pub fn install_color_scheme_change_event(runner_ref: &WebRunner) -> Result<(), JsValue> {
pub(crate) fn install_color_scheme_change_event(runner_ref: &WebRunner) -> Result<(), JsValue> {
let window = web_sys::window().unwrap();

if let Some(media_query_list) = prefers_color_scheme_dark(&window)? {
Expand All @@ -230,7 +230,7 @@ pub fn install_color_scheme_change_event(runner_ref: &WebRunner) -> Result<(), J
Ok(())
}

pub fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValue> {
pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValue> {
let canvas = canvas_element(runner_ref.try_lock().unwrap().canvas_id()).unwrap();

{
Expand Down
43 changes: 23 additions & 20 deletions crates/eframe/src/web/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@
#![allow(clippy::missing_errors_doc)] // So many `-> Result<_, JsValue>`

mod app_runner;
pub mod backend;
mod backend;
mod events;
mod input;
mod panic_handler;
pub mod screen_reader;
pub mod storage;
mod text_agent;
mod web_logger;
mod web_runner;

/// Access to the browser screen reader.
pub mod screen_reader;

/// Access to local browser storage.
pub mod storage;

pub(crate) use app_runner::AppRunner;
pub use panic_handler::{PanicHandler, PanicSummary};
pub use web_logger::WebLogger;
Expand All @@ -34,8 +38,6 @@ mod web_painter_wgpu;
pub(crate) type ActiveWebPainter = web_painter_wgpu::WebPainterWgpu;

pub use backend::*;
pub use events::*;
pub use storage::*;

use egui::Vec2;
use wasm_bindgen::prelude::*;
Expand All @@ -59,15 +61,9 @@ pub fn now_sec() -> f64 {
/ 1000.0
}

#[allow(dead_code)]
pub fn screen_size_in_native_points() -> Option<egui::Vec2> {
let window = web_sys::window()?;
Some(egui::vec2(
window.inner_width().ok()?.as_f64()? as f32,
window.inner_height().ok()?.as_f64()? as f32,
))
}

/// The native GUI scale factor, taking into account the browser zoom.
///
/// Corresponds to [`window.devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) in JavaScript.
pub fn native_pixels_per_point() -> f32 {
let pixels_per_point = web_sys::window().unwrap().device_pixel_ratio() as f32;
if pixels_per_point > 0.0 && pixels_per_point.is_finite() {
Expand All @@ -77,6 +73,9 @@ pub fn native_pixels_per_point() -> f32 {
}
}

/// Ask the browser about the preferred system theme.
///
/// `None` means unknown.
pub fn system_theme() -> Option<Theme> {
let dark_mode = prefers_color_scheme_dark(&web_sys::window()?)
.ok()??
Expand All @@ -96,13 +95,13 @@ fn theme_from_dark_mode(dark_mode: bool) -> Theme {
}
}

pub fn canvas_element(canvas_id: &str) -> Option<web_sys::HtmlCanvasElement> {
fn canvas_element(canvas_id: &str) -> Option<web_sys::HtmlCanvasElement> {
let document = web_sys::window()?.document()?;
let canvas = document.get_element_by_id(canvas_id)?;
canvas.dyn_into::<web_sys::HtmlCanvasElement>().ok()
}

pub fn canvas_element_or_die(canvas_id: &str) -> web_sys::HtmlCanvasElement {
fn canvas_element_or_die(canvas_id: &str) -> web_sys::HtmlCanvasElement {
canvas_element(canvas_id)
.unwrap_or_else(|| panic!("Failed to find canvas with id {canvas_id:?}"))
}
Expand All @@ -114,7 +113,7 @@ fn canvas_origin(canvas_id: &str) -> egui::Pos2 {
egui::pos2(rect.left() as f32, rect.top() as f32)
}

pub fn canvas_size_in_points(canvas_id: &str) -> egui::Vec2 {
fn canvas_size_in_points(canvas_id: &str) -> egui::Vec2 {
let canvas = canvas_element(canvas_id).unwrap();
let pixels_per_point = native_pixels_per_point();
egui::vec2(
Expand All @@ -123,7 +122,7 @@ pub fn canvas_size_in_points(canvas_id: &str) -> egui::Vec2 {
)
}

pub fn resize_canvas_to_screen_size(canvas_id: &str, max_size_points: egui::Vec2) -> Option<()> {
fn resize_canvas_to_screen_size(canvas_id: &str, max_size_points: egui::Vec2) -> Option<()> {
let canvas = canvas_element(canvas_id)?;
let parent = canvas.parent_element()?;

Expand Down Expand Up @@ -178,7 +177,8 @@ pub fn resize_canvas_to_screen_size(canvas_id: &str, max_size_points: egui::Vec2

// ----------------------------------------------------------------------------

pub fn set_cursor_icon(cursor: egui::CursorIcon) -> Option<()> {
/// Set the cursor icon.
fn set_cursor_icon(cursor: egui::CursorIcon) -> Option<()> {
let document = web_sys::window()?.document()?;
document
.body()?
Expand All @@ -187,8 +187,9 @@ pub fn set_cursor_icon(cursor: egui::CursorIcon) -> Option<()> {
.ok()
}

/// Set the clipboard text.
#[cfg(web_sys_unstable_apis)]
pub fn set_clipboard_text(s: &str) {
fn set_clipboard_text(s: &str) {
if let Some(window) = web_sys::window() {
if let Some(clipboard) = window.navigator().clipboard() {
let promise = clipboard.write_text(s);
Expand Down Expand Up @@ -245,6 +246,7 @@ fn cursor_web_name(cursor: egui::CursorIcon) -> &'static str {
}
}

/// Open the given url in the browser.
pub fn open_url(url: &str, new_tab: bool) -> Option<()> {
let name = if new_tab { "_blank" } else { "_self" };

Expand All @@ -267,6 +269,7 @@ pub fn location_hash() -> String {
)
}

/// Percent-decodes a string.
pub fn percent_decode(s: &str) -> String {
percent_encoding::percent_decode_str(s)
.decode_utf8_lossy()
Expand Down
3 changes: 3 additions & 0 deletions crates/eframe/src/web/panic_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,19 @@ pub struct PanicSummary {
}

impl PanicSummary {
/// Construct a summary from a panic.
pub fn new(info: &std::panic::PanicInfo<'_>) -> Self {
let message = info.to_string();
let callstack = Error::new().stack();
Self { message, callstack }
}

/// The panic message.
pub fn message(&self) -> String {
self.message.clone()
}

/// The backtrace.
pub fn callstack(&self) -> String {
self.callstack.clone()
}
Expand Down
Loading
Loading