Improve web demo for mobile (#1556)
`egui_demo_app/lib`: add "About egui" window, and improve mobile layout This makes the app responsive, removing the side bars on mobile and turning them into drop-down menus instead.
This commit is contained in:
parent
078be52ff8
commit
32b4781da2
11 changed files with 371 additions and 169 deletions
|
@ -212,22 +212,22 @@ function makeMutClosure(arg0, arg1, dtor, f) {
|
|||
|
||||
return real;
|
||||
}
|
||||
function __wbg_adapter_28(arg0, arg1, arg2) {
|
||||
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h25f84cc60118f837(arg0, arg1, addHeapObject(arg2));
|
||||
function __wbg_adapter_28(arg0, arg1) {
|
||||
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h0fd05312e5982956(arg0, arg1);
|
||||
}
|
||||
|
||||
function __wbg_adapter_31(arg0, arg1) {
|
||||
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__ha2c5a72e5c948e73(arg0, arg1);
|
||||
function __wbg_adapter_31(arg0, arg1, arg2) {
|
||||
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h67fa6b1a144b91cc(arg0, arg1, addHeapObject(arg2));
|
||||
}
|
||||
|
||||
function __wbg_adapter_34(arg0, arg1, arg2) {
|
||||
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h25f84cc60118f837(arg0, arg1, addHeapObject(arg2));
|
||||
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h67fa6b1a144b91cc(arg0, arg1, addHeapObject(arg2));
|
||||
}
|
||||
|
||||
function __wbg_adapter_37(arg0, arg1) {
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hded0e2f18c7b6997(retptr, arg0, arg1);
|
||||
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__ha165bf8c3b3285b8(retptr, arg0, arg1);
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
if (r1) {
|
||||
|
@ -1537,32 +1537,32 @@ async function init(input) {
|
|||
const ret = wasm.memory;
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper2300 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 831, __wbg_adapter_28);
|
||||
imports.wbg.__wbindgen_closure_wrapper1269 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 371, __wbg_adapter_28);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper2301 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 831, __wbg_adapter_31);
|
||||
imports.wbg.__wbindgen_closure_wrapper1270 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 371, __wbg_adapter_31);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper2302 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 831, __wbg_adapter_34);
|
||||
imports.wbg.__wbindgen_closure_wrapper1271 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 371, __wbg_adapter_34);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper2311 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 831, __wbg_adapter_37);
|
||||
imports.wbg.__wbindgen_closure_wrapper1280 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 371, __wbg_adapter_37);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper2544 = function(arg0, arg1, arg2) {
|
||||
const ret = makeClosure(arg0, arg1, 981, __wbg_adapter_40);
|
||||
imports.wbg.__wbindgen_closure_wrapper1513 = function(arg0, arg1, arg2) {
|
||||
const ret = makeClosure(arg0, arg1, 524, __wbg_adapter_40);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper2545 = function(arg0, arg1, arg2) {
|
||||
const ret = makeClosure(arg0, arg1, 981, __wbg_adapter_43);
|
||||
imports.wbg.__wbindgen_closure_wrapper1514 = function(arg0, arg1, arg2) {
|
||||
const ret = makeClosure(arg0, arg1, 524, __wbg_adapter_43);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper2583 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 1001, __wbg_adapter_46);
|
||||
imports.wbg.__wbindgen_closure_wrapper1552 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 544, __wbg_adapter_46);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
|
||||
|
|
Binary file not shown.
|
@ -177,7 +177,7 @@
|
|||
//! This means it is responsibility of the egui user to store the state (`value`) so that it persists between frames.
|
||||
//!
|
||||
//! It can be useful to read the code for the toggle switch example widget to get a better understanding
|
||||
//! of how egui works: <https://github.com/emilk/egui/blob/master/egui_demo_lib/src/apps/demo/toggle_switch.rs>.
|
||||
//! of how egui works: <https://github.com/emilk/egui/blob/master/egui_demo_lib/src/demo/toggle_switch.rs>.
|
||||
//!
|
||||
//! Read more about the pros and cons of immediate mode at <https://github.com/emilk/egui#why-immediate-mode>.
|
||||
//!
|
||||
|
|
|
@ -78,11 +78,6 @@ impl BackendPanel {
|
|||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
||||
egui::trace!(ui);
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.heading("💻 Backend");
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
||||
self.integration_ui(ui, frame);
|
||||
|
||||
|
@ -132,20 +127,11 @@ impl BackendPanel {
|
|||
}
|
||||
|
||||
fn integration_ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
||||
if frame.is_web() {
|
||||
ui.label("egui is an immediate mode GUI written in Rust, compiled to WebAssembly, rendered with WebGL.");
|
||||
ui.label(
|
||||
"Everything you see is rendered as textured triangles. There is no DOM and no HTML elements. \
|
||||
This is the web page, reinvented with game tech.");
|
||||
ui.hyperlink("https://github.com/emilk/egui");
|
||||
|
||||
ui.separator();
|
||||
}
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.label("egui running inside ");
|
||||
ui.hyperlink_to("eframe", "https://github.com/emilk/egui/tree/master/eframe");
|
||||
ui.label(".");
|
||||
});
|
||||
|
||||
if let Some(web_info) = &frame.info().web_info {
|
||||
|
@ -169,7 +155,9 @@ impl BackendPanel {
|
|||
.on_hover_text("Resize the window to be small like a phone.")
|
||||
.clicked()
|
||||
{
|
||||
frame.set_window_size(egui::Vec2::new(375.0, 812.0)); // iPhone 12 mini
|
||||
// frame.set_window_size(egui::Vec2::new(375.0, 812.0)); // iPhone 12 mini
|
||||
frame.set_window_size(egui::Vec2::new(375.0, 667.0)); // iPhone SE 2nd gen
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,12 +49,14 @@ impl FrameHistory {
|
|||
);
|
||||
egui::warn_if_debug_build(ui);
|
||||
|
||||
if !cfg!(target_arch = "wasm32") {
|
||||
egui::CollapsingHeader::new("📊 CPU usage history")
|
||||
.default_open(false)
|
||||
.show(ui, |ui| {
|
||||
self.graph(ui);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn graph(&mut self, ui: &mut egui::Ui) -> egui::Response {
|
||||
use egui::*;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use egui_demo_lib::is_mobile;
|
||||
use egui_glow::glow;
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -181,47 +182,30 @@ impl eframe::App for WrapApp {
|
|||
|
||||
egui::TopBottomPanel::top("wrap_app_top_bar").show(ctx, |ui| {
|
||||
egui::trace!(ui);
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.visuals_mut().button_frame = false;
|
||||
self.bar_contents(ui, frame);
|
||||
});
|
||||
});
|
||||
|
||||
self.state.backend_panel.update(ctx, frame);
|
||||
|
||||
if self.state.backend_panel.open || ctx.memory().everything_is_visible() {
|
||||
egui::SidePanel::left("backend_panel").show(ctx, |ui| {
|
||||
self.state.backend_panel.ui(ui, frame);
|
||||
if !is_mobile(ctx)
|
||||
&& (self.state.backend_panel.open || ctx.memory().everything_is_visible())
|
||||
{
|
||||
egui::SidePanel::left("backend_panel")
|
||||
.resizable(false)
|
||||
.show(ctx, |ui| {
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.heading("💻 Backend");
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
if ui
|
||||
.button("Reset egui")
|
||||
.on_hover_text("Forget scroll, positions, sizes etc")
|
||||
.clicked()
|
||||
{
|
||||
*ui.ctx().memory() = Default::default();
|
||||
}
|
||||
|
||||
if ui.button("Reset everything").clicked() {
|
||||
self.state = Default::default();
|
||||
*ui.ctx().memory() = Default::default();
|
||||
}
|
||||
});
|
||||
self.backend_panel_contents(ui, frame);
|
||||
});
|
||||
}
|
||||
|
||||
let mut found_anchor = false;
|
||||
|
||||
let selected_anchor = self.state.selected_anchor.clone();
|
||||
for (_name, anchor, app) in self.apps_iter_mut() {
|
||||
if anchor == selected_anchor || ctx.memory().everything_is_visible() {
|
||||
app.update(ctx, frame);
|
||||
found_anchor = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !found_anchor {
|
||||
self.state.selected_anchor = "demo".into();
|
||||
}
|
||||
self.show_selected_app(ctx, frame);
|
||||
|
||||
self.state.backend_panel.end_of_frame(ctx);
|
||||
|
||||
|
@ -234,13 +218,57 @@ impl eframe::App for WrapApp {
|
|||
}
|
||||
|
||||
impl WrapApp {
|
||||
fn backend_panel_contents(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
||||
self.state.backend_panel.ui(ui, frame);
|
||||
|
||||
ui.separator();
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
if ui
|
||||
.button("Reset egui")
|
||||
.on_hover_text("Forget scroll, positions, sizes etc")
|
||||
.clicked()
|
||||
{
|
||||
*ui.ctx().memory() = Default::default();
|
||||
ui.close_menu();
|
||||
}
|
||||
|
||||
if ui.button("Reset everything").clicked() {
|
||||
self.state = Default::default();
|
||||
*ui.ctx().memory() = Default::default();
|
||||
ui.close_menu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn show_selected_app(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
let mut found_anchor = false;
|
||||
let selected_anchor = self.state.selected_anchor.clone();
|
||||
for (_name, anchor, app) in self.apps_iter_mut() {
|
||||
if anchor == selected_anchor || ctx.memory().everything_is_visible() {
|
||||
app.update(ctx, frame);
|
||||
found_anchor = true;
|
||||
}
|
||||
}
|
||||
if !found_anchor {
|
||||
self.state.selected_anchor = "demo".into();
|
||||
}
|
||||
}
|
||||
|
||||
fn bar_contents(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
||||
// A menu-bar is a horizontal layout with some special styles applied.
|
||||
// egui::menu::bar(ui, |ui| {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
egui::widgets::global_dark_light_mode_switch(ui);
|
||||
|
||||
ui.checkbox(&mut self.state.backend_panel.open, "💻 Backend");
|
||||
ui.separator();
|
||||
|
||||
if is_mobile(ui.ctx()) {
|
||||
ui.menu_button("💻 Backend", |ui| {
|
||||
ui.set_style(ui.ctx().style()); // ignore the "menu" style set by `menu_button`.
|
||||
self.backend_panel_contents(ui, frame);
|
||||
});
|
||||
} else {
|
||||
ui.toggle_value(&mut self.state.backend_panel.open, "💻 Backend");
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
|
||||
let mut selected_anchor = self.state.selected_anchor.clone();
|
||||
|
@ -272,7 +300,6 @@ impl WrapApp {
|
|||
|
||||
egui::warn_if_debug_build(ui);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn ui_file_drag_and_drop(&mut self, ctx: &egui::Context) {
|
||||
|
|
94
egui_demo_lib/src/demo/about.rs
Normal file
94
egui_demo_lib/src/demo/about.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "serde", serde(default))]
|
||||
pub struct About {}
|
||||
|
||||
impl super::Demo for About {
|
||||
fn name(&self) -> &'static str {
|
||||
"About egui"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name())
|
||||
.default_width(320.0)
|
||||
.open(open)
|
||||
.show(ctx, |ui| {
|
||||
use super::View as _;
|
||||
self.ui(ui);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl super::View for About {
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
use egui::special_emojis::{OS_APPLE, OS_LINUX, OS_WINDOWS};
|
||||
|
||||
ui.heading("egui");
|
||||
ui.label(format!(
|
||||
"egui is an immediate mode GUI library written in Rust. egui runs both on the web and natively on {}{}{}. \
|
||||
On the web it is compiled to WebAssembly and rendered with WebGL.{}",
|
||||
OS_APPLE, OS_LINUX, OS_WINDOWS,
|
||||
if cfg!(target_arch = "wasm32") {
|
||||
" Everything you see is rendered as textured triangles. There is no DOM, HTML, JS or CSS. Just Rust."
|
||||
} else {""}
|
||||
));
|
||||
ui.label("egui is designed to be easy to use, portable, and fast.");
|
||||
|
||||
ui.add_space(12.0); // ui.separator();
|
||||
ui.heading("Immediate mode");
|
||||
about_immediate_mode(ui);
|
||||
|
||||
ui.add_space(12.0); // ui.separator();
|
||||
ui.heading("Links");
|
||||
links(ui);
|
||||
}
|
||||
}
|
||||
|
||||
fn about_immediate_mode(ui: &mut egui::Ui) {
|
||||
use crate::syntax_highlighting::code_view_ui;
|
||||
ui.style_mut().spacing.interact_size.y = 0.0; // hack to make `horizontal_wrapped` work better with text.
|
||||
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.label("Immediate mode is a GUI paradigm that lets you create a GUI with less code and simpler control flow. For example, this is how you create a ");
|
||||
let _ = ui.small_button("button");
|
||||
ui.label(" in egui:");
|
||||
});
|
||||
|
||||
ui.add_space(8.0);
|
||||
code_view_ui(
|
||||
ui,
|
||||
r#"
|
||||
if ui.button("Save").clicked() {
|
||||
my_state.save();
|
||||
}"#
|
||||
.trim_start_matches('\n'),
|
||||
);
|
||||
ui.add_space(8.0);
|
||||
|
||||
ui.label("Note how there are no callbacks or messages, and no button state to store.");
|
||||
|
||||
ui.label("Immediate mode has its roots in gaming, where everything on the screen is painted at the display refresh rate, i.e. at 60+ frames per second. \
|
||||
In immediate mode GUIs, the entire interface is layed out and painted at the same high rate. \
|
||||
This makes immediate mode GUIs especially well suited for highly interactive applications.");
|
||||
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.label("More about immediate mode ");
|
||||
ui.hyperlink_to("here", "https://github.com/emilk/egui#why-immediate-mode");
|
||||
ui.label(".");
|
||||
});
|
||||
}
|
||||
|
||||
fn links(ui: &mut egui::Ui) {
|
||||
use egui::special_emojis::{GITHUB, TWITTER};
|
||||
ui.hyperlink_to(
|
||||
format!("{} egui on GitHub", GITHUB),
|
||||
"https://github.com/emilk/egui",
|
||||
);
|
||||
ui.hyperlink_to(
|
||||
format!("{} @ernerfeldt", TWITTER),
|
||||
"https://twitter.com/ernerfeldt",
|
||||
);
|
||||
ui.hyperlink_to("egui documentation", "https://docs.rs/egui/");
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
use super::Demo;
|
||||
use egui::{Context, ScrollArea, Ui};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use super::About;
|
||||
use super::Demo;
|
||||
use super::View;
|
||||
use crate::is_mobile;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
|
@ -56,7 +60,7 @@ impl Demos {
|
|||
let Self { demos, open } = self;
|
||||
for demo in demos {
|
||||
let mut is_open = open.contains(demo.name());
|
||||
ui.checkbox(&mut is_open, demo.name());
|
||||
ui.toggle_value(&mut is_open, demo.name());
|
||||
set_open(open, demo.name(), is_open);
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +115,7 @@ impl Tests {
|
|||
let Self { demos, open } = self;
|
||||
for demo in demos {
|
||||
let mut is_open = open.contains(demo.name());
|
||||
ui.checkbox(&mut is_open, demo.name());
|
||||
ui.toggle_value(&mut is_open, demo.name());
|
||||
set_open(open, demo.name(), is_open);
|
||||
}
|
||||
}
|
||||
|
@ -141,23 +145,103 @@ fn set_open(open: &mut BTreeSet<String>, key: &'static str, is_open: bool) {
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// A menu bar in which you can select different demo windows to show.
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "serde", serde(default))]
|
||||
pub struct DemoWindows {
|
||||
about_is_open: bool,
|
||||
about: About,
|
||||
demos: Demos,
|
||||
tests: Tests,
|
||||
}
|
||||
|
||||
impl Default for DemoWindows {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
about_is_open: true,
|
||||
about: Default::default(),
|
||||
demos: Default::default(),
|
||||
tests: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DemoWindows {
|
||||
/// Show the app ui (menu bar and windows).
|
||||
/// `sidebar_ui` can be used to optionally show some things in the sidebar
|
||||
pub fn ui(&mut self, ctx: &Context) {
|
||||
let Self { demos, tests } = self;
|
||||
if is_mobile(ctx) {
|
||||
self.mobile_ui(ctx);
|
||||
} else {
|
||||
self.desktop_ui(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn mobile_ui(&mut self, ctx: &Context) {
|
||||
if self.about_is_open {
|
||||
egui::CentralPanel::default().show(ctx, |_ui| {}); // just to paint a background for the windows to be on top of. Needed on web because of https://github.com/emilk/egui/issues/1548
|
||||
|
||||
let screen_size = ctx.input().screen_rect.size();
|
||||
let default_width = (screen_size.x - 20.0).min(400.0);
|
||||
|
||||
let mut close = false;
|
||||
egui::Window::new(self.about.name())
|
||||
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
|
||||
.default_width(default_width)
|
||||
.default_height(ctx.available_rect().height() - 46.0)
|
||||
.vscroll(true)
|
||||
.open(&mut self.about_is_open)
|
||||
.resizable(false)
|
||||
.collapsible(false)
|
||||
.show(ctx, |ui| {
|
||||
self.about.ui(ui);
|
||||
ui.add_space(12.0);
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
if ui
|
||||
.button(egui::RichText::new("Continue to the demo!").size(24.0))
|
||||
.clicked()
|
||||
{
|
||||
close = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
self.about_is_open &= !close;
|
||||
} else {
|
||||
self.mobile_top_bar(ctx);
|
||||
self.show_windows(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn mobile_top_bar(&mut self, ctx: &Context) {
|
||||
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
|
||||
egui::menu::bar(ui, |ui| {
|
||||
let font_size = 20.0;
|
||||
|
||||
ui.menu_button(egui::RichText::new("⏷ demos").size(font_size), |ui| {
|
||||
ui.set_style(ui.ctx().style()); // ignore the "menu" style set by `menu_button`.
|
||||
self.demo_list_ui(ui);
|
||||
if ui.ui_contains_pointer() && ui.input().pointer.any_click() {
|
||||
ui.close_menu();
|
||||
}
|
||||
});
|
||||
|
||||
ui.with_layout(egui::Layout::right_to_left(), |ui| {
|
||||
use egui::special_emojis::{GITHUB, TWITTER};
|
||||
ui.hyperlink_to(
|
||||
egui::RichText::new(TWITTER).size(font_size),
|
||||
"https://twitter.com/ernerfeldt",
|
||||
);
|
||||
ui.hyperlink_to(
|
||||
egui::RichText::new(GITHUB).size(font_size),
|
||||
"https://github.com/emilk/egui",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn desktop_ui(&mut self, ctx: &Context) {
|
||||
egui::SidePanel::right("egui_demo_panel")
|
||||
.min_width(150.0)
|
||||
.default_width(180.0)
|
||||
.resizable(false)
|
||||
.default_width(145.0)
|
||||
.show(ctx, |ui| {
|
||||
egui::trace!(ui);
|
||||
ui.vertical_centered(|ui| {
|
||||
|
@ -166,65 +250,60 @@ impl DemoWindows {
|
|||
|
||||
ui.separator();
|
||||
|
||||
ScrollArea::vertical().show(ui, |ui| {
|
||||
use egui::special_emojis::{GITHUB, OS_APPLE, OS_LINUX, OS_WINDOWS, TWITTER};
|
||||
|
||||
ui.label("egui is an immediate mode GUI library written in Rust.");
|
||||
|
||||
ui.label(format!(
|
||||
"egui runs on the web, or natively on {}{}{}",
|
||||
OS_APPLE, OS_LINUX, OS_WINDOWS,
|
||||
));
|
||||
|
||||
use egui::special_emojis::{GITHUB, TWITTER};
|
||||
ui.hyperlink_to(
|
||||
format!("{} egui on GitHub", GITHUB),
|
||||
"https://github.com/emilk/egui",
|
||||
);
|
||||
|
||||
ui.hyperlink_to(
|
||||
format!("{} @ernerfeldt", TWITTER),
|
||||
"https://twitter.com/ernerfeldt",
|
||||
);
|
||||
|
||||
ui.separator();
|
||||
demos.checkboxes(ui);
|
||||
|
||||
self.demo_list_ui(ui);
|
||||
});
|
||||
|
||||
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
|
||||
egui::menu::bar(ui, |ui| {
|
||||
file_menu_button(ui);
|
||||
});
|
||||
});
|
||||
|
||||
self.show_windows(ctx);
|
||||
}
|
||||
|
||||
/// Show the open windows.
|
||||
fn show_windows(&mut self, ctx: &Context) {
|
||||
egui::CentralPanel::default().show(ctx, |_ui| {}); // just to paint a background for the windows to be on top of. Needed on web because of https://github.com/emilk/egui/issues/1548
|
||||
self.about.show(ctx, &mut self.about_is_open);
|
||||
self.demos.windows(ctx);
|
||||
self.tests.windows(ctx);
|
||||
}
|
||||
|
||||
fn demo_list_ui(&mut self, ui: &mut egui::Ui) {
|
||||
ScrollArea::vertical().show(ui, |ui| {
|
||||
ui.with_layout(egui::Layout::top_down_justified(egui::Align::LEFT), |ui| {
|
||||
ui.toggle_value(&mut self.about_is_open, self.about.name());
|
||||
|
||||
ui.separator();
|
||||
tests.checkboxes(ui);
|
||||
self.demos.checkboxes(ui);
|
||||
ui.separator();
|
||||
self.tests.checkboxes(ui);
|
||||
ui.separator();
|
||||
|
||||
ui.vertical_centered(|ui| {
|
||||
if ui.button("Organize windows").clicked() {
|
||||
ui.ctx().memory().reset_areas();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
|
||||
show_menu_bar(ui);
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |_ui| {}); // just to paint a background for the windows to be on top of. Needed on web because of https://github.com/emilk/egui/issues/1548
|
||||
|
||||
self.windows(ctx);
|
||||
}
|
||||
|
||||
/// Show the open windows.
|
||||
fn windows(&mut self, ctx: &Context) {
|
||||
let Self { demos, tests } = self;
|
||||
|
||||
demos.windows(ctx);
|
||||
tests.windows(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
fn show_menu_bar(ui: &mut Ui) {
|
||||
trace!(ui);
|
||||
use egui::*;
|
||||
|
||||
menu::bar(ui, |ui| {
|
||||
fn file_menu_button(ui: &mut Ui) {
|
||||
ui.menu_button("File", |ui| {
|
||||
if ui.button("Organize windows").clicked() {
|
||||
ui.ctx().memory().reset_areas();
|
||||
|
@ -239,5 +318,4 @@ fn show_menu_bar(ui: &mut Ui) {
|
|||
ui.close_menu();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub mod about;
|
||||
pub mod code_editor;
|
||||
pub mod code_example;
|
||||
pub mod context_menu;
|
||||
|
@ -30,7 +31,8 @@ pub mod window_options;
|
|||
pub mod window_with_panels;
|
||||
|
||||
pub use {
|
||||
demo_app_windows::DemoWindows, misc_demo_window::MiscDemoWindow, widget_gallery::WidgetGallery,
|
||||
about::About, demo_app_windows::DemoWindows, misc_demo_window::MiscDemoWindow,
|
||||
widget_gallery::WidgetGallery,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -370,6 +370,7 @@ impl CustomAxisDemo {
|
|||
marks
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
fn ui(&mut self, ui: &mut Ui) -> Response {
|
||||
const MINS_PER_DAY: f64 = CustomAxisDemo::MINS_PER_DAY;
|
||||
const MINS_PER_H: f64 = CustomAxisDemo::MINS_PER_H;
|
||||
|
@ -587,6 +588,7 @@ impl ItemsDemo {
|
|||
struct InteractionDemo {}
|
||||
|
||||
impl InteractionDemo {
|
||||
#[allow(clippy::unused_self)]
|
||||
fn ui(&mut self, ui: &mut Ui) -> Response {
|
||||
let plot = Plot::new("interaction_demo").height(300.0);
|
||||
|
||||
|
|
|
@ -92,3 +92,12 @@ fn test_egui_zero_window_size() {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Detect narrow screens. This is used to show a simpler UI on mobile devices,
|
||||
/// especially for the web demo at <https://egui.rs>.
|
||||
pub fn is_mobile(ctx: &egui::Context) -> bool {
|
||||
let screen_size = ctx.input().screen_rect().size();
|
||||
screen_size.x < 550.0
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue