Add a lot more CursorIcon's

This commit is contained in:
Emil Ernerfeldt 2021-03-13 12:38:03 +01:00
parent ee1fcf1ead
commit 958aea922f
8 changed files with 216 additions and 48 deletions

View file

@ -74,19 +74,118 @@ impl OpenUrl {
/// A mouse cursor icon.
///
/// egui emits a [`CursorIcon`] in [`Output`] each frame as a request to the integration.
#[derive(Clone, Copy, PartialEq)]
///
/// Loosely based on <https://developer.mozilla.org/en-US/docs/Web/CSS/cursor>.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CursorIcon {
/// Normal cursor icon, whatever that is.
Default,
/// Show no cursor
None,
// ------------------------------------
// Links and status:
/// A context menu is available
ContextMenu,
/// Question mark
Help,
/// Pointing hand, used for e.g. web links
PointingHand,
ResizeHorizontal,
ResizeNeSw,
ResizeNwSe,
ResizeVertical,
/// Shows that processing is being done, but that the program is still interactive.
Progress,
/// Not yet ready, try later.
Wait,
// ------------------------------------
// Selection:
/// Hover a cell in a table
Cell,
/// For precision work
Crosshair,
/// Text caret, e.g. "Click here to edit text"
Text,
/// Used when moving
/// Vertical text caret, e.g. "Click here to edit vertical text"
VerticalText,
// ------------------------------------
// Drag-and-drop:
/// Indicated an alias, e.g. a shortcut
Alias,
/// Indicate that a copy will be made
Copy,
/// Omnidirectional move icon (e.g. arrows in all cardinal directions)
Move,
/// Can't drop here
NoDrop,
/// Forbidden
NotAllowed,
/// The thing you are hovering can be grabbed
Grab,
/// You are grabbing the thing you are hovering
Grabbing,
// ------------------------------------
// Resizing and scrolling
/// Something can be scrolled in any direction (panned).
AllScroll,
/// Horizontal resize `-` to make something wider or more narrow (left to/from right)
ResizeHorizontal,
/// Diagonal resize `/` (right-up to/from left-down)
ResizeNeSw,
/// Diagonal resize `\` (left-up to/from right-down)
ResizeNwSe,
/// Vertical resize `|` (up-down or down-up)
ResizeVertical,
/// Enhance!
ZoomIn,
/// Let's get a better overview
ZoomOut,
}
impl CursorIcon {
pub const ALL: [CursorIcon; 25] = [
CursorIcon::Default,
CursorIcon::None,
CursorIcon::ContextMenu,
CursorIcon::Help,
CursorIcon::PointingHand,
CursorIcon::Progress,
CursorIcon::Wait,
CursorIcon::Cell,
CursorIcon::Crosshair,
CursorIcon::Text,
CursorIcon::VerticalText,
CursorIcon::Alias,
CursorIcon::Copy,
CursorIcon::Move,
CursorIcon::NoDrop,
CursorIcon::NotAllowed,
CursorIcon::Grab,
CursorIcon::Grabbing,
CursorIcon::AllScroll,
CursorIcon::ResizeHorizontal,
CursorIcon::ResizeNeSw,
CursorIcon::ResizeNwSe,
CursorIcon::ResizeVertical,
CursorIcon::ZoomIn,
CursorIcon::ZoomOut,
];
}
impl Default for CursorIcon {

View file

@ -1,6 +1,6 @@
use crate::{
emath::{lerp, Align, Pos2, Rect, Vec2},
PointerButton, NUM_POINTER_BUTTONS,
CursorIcon, PointerButton, NUM_POINTER_BUTTONS,
};
use crate::{CtxRef, Id, LayerId, Sense, Ui};
@ -302,6 +302,14 @@ impl Response {
self.on_hover_text(text)
}
/// When hovered, use this icon for the mouse cursor.
pub fn on_hover_cursor(self, cursor: CursorIcon) -> Self {
if self.hovered() {
self.ctx.output().cursor_icon = cursor;
}
self
}
/// Check for more interactions (e.g. sense clicks on a `Response` returned from a label).
///
/// ```

View file

@ -475,7 +475,7 @@ impl Widget for Plot {
prepared.ui(ui, &response);
}
response
response.on_hover_cursor(CursorIcon::Crosshair)
}
}

View file

@ -26,6 +26,7 @@ impl Default for Demos {
Box::new(super::window_options::WindowOptions::default()),
Box::new(super::tests::WindowResizeTest::default()),
// Tests:
Box::new(super::tests::CursorTest::default()),
Box::new(super::tests::IdTest::default()),
Box::new(super::tests::InputTest::default()),
Box::new(super::layout_test::LayoutTest::default()),

View file

@ -1,3 +1,34 @@
#[derive(Default)]
pub struct CursorTest {}
impl super::Demo for CursorTest {
fn name(&self) -> &'static str {
"Cursor Test"
}
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
egui::Window::new(self.name()).open(open).show(ctx, |ui| {
use super::View;
self.ui(ui);
});
}
}
impl super::View for CursorTest {
fn ui(&mut self, ui: &mut egui::Ui) {
ui.heading("Hover to switch cursor icon:");
ui.vertical_centered_justified(|ui| {
for &cursor_icon in &egui::CursorIcon::ALL {
let _ = ui
.button(format!("{:?}", cursor_icon))
.on_hover_cursor(cursor_icon);
}
});
}
}
// ----------------------------------------------------------------------------
#[derive(Default)]
pub struct IdTest {}

