egui/egui_glium/src/lib.rs

555 lines
20 KiB
Rust
Raw Normal View History

//! [`egui`] bindings for [`glium`](https://github.com/glium/glium).
//!
//! The main type you want to use is [`EguiGlium`].
//!
//! This library is an [`epi`] backend.
//! If you are writing an app, you may want to look at [`eframe`](https://docs.rs/eframe) instead.
// Forbid warnings in release builds:
#![cfg_attr(not(debug_assertions), deny(warnings))]
// Disabled so we can support rust 1.51:
// #![deny(
// rustdoc::broken_intra_doc_links,
// rustdoc::invalid_codeblock_attributes,
// rustdoc::missing_crate_level_docs,
// rustdoc::private_intra_doc_links
// )]
#![forbid(unsafe_code)]
2021-01-02 11:02:26 +00:00
#![warn(clippy::all, rust_2018_idioms)]
2021-01-02 15:31:45 +00:00
#![allow(clippy::manual_range_contains, clippy::single_match)]
2020-07-22 16:01:27 +00:00
2020-07-23 16:54:16 +00:00
mod backend;
#[cfg(feature = "http")]
pub mod http;
2019-04-21 08:13:05 +00:00
mod painter;
#[cfg(feature = "persistence")]
pub mod persistence;
pub mod screen_reader;
pub mod window_settings;
2019-04-21 08:13:05 +00:00
2020-07-23 16:54:16 +00:00
pub use backend::*;
2019-04-21 08:13:05 +00:00
pub use painter::Painter;
pub use epi::NativeOptions;
use {
copypasta::ClipboardProvider,
egui::*,
Basic multi touch support (issue #279) (#306) * translate touch events from glium to egui Unfortunately, winit does not seem to create _Touch_ events for the touch pad on my mac. Only _TouchpadPressure_ events are sent. Found some issues (like [this](https://github.com/rust-windowing/winit/issues/54)), but I am not sure what they exactly mean: Sometimes, touch events are mixed with touch-to-pointer translation in the discussions. * translate touch events from web_sys to egui The are a few open topics: - egui_web currently translates touch events into pointer events. I guess this should change, such that egui itself performs this kind of conversion. - `pub fn egui_web::pos_from_touch_event` is a public function, but I would like to change the return type to an `Option`. Shouldn't this function be private, anyway? * introduce `TouchState` and `Gesture` InputState.touch was introduced with type `TouchState`, just as InputState.pointer is of type `Pointer`. The TouchState internally relies on a collection of `Gesture`s. This commit provides the first rudimentary implementation of a Gesture, but has no functionality, yet. * add method InputState::zoom() So far, the method always returns `None`, but it should work as soon as the `Zoom` gesture is implemented. * manage one `TouchState` per individual device Although quite unlikely, it is still possible to connect more than one touch device. (I have three touch pads connected to my MacBook in total, but unfortunately `winit` sends touch events for none of them.) We do not want to mix-up the touches from different devices. * implement control loop for gesture detection The basic idea is that each gesture can focus on detection logic and does not have to care (too much) about managing touch state in general. * streamline `Gesture` trait, simplifying impl's * implement first version of Zoom gesture * fix failing doctest a simple `TODO` should be enough * get rid of `Gesture`s * Provide a Zoom/Rotate window in the demo app For now, it works for two fingers only. The third finger interrupts the gesture. Bugs: - Pinching in the demo window also moves the window -> Pointer events must be ignored when touch is active - Pinching also works when doing it outside the demo window -> it would be nice to return the touch info in the `Response` of the painter allocation * fix comments and non-idiomatic code * update touch state *each frame* * change egui_demo to use *relative* touch data * support more than two fingers This commit includes an improved Demo Window for egui_demo, and a complete re-write of the gesture detection. The PR should be ready for review, soon. * cleanup code and comments for review * minor code simplifications * oops – forgot the changelog * resolve comment https://github.com/emilk/egui/pull/306/files/fee8ed83dbe715b5b70433faacfe74b59c99e4a4#r623226656 * accept suggestion https://github.com/emilk/egui/pull/306#discussion_r623229228 Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com> * fix syntax error (dough!) * remove `dbg!` (why didnt clippy see this?) * apply suggested diffs from review * fix conversion of physical location to Pos2 * remove redundanct type `TouchAverages` * remove trailing space * avoid initial translation jump in plot demo * extend the demo so it shows off translation Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2021-05-06 19:01:10 +00:00
glium::glutin::{
self,
event::{Force, VirtualKeyCode},
event_loop::ControlFlow,
},
std::hash::{Hash, Hasher},
};
pub use copypasta::ClipboardContext; // TODO: remove
2020-11-13 10:04:45 +00:00
pub struct GliumInputState {
pub pointer_pos_in_points: Option<Pos2>,
pub raw: egui::RawInput,
2020-11-13 10:04:45 +00:00
}
impl GliumInputState {
pub fn from_pixels_per_point(pixels_per_point: f32) -> Self {
Self {
pointer_pos_in_points: Default::default(),
2020-11-13 10:04:45 +00:00
raw: egui::RawInput {
pixels_per_point: Some(pixels_per_point),
..Default::default()
},
}
}
}
pub fn input_to_egui(
pixels_per_point: f32,
2021-01-02 11:02:26 +00:00
event: glutin::event::WindowEvent<'_>,
clipboard: Option<&mut ClipboardContext>,
2020-11-13 10:04:45 +00:00
input_state: &mut GliumInputState,
control_flow: &mut ControlFlow,
) {
2021-01-17 01:31:37 +00:00
use glutin::event::WindowEvent;
match event {
2021-01-17 01:31:37 +00:00
WindowEvent::CloseRequested | WindowEvent::Destroyed => *control_flow = ControlFlow::Exit,
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
input_state.raw.pixels_per_point = Some(scale_factor as f32);
}
WindowEvent::MouseInput { state, button, .. } => {
if let Some(pos_in_points) = input_state.pointer_pos_in_points {
if let Some(button) = translate_mouse_button(button) {
input_state.raw.events.push(egui::Event::PointerButton {
pos: pos_in_points,
button,
pressed: state == glutin::event::ElementState::Pressed,
modifiers: input_state.raw.modifiers,
});
}
}
}
2021-01-17 01:31:37 +00:00
WindowEvent::CursorMoved {
position: pos_in_pixels,
..
} => {
let pos_in_points = pos2(
pos_in_pixels.x as f32 / pixels_per_point,
pos_in_pixels.y as f32 / pixels_per_point,
);
input_state.pointer_pos_in_points = Some(pos_in_points);
input_state
.raw
.events
.push(egui::Event::PointerMoved(pos_in_points));
}
2021-01-17 01:31:37 +00:00
WindowEvent::CursorLeft { .. } => {
input_state.pointer_pos_in_points = None;
input_state.raw.events.push(egui::Event::PointerGone);
}
2021-01-17 01:31:37 +00:00
WindowEvent::ReceivedCharacter(ch) => {
if is_printable_char(ch)
2020-11-15 13:21:21 +00:00
&& !input_state.raw.modifiers.ctrl
&& !input_state.raw.modifiers.mac_cmd
{
2020-11-13 10:04:45 +00:00
input_state.raw.events.push(Event::Text(ch.to_string()));
}
}
2021-01-17 01:31:37 +00:00
WindowEvent::KeyboardInput { input, .. } => {
if let Some(keycode) = input.virtual_keycode {
let pressed = input.state == glutin::event::ElementState::Pressed;
2020-11-13 10:04:45 +00:00
// We could also use `WindowEvent::ModifiersChanged` instead, I guess.
if matches!(keycode, VirtualKeyCode::LAlt | VirtualKeyCode::RAlt) {
2020-11-15 13:21:21 +00:00
input_state.raw.modifiers.alt = pressed;
}
if matches!(keycode, VirtualKeyCode::LControl | VirtualKeyCode::RControl) {
2020-11-15 13:21:21 +00:00
input_state.raw.modifiers.ctrl = pressed;
if !cfg!(target_os = "macos") {
2020-11-15 13:21:21 +00:00
input_state.raw.modifiers.command = pressed;
}
}
if matches!(keycode, VirtualKeyCode::LShift | VirtualKeyCode::RShift) {
2020-11-15 13:21:21 +00:00
input_state.raw.modifiers.shift = pressed;
}
if cfg!(target_os = "macos")
&& matches!(keycode, VirtualKeyCode::LWin | VirtualKeyCode::RWin)
{
2020-11-15 13:21:21 +00:00
input_state.raw.modifiers.mac_cmd = pressed;
input_state.raw.modifiers.command = pressed;
}
if pressed {
2020-11-13 10:04:45 +00:00
if cfg!(target_os = "macos")
2020-11-15 13:21:21 +00:00
&& input_state.raw.modifiers.mac_cmd
&& keycode == VirtualKeyCode::Q
2020-11-13 10:04:45 +00:00
{
*control_flow = ControlFlow::Exit;
}
// VirtualKeyCode::Paste etc in winit are broken/untrustworthy,
// so we detect these things manually:
if is_cut_command(input_state.raw.modifiers, keycode) {
2020-11-13 10:04:45 +00:00
input_state.raw.events.push(Event::Cut);
} else if is_copy_command(input_state.raw.modifiers, keycode) {
2020-11-13 10:04:45 +00:00
input_state.raw.events.push(Event::Copy);
} else if is_paste_command(input_state.raw.modifiers, keycode) {
if let Some(clipboard) = clipboard {
match clipboard.get_contents() {
Ok(contents) => {
2020-11-13 10:04:45 +00:00
input_state.raw.events.push(Event::Text(contents));
}
Err(err) => {
eprintln!("Paste error: {}", err);
}
}
}
}
}
if let Some(key) = translate_virtual_key_code(keycode) {
input_state.raw.events.push(Event::Key {
key,
pressed,
modifiers: input_state.raw.modifiers,
});
}
}
}
WindowEvent::Focused(_) => {
// We will not be given a KeyboardInput event when the modifiers are released while
// the window does not have focus. Unset all modifier state to be safe.
input_state.raw.modifiers = Modifiers::default();
}
2021-01-17 01:31:37 +00:00
WindowEvent::MouseWheel { delta, .. } => {
let mut delta = match delta {
glutin::event::MouseScrollDelta::LineDelta(x, y) => {
let line_height = 8.0; // magic value!
vec2(x, y) * line_height
}
glutin::event::MouseScrollDelta::PixelDelta(delta) => {
vec2(delta.x as f32, delta.y as f32) / pixels_per_point
}
};
if cfg!(target_os = "macos") {
// This is still buggy in winit despite
// https://github.com/rust-windowing/winit/issues/1695 being closed
delta.x *= -1.0;
}
if input_state.raw.modifiers.ctrl || input_state.raw.modifiers.command {
// Treat as zoom instead:
input_state.raw.zoom_delta *= (delta.y / 200.0).exp();
} else {
input_state.raw.scroll_delta += delta;
}
}
Basic multi touch support (issue #279) (#306) * translate touch events from glium to egui Unfortunately, winit does not seem to create _Touch_ events for the touch pad on my mac. Only _TouchpadPressure_ events are sent. Found some issues (like [this](https://github.com/rust-windowing/winit/issues/54)), but I am not sure what they exactly mean: Sometimes, touch events are mixed with touch-to-pointer translation in the discussions. * translate touch events from web_sys to egui The are a few open topics: - egui_web currently translates touch events into pointer events. I guess this should change, such that egui itself performs this kind of conversion. - `pub fn egui_web::pos_from_touch_event` is a public function, but I would like to change the return type to an `Option`. Shouldn't this function be private, anyway? * introduce `TouchState` and `Gesture` InputState.touch was introduced with type `TouchState`, just as InputState.pointer is of type `Pointer`. The TouchState internally relies on a collection of `Gesture`s. This commit provides the first rudimentary implementation of a Gesture, but has no functionality, yet. * add method InputState::zoom() So far, the method always returns `None`, but it should work as soon as the `Zoom` gesture is implemented. * manage one `TouchState` per individual device Although quite unlikely, it is still possible to connect more than one touch device. (I have three touch pads connected to my MacBook in total, but unfortunately `winit` sends touch events for none of them.) We do not want to mix-up the touches from different devices. * implement control loop for gesture detection The basic idea is that each gesture can focus on detection logic and does not have to care (too much) about managing touch state in general. * streamline `Gesture` trait, simplifying impl's * implement first version of Zoom gesture * fix failing doctest a simple `TODO` should be enough * get rid of `Gesture`s * Provide a Zoom/Rotate window in the demo app For now, it works for two fingers only. The third finger interrupts the gesture. Bugs: - Pinching in the demo window also moves the window -> Pointer events must be ignored when touch is active - Pinching also works when doing it outside the demo window -> it would be nice to return the touch info in the `Response` of the painter allocation * fix comments and non-idiomatic code * update touch state *each frame* * change egui_demo to use *relative* touch data * support more than two fingers This commit includes an improved Demo Window for egui_demo, and a complete re-write of the gesture detection. The PR should be ready for review, soon. * cleanup code and comments for review * minor code simplifications * oops – forgot the changelog * resolve comment https://github.com/emilk/egui/pull/306/files/fee8ed83dbe715b5b70433faacfe74b59c99e4a4#r623226656 * accept suggestion https://github.com/emilk/egui/pull/306#discussion_r623229228 Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com> * fix syntax error (dough!) * remove `dbg!` (why didnt clippy see this?) * apply suggested diffs from review * fix conversion of physical location to Pos2 * remove redundanct type `TouchAverages` * remove trailing space * avoid initial translation jump in plot demo * extend the demo so it shows off translation Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2021-05-06 19:01:10 +00:00
WindowEvent::TouchpadPressure {
// device_id,
// pressure,
// stage,
..
} => {
// TODO
}
WindowEvent::Touch(touch) => {
let pixels_per_point_recip = 1. / pixels_per_point;
let mut hasher = std::collections::hash_map::DefaultHasher::new();
touch.device_id.hash(&mut hasher);
input_state.raw.events.push(Event::Touch {
device_id: TouchDeviceId(hasher.finish()),
id: TouchId::from(touch.id),
phase: match touch.phase {
glutin::event::TouchPhase::Started => egui::TouchPhase::Start,
glutin::event::TouchPhase::Moved => egui::TouchPhase::Move,
glutin::event::TouchPhase::Ended => egui::TouchPhase::End,
glutin::event::TouchPhase::Cancelled => egui::TouchPhase::Cancel,
},
pos: pos2(touch.location.x as f32 * pixels_per_point_recip,
touch.location.y as f32 * pixels_per_point_recip),
force: match touch.force {
Some(Force::Normalized(force)) => force as f32,
Some(Force::Calibrated {
force,
max_possible_force,
..
}) => (force / max_possible_force) as f32,
None => 0_f32,
},
});
}
_ => {
// dbg!(event);
}
}
}
/// Glium sends special keys (backspace, delete, F1, ...) as characters.
/// Ignore those.
/// We also ignore '\r', '\n', '\t'.
/// Newlines are handled by the `Key::Enter` event.
fn is_printable_char(chr: char) -> bool {
let is_in_private_use_area = '\u{e000}' <= chr && chr <= '\u{f8ff}'
|| '\u{f0000}' <= chr && chr <= '\u{ffffd}'
|| '\u{100000}' <= chr && chr <= '\u{10fffd}';
!is_in_private_use_area && !chr.is_ascii_control()
}
fn is_cut_command(modifiers: egui::Modifiers, keycode: VirtualKeyCode) -> bool {
(modifiers.command && keycode == VirtualKeyCode::X)
|| (cfg!(target_os = "windows") && modifiers.shift && keycode == VirtualKeyCode::Delete)
}
fn is_copy_command(modifiers: egui::Modifiers, keycode: VirtualKeyCode) -> bool {
(modifiers.command && keycode == VirtualKeyCode::C)
|| (cfg!(target_os = "windows") && modifiers.ctrl && keycode == VirtualKeyCode::Insert)
}
fn is_paste_command(modifiers: egui::Modifiers, keycode: VirtualKeyCode) -> bool {
(modifiers.command && keycode == VirtualKeyCode::V)
|| (cfg!(target_os = "windows") && modifiers.shift && keycode == VirtualKeyCode::Insert)
}
pub fn translate_mouse_button(button: glutin::event::MouseButton) -> Option<egui::PointerButton> {
match button {
glutin::event::MouseButton::Left => Some(egui::PointerButton::Primary),
glutin::event::MouseButton::Right => Some(egui::PointerButton::Secondary),
glutin::event::MouseButton::Middle => Some(egui::PointerButton::Middle),
_ => None,
}
}
pub fn translate_virtual_key_code(key: VirtualKeyCode) -> Option<egui::Key> {
use VirtualKeyCode::*;
Some(match key {
Down => Key::ArrowDown,
Left => Key::ArrowLeft,
Right => Key::ArrowRight,
Up => Key::ArrowUp,
Escape => Key::Escape,
Tab => Key::Tab,
Back => Key::Backspace,
Return => Key::Enter,
2020-12-13 09:00:20 +00:00
Space => Key::Space,
2020-11-15 13:21:21 +00:00
Insert => Key::Insert,
Delete => Key::Delete,
Home => Key::Home,
End => Key::End,
PageUp => Key::PageUp,
PageDown => Key::PageDown,
Key0 | Numpad0 => Key::Num0,
Key1 | Numpad1 => Key::Num1,
Key2 | Numpad2 => Key::Num2,
Key3 | Numpad3 => Key::Num3,
Key4 | Numpad4 => Key::Num4,
Key5 | Numpad5 => Key::Num5,
Key6 | Numpad6 => Key::Num6,
Key7 | Numpad7 => Key::Num7,
Key8 | Numpad8 => Key::Num8,
Key9 | Numpad9 => Key::Num9,
2020-11-15 13:21:21 +00:00
A => Key::A,
B => Key::B,
C => Key::C,
D => Key::D,
E => Key::E,
F => Key::F,
G => Key::G,
H => Key::H,
I => Key::I,
J => Key::J,
2020-11-15 13:21:21 +00:00
K => Key::K,
L => Key::L,
M => Key::M,
N => Key::N,
O => Key::O,
P => Key::P,
Q => Key::Q,
R => Key::R,
S => Key::S,
T => Key::T,
2020-11-15 13:21:21 +00:00
U => Key::U,
V => Key::V,
2020-11-15 13:21:21 +00:00
W => Key::W,
X => Key::X,
Y => Key::Y,
2020-11-15 13:21:21 +00:00
Z => Key::Z,
_ => {
return None;
}
})
}
2021-03-13 11:38:03 +00:00
fn translate_cursor(cursor_icon: egui::CursorIcon) -> Option<glutin::window::CursorIcon> {
match cursor_icon {
2021-03-13 11:38:03 +00:00
CursorIcon::None => None,
CursorIcon::Alias => Some(glutin::window::CursorIcon::Alias),
CursorIcon::AllScroll => Some(glutin::window::CursorIcon::AllScroll),
CursorIcon::Cell => Some(glutin::window::CursorIcon::Cell),
CursorIcon::ContextMenu => Some(glutin::window::CursorIcon::ContextMenu),
CursorIcon::Copy => Some(glutin::window::CursorIcon::Copy),
CursorIcon::Crosshair => Some(glutin::window::CursorIcon::Crosshair),
CursorIcon::Default => Some(glutin::window::CursorIcon::Default),
CursorIcon::Grab => Some(glutin::window::CursorIcon::Grab),
CursorIcon::Grabbing => Some(glutin::window::CursorIcon::Grabbing),
CursorIcon::Help => Some(glutin::window::CursorIcon::Help),
CursorIcon::Move => Some(glutin::window::CursorIcon::Move),
CursorIcon::NoDrop => Some(glutin::window::CursorIcon::NoDrop),
CursorIcon::NotAllowed => Some(glutin::window::CursorIcon::NotAllowed),
CursorIcon::PointingHand => Some(glutin::window::CursorIcon::Hand),
CursorIcon::Progress => Some(glutin::window::CursorIcon::Progress),
CursorIcon::ResizeHorizontal => Some(glutin::window::CursorIcon::EwResize),
CursorIcon::ResizeNeSw => Some(glutin::window::CursorIcon::NeswResize),
CursorIcon::ResizeNwSe => Some(glutin::window::CursorIcon::NwseResize),
CursorIcon::ResizeVertical => Some(glutin::window::CursorIcon::NsResize),
CursorIcon::Text => Some(glutin::window::CursorIcon::Text),
CursorIcon::VerticalText => Some(glutin::window::CursorIcon::VerticalText),
CursorIcon::Wait => Some(glutin::window::CursorIcon::Wait),
CursorIcon::ZoomIn => Some(glutin::window::CursorIcon::ZoomIn),
CursorIcon::ZoomOut => Some(glutin::window::CursorIcon::ZoomOut),
}
}
fn set_cursor_icon(display: &glium::backend::glutin::Display, cursor_icon: egui::CursorIcon) {
if let Some(cursor_icon) = translate_cursor(cursor_icon) {
display.gl_window().window().set_cursor_visible(true);
display.gl_window().window().set_cursor_icon(cursor_icon);
} else {
display.gl_window().window().set_cursor_visible(false);
}
}
pub fn handle_output(
output: egui::Output,
clipboard: Option<&mut ClipboardContext>,
display: &glium::Display,
) {
if let Some(open) = output.open_url {
if let Err(err) = webbrowser::open(&open.url) {
2020-10-01 20:40:49 +00:00
eprintln!("Failed to open url: {}", err);
}
}
if !output.copied_text.is_empty() {
if let Some(clipboard) = clipboard {
if let Err(err) = clipboard.set_contents(output.copied_text) {
eprintln!("Copy/Cut error: {}", err);
}
}
}
if let Some(egui::Pos2 { x, y }) = output.text_cursor_pos {
display
.gl_window()
.window()
.set_ime_position(glium::glutin::dpi::LogicalPosition { x, y })
}
}
pub fn init_clipboard() -> Option<ClipboardContext> {
match ClipboardContext::new() {
Ok(clipboard) => Some(clipboard),
Err(err) => {
eprintln!("Failed to initialize clipboard: {}", err);
None
}
}
}
// ----------------------------------------------------------------------------
/// Time of day as seconds since midnight. Used for clock in demo app.
pub fn seconds_since_midnight() -> Option<f64> {
#[cfg(feature = "time")]
{
use chrono::Timelike;
let time = chrono::Local::now().time();
let seconds_since_midnight =
time.num_seconds_from_midnight() as f64 + 1e-9 * (time.nanosecond() as f64);
Some(seconds_since_midnight)
}
#[cfg(not(feature = "time"))]
None
}
pub fn screen_size_in_pixels(display: &glium::Display) -> Vec2 {
let (width_in_pixels, height_in_pixels) = display.get_framebuffer_dimensions();
vec2(width_in_pixels as f32, height_in_pixels as f32)
}
pub fn native_pixels_per_point(display: &glium::Display) -> f32 {
display.gl_window().window().scale_factor() as f32
}
// ----------------------------------------------------------------------------
/// Use [`egui`] from a [`glium`] app.
pub struct EguiGlium {
egui_ctx: egui::CtxRef,
start_time: std::time::Instant,
clipboard: Option<crate::ClipboardContext>,
input_state: crate::GliumInputState,
painter: crate::Painter,
current_cursor_icon: egui::CursorIcon,
screen_reader: crate::screen_reader::ScreenReader,
}
impl EguiGlium {
pub fn new(display: &glium::Display) -> Self {
Self {
egui_ctx: Default::default(),
start_time: std::time::Instant::now(),
clipboard: crate::init_clipboard(),
input_state: crate::GliumInputState::from_pixels_per_point(
crate::native_pixels_per_point(display),
),
painter: crate::Painter::new(display),
current_cursor_icon: egui::CursorIcon::Default,
screen_reader: crate::screen_reader::ScreenReader::default(),
}
}
pub fn ctx(&self) -> &egui::CtxRef {
&self.egui_ctx
}
pub fn ctx_and_painter_mut(&mut self) -> (&egui::CtxRef, &mut crate::Painter) {
(&self.egui_ctx, &mut self.painter)
}
pub fn on_event(
&mut self,
event: glium::glutin::event::WindowEvent<'_>,
control_flow: &mut glium::glutin::event_loop::ControlFlow,
) {
crate::input_to_egui(
self.egui_ctx.pixels_per_point(),
event,
self.clipboard.as_mut(),
&mut self.input_state,
control_flow,
);
}
pub fn begin_frame(&mut self, display: &glium::Display) {
let pixels_per_point = self
.input_state
.raw
.pixels_per_point
.unwrap_or_else(|| self.egui_ctx.pixels_per_point());
self.input_state.raw.time = Some(self.start_time.elapsed().as_nanos() as f64 * 1e-9);
self.input_state.raw.screen_rect = Some(Rect::from_min_size(
Default::default(),
2021-06-22 21:25:54 +00:00
screen_size_in_pixels(display) / pixels_per_point,
));
self.egui_ctx.begin_frame(self.input_state.raw.take());
}
/// Returns `needs_repaint` and shapes to draw.
pub fn end_frame(
&mut self,
display: &glium::Display,
) -> (bool, Vec<egui::epaint::ClippedShape>) {
let (egui_output, shapes) = self.egui_ctx.end_frame();
if self.egui_ctx.memory().options.screen_reader {
self.screen_reader.speak(&egui_output.events_description());
}
if self.current_cursor_icon != egui_output.cursor_icon {
// call only when changed to prevent flickering near frame boundary
// when Windows OS tries to control cursor icon for window resizing
set_cursor_icon(display, egui_output.cursor_icon);
self.current_cursor_icon = egui_output.cursor_icon;
}
let needs_repaint = egui_output.needs_repaint;
handle_output(egui_output, self.clipboard.as_mut(), display);
(needs_repaint, shapes)
}
pub fn paint(
&mut self,
display: &glium::Display,
target: &mut glium::Frame,
shapes: Vec<egui::epaint::ClippedShape>,
) {
let clipped_meshes = self.egui_ctx.tessellate(shapes);
self.painter.paint_meshes(
display,
target,
self.egui_ctx.pixels_per_point(),
clipped_meshes,
&self.egui_ctx.texture(),
);
}
}