Add helpers for zooming an app using Ctrl+Plus and Ctrl+Minus (#2239)
* Using tracing-subscriber in hello_world example * Add Key::Plus/Minus/Equals * Warn if failing to guess OS from User-Agent * Remove jitter when using Context::set_pixels_per_point * Demo app: zoom in/out using ⌘+ and ⌘- * Demo app: make backend panel GUI scale slider better * Optimize debug builds a bit * typo * Update changelog * Add helper module `egui::gui_zoom` for zooming an app * Better names, and update changelog * Combine Plus and Equals keys * Last fix * Fix docs
This commit is contained in:
parent
25718f2774
commit
a0b3f1126b
15 changed files with 290 additions and 112 deletions
|
@ -13,10 +13,13 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
|
||||||
* Added `Button::shortcut_text` for showing keyboard shortcuts in menu buttons ([#2202](https://github.com/emilk/egui/pull/2202)).
|
* Added `Button::shortcut_text` for showing keyboard shortcuts in menu buttons ([#2202](https://github.com/emilk/egui/pull/2202)).
|
||||||
* Added `egui::KeyboardShortcut` for showing keyboard shortcuts in menu buttons ([#2202](https://github.com/emilk/egui/pull/2202)).
|
* Added `egui::KeyboardShortcut` for showing keyboard shortcuts in menu buttons ([#2202](https://github.com/emilk/egui/pull/2202)).
|
||||||
* Texture loading now takes a `TexureOptions` with minification and magnification filters ([#2224](https://github.com/emilk/egui/pull/2224)).
|
* Texture loading now takes a `TexureOptions` with minification and magnification filters ([#2224](https://github.com/emilk/egui/pull/2224)).
|
||||||
|
* Added `Key::Minus` and `Key::Equals` ([#2239](https://github.com/emilk/egui/pull/2239)).
|
||||||
|
* Added `egui::gui_zoom` module with helpers for scaling the whole GUI of an app ([#2239](https://github.com/emilk/egui/pull/2239)).
|
||||||
|
|
||||||
### Fixed 🐛
|
### Fixed 🐛
|
||||||
* ⚠️ BREAKING: Fix text being too small ([#2069](https://github.com/emilk/egui/pull/2069)).
|
* ⚠️ BREAKING: Fix text being too small ([#2069](https://github.com/emilk/egui/pull/2069)).
|
||||||
* Improved text rendering ([#2071](https://github.com/emilk/egui/pull/2071)).
|
* Improved text rendering ([#2071](https://github.com/emilk/egui/pull/2071)).
|
||||||
|
* Less jitter when calling `Context::set_pixels_per_point` ([#2239](https://github.com/emilk/egui/pull/2239)).
|
||||||
|
|
||||||
|
|
||||||
## 0.19.0 - 2022-08-20
|
## 0.19.0 - 2022-08-20
|
||||||
|
|
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1926,6 +1926,7 @@ name = "hello_world"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"eframe",
|
"eframe",
|
||||||
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -15,9 +15,6 @@ members = [
|
||||||
"examples/*",
|
"examples/*",
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.dev]
|
|
||||||
split-debuginfo = "unpacked" # faster debug builds on mac
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
# lto = true # VERY slightly smaller wasm
|
# lto = true # VERY slightly smaller wasm
|
||||||
# opt-level = 's' # 10-20% smaller wasm compared to `opt-level = 3`
|
# opt-level = 's' # 10-20% smaller wasm compared to `opt-level = 3`
|
||||||
|
@ -26,3 +23,12 @@ opt-level = 2 # fast and small wasm, basically same as `opt-level = 's'`
|
||||||
# opt-level = 3 # unecessarily large wasm for no performance gain
|
# opt-level = 3 # unecessarily large wasm for no performance gain
|
||||||
|
|
||||||
# debug = true # include debug symbols, useful when profiling wasm
|
# debug = true # include debug symbols, useful when profiling wasm
|
||||||
|
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
split-debuginfo = "unpacked" # faster debug builds on mac
|
||||||
|
opt-level = 1 # Make debug builds run faster
|
||||||
|
|
||||||
|
# Optimize all dependencies even in debug builds (does not affect workspace packages):
|
||||||
|
[profile.dev.package."*"]
|
||||||
|
opt-level = 2
|
||||||
|
|
|
@ -113,83 +113,88 @@ pub fn should_ignore_key(key: &str) -> bool {
|
||||||
/// Web sends all all keys as strings, so it is up to us to figure out if it is
|
/// Web sends all all keys as strings, so it is up to us to figure out if it is
|
||||||
/// a real text input or the name of a key.
|
/// a real text input or the name of a key.
|
||||||
pub fn translate_key(key: &str) -> Option<egui::Key> {
|
pub fn translate_key(key: &str) -> Option<egui::Key> {
|
||||||
|
use egui::Key;
|
||||||
|
|
||||||
match key {
|
match key {
|
||||||
"ArrowDown" => Some(egui::Key::ArrowDown),
|
"ArrowDown" => Some(Key::ArrowDown),
|
||||||
"ArrowLeft" => Some(egui::Key::ArrowLeft),
|
"ArrowLeft" => Some(Key::ArrowLeft),
|
||||||
"ArrowRight" => Some(egui::Key::ArrowRight),
|
"ArrowRight" => Some(Key::ArrowRight),
|
||||||
"ArrowUp" => Some(egui::Key::ArrowUp),
|
"ArrowUp" => Some(Key::ArrowUp),
|
||||||
|
|
||||||
"Esc" | "Escape" => Some(egui::Key::Escape),
|
"Esc" | "Escape" => Some(Key::Escape),
|
||||||
"Tab" => Some(egui::Key::Tab),
|
"Tab" => Some(Key::Tab),
|
||||||
"Backspace" => Some(egui::Key::Backspace),
|
"Backspace" => Some(Key::Backspace),
|
||||||
"Enter" => Some(egui::Key::Enter),
|
"Enter" => Some(Key::Enter),
|
||||||
"Space" | " " => Some(egui::Key::Space),
|
"Space" | " " => Some(Key::Space),
|
||||||
|
|
||||||
"Help" | "Insert" => Some(egui::Key::Insert),
|
"Help" | "Insert" => Some(Key::Insert),
|
||||||
"Delete" => Some(egui::Key::Delete),
|
"Delete" => Some(Key::Delete),
|
||||||
"Home" => Some(egui::Key::Home),
|
"Home" => Some(Key::Home),
|
||||||
"End" => Some(egui::Key::End),
|
"End" => Some(Key::End),
|
||||||
"PageUp" => Some(egui::Key::PageUp),
|
"PageUp" => Some(Key::PageUp),
|
||||||
"PageDown" => Some(egui::Key::PageDown),
|
"PageDown" => Some(Key::PageDown),
|
||||||
|
|
||||||
"0" => Some(egui::Key::Num0),
|
"-" => Some(Key::Minus),
|
||||||
"1" => Some(egui::Key::Num1),
|
"+" | "=" => Some(Key::PlusEquals),
|
||||||
"2" => Some(egui::Key::Num2),
|
|
||||||
"3" => Some(egui::Key::Num3),
|
|
||||||
"4" => Some(egui::Key::Num4),
|
|
||||||
"5" => Some(egui::Key::Num5),
|
|
||||||
"6" => Some(egui::Key::Num6),
|
|
||||||
"7" => Some(egui::Key::Num7),
|
|
||||||
"8" => Some(egui::Key::Num8),
|
|
||||||
"9" => Some(egui::Key::Num9),
|
|
||||||
|
|
||||||
"a" | "A" => Some(egui::Key::A),
|
"0" => Some(Key::Num0),
|
||||||
"b" | "B" => Some(egui::Key::B),
|
"1" => Some(Key::Num1),
|
||||||
"c" | "C" => Some(egui::Key::C),
|
"2" => Some(Key::Num2),
|
||||||
"d" | "D" => Some(egui::Key::D),
|
"3" => Some(Key::Num3),
|
||||||
"e" | "E" => Some(egui::Key::E),
|
"4" => Some(Key::Num4),
|
||||||
"f" | "F" => Some(egui::Key::F),
|
"5" => Some(Key::Num5),
|
||||||
"g" | "G" => Some(egui::Key::G),
|
"6" => Some(Key::Num6),
|
||||||
"h" | "H" => Some(egui::Key::H),
|
"7" => Some(Key::Num7),
|
||||||
"i" | "I" => Some(egui::Key::I),
|
"8" => Some(Key::Num8),
|
||||||
"j" | "J" => Some(egui::Key::J),
|
"9" => Some(Key::Num9),
|
||||||
"k" | "K" => Some(egui::Key::K),
|
|
||||||
"l" | "L" => Some(egui::Key::L),
|
|
||||||
"m" | "M" => Some(egui::Key::M),
|
|
||||||
"n" | "N" => Some(egui::Key::N),
|
|
||||||
"o" | "O" => Some(egui::Key::O),
|
|
||||||
"p" | "P" => Some(egui::Key::P),
|
|
||||||
"q" | "Q" => Some(egui::Key::Q),
|
|
||||||
"r" | "R" => Some(egui::Key::R),
|
|
||||||
"s" | "S" => Some(egui::Key::S),
|
|
||||||
"t" | "T" => Some(egui::Key::T),
|
|
||||||
"u" | "U" => Some(egui::Key::U),
|
|
||||||
"v" | "V" => Some(egui::Key::V),
|
|
||||||
"w" | "W" => Some(egui::Key::W),
|
|
||||||
"x" | "X" => Some(egui::Key::X),
|
|
||||||
"y" | "Y" => Some(egui::Key::Y),
|
|
||||||
"z" | "Z" => Some(egui::Key::Z),
|
|
||||||
|
|
||||||
"F1" => Some(egui::Key::F1),
|
"a" | "A" => Some(Key::A),
|
||||||
"F2" => Some(egui::Key::F2),
|
"b" | "B" => Some(Key::B),
|
||||||
"F3" => Some(egui::Key::F3),
|
"c" | "C" => Some(Key::C),
|
||||||
"F4" => Some(egui::Key::F4),
|
"d" | "D" => Some(Key::D),
|
||||||
"F5" => Some(egui::Key::F5),
|
"e" | "E" => Some(Key::E),
|
||||||
"F6" => Some(egui::Key::F6),
|
"f" | "F" => Some(Key::F),
|
||||||
"F7" => Some(egui::Key::F7),
|
"g" | "G" => Some(Key::G),
|
||||||
"F8" => Some(egui::Key::F8),
|
"h" | "H" => Some(Key::H),
|
||||||
"F9" => Some(egui::Key::F9),
|
"i" | "I" => Some(Key::I),
|
||||||
"F10" => Some(egui::Key::F10),
|
"j" | "J" => Some(Key::J),
|
||||||
"F11" => Some(egui::Key::F11),
|
"k" | "K" => Some(Key::K),
|
||||||
"F12" => Some(egui::Key::F12),
|
"l" | "L" => Some(Key::L),
|
||||||
"F13" => Some(egui::Key::F13),
|
"m" | "M" => Some(Key::M),
|
||||||
"F14" => Some(egui::Key::F14),
|
"n" | "N" => Some(Key::N),
|
||||||
"F15" => Some(egui::Key::F15),
|
"o" | "O" => Some(Key::O),
|
||||||
"F16" => Some(egui::Key::F16),
|
"p" | "P" => Some(Key::P),
|
||||||
"F17" => Some(egui::Key::F17),
|
"q" | "Q" => Some(Key::Q),
|
||||||
"F18" => Some(egui::Key::F18),
|
"r" | "R" => Some(Key::R),
|
||||||
"F19" => Some(egui::Key::F19),
|
"s" | "S" => Some(Key::S),
|
||||||
"F20" => Some(egui::Key::F20),
|
"t" | "T" => Some(Key::T),
|
||||||
|
"u" | "U" => Some(Key::U),
|
||||||
|
"v" | "V" => Some(Key::V),
|
||||||
|
"w" | "W" => Some(Key::W),
|
||||||
|
"x" | "X" => Some(Key::X),
|
||||||
|
"y" | "Y" => Some(Key::Y),
|
||||||
|
"z" | "Z" => Some(Key::Z),
|
||||||
|
|
||||||
|
"F1" => Some(Key::F1),
|
||||||
|
"F2" => Some(Key::F2),
|
||||||
|
"F3" => Some(Key::F3),
|
||||||
|
"F4" => Some(Key::F4),
|
||||||
|
"F5" => Some(Key::F5),
|
||||||
|
"F6" => Some(Key::F6),
|
||||||
|
"F7" => Some(Key::F7),
|
||||||
|
"F8" => Some(Key::F8),
|
||||||
|
"F9" => Some(Key::F9),
|
||||||
|
"F10" => Some(Key::F10),
|
||||||
|
"F11" => Some(Key::F11),
|
||||||
|
"F12" => Some(Key::F12),
|
||||||
|
"F13" => Some(Key::F13),
|
||||||
|
"F14" => Some(Key::F14),
|
||||||
|
"F15" => Some(Key::F15),
|
||||||
|
"F16" => Some(Key::F16),
|
||||||
|
"F17" => Some(Key::F17),
|
||||||
|
"F18" => Some(Key::F18),
|
||||||
|
"F19" => Some(Key::F19),
|
||||||
|
"F20" => Some(Key::F20),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -710,6 +710,11 @@ fn translate_virtual_key_code(key: winit::event::VirtualKeyCode) -> Option<egui:
|
||||||
VirtualKeyCode::PageUp => Key::PageUp,
|
VirtualKeyCode::PageUp => Key::PageUp,
|
||||||
VirtualKeyCode::PageDown => Key::PageDown,
|
VirtualKeyCode::PageDown => Key::PageDown,
|
||||||
|
|
||||||
|
VirtualKeyCode::Minus => Key::Minus,
|
||||||
|
// Using Mac the key with the Plus sign on it is reported as the Equals key
|
||||||
|
// (with both English and Swedish keyboard).
|
||||||
|
VirtualKeyCode::Equals => Key::PlusEquals,
|
||||||
|
|
||||||
VirtualKeyCode::Key0 | VirtualKeyCode::Numpad0 => Key::Num0,
|
VirtualKeyCode::Key0 | VirtualKeyCode::Numpad0 => Key::Num0,
|
||||||
VirtualKeyCode::Key1 | VirtualKeyCode::Numpad1 => Key::Num1,
|
VirtualKeyCode::Key1 | VirtualKeyCode::Numpad1 => Key::Num1,
|
||||||
VirtualKeyCode::Key2 | VirtualKeyCode::Numpad2 => Key::Num2,
|
VirtualKeyCode::Key2 | VirtualKeyCode::Numpad2 => Key::Num2,
|
||||||
|
|
|
@ -65,18 +65,25 @@ struct ContextImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextImpl {
|
impl ContextImpl {
|
||||||
fn begin_frame_mut(&mut self, new_raw_input: RawInput) {
|
fn begin_frame_mut(&mut self, mut new_raw_input: RawInput) {
|
||||||
self.has_requested_repaint_this_frame = false; // allow new calls during the frame
|
self.has_requested_repaint_this_frame = false; // allow new calls during the frame
|
||||||
|
|
||||||
|
if let Some(new_pixels_per_point) = self.memory.new_pixels_per_point.take() {
|
||||||
|
new_raw_input.pixels_per_point = Some(new_pixels_per_point);
|
||||||
|
|
||||||
|
// This is a bit hacky, but is required to avoid jitter:
|
||||||
|
let ratio = self.input.pixels_per_point / new_pixels_per_point;
|
||||||
|
let mut rect = self.input.screen_rect;
|
||||||
|
rect.min = (ratio * rect.min.to_vec2()).to_pos2();
|
||||||
|
rect.max = (ratio * rect.max.to_vec2()).to_pos2();
|
||||||
|
new_raw_input.screen_rect = Some(rect);
|
||||||
|
}
|
||||||
|
|
||||||
self.memory.begin_frame(&self.input, &new_raw_input);
|
self.memory.begin_frame(&self.input, &new_raw_input);
|
||||||
|
|
||||||
self.input = std::mem::take(&mut self.input)
|
self.input = std::mem::take(&mut self.input)
|
||||||
.begin_frame(new_raw_input, self.requested_repaint_last_frame);
|
.begin_frame(new_raw_input, self.requested_repaint_last_frame);
|
||||||
|
|
||||||
if let Some(new_pixels_per_point) = self.memory.new_pixels_per_point.take() {
|
|
||||||
self.input.pixels_per_point = new_pixels_per_point;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.frame_state.begin_frame(&self.input);
|
self.frame_state.begin_frame(&self.input);
|
||||||
|
|
||||||
self.update_fonts_mut();
|
self.update_fonts_mut();
|
||||||
|
|
|
@ -13,10 +13,10 @@ use crate::emath::*;
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct RawInput {
|
pub struct RawInput {
|
||||||
/// Position and size of the area that egui should use.
|
/// Position and size of the area that egui should use, in points.
|
||||||
/// Usually you would set this to
|
/// Usually you would set this to
|
||||||
///
|
///
|
||||||
/// `Some(Rect::from_pos_size(Default::default(), screen_size))`.
|
/// `Some(Rect::from_pos_size(Default::default(), screen_size_in_points))`.
|
||||||
///
|
///
|
||||||
/// but you could also constrain egui to some smaller portion of your window if you like.
|
/// but you could also constrain egui to some smaller portion of your window if you like.
|
||||||
///
|
///
|
||||||
|
@ -516,13 +516,13 @@ impl ModifierNames<'static> {
|
||||||
concat: "",
|
concat: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Alt, Ctrl, Shift, Command
|
/// Alt, Ctrl, Shift, Cmd
|
||||||
pub const NAMES: Self = Self {
|
pub const NAMES: Self = Self {
|
||||||
is_short: false,
|
is_short: false,
|
||||||
alt: "Alt",
|
alt: "Alt",
|
||||||
ctrl: "Ctrl",
|
ctrl: "Ctrl",
|
||||||
shift: "Shift",
|
shift: "Shift",
|
||||||
mac_cmd: "Command",
|
mac_cmd: "Cmd",
|
||||||
concat: "+",
|
concat: "+",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -585,6 +585,11 @@ pub enum Key {
|
||||||
PageUp,
|
PageUp,
|
||||||
PageDown,
|
PageDown,
|
||||||
|
|
||||||
|
/// The virtual keycode for the Minus key.
|
||||||
|
Minus,
|
||||||
|
/// The virtual keycode for the Plus/Equals key.
|
||||||
|
PlusEquals,
|
||||||
|
|
||||||
/// Either from the main row or from the numpad.
|
/// Either from the main row or from the numpad.
|
||||||
Num0,
|
Num0,
|
||||||
/// Either from the main row or from the numpad.
|
/// Either from the main row or from the numpad.
|
||||||
|
@ -667,6 +672,8 @@ impl Key {
|
||||||
Key::ArrowLeft => "⏴",
|
Key::ArrowLeft => "⏴",
|
||||||
Key::ArrowRight => "⏵",
|
Key::ArrowRight => "⏵",
|
||||||
Key::ArrowUp => "⏶",
|
Key::ArrowUp => "⏶",
|
||||||
|
Key::Minus => "-",
|
||||||
|
Key::PlusEquals => "+",
|
||||||
_ => self.name(),
|
_ => self.name(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -689,6 +696,8 @@ impl Key {
|
||||||
Key::End => "End",
|
Key::End => "End",
|
||||||
Key::PageUp => "PageUp",
|
Key::PageUp => "PageUp",
|
||||||
Key::PageDown => "PageDown",
|
Key::PageDown => "PageDown",
|
||||||
|
Key::Minus => "Minus",
|
||||||
|
Key::PlusEquals => "Plus",
|
||||||
Key::Num0 => "0",
|
Key::Num0 => "0",
|
||||||
Key::Num1 => "1",
|
Key::Num1 => "1",
|
||||||
Key::Num2 => "2",
|
Key::Num2 => "2",
|
||||||
|
|
117
crates/egui/src/gui_zoom.rs
Normal file
117
crates/egui/src/gui_zoom.rs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
//! Helpers for zooming the whole GUI of an app (changing [`Context::pixels_per_point`].
|
||||||
|
//!
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
/// The suggested keyboard shortcuts for global gui zooming.
|
||||||
|
pub mod kb_shortcuts {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub const ZOOM_IN: KeyboardShortcut =
|
||||||
|
KeyboardShortcut::new(Modifiers::COMMAND, Key::PlusEquals);
|
||||||
|
pub const ZOOM_OUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::Minus);
|
||||||
|
pub const ZOOM_RESET: KeyboardShortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::Num0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Let the user scale the GUI (change `Context::pixels_per_point`) by pressing
|
||||||
|
/// Cmd+Plus, Cmd+Minus or Cmd+0, just like in a browser.
|
||||||
|
///
|
||||||
|
/// When using [`eframe`](https://github.com/emilk/egui/tree/master/crates/eframe), you want to call this as:
|
||||||
|
/// ```ignore
|
||||||
|
/// // On web, the browser controls the gui zoom.
|
||||||
|
/// if !frame.is_web() {
|
||||||
|
/// egui::gui_zoom::zoom_with_keyboard_shortcuts(
|
||||||
|
/// ctx,
|
||||||
|
/// frame.info().native_pixels_per_point,
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn zoom_with_keyboard_shortcuts(ctx: &Context, native_pixels_per_point: Option<f32>) {
|
||||||
|
if ctx.input_mut().consume_shortcut(&kb_shortcuts::ZOOM_RESET) {
|
||||||
|
if let Some(native_pixels_per_point) = native_pixels_per_point {
|
||||||
|
ctx.set_pixels_per_point(native_pixels_per_point);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ctx.input_mut().consume_shortcut(&kb_shortcuts::ZOOM_IN) {
|
||||||
|
zoom_in(ctx);
|
||||||
|
}
|
||||||
|
if ctx.input_mut().consume_shortcut(&kb_shortcuts::ZOOM_OUT) {
|
||||||
|
zoom_out(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MIN_PIXELS_PER_POINT: f32 = 0.2;
|
||||||
|
const MAX_PIXELS_PER_POINT: f32 = 4.0;
|
||||||
|
|
||||||
|
/// Make everything larger.
|
||||||
|
pub fn zoom_in(ctx: &Context) {
|
||||||
|
let mut pixels_per_point = ctx.pixels_per_point();
|
||||||
|
pixels_per_point += 0.1;
|
||||||
|
pixels_per_point = pixels_per_point.clamp(MIN_PIXELS_PER_POINT, MAX_PIXELS_PER_POINT);
|
||||||
|
pixels_per_point = (pixels_per_point * 10.).round() / 10.;
|
||||||
|
ctx.set_pixels_per_point(pixels_per_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make everything smaller.
|
||||||
|
pub fn zoom_out(ctx: &Context) {
|
||||||
|
let mut pixels_per_point = ctx.pixels_per_point();
|
||||||
|
pixels_per_point -= 0.1;
|
||||||
|
pixels_per_point = pixels_per_point.clamp(MIN_PIXELS_PER_POINT, MAX_PIXELS_PER_POINT);
|
||||||
|
pixels_per_point = (pixels_per_point * 10.).round() / 10.;
|
||||||
|
ctx.set_pixels_per_point(pixels_per_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show buttons for zooming the ui.
|
||||||
|
///
|
||||||
|
/// This is meant to be called from within a menu (See [`Ui::menu_button`]).
|
||||||
|
///
|
||||||
|
/// When using [`eframe`](https://github.com/emilk/egui/tree/master/crates/eframe), you want to call this as:
|
||||||
|
/// ```ignore
|
||||||
|
/// // On web, the browser controls the gui zoom.
|
||||||
|
/// if !frame.is_web() {
|
||||||
|
/// ui.menu_button("View", |ui| {
|
||||||
|
/// egui::gui_zoom::zoom_menu_buttons(
|
||||||
|
/// ui,
|
||||||
|
/// frame.info().native_pixels_per_point,
|
||||||
|
/// );
|
||||||
|
/// });
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn zoom_menu_buttons(ui: &mut Ui, native_pixels_per_point: Option<f32>) {
|
||||||
|
if ui
|
||||||
|
.add_enabled(
|
||||||
|
ui.ctx().pixels_per_point() < MAX_PIXELS_PER_POINT,
|
||||||
|
Button::new("Zoom In").shortcut_text(ui.ctx().format_shortcut(&kb_shortcuts::ZOOM_IN)),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
zoom_in(ui.ctx());
|
||||||
|
ui.close_menu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.add_enabled(
|
||||||
|
ui.ctx().pixels_per_point() > MIN_PIXELS_PER_POINT,
|
||||||
|
Button::new("Zoom Out")
|
||||||
|
.shortcut_text(ui.ctx().format_shortcut(&kb_shortcuts::ZOOM_OUT)),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
zoom_out(ui.ctx());
|
||||||
|
ui.close_menu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(native_pixels_per_point) = native_pixels_per_point {
|
||||||
|
if ui
|
||||||
|
.add_enabled(
|
||||||
|
ui.ctx().pixels_per_point() != native_pixels_per_point,
|
||||||
|
Button::new("Reset Zoom")
|
||||||
|
.shortcut_text(ui.ctx().format_shortcut(&kb_shortcuts::ZOOM_RESET)),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
ui.ctx().set_pixels_per_point(native_pixels_per_point);
|
||||||
|
ui.close_menu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -305,6 +305,7 @@ mod context;
|
||||||
mod data;
|
mod data;
|
||||||
mod frame_state;
|
mod frame_state;
|
||||||
pub(crate) mod grid;
|
pub(crate) mod grid;
|
||||||
|
pub mod gui_zoom;
|
||||||
mod id;
|
mod id;
|
||||||
mod input_state;
|
mod input_state;
|
||||||
pub mod introspection;
|
pub mod introspection;
|
||||||
|
|
|
@ -65,6 +65,11 @@ impl OperatingSystem {
|
||||||
{
|
{
|
||||||
Self::Nix
|
Self::Nix
|
||||||
} else {
|
} else {
|
||||||
|
#[cfg(feature = "tracing")]
|
||||||
|
tracing::warn!(
|
||||||
|
"egui: Failed to guess operating system from User-Agent {:?}. Please file an issue at https://github.com/emilk/egui/issues",
|
||||||
|
user_agent);
|
||||||
|
|
||||||
Self::Unknown
|
Self::Unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,13 +161,10 @@ impl BackendPanel {
|
||||||
ui.monospace(format!("{:#?}", frame.info().web_info.location));
|
ui.monospace(format!("{:#?}", frame.info().web_info.location));
|
||||||
});
|
});
|
||||||
|
|
||||||
// For instance: `eframe` web sets `pixels_per_point` every frame to force
|
// On web, the browser controls `pixels_per_point`.
|
||||||
// egui to use the same scale as the web zoom factor.
|
let integration_controls_pixels_per_point = frame.is_web();
|
||||||
let integration_controls_pixels_per_point = ui.input().raw.pixels_per_point.is_some();
|
|
||||||
if !integration_controls_pixels_per_point {
|
if !integration_controls_pixels_per_point {
|
||||||
if let Some(new_pixels_per_point) = self.pixels_per_point_ui(ui, &frame.info()) {
|
self.pixels_per_point_ui(ui, &frame.info());
|
||||||
ui.ctx().set_pixels_per_point(new_pixels_per_point);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
@ -202,27 +199,36 @@ impl BackendPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pixels_per_point_ui(
|
fn pixels_per_point_ui(&mut self, ui: &mut egui::Ui, info: &eframe::IntegrationInfo) {
|
||||||
&mut self,
|
let pixels_per_point = self
|
||||||
ui: &mut egui::Ui,
|
.pixels_per_point
|
||||||
info: &eframe::IntegrationInfo,
|
.get_or_insert_with(|| ui.ctx().pixels_per_point());
|
||||||
) -> Option<f32> {
|
|
||||||
let pixels_per_point = self.pixels_per_point.get_or_insert_with(|| {
|
let mut reset = false;
|
||||||
info.native_pixels_per_point
|
|
||||||
.unwrap_or_else(|| ui.ctx().pixels_per_point())
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.spacing_mut().slider_width = 90.0;
|
ui.spacing_mut().slider_width = 90.0;
|
||||||
ui.add(
|
|
||||||
|
let response = ui
|
||||||
|
.add(
|
||||||
egui::Slider::new(pixels_per_point, 0.5..=5.0)
|
egui::Slider::new(pixels_per_point, 0.5..=5.0)
|
||||||
.logarithmic(true)
|
.logarithmic(true)
|
||||||
.clamp_to_range(true)
|
.clamp_to_range(true)
|
||||||
.text("Scale"),
|
.text("Scale"),
|
||||||
)
|
)
|
||||||
.on_hover_text("Physical pixels per point.");
|
.on_hover_text("Physical pixels per point.");
|
||||||
|
|
||||||
|
if response.drag_released() {
|
||||||
|
// We wait until mouse release to activate:
|
||||||
|
ui.ctx().set_pixels_per_point(*pixels_per_point);
|
||||||
|
reset = true;
|
||||||
|
} else if !response.is_pointer_button_down_on() {
|
||||||
|
// When not dragging, show the current pixels_per_point so others can change it.
|
||||||
|
reset = true;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(native_pixels_per_point) = info.native_pixels_per_point {
|
if let Some(native_pixels_per_point) = info.native_pixels_per_point {
|
||||||
let enabled = *pixels_per_point != native_pixels_per_point;
|
let enabled = ui.ctx().pixels_per_point() != native_pixels_per_point;
|
||||||
if ui
|
if ui
|
||||||
.add_enabled(enabled, egui::Button::new("Reset"))
|
.add_enabled(enabled, egui::Button::new("Reset"))
|
||||||
.on_hover_text(format!(
|
.on_hover_text(format!(
|
||||||
|
@ -231,16 +237,13 @@ impl BackendPanel {
|
||||||
))
|
))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
*pixels_per_point = native_pixels_per_point;
|
ui.ctx().set_pixels_per_point(native_pixels_per_point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// We wait until mouse release to activate:
|
if reset {
|
||||||
if ui.ctx().is_using_pointer() {
|
self.pixels_per_point = None;
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(*pixels_per_point)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -209,6 +209,11 @@ impl eframe::App for WrapApp {
|
||||||
self.state.backend_panel.end_of_frame(ctx);
|
self.state.backend_panel.end_of_frame(ctx);
|
||||||
|
|
||||||
self.ui_file_drag_and_drop(ctx);
|
self.ui_file_drag_and_drop(ctx);
|
||||||
|
|
||||||
|
// On web, the browser controls `pixels_per_point`.
|
||||||
|
if !frame.is_web() {
|
||||||
|
egui::gui_zoom::zoom_with_keyboard_shortcuts(ctx, frame.info().native_pixels_per_point);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "glow")]
|
#[cfg(feature = "glow")]
|
||||||
|
|
|
@ -321,6 +321,13 @@ fn file_menu_button(ui: &mut Ui) {
|
||||||
ui.set_min_width(220.0);
|
ui.set_min_width(220.0);
|
||||||
ui.style_mut().wrap = Some(false);
|
ui.style_mut().wrap = Some(false);
|
||||||
|
|
||||||
|
// On the web the browser controls the zoom
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
{
|
||||||
|
egui::gui_zoom::zoom_menu_buttons(ui, None);
|
||||||
|
ui.separator();
|
||||||
|
}
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
.add(
|
.add(
|
||||||
egui::Button::new("Organize Windows")
|
egui::Button::new("Organize Windows")
|
||||||
|
|
|
@ -10,3 +10,4 @@ publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
eframe = { path = "../../crates/eframe" }
|
eframe = { path = "../../crates/eframe" }
|
||||||
|
tracing-subscriber = "0.3"
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
// Log to stdout (if you run with `RUST_LOG=debug`).
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let options = eframe::NativeOptions::default();
|
let options = eframe::NativeOptions::default();
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
"My egui App",
|
"My egui App",
|
||||||
|
|
Loading…
Reference in a new issue