View file

@ -173,7 +173,7 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
let mut previous_frame_time = None;
let mut painter = Painter::new(&display);
let mut clipboard = init_clipboard();
let mut previous_cursor_icon = None;
let mut current_cursor_icon = CursorIcon::Default;
#[cfg(feature = "persistence")]
let mut last_auto_save = Instant::now();
@ -209,14 +209,10 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
ctx.clear_animations();
let (egui_output, _shapes) = ctx.end_frame();
let new_cursor_icon = egui_output.cursor_icon;
handle_output(egui_output, clipboard.as_mut());
display
.gl_window()
.window()
.set_cursor_icon(translate_cursor(new_cursor_icon));
previous_cursor_icon = Some(new_cursor_icon);
set_cursor_icon(&display, egui_output.cursor_icon);
current_cursor_icon = egui_output.cursor_icon;
handle_output(egui_output, clipboard.as_mut());
// TODO: handle app_output
// eprintln!("Warmed up in {} ms", warm_up_start.elapsed().as_millis())
@ -285,18 +281,13 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
}
screen_reader.speak(&egui_output.events_description());
let new_cursor_icon = egui_output.cursor_icon;
handle_output(egui_output, clipboard.as_mut());
if Some(new_cursor_icon) != previous_cursor_icon {
if 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
display
.gl_window()
.window()
.set_cursor_icon(translate_cursor(new_cursor_icon));
previous_cursor_icon = Some(new_cursor_icon);
set_cursor_icon(&display, egui_output.cursor_icon);
current_cursor_icon = egui_output.cursor_icon;
}
handle_output(egui_output, clipboard.as_mut());
#[cfg(feature = "persistence")]
if let Some(storage) = &mut storage {

View file

@ -263,17 +263,43 @@ pub fn translate_virtual_key_code(key: VirtualKeyCode) -> Option<egui::Key> {
})
}
pub fn translate_cursor(cursor_icon: egui::CursorIcon) -> glutin::window::CursorIcon {
fn translate_cursor(cursor_icon: egui::CursorIcon) -> Option<glutin::window::CursorIcon> {
match cursor_icon {
CursorIcon::Default => glutin::window::CursorIcon::Default,
CursorIcon::PointingHand => glutin::window::CursorIcon::Hand,
CursorIcon::ResizeHorizontal => glutin::window::CursorIcon::EwResize,
CursorIcon::ResizeNeSw => glutin::window::CursorIcon::NeswResize,
CursorIcon::ResizeNwSe => glutin::window::CursorIcon::NwseResize,
CursorIcon::ResizeVertical => glutin::window::CursorIcon::NsResize,
CursorIcon::Text => glutin::window::CursorIcon::Text,
CursorIcon::Grab => glutin::window::CursorIcon::Grab,
CursorIcon::Grabbing => glutin::window::CursorIcon::Grabbing,
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);
}
}

View file

@ -283,20 +283,32 @@ where
}
fn cursor_web_name(cursor: egui::CursorIcon) -> &'static str {
use egui::CursorIcon::*;
match cursor {
Default => "default",
PointingHand => "pointer",
ResizeHorizontal => "ew-resize",
ResizeNeSw => "nesw-resize",
ResizeNwSe => "nwse-resize",
ResizeVertical => "ns-resize",
Text => "text",
Grab => "grab",
Grabbing => "grabbing",
// "no-drop"
// "not-allowed"
// default, help, pointer, progress, wait, cell, crosshair, text, alias, copy, move
egui::CursorIcon::Alias => "alias",
egui::CursorIcon::AllScroll => "all-scroll",
egui::CursorIcon::Cell => "cell",
egui::CursorIcon::ContextMenu => "context-menu",
egui::CursorIcon::Copy => "copy",
egui::CursorIcon::Crosshair => "crosshair",
egui::CursorIcon::Default => "default",
egui::CursorIcon::Grab => "grab",
egui::CursorIcon::Grabbing => "grabbing",
egui::CursorIcon::Help => "help",
egui::CursorIcon::Move => "move",
egui::CursorIcon::NoDrop => "no-drop",
egui::CursorIcon::None => "none",
egui::CursorIcon::NotAllowed => "not-allowed",
egui::CursorIcon::PointingHand => "pointer",
egui::CursorIcon::Progress => "progress",
egui::CursorIcon::ResizeHorizontal => "ew-resize",
egui::CursorIcon::ResizeNeSw => "nesw-resize",
egui::CursorIcon::ResizeNwSe => "nwse-resize",
egui::CursorIcon::ResizeVertical => "ns-resize",
egui::CursorIcon::Text => "text",
egui::CursorIcon::VerticalText => "vertical-text",
egui::CursorIcon::Wait => "wait",
egui::CursorIcon::ZoomIn => "zoom-in",
egui::CursorIcon::ZoomOut => "zoom-out",
}
}