mirror of
https://github.com/emilk/egui.git
synced 2026-08-31 22:00:03 -04:00
Merge branch 'main' into common-panels
This commit is contained in:
253
crates/egui_demo_app/src/accessibility_inspector.rs
Normal file
253
crates/egui_demo_app/src/accessibility_inspector.rs
Normal file
@@ -0,0 +1,253 @@
|
||||
use accesskit::{Action, ActionRequest, NodeId};
|
||||
use accesskit_consumer::{FilterResult, Node, Tree, TreeChangeHandler};
|
||||
use eframe::epaint::text::TextWrapMode;
|
||||
use egui::collapsing_header::CollapsingState;
|
||||
use egui::{
|
||||
Button, Color32, Context, Event, Frame, FullOutput, Id, Key, KeyboardShortcut, Label,
|
||||
Modifiers, RawInput, RichText, ScrollArea, SidePanel, TopBottomPanel, Ui,
|
||||
};
|
||||
use std::mem;
|
||||
|
||||
/// This [`egui::Plugin`] adds an inspector Panel.
|
||||
///
|
||||
/// It can be opened with the `(Cmd/Ctrl)+Alt+I`. It shows the current AccessKit tree and details
|
||||
/// for the selected node.
|
||||
/// Useful when debugging accessibility issues or trying to understand the structure of the Ui.
|
||||
///
|
||||
/// Add via
|
||||
/// ```
|
||||
/// # use egui_demo_app::accessibility_inspector::AccessibilityInspectorPlugin;
|
||||
/// # let ctx = egui::Context::default();
|
||||
/// ctx.add_plugin(AccessibilityInspectorPlugin::default());
|
||||
/// ```
|
||||
#[derive(Default, Debug)]
|
||||
pub struct AccessibilityInspectorPlugin {
|
||||
pub open: bool,
|
||||
tree: Option<accesskit_consumer::Tree>,
|
||||
selected_node: Option<Id>,
|
||||
queued_action: Option<ActionRequest>,
|
||||
}
|
||||
|
||||
struct ChangeHandler;
|
||||
|
||||
impl TreeChangeHandler for ChangeHandler {
|
||||
fn node_added(&mut self, _node: &Node<'_>) {}
|
||||
|
||||
fn node_updated(&mut self, _old_node: &Node<'_>, _new_node: &Node<'_>) {}
|
||||
|
||||
fn focus_moved(&mut self, _old_node: Option<&Node<'_>>, _new_node: Option<&Node<'_>>) {}
|
||||
|
||||
fn node_removed(&mut self, _node: &Node<'_>) {}
|
||||
}
|
||||
|
||||
impl egui::Plugin for AccessibilityInspectorPlugin {
|
||||
fn debug_name(&self) -> &'static str {
|
||||
"Accessibility Inspector"
|
||||
}
|
||||
|
||||
fn input_hook(&mut self, input: &mut RawInput) {
|
||||
if let Some(queued_action) = self.queued_action.take() {
|
||||
input
|
||||
.events
|
||||
.push(Event::AccessKitActionRequest(queued_action));
|
||||
}
|
||||
}
|
||||
|
||||
fn output_hook(&mut self, output: &mut FullOutput) {
|
||||
if let Some(update) = output.platform_output.accesskit_update.clone() {
|
||||
self.tree = match mem::take(&mut self.tree) {
|
||||
None => {
|
||||
// Create a new tree if it doesn't exist
|
||||
Some(Tree::new(update, true))
|
||||
}
|
||||
Some(mut tree) => {
|
||||
// Update the tree with the latest accesskit data
|
||||
tree.update_and_process_changes(update, &mut ChangeHandler);
|
||||
|
||||
Some(tree)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_begin_pass(&mut self, ctx: &Context) {
|
||||
if ctx.input_mut(|i| {
|
||||
i.consume_shortcut(&KeyboardShortcut::new(
|
||||
Modifiers::COMMAND | Modifiers::ALT,
|
||||
Key::I,
|
||||
))
|
||||
}) {
|
||||
self.open = !self.open;
|
||||
}
|
||||
|
||||
if !self.open {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.enable_accesskit();
|
||||
|
||||
SidePanel::right(Self::id()).show(ctx, |ui| {
|
||||
ui.heading("🔎 AccessKit Inspector");
|
||||
if let Some(selected_node) = self.selected_node {
|
||||
TopBottomPanel::bottom(Self::id().with("details_panel"))
|
||||
.frame(Frame::new())
|
||||
.show_separator_line(false)
|
||||
.show_inside(ui, |ui| {
|
||||
self.selection_ui(ui, selected_node);
|
||||
});
|
||||
}
|
||||
|
||||
ui.style_mut().wrap_mode = Some(TextWrapMode::Truncate);
|
||||
ScrollArea::vertical().show(ui, |ui| {
|
||||
if let Some(tree) = &self.tree {
|
||||
Self::node_ui(ui, &tree.state().root(), &mut self.selected_node);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl AccessibilityInspectorPlugin {
|
||||
fn id() -> Id {
|
||||
Id::new("Accessibility Inspector")
|
||||
}
|
||||
|
||||
fn selection_ui(&mut self, ui: &mut Ui, selected_node: Id) {
|
||||
ui.separator();
|
||||
|
||||
if let Some(tree) = &self.tree
|
||||
&& let Some(node) = tree.state().node_by_id(NodeId::from(selected_node.value()))
|
||||
{
|
||||
let node_response = ui.ctx().read_response(selected_node);
|
||||
|
||||
if let Some(widget_response) = node_response {
|
||||
ui.ctx().debug_painter().debug_rect(
|
||||
widget_response.rect,
|
||||
ui.style_mut().visuals.selection.bg_fill,
|
||||
"",
|
||||
);
|
||||
}
|
||||
|
||||
egui::Grid::new("node_details_grid")
|
||||
.num_columns(2)
|
||||
.show(ui, |ui| {
|
||||
ui.label("Node ID");
|
||||
ui.strong(format!("{selected_node:?}"));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Role");
|
||||
ui.strong(format!("{:?}", node.role()));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Label");
|
||||
ui.add(
|
||||
Label::new(RichText::new(node.label().unwrap_or_default()).strong())
|
||||
.truncate(),
|
||||
);
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Value");
|
||||
ui.add(
|
||||
Label::new(RichText::new(node.value().unwrap_or_default()).strong())
|
||||
.truncate(),
|
||||
);
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Children");
|
||||
ui.label(RichText::new(node.children().len().to_string()).strong());
|
||||
|
||||
ui.end_row();
|
||||
});
|
||||
|
||||
ui.label("Actions");
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
// Iterate through all possible actions via the `Action::n` helper.
|
||||
let mut current_action = 0;
|
||||
let all_actions = std::iter::from_fn(|| {
|
||||
let action = Action::n(current_action);
|
||||
current_action += 1;
|
||||
action
|
||||
});
|
||||
|
||||
for action in all_actions {
|
||||
if node.supports_action(action, &|_node| FilterResult::Include)
|
||||
&& ui.button(format!("{action:?}")).clicked()
|
||||
{
|
||||
let action_request = ActionRequest {
|
||||
target: node.id(),
|
||||
action,
|
||||
data: None,
|
||||
};
|
||||
self.queued_action = Some(action_request);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ui.label("Node not found");
|
||||
}
|
||||
}
|
||||
|
||||
fn node_ui(ui: &mut Ui, node: &Node<'_>, selected_node: &mut Option<Id>) {
|
||||
if node.id() == Self::id().value().into()
|
||||
|| node
|
||||
.value()
|
||||
.as_deref()
|
||||
.is_some_and(|l| l.contains("AccessKit Inspector"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
let label = node
|
||||
.label()
|
||||
.or(node.value())
|
||||
.unwrap_or(node.id().0.to_string());
|
||||
let label = format!("({:?}) {}", node.role(), label);
|
||||
|
||||
// Safety: This is safe since the `accesskit::NodeId` was created from an `egui::Id`.
|
||||
#[expect(unsafe_code)]
|
||||
let egui_node_id = unsafe { Id::from_high_entropy_bits(node.id().0) };
|
||||
|
||||
ui.push_id(node.id(), |ui| {
|
||||
let child_count = node.children().len();
|
||||
let has_children = child_count > 0;
|
||||
let default_open = child_count == 1 && node.role() != accesskit::Role::Label;
|
||||
|
||||
let mut collapsing = CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
egui_node_id.with("ak_collapse"),
|
||||
default_open,
|
||||
);
|
||||
|
||||
let header_response = ui.horizontal(|ui| {
|
||||
let text = if collapsing.is_open() { "⏷" } else { "⏵" };
|
||||
|
||||
if ui
|
||||
.add_visible(has_children, Button::new(text).frame_when_inactive(false))
|
||||
.clicked()
|
||||
{
|
||||
collapsing.set_open(!collapsing.is_open());
|
||||
}
|
||||
let label_response =
|
||||
ui.selectable_value(selected_node, Some(egui_node_id), label.clone());
|
||||
if label_response.hovered() {
|
||||
let widget_response = ui.ctx().read_response(egui_node_id);
|
||||
|
||||
if let Some(widget_response) = widget_response {
|
||||
ui.ctx()
|
||||
.debug_painter()
|
||||
.debug_rect(widget_response.rect, Color32::RED, "");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if has_children {
|
||||
collapsing.show_body_indented(&header_response.response, ui, |ui| {
|
||||
node.children().for_each(|c| {
|
||||
Self::node_ui(ui, &c, selected_node);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
collapsing.store(ui.ctx());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ struct RotatingTriangle {
|
||||
vertex_array: glow::VertexArray,
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)] // we need unsafe code to use glow
|
||||
#[expect(unsafe_code)] // we need unsafe code to use glow
|
||||
impl RotatingTriangle {
|
||||
fn new(gl: &glow::Context) -> Option<Self> {
|
||||
use glow::HasContext as _;
|
||||
@@ -91,10 +91,7 @@ impl RotatingTriangle {
|
||||
let program = gl.create_program().expect("Cannot create program");
|
||||
|
||||
if !shader_version.is_new_shader_interface() {
|
||||
log::warn!(
|
||||
"Custom 3D painting hasn't been ported to {:?}",
|
||||
shader_version
|
||||
);
|
||||
log::warn!("Custom 3D painting hasn't been ported to {shader_version:?}");
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::num::NonZeroU64;
|
||||
|
||||
use eframe::{
|
||||
egui_wgpu::wgpu::util::DeviceExt,
|
||||
egui_wgpu::wgpu::util::DeviceExt as _,
|
||||
egui_wgpu::{self, wgpu},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use egui::{
|
||||
Color32, Painter, Pos2, Rect, Shape, Stroke, Ui, Vec2,
|
||||
containers::{CollapsingHeader, Frame},
|
||||
emath, pos2,
|
||||
widgets::Slider,
|
||||
Color32, Painter, Pos2, Rect, Shape, Stroke, Ui, Vec2,
|
||||
};
|
||||
use std::f32::consts::TAU;
|
||||
|
||||
@@ -73,7 +73,7 @@ impl FractalClock {
|
||||
));
|
||||
} else {
|
||||
ui.label("The fractal_clock clock is not showing the correct time");
|
||||
};
|
||||
}
|
||||
ui.label(format!("Painted line count: {}", self.line_count));
|
||||
|
||||
ui.checkbox(&mut self.paused, "Paused");
|
||||
|
||||
@@ -53,7 +53,7 @@ pub struct HttpApp {
|
||||
impl Default for HttpApp {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
url: "https://raw.githubusercontent.com/emilk/egui/master/README.md".to_owned(),
|
||||
url: "https://raw.githubusercontent.com/emilk/egui/main/README.md".to_owned(),
|
||||
promise: Default::default(),
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ fn ui_url(ui: &mut egui::Ui, frame: &eframe::Frame, url: &mut String) -> bool {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Source code for this example").clicked() {
|
||||
*url = format!(
|
||||
"https://raw.githubusercontent.com/emilk/egui/master/{}",
|
||||
"https://raw.githubusercontent.com/emilk/egui/main/{}",
|
||||
file!()
|
||||
);
|
||||
trigger_fetch = true;
|
||||
@@ -238,7 +238,7 @@ impl ColoredText {
|
||||
pub fn ui(&self, ui: &mut egui::Ui) {
|
||||
let mut job = self.0.clone();
|
||||
job.wrap.max_width = ui.available_width();
|
||||
let galley = ui.fonts(|f| f.layout_job(job));
|
||||
let galley = ui.fonts_mut(|f| f.layout_job(job));
|
||||
ui.add(egui::Label::new(galley).selectable(true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use egui::emath::Rot2;
|
||||
use egui::panel::HorizontalSide;
|
||||
use egui::panel::PanelSide;
|
||||
use egui::panel::VerticalSide;
|
||||
use egui::ImageFit;
|
||||
use egui::Slider;
|
||||
use egui::Vec2;
|
||||
use egui::emath::Rot2;
|
||||
use egui::panel::Side;
|
||||
use egui::panel::TopBottomSide;
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct ImageViewer {
|
||||
@@ -53,31 +52,28 @@ impl Default for ImageViewer {
|
||||
|
||||
impl eframe::App for ImageViewer {
|
||||
fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
|
||||
egui::Panel::new(PanelSide::Horizontal(HorizontalSide::Top), "url bar").show(
|
||||
ctx,
|
||||
|ui| {
|
||||
ui.horizontal_centered(|ui| {
|
||||
let label = ui.label("URI:");
|
||||
ui.text_edit_singleline(&mut self.uri_edit_text)
|
||||
.labelled_by(label.id);
|
||||
if ui.small_button("✔").clicked() {
|
||||
ctx.forget_image(&self.current_uri);
|
||||
self.uri_edit_text = self.uri_edit_text.trim().to_owned();
|
||||
self.current_uri = self.uri_edit_text.clone();
|
||||
};
|
||||
egui::TopBottomPanel::new(TopBottomSide::Top, "url bar").show(ctx, |ui| {
|
||||
ui.horizontal_centered(|ui| {
|
||||
let label = ui.label("URI:");
|
||||
ui.text_edit_singleline(&mut self.uri_edit_text)
|
||||
.labelled_by(label.id);
|
||||
if ui.small_button("✔").clicked() {
|
||||
ctx.forget_image(&self.current_uri);
|
||||
self.uri_edit_text = self.uri_edit_text.trim().to_owned();
|
||||
self.current_uri = self.uri_edit_text.clone();
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if ui.button("file…").clicked() {
|
||||
if let Some(path) = rfd::FileDialog::new().pick_file() {
|
||||
self.uri_edit_text = format!("file://{}", path.display());
|
||||
self.current_uri = self.uri_edit_text.clone();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if ui.button("file…").clicked()
|
||||
&& let Some(path) = rfd::FileDialog::new().pick_file()
|
||||
{
|
||||
self.uri_edit_text = format!("file://{}", path.display());
|
||||
self.current_uri = self.uri_edit_text.clone();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
egui::Panel::new(PanelSide::Vertical(VerticalSide::Left), "controls").show(ctx, |ui| {
|
||||
egui::SidePanel::new(Side::Left, "controls").show(ctx, |ui| {
|
||||
// uv
|
||||
ui.label("UV");
|
||||
ui.add(Slider::new(&mut self.image_options.uv.min.x, 0.0..=1.0).text("min x"));
|
||||
|
||||
@@ -110,7 +110,7 @@ impl BackendPanel {
|
||||
if cfg!(debug_assertions) && cfg!(target_arch = "wasm32") {
|
||||
ui.separator();
|
||||
// For testing panic handling on web:
|
||||
#[allow(clippy::manual_assert)]
|
||||
#[expect(clippy::manual_assert)]
|
||||
if ui.button("panic!()").clicked() {
|
||||
panic!("intentional panic!");
|
||||
}
|
||||
@@ -146,6 +146,10 @@ impl BackendPanel {
|
||||
// builds to keep the noise down in the official demo.
|
||||
if cfg!(debug_assertions) {
|
||||
ui.collapsing("More…", |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Total ui frames:");
|
||||
ui.monospace(ui.ctx().cumulative_frame_nr().to_string());
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Total ui passes:");
|
||||
ui.monospace(ui.ctx().cumulative_pass_nr().to_string());
|
||||
@@ -183,7 +187,7 @@ fn integration_ui(ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
|
||||
ui.label("egui running inside ");
|
||||
ui.hyperlink_to(
|
||||
"eframe",
|
||||
"https://github.com/emilk/egui/tree/master/crates/eframe",
|
||||
"https://github.com/emilk/egui/tree/main/crates/eframe",
|
||||
);
|
||||
ui.label(".");
|
||||
});
|
||||
@@ -333,7 +337,7 @@ fn integration_ui(ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
|
||||
.send_viewport_cmd(egui::ViewportCommand::InnerSize(size));
|
||||
ui.ctx()
|
||||
.send_viewport_cmd(egui::ViewportCommand::Fullscreen(false));
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ impl FrameHistory {
|
||||
}
|
||||
|
||||
fn graph(&self, ui: &mut egui::Ui) -> egui::Response {
|
||||
use egui::{emath, epaint, pos2, vec2, Pos2, Rect, Sense, Shape, Stroke, TextStyle};
|
||||
use egui::{Pos2, Rect, Sense, Shape, Stroke, TextStyle, emath, epaint, pos2, vec2};
|
||||
|
||||
ui.label("egui CPU usage history");
|
||||
|
||||
@@ -90,7 +90,7 @@ impl FrameHistory {
|
||||
));
|
||||
let cpu_usage = to_screen.inverse().transform_pos(pointer_pos).y;
|
||||
let text = format!("{:.1} ms", 1e3 * cpu_usage);
|
||||
shapes.push(ui.fonts(|f| {
|
||||
shapes.push(ui.fonts_mut(|f| {
|
||||
Shape::text(
|
||||
f,
|
||||
pos2(rect.left(), y),
|
||||
|
||||
@@ -10,13 +10,14 @@ pub use wrap_app::{Anchor, WrapApp};
|
||||
|
||||
/// Time of day as seconds since midnight. Used for clock in demo app.
|
||||
pub(crate) fn seconds_since_midnight() -> f64 {
|
||||
use chrono::Timelike;
|
||||
use chrono::Timelike as _;
|
||||
let time = chrono::Local::now().time();
|
||||
time.num_seconds_from_midnight() as f64 + 1e-9 * (time.nanosecond() as f64)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[cfg(feature = "accessibility_inspector")]
|
||||
pub mod accessibility_inspector;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod web;
|
||||
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
|
||||
#![allow(clippy::never_loop)] // False positive
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; // Much faster allocator, can give 20% speedups: https://github.com/emilk/egui/pull/7029
|
||||
|
||||
// When compiling natively:
|
||||
fn main() -> eframe::Result {
|
||||
fn main() {
|
||||
for arg in std::env::args().skip(1) {
|
||||
match arg.as_str() {
|
||||
"--profile" => {
|
||||
@@ -13,7 +16,9 @@ fn main() -> eframe::Result {
|
||||
start_puffin_server();
|
||||
|
||||
#[cfg(not(feature = "puffin"))]
|
||||
panic!("Unknown argument: {arg} - you need to enable the 'puffin' feature to use this.");
|
||||
panic!(
|
||||
"Unknown argument: {arg} - you need to enable the 'puffin' feature to use this."
|
||||
);
|
||||
}
|
||||
|
||||
_ => {
|
||||
@@ -36,7 +41,12 @@ fn main() -> eframe::Result {
|
||||
rust_log += &format!(",{loud_crate}=warn");
|
||||
}
|
||||
}
|
||||
std::env::set_var("RUST_LOG", rust_log);
|
||||
|
||||
// SAFETY: we call this from the main thread without any other threads running.
|
||||
#[expect(unsafe_code)]
|
||||
unsafe {
|
||||
std::env::set_var("RUST_LOG", rust_log);
|
||||
}
|
||||
}
|
||||
|
||||
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
|
||||
@@ -52,11 +62,27 @@ fn main() -> eframe::Result {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
let result = eframe::run_native(
|
||||
"egui demo app",
|
||||
options,
|
||||
Box::new(|cc| Ok(Box::new(egui_demo_app::WrapApp::new(cc)))),
|
||||
)
|
||||
);
|
||||
|
||||
match result {
|
||||
Ok(()) => {}
|
||||
Err(err) => {
|
||||
// This produces a nicer error message than returning the `Result`:
|
||||
print_error_and_exit(&err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_error_and_exit(err: &eframe::Error) -> ! {
|
||||
#![expect(clippy::print_stderr)]
|
||||
#![expect(clippy::exit)]
|
||||
|
||||
eprintln!("Error: {err}");
|
||||
std::process::exit(1)
|
||||
}
|
||||
|
||||
#[cfg(feature = "puffin")]
|
||||
@@ -75,11 +101,11 @@ fn start_puffin_server() {
|
||||
|
||||
// We can store the server if we want, but in this case we just want
|
||||
// it to keep running. Dropping it closes the server, so let's not drop it!
|
||||
#[allow(clippy::mem_forget)]
|
||||
#[expect(clippy::mem_forget)]
|
||||
std::mem::forget(puffin_server);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Failed to start puffin server: {err}");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ pub struct WebHandle {
|
||||
#[wasm_bindgen]
|
||||
impl WebHandle {
|
||||
/// Installs a panic hook, then returns.
|
||||
#[allow(clippy::new_without_default)]
|
||||
#[allow(clippy::new_without_default, clippy::allow_attributes)]
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
// Redirect [`log`] message to `console.log` and friends:
|
||||
|
||||
@@ -80,9 +80,10 @@ impl eframe::App for ColorTestApp {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub enum Anchor {
|
||||
#[default]
|
||||
Demo,
|
||||
|
||||
EasyMarkEditor,
|
||||
@@ -134,13 +135,7 @@ impl std::fmt::Display for Anchor {
|
||||
|
||||
impl From<Anchor> for egui::WidgetText {
|
||||
fn from(value: Anchor) -> Self {
|
||||
Self::RichText(egui::RichText::new(value.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Anchor {
|
||||
fn default() -> Self {
|
||||
Self::Demo
|
||||
Self::from(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +183,11 @@ impl WrapApp {
|
||||
// This gives us image support:
|
||||
egui_extras::install_image_loaders(&cc.egui_ctx);
|
||||
|
||||
#[allow(unused_mut)]
|
||||
#[cfg(feature = "accessibility_inspector")]
|
||||
cc.egui_ctx
|
||||
.add_plugin(crate::accessibility_inspector::AccessibilityInspectorPlugin::default());
|
||||
|
||||
#[allow(unused_mut, clippy::allow_attributes)]
|
||||
let mut slf = Self {
|
||||
state: State::default(),
|
||||
|
||||
@@ -199,10 +198,10 @@ impl WrapApp {
|
||||
};
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
if let Some(storage) = cc.storage {
|
||||
if let Some(state) = eframe::get_value(storage, eframe::APP_KEY) {
|
||||
slf.state = state;
|
||||
}
|
||||
if let Some(storage) = cc.storage
|
||||
&& let Some(state) = eframe::get_value(storage, eframe::APP_KEY)
|
||||
{
|
||||
slf.state = state;
|
||||
}
|
||||
|
||||
slf
|
||||
@@ -384,12 +383,12 @@ impl WrapApp {
|
||||
.clicked()
|
||||
{
|
||||
ui.ctx().memory_mut(|mem| *mem = Default::default());
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
|
||||
if ui.button("Reset everything").clicked() {
|
||||
*cmd = Command::ResetEverything;
|
||||
ui.close_menu();
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -472,10 +471,10 @@ impl WrapApp {
|
||||
let painter =
|
||||
ctx.layer_painter(LayerId::new(Order::Foreground, Id::new("file_drop_target")));
|
||||
|
||||
let screen_rect = ctx.screen_rect();
|
||||
painter.rect_filled(screen_rect, 0.0, Color32::from_black_alpha(192));
|
||||
let content_rect = ctx.content_rect();
|
||||
painter.rect_filled(content_rect, 0.0, Color32::from_black_alpha(192));
|
||||
painter.text(
|
||||
screen_rect.center(),
|
||||
content_rect.center(),
|
||||
Align2::CENTER_CENTER,
|
||||
text,
|
||||
TextStyle::Heading.resolve(&ctx.style()),
|
||||
|
||||
Reference in New Issue
Block a user