mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-17 08:28:44 +00:00
Pull input+winit stuff from 0.1-dev
This commit is contained in:
parent
0825a8c97b
commit
721bf46746
@ -1,13 +1,11 @@
|
||||
use imgui::{FontGlyphRange, ImFontConfig, Context, Ui};
|
||||
use imgui_gfx_renderer::{Renderer, Shaders};
|
||||
use imgui_winit_support;
|
||||
use imgui_winit_support::{WinitPlatform, HiDpiMode};
|
||||
use std::time::Instant;
|
||||
|
||||
#[cfg(feature = "opengl")]
|
||||
pub fn run<F: FnMut(&Ui) -> bool>(title: String, clear_color: [f32; 4], mut run_ui: F) {
|
||||
use gfx::{self, Device};
|
||||
use gfx_window_glutin;
|
||||
use glutin;
|
||||
use gfx::{Device};
|
||||
|
||||
type ColorFormat = gfx::format::Rgba8;
|
||||
type DepthFormat = gfx::format::DepthStencil;
|
||||
@ -60,10 +58,10 @@ pub fn run<F: FnMut(&Ui) -> bool>(title: String, clear_color: [f32; 4], mut run_
|
||||
}
|
||||
imgui.set_ini_filename(None);
|
||||
|
||||
// In the examples we only use integer DPI factors, because the UI can get very blurry
|
||||
// otherwise. This might or might not be what you want in a real application.
|
||||
let hidpi_factor = window.get_hidpi_factor().round();
|
||||
let mut platform = WinitPlatform::init(&mut imgui);
|
||||
platform.attach_window(imgui.io_mut(), &window, HiDpiMode::Rounded);
|
||||
|
||||
let hidpi_factor = platform.hidpi_factor();
|
||||
let font_size = (13.0 * hidpi_factor) as f32;
|
||||
|
||||
imgui.fonts().add_default_font_with_config(
|
||||
@ -89,8 +87,6 @@ pub fn run<F: FnMut(&Ui) -> bool>(title: String, clear_color: [f32; 4], mut run_
|
||||
let mut renderer = Renderer::init(&mut imgui, &mut factory, shaders, main_color.clone())
|
||||
.expect("Failed to initialize renderer");
|
||||
|
||||
imgui_winit_support::configure_keys(&mut imgui);
|
||||
|
||||
let mut last_frame = Instant::now();
|
||||
let mut quit = false;
|
||||
|
||||
@ -101,12 +97,7 @@ pub fn run<F: FnMut(&Ui) -> bool>(title: String, clear_color: [f32; 4], mut run_
|
||||
WindowEvent::{CloseRequested, Resized},
|
||||
};
|
||||
|
||||
imgui_winit_support::handle_event(
|
||||
&mut imgui,
|
||||
&event,
|
||||
window.get_hidpi_factor(),
|
||||
hidpi_factor,
|
||||
);
|
||||
platform.handle_event(imgui.io_mut(), &window, &event);
|
||||
|
||||
if let Event::WindowEvent { event, .. } = event {
|
||||
match event {
|
||||
@ -123,16 +114,11 @@ pub fn run<F: FnMut(&Ui) -> bool>(title: String, clear_color: [f32; 4], mut run_
|
||||
break;
|
||||
}
|
||||
|
||||
let now = Instant::now();
|
||||
let delta = now - last_frame;
|
||||
let delta_s = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0;
|
||||
last_frame = now;
|
||||
let io = imgui.io_mut();
|
||||
platform.prepare_frame(io, &window).expect("Failed to start frame");
|
||||
last_frame = io.update_delta_time(last_frame);
|
||||
|
||||
imgui_winit_support::update_mouse_cursor(&imgui, &window);
|
||||
|
||||
let frame_size = imgui_winit_support::get_frame_size(&window, hidpi_factor).unwrap();
|
||||
|
||||
let ui = imgui.frame(frame_size, delta_s);
|
||||
let ui = imgui.frame();
|
||||
if !run_ui(&ui) {
|
||||
break;
|
||||
}
|
||||
@ -266,6 +252,7 @@ pub fn run<F: FnMut(&Ui) -> bool>(title: String, clear_color: [f32; 4], mut run_
|
||||
}
|
||||
|
||||
encoder.clear(&main_color, clear_color);
|
||||
platform.prepare_render(&ui, &window);
|
||||
renderer
|
||||
.render(ui, &mut factory, &mut encoder)
|
||||
.expect("Rendering failed");
|
||||
|
||||
@ -4,7 +4,7 @@ use gfx::pso::{PipelineData, PipelineState};
|
||||
use gfx::texture::{FilterMethod, SamplerInfo, WrapMode};
|
||||
use gfx::traits::FactoryExt;
|
||||
use gfx::{CommandBuffer, Encoder, Factory, IntoIndexBuffer, Rect, Resources, Slice};
|
||||
use imgui::{Context, DrawList, FrameSize, ImDrawIdx, ImDrawVert, ImTexture, Textures, Ui};
|
||||
use imgui::{Context, DrawList, ImDrawIdx, ImDrawVert, ImTexture, Textures, Ui};
|
||||
|
||||
pub type RendererResult<T> = Result<T, RendererError>;
|
||||
|
||||
@ -261,10 +261,8 @@ impl<R: Resources> Renderer<R> {
|
||||
factory: &mut F,
|
||||
encoder: &mut Encoder<R, C>,
|
||||
) -> RendererResult<()> {
|
||||
let FrameSize {
|
||||
logical_size: (width, height),
|
||||
hidpi_factor,
|
||||
} = ui.frame_size();
|
||||
let [width, height] = ui.io().display_size;
|
||||
let hidpi_factor = ui.io().display_framebuffer_scale[0];
|
||||
|
||||
if !(width > 0.0 && height > 0.0) {
|
||||
return Ok(());
|
||||
|
||||
@ -3,7 +3,7 @@ use glium::{
|
||||
Texture2d,
|
||||
};
|
||||
use imgui::{FontGlyphRange, ImFontConfig, self, Ui};
|
||||
use imgui_winit_support;
|
||||
use imgui_winit_support::{HiDpiMode, WinitPlatform};
|
||||
use std::rc::Rc;
|
||||
use std::time::Instant;
|
||||
|
||||
@ -29,10 +29,10 @@ where
|
||||
let mut imgui = imgui::Context::create();
|
||||
imgui.set_ini_filename(None);
|
||||
|
||||
// In the examples we only use integer DPI factors, because the UI can get very blurry
|
||||
// otherwise. This might or might not be what you want in a real application.
|
||||
let hidpi_factor = window.get_hidpi_factor().round();
|
||||
let mut platform = WinitPlatform::init(&mut imgui);
|
||||
platform.attach_window(imgui.io_mut(), &window, HiDpiMode::Rounded);
|
||||
|
||||
let hidpi_factor = platform.hidpi_factor();
|
||||
let font_size = (13.0 * hidpi_factor) as f32;
|
||||
|
||||
imgui.fonts().add_default_font_with_config(
|
||||
@ -53,12 +53,10 @@ where
|
||||
&FontGlyphRange::japanese(),
|
||||
);
|
||||
|
||||
imgui.set_font_global_scale((1.0 / hidpi_factor) as f32);
|
||||
imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32;
|
||||
|
||||
let mut renderer = Renderer::init(&mut imgui, &display).expect("Failed to initialize renderer");
|
||||
|
||||
imgui_winit_support::configure_keys(&mut imgui);
|
||||
|
||||
let mut last_frame = Instant::now();
|
||||
let mut quit = false;
|
||||
|
||||
@ -66,12 +64,7 @@ where
|
||||
events_loop.poll_events(|event| {
|
||||
use glium::glutin::{Event, WindowEvent::CloseRequested};
|
||||
|
||||
imgui_winit_support::handle_event(
|
||||
&mut imgui,
|
||||
&event,
|
||||
window.get_hidpi_factor(),
|
||||
hidpi_factor,
|
||||
);
|
||||
platform.handle_event(imgui.io_mut(), &window, &event);
|
||||
|
||||
if let Event::WindowEvent { event, .. } = event {
|
||||
match event {
|
||||
@ -81,16 +74,12 @@ where
|
||||
}
|
||||
});
|
||||
|
||||
let now = Instant::now();
|
||||
let delta = now - last_frame;
|
||||
let delta_s = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0;
|
||||
last_frame = now;
|
||||
|
||||
imgui_winit_support::update_mouse_cursor(&imgui, &window);
|
||||
|
||||
let frame_size = imgui_winit_support::get_frame_size(&window, hidpi_factor).unwrap();
|
||||
|
||||
let ui = imgui.frame(frame_size, delta_s);
|
||||
let io = imgui.io_mut();
|
||||
platform
|
||||
.prepare_frame(io, &window)
|
||||
.expect("Failed to start frame");
|
||||
last_frame = io.update_delta_time(last_frame);
|
||||
let ui = imgui.frame();
|
||||
if !run_ui(&ui, display.get_context(), renderer.textures()) {
|
||||
break;
|
||||
}
|
||||
@ -102,6 +91,7 @@ where
|
||||
clear_color[2],
|
||||
clear_color[3],
|
||||
);
|
||||
platform.prepare_render(&ui, &window);
|
||||
renderer.render(&mut target, ui).expect("Rendering failed");
|
||||
target.finish().unwrap();
|
||||
|
||||
|
||||
@ -1051,17 +1051,17 @@ fn show_example_app_custom_rendering(ui: &Ui, state: &mut CustomRenderingState,
|
||||
if state.adding_line {
|
||||
adding_preview = true;
|
||||
state.points.push(mouse_pos_in_canvas);
|
||||
if !ui.imgui().is_mouse_down(ImMouseButton::Left) {
|
||||
if !ui.imgui().is_mouse_down(MouseButton::Left) {
|
||||
state.adding_line = false;
|
||||
adding_preview = false;
|
||||
}
|
||||
}
|
||||
if ui.is_item_hovered() {
|
||||
if !state.adding_line && ui.imgui().is_mouse_clicked(ImMouseButton::Left) {
|
||||
if !state.adding_line && ui.imgui().is_mouse_clicked(MouseButton::Left) {
|
||||
state.points.push(mouse_pos_in_canvas);
|
||||
state.adding_line = true;
|
||||
}
|
||||
if ui.imgui().is_mouse_clicked(ImMouseButton::Right) && !state.points.is_empty() {
|
||||
if ui.imgui().is_mouse_clicked(MouseButton::Right) && !state.points.is_empty() {
|
||||
state.adding_line = false;
|
||||
adding_preview = false;
|
||||
state.points.pop();
|
||||
|
||||
@ -4,7 +4,7 @@ use glium::program;
|
||||
use glium::texture;
|
||||
use glium::vertex;
|
||||
use glium::{uniform, DrawError, IndexBuffer, Program, Surface, Texture2d, VertexBuffer};
|
||||
use imgui::{self, DrawList, FrameSize, ImTexture, Textures, Ui};
|
||||
use imgui::{self, DrawList, ImTexture, Textures, Ui};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
@ -85,10 +85,8 @@ impl Renderer {
|
||||
|
||||
pub fn render<'a, S: Surface>(&mut self, surface: &mut S, ui: Ui<'a>) -> RendererResult<()> {
|
||||
let _ = self.ctx.insert_debug_marker("imgui-rs: starting rendering");
|
||||
let FrameSize {
|
||||
logical_size: (width, height),
|
||||
hidpi_factor,
|
||||
} = ui.frame_size();
|
||||
let [width, height] = ui.io().display_size;
|
||||
let hidpi_factor = ui.io().display_framebuffer_scale[0];
|
||||
if !(width > 0.0 && height > 0.0) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -26,102 +26,3 @@ impl ImGuiDataType {
|
||||
ImGuiDataType::Double,
|
||||
];
|
||||
}
|
||||
|
||||
/// A key identifier (ImGui-side enum)
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ImGuiKey {
|
||||
Tab,
|
||||
LeftArrow,
|
||||
RightArrow,
|
||||
UpArrow,
|
||||
DownArrow,
|
||||
PageUp,
|
||||
PageDown,
|
||||
Home,
|
||||
End,
|
||||
Insert,
|
||||
Delete,
|
||||
Backspace,
|
||||
Space,
|
||||
Enter,
|
||||
Escape,
|
||||
/// for text edit CTRL+A: select all
|
||||
A,
|
||||
/// for text edit CTRL+C: copy
|
||||
C,
|
||||
/// for text edit CTRL+V: paste
|
||||
V,
|
||||
/// for text edit CTRL+X: cut
|
||||
X,
|
||||
/// for text edit CTRL+Y: redo
|
||||
Y,
|
||||
/// for text edit CTRL+Z: undo
|
||||
Z,
|
||||
}
|
||||
impl ImGuiKey {
|
||||
/// All possible `ImGuiKey` variants
|
||||
pub const VARIANTS: [ImGuiKey; 21] = [
|
||||
ImGuiKey::Tab,
|
||||
ImGuiKey::LeftArrow,
|
||||
ImGuiKey::RightArrow,
|
||||
ImGuiKey::UpArrow,
|
||||
ImGuiKey::DownArrow,
|
||||
ImGuiKey::PageUp,
|
||||
ImGuiKey::PageDown,
|
||||
ImGuiKey::Home,
|
||||
ImGuiKey::End,
|
||||
ImGuiKey::Insert,
|
||||
ImGuiKey::Delete,
|
||||
ImGuiKey::Backspace,
|
||||
ImGuiKey::Space,
|
||||
ImGuiKey::Enter,
|
||||
ImGuiKey::Escape,
|
||||
ImGuiKey::A,
|
||||
ImGuiKey::C,
|
||||
ImGuiKey::V,
|
||||
ImGuiKey::X,
|
||||
ImGuiKey::Y,
|
||||
ImGuiKey::Z,
|
||||
];
|
||||
pub const COUNT: usize = 21;
|
||||
}
|
||||
|
||||
/// A mouse cursor identifier
|
||||
///
|
||||
/// User code may request binding to display given cursor, which is why we have some cursors that
|
||||
/// are marked unused here
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ImGuiMouseCursor {
|
||||
None = -1,
|
||||
Arrow = 0,
|
||||
/// When hovering over InputText, etc.
|
||||
TextInput,
|
||||
/// (Unused by imgui functions)
|
||||
ResizeAll,
|
||||
/// When hovering over an horizontal border
|
||||
ResizeNS,
|
||||
/// When hovering over a vertical border or a column
|
||||
ResizeEW,
|
||||
/// When hovering over the bottom-left corner of a window
|
||||
ResizeNESW,
|
||||
/// When hovering over the bottom-right corner of a window
|
||||
ResizeNWSE,
|
||||
/// (Unused by imgui functions. Use for e.g. hyperlinks)
|
||||
Hand,
|
||||
}
|
||||
impl ImGuiMouseCursor {
|
||||
/// All possible `ImGuiMouseCursor` variants, except None
|
||||
pub const VARIANTS: [ImGuiMouseCursor; 8] = [
|
||||
// None variant intentionally skipped
|
||||
ImGuiMouseCursor::Arrow,
|
||||
ImGuiMouseCursor::TextInput,
|
||||
ImGuiMouseCursor::ResizeAll,
|
||||
ImGuiMouseCursor::ResizeNS,
|
||||
ImGuiMouseCursor::ResizeEW,
|
||||
ImGuiMouseCursor::ResizeNESW,
|
||||
ImGuiMouseCursor::ResizeNWSE,
|
||||
ImGuiMouseCursor::Hand,
|
||||
];
|
||||
}
|
||||
|
||||
@ -62,15 +62,22 @@ pub use bindings::{
|
||||
ImGuiIO_ClearInputCharacters, ImGuiInputTextCallback, ImGuiInputTextCallbackData,
|
||||
ImGuiInputTextCallbackData_DeleteChars, ImGuiInputTextCallbackData_HasSelection,
|
||||
ImGuiInputTextCallbackData_ImGuiInputTextCallbackData, ImGuiInputTextCallbackData_InsertChars,
|
||||
ImGuiInputTextCallbackData_destroy, ImGuiKey_COUNT, ImGuiListClipper, ImGuiNavInput_,
|
||||
ImGuiNavInput_Activate, ImGuiNavInput_COUNT, ImGuiNavInput_Cancel, ImGuiNavInput_DpadDown,
|
||||
ImGuiNavInput_DpadLeft, ImGuiNavInput_DpadRight, ImGuiNavInput_DpadUp, ImGuiNavInput_FocusNext,
|
||||
ImGuiNavInput_FocusPrev, ImGuiNavInput_Input, ImGuiNavInput_InternalStart_,
|
||||
ImGuiNavInput_KeyDown_, ImGuiNavInput_KeyLeft_, ImGuiNavInput_KeyMenu_,
|
||||
ImGuiNavInput_KeyRight_, ImGuiNavInput_KeyTab_, ImGuiNavInput_KeyUp_, ImGuiNavInput_LStickDown,
|
||||
ImGuiNavInput_LStickLeft, ImGuiNavInput_LStickRight, ImGuiNavInput_LStickUp,
|
||||
ImGuiNavInput_Menu, ImGuiNavInput_TweakFast, ImGuiNavInput_TweakSlow, ImGuiPayload,
|
||||
ImGuiSizeCallback, ImGuiStorage, ImGuiStyle, ImGuiStyleVar, ImGuiStyleVar_,
|
||||
ImGuiInputTextCallbackData_destroy, ImGuiKey, ImGuiKey_, ImGuiKey_A, ImGuiKey_Backspace,
|
||||
ImGuiKey_C, ImGuiKey_COUNT, ImGuiKey_Delete, ImGuiKey_DownArrow, ImGuiKey_End, ImGuiKey_Enter,
|
||||
ImGuiKey_Escape, ImGuiKey_Home, ImGuiKey_Insert, ImGuiKey_LeftArrow, ImGuiKey_PageDown,
|
||||
ImGuiKey_PageUp, ImGuiKey_RightArrow, ImGuiKey_Space, ImGuiKey_Tab, ImGuiKey_UpArrow,
|
||||
ImGuiKey_V, ImGuiKey_X, ImGuiKey_Y, ImGuiKey_Z, ImGuiListClipper, ImGuiMouseCursor,
|
||||
ImGuiMouseCursor_, ImGuiMouseCursor_Arrow, ImGuiMouseCursor_COUNT, ImGuiMouseCursor_Hand,
|
||||
ImGuiMouseCursor_None, ImGuiMouseCursor_ResizeAll, ImGuiMouseCursor_ResizeEW,
|
||||
ImGuiMouseCursor_ResizeNESW, ImGuiMouseCursor_ResizeNS, ImGuiMouseCursor_ResizeNWSE,
|
||||
ImGuiMouseCursor_TextInput, ImGuiNavInput_, ImGuiNavInput_Activate, ImGuiNavInput_COUNT,
|
||||
ImGuiNavInput_Cancel, ImGuiNavInput_DpadDown, ImGuiNavInput_DpadLeft, ImGuiNavInput_DpadRight,
|
||||
ImGuiNavInput_DpadUp, ImGuiNavInput_FocusNext, ImGuiNavInput_FocusPrev, ImGuiNavInput_Input,
|
||||
ImGuiNavInput_InternalStart_, ImGuiNavInput_KeyDown_, ImGuiNavInput_KeyLeft_,
|
||||
ImGuiNavInput_KeyMenu_, ImGuiNavInput_KeyRight_, ImGuiNavInput_KeyTab_, ImGuiNavInput_KeyUp_,
|
||||
ImGuiNavInput_LStickDown, ImGuiNavInput_LStickLeft, ImGuiNavInput_LStickRight,
|
||||
ImGuiNavInput_LStickUp, ImGuiNavInput_Menu, ImGuiNavInput_TweakFast, ImGuiNavInput_TweakSlow,
|
||||
ImGuiPayload, ImGuiSizeCallback, ImGuiStorage, ImGuiStyle, ImGuiStyleVar, ImGuiStyleVar_,
|
||||
ImGuiStyleVar_Alpha, ImGuiStyleVar_ButtonTextAlign, ImGuiStyleVar_COUNT,
|
||||
ImGuiStyleVar_ChildBorderSize, ImGuiStyleVar_ChildRounding, ImGuiStyleVar_FrameBorderSize,
|
||||
ImGuiStyleVar_FramePadding, ImGuiStyleVar_FrameRounding, ImGuiStyleVar_GrabMinSize,
|
||||
|
||||
@ -1,259 +1,402 @@
|
||||
//! This crate provides support functions to simplify integrating imgui-rs with winit.
|
||||
//! This crate provides a winit-based backend platform for imgui-rs.
|
||||
//!
|
||||
//! A backend platform handles window/input device events and manages their state.
|
||||
//!
|
||||
//! # Using the library
|
||||
//!
|
||||
//! In your initialization code call `configure_keys`:
|
||||
//! There are five things you need to do to use this library correctly:
|
||||
//!
|
||||
//! 1. Initialize a `WinitPlatform` instance
|
||||
//! 2. Attach it to a winit `Window`
|
||||
//! 3. Pass events to the platform (every frame)
|
||||
//! 4. Call frame preparation callback (every frame)
|
||||
//! 5. Call render preparation callback (every frame)
|
||||
//!
|
||||
//! ## Complete example (without a renderer)
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use imgui::Context;
|
||||
//! use imgui_winit_support::{HiDpiMode, WinitPlatform};
|
||||
//! use std::time::Instant;
|
||||
//! use winit::{Event, EventsLoop, Window, WindowEvent};
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! let mut imgui = Context::create();
|
||||
//! imgui_winit_support::configure_keys(&mut imgui);
|
||||
//! # }
|
||||
//! ```
|
||||
//! fn main() {
|
||||
//! let mut events_loop = EventsLoop::new();
|
||||
//! let mut window = Window::new(&events_loop).unwrap();
|
||||
//!
|
||||
//! In your main loop you should already be retrieving events from winit and handling them. All
|
||||
//! you need to do is pass each event to `imgui_winit_support` as well:
|
||||
//! let mut imgui = Context::create();
|
||||
//! // configure imgui-rs Context if necessary
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # use imgui::Context;
|
||||
//! # use winit::EventsLoop;
|
||||
//! # fn main() {
|
||||
//! # let mut events_loop = EventsLoop::new();
|
||||
//! # let mut imgui = Context::create();
|
||||
//! # let window_hidpi_factor = 1.0;
|
||||
//! # let app_hidpi_factor = 1.0;
|
||||
//! events_loop.poll_events(|event| {
|
||||
//! // do application-specific stuff with event
|
||||
//! let mut platform = WinitPlatform::init(&mut imgui); // step 1
|
||||
//! platform.attach_window(imgui.io_mut(), &window, HiDpiMode::Default); // step 2
|
||||
//!
|
||||
//! imgui_winit_support::handle_event(
|
||||
//! &mut imgui,
|
||||
//! &event,
|
||||
//! window_hidpi_factor,
|
||||
//! app_hidpi_factor
|
||||
//! );
|
||||
//! });
|
||||
//! # }
|
||||
//! ```
|
||||
//! let mut last_frame = Instant::now();
|
||||
//! let mut run = true;
|
||||
//! while run {
|
||||
//! events_loop.poll_events(|event| {
|
||||
//! platform.handle_event(imgui.io_mut(), &window, &event); // step 3
|
||||
//!
|
||||
//! # Advanced use cases
|
||||
//!
|
||||
//! In more advanced use cases you might want to handle and filter events yourself and call some of
|
||||
//! the various smaller helper functions exported by the library.
|
||||
//!
|
||||
//! For example, you might want to customize mouse wheel line scrolling amount:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # use imgui::Context;
|
||||
//! # use winit::{EventsLoop, Event, WindowEvent, MouseScrollDelta, TouchPhase};
|
||||
//! # fn main() {
|
||||
//! # let mut events_loop = EventsLoop::new();
|
||||
//! # let mut imgui = Context::create();
|
||||
//! # let window_hidpi_factor = 1.0;
|
||||
//! # let app_hidpi_factor = 1.0;
|
||||
//! events_loop.poll_events(|event| {
|
||||
//! // do application-specific stuff with event
|
||||
//!
|
||||
//! // default handling for events
|
||||
//! imgui_winit_support::handle_event(
|
||||
//! &mut imgui,
|
||||
//! &event,
|
||||
//! window_hidpi_factor,
|
||||
//! app_hidpi_factor
|
||||
//! );
|
||||
//!
|
||||
//! // Scroll 10 times the pixels per line by handling LineDelta events again and
|
||||
//! // overriding the mouse wheel value
|
||||
//! if let Event::WindowEvent { event, .. } = event {
|
||||
//! match event {
|
||||
//! WindowEvent::MouseWheel {
|
||||
//! delta: MouseScrollDelta::LineDelta(_, lines),
|
||||
//! phase: TouchPhase::Moved,
|
||||
//! ..
|
||||
//! } => {
|
||||
//! imgui.set_mouse_wheel(lines * 10.0);
|
||||
//! // application-specific event handling
|
||||
//! // for example:
|
||||
//! if let Event::WindowEvent { event, .. } = event {
|
||||
//! match event {
|
||||
//! WindowEvent::CloseRequested => run = false,
|
||||
//! _ => (),
|
||||
//! }
|
||||
//! }
|
||||
//! _ => ()
|
||||
//! }
|
||||
//! });
|
||||
//!
|
||||
//! platform.prepare_frame(imgui.io_mut(), &window) // step 4
|
||||
//! .expect("Failed to prepare frame");
|
||||
//! last_frame = imgui.io_mut().update_delta_time(last_frame);
|
||||
//! let ui = imgui.frame();
|
||||
//!
|
||||
//! // application-specific rendering *under the UI*
|
||||
//!
|
||||
//! // construct the UI
|
||||
//!
|
||||
//! platform.prepare_render(&ui, &window); // step 5
|
||||
//! // render the UI with a renderer
|
||||
//! // renderer.render(..., ui).expect("UI rendering failed");
|
||||
//!
|
||||
//! // application-specific rendering *over the UI*
|
||||
//! }
|
||||
//! });
|
||||
//! # }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use imgui::{Context, FrameSize, ImGuiKey, ImGuiMouseCursor};
|
||||
use imgui::{self, BackendFlags, ConfigFlags, Context, ImString, Io, Key, Ui};
|
||||
use std::cmp::Ordering;
|
||||
use winit::dpi::{LogicalPosition, LogicalSize};
|
||||
use winit::{
|
||||
ElementState, Event, KeyboardInput, ModifiersState, MouseButton, MouseCursor, MouseScrollDelta,
|
||||
DeviceEvent, ElementState, Event, KeyboardInput, MouseButton, MouseCursor, MouseScrollDelta,
|
||||
TouchPhase, VirtualKeyCode, Window, WindowEvent,
|
||||
};
|
||||
|
||||
/// Configure imgui key map with winit `VirtualKeyCode` values
|
||||
pub fn configure_keys(imgui: &mut Context) {
|
||||
imgui.set_imgui_key(ImGuiKey::Tab, VirtualKeyCode::Tab as _);
|
||||
imgui.set_imgui_key(ImGuiKey::LeftArrow, VirtualKeyCode::Left as _);
|
||||
imgui.set_imgui_key(ImGuiKey::RightArrow, VirtualKeyCode::Right as _);
|
||||
imgui.set_imgui_key(ImGuiKey::UpArrow, VirtualKeyCode::Up as _);
|
||||
imgui.set_imgui_key(ImGuiKey::DownArrow, VirtualKeyCode::Down as _);
|
||||
imgui.set_imgui_key(ImGuiKey::PageUp, VirtualKeyCode::PageUp as _);
|
||||
imgui.set_imgui_key(ImGuiKey::PageDown, VirtualKeyCode::PageDown as _);
|
||||
imgui.set_imgui_key(ImGuiKey::Home, VirtualKeyCode::Home as _);
|
||||
imgui.set_imgui_key(ImGuiKey::End, VirtualKeyCode::End as _);
|
||||
imgui.set_imgui_key(ImGuiKey::Delete, VirtualKeyCode::Delete as _);
|
||||
imgui.set_imgui_key(ImGuiKey::Backspace, VirtualKeyCode::Back as _);
|
||||
imgui.set_imgui_key(ImGuiKey::Enter, VirtualKeyCode::Return as _);
|
||||
imgui.set_imgui_key(ImGuiKey::Escape, VirtualKeyCode::Escape as _);
|
||||
imgui.set_imgui_key(ImGuiKey::A, VirtualKeyCode::A as _);
|
||||
imgui.set_imgui_key(ImGuiKey::C, VirtualKeyCode::C as _);
|
||||
imgui.set_imgui_key(ImGuiKey::V, VirtualKeyCode::V as _);
|
||||
imgui.set_imgui_key(ImGuiKey::X, VirtualKeyCode::X as _);
|
||||
imgui.set_imgui_key(ImGuiKey::Y, VirtualKeyCode::Y as _);
|
||||
imgui.set_imgui_key(ImGuiKey::Z, VirtualKeyCode::Z as _);
|
||||
/// winit backend platform state
|
||||
#[derive(Debug)]
|
||||
pub struct WinitPlatform {
|
||||
hidpi_mode: ActiveHiDpiMode,
|
||||
hidpi_factor: f64,
|
||||
}
|
||||
|
||||
/// Update imgui keyboard state
|
||||
pub fn handle_keyboard_input(imgui: &mut Context, event: KeyboardInput) {
|
||||
handle_modifiers(imgui, event.modifiers);
|
||||
if let Some(key) = event.virtual_keycode {
|
||||
let state_bool = event.state == ElementState::Pressed;
|
||||
imgui.set_key(key as _, state_bool);
|
||||
match key {
|
||||
VirtualKeyCode::LShift | VirtualKeyCode::RShift => imgui.set_key_shift(state_bool),
|
||||
VirtualKeyCode::LControl | VirtualKeyCode::RControl => imgui.set_key_ctrl(state_bool),
|
||||
VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => imgui.set_key_alt(state_bool),
|
||||
VirtualKeyCode::LWin | VirtualKeyCode::RWin => imgui.set_key_super(state_bool),
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum ActiveHiDpiMode {
|
||||
Default,
|
||||
Rounded,
|
||||
Locked,
|
||||
}
|
||||
|
||||
/// DPI factor handling mode.
|
||||
///
|
||||
/// Applications that use imgui-rs might want to customize the used DPI factor and not use
|
||||
/// directly the value coming from winit.
|
||||
///
|
||||
/// **Note: if you use a mode other than default and the DPI factor is adjusted, winit and imgui-rs
|
||||
/// will use different logical coordinates, so be careful if you pass around logical size or
|
||||
/// position values.**
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum HiDpiMode {
|
||||
/// The DPI factor from winit is used directly without adjustment
|
||||
Default,
|
||||
/// The DPI factor from winit is rounded to an integer value.
|
||||
///
|
||||
/// This prevents the user interface from becoming blurry with non-integer scaling.
|
||||
Rounded,
|
||||
/// The DPI factor from winit is ignored, and the included value is used instead.
|
||||
///
|
||||
/// This is useful if you want to force some DPI factor (e.g. 1.0) and not care about the value
|
||||
/// coming from winit.
|
||||
Locked(f64),
|
||||
}
|
||||
|
||||
impl HiDpiMode {
|
||||
fn apply(&self, hidpi_factor: f64) -> (ActiveHiDpiMode, f64) {
|
||||
match *self {
|
||||
HiDpiMode::Default => (ActiveHiDpiMode::Default, hidpi_factor),
|
||||
HiDpiMode::Rounded => (ActiveHiDpiMode::Rounded, hidpi_factor.round()),
|
||||
HiDpiMode::Locked(value) => (ActiveHiDpiMode::Locked, value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WinitPlatform {
|
||||
/// Initializes a winit platform instance and configures imgui.
|
||||
///
|
||||
/// This function configures imgui-rs in the following ways:
|
||||
///
|
||||
/// * backend flags are updated
|
||||
/// * keys are configured
|
||||
/// * platform name is set
|
||||
pub fn init(imgui: &mut Context) -> WinitPlatform {
|
||||
let io = imgui.io_mut();
|
||||
io.backend_flags.insert(BackendFlags::HAS_MOUSE_CURSORS);
|
||||
io.backend_flags.insert(BackendFlags::HAS_SET_MOUSE_POS);
|
||||
io[Key::Tab] = VirtualKeyCode::Tab as _;
|
||||
io[Key::LeftArrow] = VirtualKeyCode::Left as _;
|
||||
io[Key::RightArrow] = VirtualKeyCode::Right as _;
|
||||
io[Key::UpArrow] = VirtualKeyCode::Up as _;
|
||||
io[Key::DownArrow] = VirtualKeyCode::Down as _;
|
||||
io[Key::PageUp] = VirtualKeyCode::PageUp as _;
|
||||
io[Key::PageDown] = VirtualKeyCode::PageDown as _;
|
||||
io[Key::Home] = VirtualKeyCode::Home as _;
|
||||
io[Key::End] = VirtualKeyCode::End as _;
|
||||
io[Key::Insert] = VirtualKeyCode::Insert as _;
|
||||
io[Key::Delete] = VirtualKeyCode::Delete as _;
|
||||
io[Key::Backspace] = VirtualKeyCode::Back as _;
|
||||
io[Key::Space] = VirtualKeyCode::Space as _;
|
||||
io[Key::Enter] = VirtualKeyCode::Return as _;
|
||||
io[Key::Escape] = VirtualKeyCode::Escape as _;
|
||||
io[Key::A] = VirtualKeyCode::A as _;
|
||||
io[Key::C] = VirtualKeyCode::C as _;
|
||||
io[Key::V] = VirtualKeyCode::V as _;
|
||||
io[Key::X] = VirtualKeyCode::X as _;
|
||||
io[Key::Y] = VirtualKeyCode::Y as _;
|
||||
io[Key::Z] = VirtualKeyCode::Z as _;
|
||||
imgui.set_platform_name(Some(ImString::from(format!(
|
||||
"imgui-winit-support {}",
|
||||
env!("CARGO_PKG_VERSION")
|
||||
))));
|
||||
WinitPlatform {
|
||||
hidpi_mode: ActiveHiDpiMode::Default,
|
||||
hidpi_factor: 1.0,
|
||||
}
|
||||
}
|
||||
/// Attaches the platform instance to a winit window.
|
||||
///
|
||||
/// This function configures imgui-rs in the following ways:
|
||||
///
|
||||
/// * framebuffer scale (= DPI factor) is set
|
||||
/// * display size is set
|
||||
pub fn attach_window(&mut self, io: &mut Io, window: &Window, hidpi_mode: HiDpiMode) {
|
||||
let (hidpi_mode, hidpi_factor) = hidpi_mode.apply(window.get_hidpi_factor());
|
||||
self.hidpi_mode = hidpi_mode;
|
||||
self.hidpi_factor = hidpi_factor;
|
||||
io.display_framebuffer_scale = [hidpi_factor as f32, hidpi_factor as f32];
|
||||
if let Some(logical_size) = window.get_inner_size() {
|
||||
let logical_size = self.scale_size_from_winit(window, logical_size);
|
||||
io.display_size = [logical_size.width as f32, logical_size.height as f32];
|
||||
}
|
||||
}
|
||||
/// Returns the current DPI factor.
|
||||
///
|
||||
/// The value might not be the same as the winit DPI factor (depends on the used DPI mode)
|
||||
pub fn hidpi_factor(&self) -> f64 {
|
||||
self.hidpi_factor
|
||||
}
|
||||
/// Scales a logical size coming from winit using the current DPI mode.
|
||||
///
|
||||
/// This utility function is useful if you are using a DPI mode other than default, and want
|
||||
/// your application to use the same logical coordinates as imgui-rs.
|
||||
pub fn scale_size_from_winit(&self, window: &Window, logical_size: LogicalSize) -> LogicalSize {
|
||||
match self.hidpi_mode {
|
||||
ActiveHiDpiMode::Default => logical_size,
|
||||
_ => logical_size
|
||||
.to_physical(window.get_hidpi_factor())
|
||||
.to_logical(self.hidpi_factor),
|
||||
}
|
||||
}
|
||||
/// Scales a logical position coming from winit using the current DPI mode.
|
||||
///
|
||||
/// This utility function is useful if you are using a DPI mode other than default, and want
|
||||
/// your application to use the same logical coordinates as imgui-rs.
|
||||
pub fn scale_pos_from_winit(
|
||||
&self,
|
||||
window: &Window,
|
||||
logical_pos: LogicalPosition,
|
||||
) -> LogicalPosition {
|
||||
match self.hidpi_mode {
|
||||
ActiveHiDpiMode::Default => logical_pos,
|
||||
_ => logical_pos
|
||||
.to_physical(window.get_hidpi_factor())
|
||||
.to_logical(self.hidpi_factor),
|
||||
}
|
||||
}
|
||||
/// Scales a logical position for winit using the current DPI mode.
|
||||
///
|
||||
/// This utility function is useful if you are using a DPI mode other than default, and want
|
||||
/// your application to use the same logical coordinates as imgui-rs.
|
||||
pub fn scale_pos_for_winit(
|
||||
&self,
|
||||
window: &Window,
|
||||
logical_pos: LogicalPosition,
|
||||
) -> LogicalPosition {
|
||||
match self.hidpi_mode {
|
||||
ActiveHiDpiMode::Default => logical_pos,
|
||||
_ => logical_pos
|
||||
.to_physical(self.hidpi_factor)
|
||||
.to_logical(window.get_hidpi_factor()),
|
||||
}
|
||||
}
|
||||
/// Handles a winit event.
|
||||
///
|
||||
/// This function performs the following actions (depends on the event):
|
||||
///
|
||||
/// * window size / dpi factor changes are applied
|
||||
/// * keyboard state is updated
|
||||
/// * mouse state is updated
|
||||
pub fn handle_event(&mut self, io: &mut Io, window: &Window, event: &Event) {
|
||||
match *event {
|
||||
Event::WindowEvent {
|
||||
window_id,
|
||||
ref event,
|
||||
} if window_id == window.id() => {
|
||||
self.handle_window_event(io, window, event);
|
||||
}
|
||||
// Track key release events outside our window. If we don't do this,
|
||||
// we might never see the release event if some other window gets focus.
|
||||
Event::DeviceEvent {
|
||||
event:
|
||||
DeviceEvent::Key(KeyboardInput {
|
||||
state: ElementState::Released,
|
||||
virtual_keycode: Some(key),
|
||||
..
|
||||
}),
|
||||
..
|
||||
} => {
|
||||
io.keys_down[key as usize] = false;
|
||||
match key {
|
||||
VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = false,
|
||||
VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = false,
|
||||
VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = false,
|
||||
VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = false,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Update imgui keyboard modifier state
|
||||
pub fn handle_modifiers(imgui: &mut Context, modifiers: ModifiersState) {
|
||||
imgui.set_key_shift(modifiers.shift);
|
||||
imgui.set_key_ctrl(modifiers.ctrl);
|
||||
imgui.set_key_alt(modifiers.alt);
|
||||
imgui.set_key_super(modifiers.logo);
|
||||
}
|
||||
|
||||
/// Update imgui mouse wheel position
|
||||
pub fn handle_mouse_scroll_delta(
|
||||
imgui: &mut Context,
|
||||
delta: MouseScrollDelta,
|
||||
window_hidpi_factor: f64,
|
||||
app_hidpi_factor: f64,
|
||||
) {
|
||||
match delta {
|
||||
MouseScrollDelta::LineDelta(_, y) => imgui.set_mouse_wheel(y),
|
||||
MouseScrollDelta::PixelDelta(pos) => {
|
||||
let pos = pos
|
||||
.to_physical(window_hidpi_factor)
|
||||
.to_logical(app_hidpi_factor);
|
||||
imgui.set_mouse_wheel(pos.y as f32)
|
||||
fn handle_window_event(&mut self, io: &mut Io, window: &Window, event: &WindowEvent) {
|
||||
match *event {
|
||||
WindowEvent::Resized(logical_size) => {
|
||||
let logical_size = self.scale_size_from_winit(window, logical_size);
|
||||
io.display_size = [logical_size.width as f32, logical_size.height as f32];
|
||||
}
|
||||
WindowEvent::HiDpiFactorChanged(scale) => {
|
||||
let hidpi_factor = match self.hidpi_mode {
|
||||
ActiveHiDpiMode::Default => scale,
|
||||
ActiveHiDpiMode::Rounded => scale.round(),
|
||||
_ => return,
|
||||
};
|
||||
// Mouse position needs to be changed while we still have both the old and the new
|
||||
// values
|
||||
if io.mouse_pos[0].is_finite() && io.mouse_pos[1].is_finite() {
|
||||
io.mouse_pos = [
|
||||
io.mouse_pos[0] * (hidpi_factor / self.hidpi_factor) as f32,
|
||||
io.mouse_pos[1] * (hidpi_factor / self.hidpi_factor) as f32,
|
||||
];
|
||||
}
|
||||
self.hidpi_factor = hidpi_factor;
|
||||
io.display_framebuffer_scale = [hidpi_factor as f32, hidpi_factor as f32];
|
||||
// Window size might change too if we are using DPI rounding
|
||||
if let Some(logical_size) = window.get_inner_size() {
|
||||
let logical_size = self.scale_size_from_winit(window, logical_size);
|
||||
io.display_size = [logical_size.width as f32, logical_size.height as f32];
|
||||
}
|
||||
}
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(key),
|
||||
state,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
let pressed = state == ElementState::Pressed;
|
||||
io.keys_down[key as usize] = pressed;
|
||||
match key {
|
||||
VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = pressed,
|
||||
VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = pressed,
|
||||
VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = pressed,
|
||||
VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = pressed,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
WindowEvent::ReceivedCharacter(ch) => io.add_input_character(ch),
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
let position = self.scale_pos_from_winit(window, position);
|
||||
io.mouse_pos = [position.x as f32, position.y as f32];
|
||||
}
|
||||
WindowEvent::MouseWheel {
|
||||
delta,
|
||||
phase: TouchPhase::Moved,
|
||||
..
|
||||
} => match delta {
|
||||
MouseScrollDelta::LineDelta(h, v) => {
|
||||
io.mouse_wheel_h = h;
|
||||
io.mouse_wheel = v;
|
||||
}
|
||||
MouseScrollDelta::PixelDelta(pos) => {
|
||||
match pos.x.partial_cmp(&0.0) {
|
||||
Some(Ordering::Greater) => io.mouse_wheel_h += 1.0,
|
||||
Some(Ordering::Less) => io.mouse_wheel_h -= 1.0,
|
||||
_ => (),
|
||||
}
|
||||
match pos.y.partial_cmp(&0.0) {
|
||||
Some(Ordering::Greater) => io.mouse_wheel += 1.0,
|
||||
Some(Ordering::Less) => io.mouse_wheel -= 1.0,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
WindowEvent::MouseInput { state, button, .. } => {
|
||||
let pressed = state == ElementState::Pressed;
|
||||
match button {
|
||||
MouseButton::Left => io.mouse_down[0] = pressed,
|
||||
MouseButton::Right => io.mouse_down[1] = pressed,
|
||||
MouseButton::Middle => io.mouse_down[2] = pressed,
|
||||
MouseButton::Other(idx @ 0...4) => io.mouse_down[idx as usize] = pressed,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
/// Frame preparation callback.
|
||||
///
|
||||
/// Call this before calling the imgui-rs context `frame` function.
|
||||
/// This function performs the following actions:
|
||||
///
|
||||
/// * mouse cursor is repositioned (if requested by imgui-rs)
|
||||
pub fn prepare_frame(&self, io: &mut Io, window: &Window) -> Result<(), String> {
|
||||
if io.want_set_mouse_pos {
|
||||
let logical_pos = self.scale_pos_for_winit(
|
||||
window,
|
||||
LogicalPosition::new(f64::from(io.mouse_pos[0]), f64::from(io.mouse_pos[1])),
|
||||
);
|
||||
window.set_cursor_position(logical_pos)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
/// Render preparation callback.
|
||||
///
|
||||
/// Call this before calling the imgui-rs UI `render_with`/`render` function.
|
||||
/// This function performs the following actions:
|
||||
///
|
||||
/// * mouse cursor is changed and/or hidden (if requested by imgui-rs)
|
||||
pub fn prepare_render(&self, ui: &Ui, window: &Window) {
|
||||
let io = ui.io();
|
||||
if !io
|
||||
.config_flags
|
||||
.contains(ConfigFlags::NO_MOUSE_CURSOR_CHANGE)
|
||||
{
|
||||
match ui.mouse_cursor() {
|
||||
Some(mouse_cursor) if !io.mouse_draw_cursor => {
|
||||
window.hide_cursor(false);
|
||||
window.set_cursor(match mouse_cursor {
|
||||
imgui::MouseCursor::Arrow => MouseCursor::Arrow,
|
||||
imgui::MouseCursor::TextInput => MouseCursor::Text,
|
||||
imgui::MouseCursor::ResizeAll => MouseCursor::Move,
|
||||
imgui::MouseCursor::ResizeNS => MouseCursor::NsResize,
|
||||
imgui::MouseCursor::ResizeEW => MouseCursor::EwResize,
|
||||
imgui::MouseCursor::ResizeNESW => MouseCursor::NeswResize,
|
||||
imgui::MouseCursor::ResizeNWSE => MouseCursor::NwseResize,
|
||||
imgui::MouseCursor::Hand => MouseCursor::Hand,
|
||||
});
|
||||
}
|
||||
_ => window.hide_cursor(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Update imgui mouse button state
|
||||
pub fn handle_mouse_button_state(imgui: &mut Context, button: MouseButton, state: ElementState) {
|
||||
let mut states = imgui.mouse_down();
|
||||
let state_bool = state == ElementState::Pressed;
|
||||
match button {
|
||||
MouseButton::Left => states[0] = state_bool,
|
||||
MouseButton::Right => states[1] = state_bool,
|
||||
MouseButton::Middle => states[2] = state_bool,
|
||||
MouseButton::Other(idx @ 0...4) => states[idx as usize] = state_bool,
|
||||
_ => (),
|
||||
}
|
||||
imgui.set_mouse_down(states);
|
||||
}
|
||||
|
||||
/// Update imgui state from winit event
|
||||
pub fn handle_event(
|
||||
imgui: &mut Context,
|
||||
event: &Event,
|
||||
window_hidpi_factor: f64,
|
||||
app_hidpi_factor: f64,
|
||||
) {
|
||||
if let Event::WindowEvent { ref event, .. } = event {
|
||||
handle_window_event(imgui, event, window_hidpi_factor, app_hidpi_factor)
|
||||
}
|
||||
}
|
||||
|
||||
/// Update imgui state from winit window event
|
||||
pub fn handle_window_event(
|
||||
imgui: &mut Context,
|
||||
event: &WindowEvent,
|
||||
window_hidpi_factor: f64,
|
||||
app_hidpi_factor: f64,
|
||||
) {
|
||||
use self::WindowEvent::*;
|
||||
match event {
|
||||
KeyboardInput { input, .. } => handle_keyboard_input(imgui, *input),
|
||||
ReceivedCharacter(ch) => imgui.add_input_character(*ch),
|
||||
CursorMoved {
|
||||
position,
|
||||
modifiers,
|
||||
..
|
||||
} => {
|
||||
let position = position
|
||||
.to_physical(window_hidpi_factor)
|
||||
.to_logical(app_hidpi_factor);
|
||||
imgui.set_mouse_pos(position.x as f32, position.y as f32);
|
||||
handle_modifiers(imgui, *modifiers);
|
||||
}
|
||||
MouseWheel {
|
||||
delta,
|
||||
modifiers,
|
||||
phase: TouchPhase::Moved,
|
||||
..
|
||||
} => {
|
||||
handle_mouse_scroll_delta(imgui, *delta, window_hidpi_factor, app_hidpi_factor);
|
||||
handle_modifiers(imgui, *modifiers);
|
||||
}
|
||||
MouseInput {
|
||||
state,
|
||||
button,
|
||||
modifiers,
|
||||
..
|
||||
} => {
|
||||
handle_mouse_button_state(imgui, *button, *state);
|
||||
handle_modifiers(imgui, *modifiers);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
/// Update winit window mouse cursor state
|
||||
pub fn update_mouse_cursor(imgui: &Context, window: &Window) {
|
||||
let mouse_cursor = imgui.mouse_cursor();
|
||||
if imgui.mouse_draw_cursor() || mouse_cursor == ImGuiMouseCursor::None {
|
||||
// Hide OS cursor
|
||||
window.hide_cursor(true);
|
||||
} else {
|
||||
// Set OS cursor
|
||||
window.hide_cursor(false);
|
||||
window.set_cursor(match mouse_cursor {
|
||||
ImGuiMouseCursor::None => unreachable!("mouse_cursor was None!"),
|
||||
ImGuiMouseCursor::Arrow => MouseCursor::Arrow,
|
||||
ImGuiMouseCursor::TextInput => MouseCursor::Text,
|
||||
ImGuiMouseCursor::ResizeAll => MouseCursor::Move,
|
||||
ImGuiMouseCursor::ResizeNS => MouseCursor::NsResize,
|
||||
ImGuiMouseCursor::ResizeEW => MouseCursor::EwResize,
|
||||
ImGuiMouseCursor::ResizeNESW => MouseCursor::NeswResize,
|
||||
ImGuiMouseCursor::ResizeNWSE => MouseCursor::NwseResize,
|
||||
ImGuiMouseCursor::Hand => MouseCursor::Hand,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current frame size for imgui frame rendering.
|
||||
///
|
||||
/// Returns `None` if the window no longer exists
|
||||
pub fn get_frame_size(window: &Window, app_hidpi_factor: f64) -> Option<FrameSize> {
|
||||
window.get_inner_size().map(|logical_size| FrameSize {
|
||||
logical_size: logical_size
|
||||
.to_physical(window.get_hidpi_factor())
|
||||
.to_logical(app_hidpi_factor)
|
||||
.into(),
|
||||
hidpi_factor: app_hidpi_factor,
|
||||
})
|
||||
}
|
||||
|
||||
@ -367,4 +367,10 @@ impl Context {
|
||||
&mut *(sys::igGetStyle() as *mut Style)
|
||||
}
|
||||
}
|
||||
pub fn frame<'ui, 'a: 'ui>(&'a mut self) -> Ui<'ui> {
|
||||
unsafe {
|
||||
sys::igNewFrame();
|
||||
}
|
||||
Ui { ctx: self }
|
||||
}
|
||||
}
|
||||
|
||||
93
src/input/keyboard.rs
Normal file
93
src/input/keyboard.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
/// A key identifier
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum Key {
|
||||
Tab = sys::ImGuiKey_Tab,
|
||||
LeftArrow = sys::ImGuiKey_LeftArrow,
|
||||
RightArrow = sys::ImGuiKey_RightArrow,
|
||||
UpArrow = sys::ImGuiKey_UpArrow,
|
||||
DownArrow = sys::ImGuiKey_DownArrow,
|
||||
PageUp = sys::ImGuiKey_PageUp,
|
||||
PageDown = sys::ImGuiKey_PageDown,
|
||||
Home = sys::ImGuiKey_Home,
|
||||
End = sys::ImGuiKey_End,
|
||||
Insert = sys::ImGuiKey_Insert,
|
||||
Delete = sys::ImGuiKey_Delete,
|
||||
Backspace = sys::ImGuiKey_Backspace,
|
||||
Space = sys::ImGuiKey_Space,
|
||||
Enter = sys::ImGuiKey_Enter,
|
||||
Escape = sys::ImGuiKey_Escape,
|
||||
A = sys::ImGuiKey_A,
|
||||
C = sys::ImGuiKey_C,
|
||||
V = sys::ImGuiKey_V,
|
||||
X = sys::ImGuiKey_X,
|
||||
Y = sys::ImGuiKey_Y,
|
||||
Z = sys::ImGuiKey_Z,
|
||||
}
|
||||
|
||||
impl Key {
|
||||
/// All possible `Key` variants
|
||||
pub const VARIANTS: [Key; Key::COUNT] = [
|
||||
Key::Tab,
|
||||
Key::LeftArrow,
|
||||
Key::RightArrow,
|
||||
Key::UpArrow,
|
||||
Key::DownArrow,
|
||||
Key::PageUp,
|
||||
Key::PageDown,
|
||||
Key::Home,
|
||||
Key::End,
|
||||
Key::Insert,
|
||||
Key::Delete,
|
||||
Key::Backspace,
|
||||
Key::Space,
|
||||
Key::Enter,
|
||||
Key::Escape,
|
||||
Key::A,
|
||||
Key::C,
|
||||
Key::V,
|
||||
Key::X,
|
||||
Key::Y,
|
||||
Key::Z,
|
||||
];
|
||||
/// Total count of `Key` variants
|
||||
pub const COUNT: usize = sys::ImGuiKey_COUNT as usize;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_key_variants() {
|
||||
for (idx, &value) in Key::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Returns the key index of the given key identifier.
|
||||
///
|
||||
/// Equivalent to indexing the Io struct `key_map` field: `ui.io().key_map[key]`
|
||||
pub fn key_index(&self, key: Key) -> u32 {
|
||||
unsafe { sys::igGetKeyIndex(key as i32) as u32 }
|
||||
}
|
||||
/// Returns true if the key is being held.
|
||||
///
|
||||
/// Equivalent to indexing the Io struct `keys_down` field: `ui.io().keys_down[key_index]`
|
||||
pub fn is_key_down(&self, key_index: u32) -> bool {
|
||||
unsafe { sys::igIsKeyDown(key_index as i32) }
|
||||
}
|
||||
/// Returns true if the key was pressed (went from !down to down).
|
||||
///
|
||||
/// Affected by key repeat settings (`io.key_repeat_delay`, `io.key_repeat_rate`)
|
||||
pub fn is_key_pressed(&self, key_index: u32) -> bool {
|
||||
unsafe { sys::igIsKeyPressed(key_index as i32, true) }
|
||||
}
|
||||
/// Returns a count of key presses using the given repeat rate/delay settings.
|
||||
///
|
||||
/// Usually returns 0 or 1, but might be >1 if `rate` is small enough that `io.delta_time` >
|
||||
/// `rate`.
|
||||
pub fn key_pressed_amount(&self, key_index: u32, repeat_delay: f32, rate: f32) -> u32 {
|
||||
unsafe { sys::igGetKeyPressedAmount(key_index as i32, repeat_delay, rate) as u32 }
|
||||
}
|
||||
}
|
||||
2
src/input/mod.rs
Normal file
2
src/input/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod keyboard;
|
||||
pub mod mouse;
|
||||
172
src/input/mouse.rs
Normal file
172
src/input/mouse.rs
Normal file
@ -0,0 +1,172 @@
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
/// Represents one of the supported mouse buttons
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum MouseButton {
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
Middle = 2,
|
||||
Extra1 = 3,
|
||||
Extra2 = 4,
|
||||
}
|
||||
|
||||
impl MouseButton {
|
||||
/// All possible `MouseButton` varirants
|
||||
pub const VARIANTS: [MouseButton; MouseButton::COUNT] = [
|
||||
MouseButton::Left,
|
||||
MouseButton::Right,
|
||||
MouseButton::Middle,
|
||||
MouseButton::Extra1,
|
||||
MouseButton::Extra2,
|
||||
];
|
||||
/// Total count of `MouseButton` variants
|
||||
pub const COUNT: usize = 5;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_button_variants() {
|
||||
for (idx, &value) in MouseButton::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
/// Mouse cursor type identifier
|
||||
#[repr(i32)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum MouseCursor {
|
||||
Arrow = sys::ImGuiMouseCursor_Arrow,
|
||||
/// Automatically used when hovering over text inputs, etc.
|
||||
TextInput = sys::ImGuiMouseCursor_TextInput,
|
||||
/// Not used automatically
|
||||
ResizeAll = sys::ImGuiMouseCursor_ResizeAll,
|
||||
/// Automatically used when hovering over a horizontal border
|
||||
ResizeNS = sys::ImGuiMouseCursor_ResizeNS,
|
||||
/// Automatically used when hovering over a vertical border or a column
|
||||
ResizeEW = sys::ImGuiMouseCursor_ResizeEW,
|
||||
/// Automatically used when hovering over the bottom-left corner of a window
|
||||
ResizeNESW = sys::ImGuiMouseCursor_ResizeNESW,
|
||||
/// Automatically used when hovering over the bottom-right corner of a window
|
||||
ResizeNWSE = sys::ImGuiMouseCursor_ResizeNWSE,
|
||||
/// Not used automatically, use for e.g. hyperlinks
|
||||
Hand = sys::ImGuiMouseCursor_Hand,
|
||||
}
|
||||
|
||||
impl MouseCursor {
|
||||
/// All possible `MouseCursor` varirants
|
||||
pub const VARIANTS: [MouseCursor; MouseCursor::COUNT] = [
|
||||
MouseCursor::Arrow,
|
||||
MouseCursor::TextInput,
|
||||
MouseCursor::ResizeAll,
|
||||
MouseCursor::ResizeNS,
|
||||
MouseCursor::ResizeEW,
|
||||
MouseCursor::ResizeNESW,
|
||||
MouseCursor::ResizeNWSE,
|
||||
MouseCursor::Hand,
|
||||
];
|
||||
/// Total count of `MouseCursor` variants
|
||||
pub const COUNT: usize = sys::ImGuiMouseCursor_COUNT as usize;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_cursor_variants() {
|
||||
for (idx, &value) in MouseCursor::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Returns true if the given mouse button is held down.
|
||||
///
|
||||
/// Equivalent to indexing the Io struct with the button, e.g. `ui.io()[button]`.
|
||||
pub fn is_mouse_down(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDown(button as i32) }
|
||||
}
|
||||
/// Returns true if any mouse button is held down
|
||||
pub fn is_any_mouse_down(&self) -> bool {
|
||||
unsafe { sys::igIsAnyMouseDown() }
|
||||
}
|
||||
/// Returns true if the given mouse button was clicked (went from !down to down)
|
||||
pub fn is_mouse_clicked(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseClicked(button as i32, false) }
|
||||
}
|
||||
/// Returns true if the given mouse button was double-clicked
|
||||
pub fn is_mouse_double_clicked(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDoubleClicked(button as i32) }
|
||||
}
|
||||
/// Returns true if the given mouse button was released (went from down to !down)
|
||||
pub fn is_mouse_released(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseReleased(button as i32) }
|
||||
}
|
||||
/// Returns true if the mouse is currently dragging with the given mouse button held down
|
||||
pub fn is_mouse_dragging(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDragging(button as i32, -1.0) }
|
||||
}
|
||||
/// Returns true if the mouse is currently dragging with the given mouse button held down.
|
||||
///
|
||||
/// If the given threshold is invalid or negative, the global distance threshold is used
|
||||
/// (`io.mouse_drag_threshold`).
|
||||
pub fn is_mouse_dragging_with_threshold(&self, button: MouseButton, threshold: f32) -> bool {
|
||||
unsafe { sys::igIsMouseDragging(button as i32, threshold) }
|
||||
}
|
||||
/// Returns true if the mouse is hovering over the given bounding rect.
|
||||
///
|
||||
/// Clipped by current clipping settings, but disregards other factors like focus, window
|
||||
/// ordering, modal popup blocking.
|
||||
pub fn is_mouse_hovering_rect(r_min: [f32; 2], r_max: [f32; 2]) -> bool {
|
||||
unsafe { sys::igIsMouseHoveringRect(r_min.into(), r_max.into(), true) }
|
||||
}
|
||||
/// Returns the mouse position backed up at the time of opening a popup
|
||||
pub fn mouse_pos_on_opening_current_popup(&self) -> [f32; 2] {
|
||||
unsafe { sys::igGetMousePosOnOpeningCurrentPopup_nonUDT2().into() }
|
||||
}
|
||||
/// Returns the delta from the initial clicking position.
|
||||
///
|
||||
/// This is locked and returns [0.0, 0.0] until the mouse has moved past the global distance
|
||||
/// threshold (`io.mouse_drag_threshold`).
|
||||
pub fn mouse_drag_delta(&self, button: MouseButton) -> [f32; 2] {
|
||||
unsafe { sys::igGetMouseDragDelta_nonUDT2(button as i32, -1.0).into() }
|
||||
}
|
||||
/// Returns the delta from the initial clicking position.
|
||||
///
|
||||
/// This is locked and returns [0.0, 0.0] until the mouse has moved past the given threshold.
|
||||
/// If the given threshold is invalid or negative, the global distance threshold is used
|
||||
/// (`io.mouse_drag_threshold`).
|
||||
pub fn mouse_drag_delta_with_threshold(&self, button: MouseButton, threshold: f32) -> [f32; 2] {
|
||||
unsafe { sys::igGetMouseDragDelta_nonUDT2(button as i32, threshold).into() }
|
||||
}
|
||||
/// Resets the current delta from initial clicking position.
|
||||
pub fn reset_mouse_drag_delta(&self, button: MouseButton) {
|
||||
// This mutates the Io struct, but targets an internal field so there can't be any
|
||||
// references to it
|
||||
unsafe { sys::igResetMouseDragDelta(button as i32) }
|
||||
}
|
||||
/// Get the currently desired mouse cursor type.
|
||||
///
|
||||
/// Returns `None` if no cursor should be displayed
|
||||
pub fn mouse_cursor(&self) -> Option<MouseCursor> {
|
||||
match unsafe { sys::igGetMouseCursor() } {
|
||||
sys::ImGuiMouseCursor_Arrow => Some(MouseCursor::Arrow),
|
||||
sys::ImGuiMouseCursor_TextInput => Some(MouseCursor::TextInput),
|
||||
sys::ImGuiMouseCursor_ResizeAll => Some(MouseCursor::ResizeAll),
|
||||
sys::ImGuiMouseCursor_ResizeNS => Some(MouseCursor::ResizeNS),
|
||||
sys::ImGuiMouseCursor_ResizeEW => Some(MouseCursor::ResizeEW),
|
||||
sys::ImGuiMouseCursor_ResizeNESW => Some(MouseCursor::ResizeNESW),
|
||||
sys::ImGuiMouseCursor_ResizeNWSE => Some(MouseCursor::ResizeNWSE),
|
||||
sys::ImGuiMouseCursor_Hand => Some(MouseCursor::Hand),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
/// Set the desired mouse cursor type.
|
||||
///
|
||||
/// Passing `None` hides the mouse cursor.
|
||||
pub fn set_mouse_cursor(&self, cursor_type: Option<MouseCursor>) {
|
||||
unsafe {
|
||||
sys::igSetMouseCursor(
|
||||
cursor_type
|
||||
.map(|x| x as i32)
|
||||
.unwrap_or(sys::ImGuiMouseCursor_None),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/io.rs
41
src/io.rs
@ -4,6 +4,8 @@ use std::ops::{Index, IndexMut};
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::input::keyboard::Key;
|
||||
use crate::input::mouse::MouseButton;
|
||||
use crate::internal::{ImVector, RawCast};
|
||||
use crate::sys;
|
||||
|
||||
@ -334,6 +336,45 @@ impl Io {
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<Key> for Io {
|
||||
type Output = u32;
|
||||
fn index(&self, index: Key) -> &u32 {
|
||||
&self.key_map[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<Key> for Io {
|
||||
fn index_mut(&mut self, index: Key) -> &mut u32 {
|
||||
&mut self.key_map[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<NavInput> for Io {
|
||||
type Output = f32;
|
||||
fn index(&self, index: NavInput) -> &f32 {
|
||||
&self.nav_inputs[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<NavInput> for Io {
|
||||
fn index_mut(&mut self, index: NavInput) -> &mut f32 {
|
||||
&mut self.nav_inputs[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<MouseButton> for Io {
|
||||
type Output = bool;
|
||||
fn index(&self, index: MouseButton) -> &bool {
|
||||
&self.mouse_down[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<MouseButton> for Io {
|
||||
fn index_mut(&mut self, index: MouseButton) -> &mut bool {
|
||||
&mut self.mouse_down[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_io_memory_layout() {
|
||||
use std::mem;
|
||||
|
||||
132
src/lib.rs
132
src/lib.rs
@ -22,7 +22,9 @@ pub use self::drag::{
|
||||
};
|
||||
pub use self::fonts::{FontGlyphRange, ImFont, ImFontAtlas, ImFontConfig};
|
||||
pub use self::image::{ImTexture, Image, ImageButton, Textures};
|
||||
pub use self::input::{
|
||||
pub use self::input::keyboard::*;
|
||||
pub use self::input::mouse::*;
|
||||
pub use self::input_widget::{
|
||||
InputFloat, InputFloat2, InputFloat3, InputFloat4, InputInt, InputInt2, InputInt3, InputInt4,
|
||||
InputText, InputTextMultiline,
|
||||
};
|
||||
@ -40,8 +42,8 @@ pub use self::string::{ImStr, ImString};
|
||||
pub use self::style::*;
|
||||
pub use self::sys::{
|
||||
ImDrawIdx, ImDrawVert, ImGuiColorEditFlags, ImGuiFocusedFlags, ImGuiHoveredFlags,
|
||||
ImGuiInputTextFlags, ImGuiKey, ImGuiMouseCursor, ImGuiSelectableFlags, ImGuiTreeNodeFlags,
|
||||
ImGuiWindowFlags, ImVec2, ImVec4,
|
||||
ImGuiInputTextFlags, ImGuiSelectableFlags, ImGuiTreeNodeFlags, ImGuiWindowFlags, ImVec2,
|
||||
ImVec4,
|
||||
};
|
||||
pub use self::trees::{CollapsingHeader, TreeNode};
|
||||
pub use self::window::Window;
|
||||
@ -55,6 +57,7 @@ mod drag;
|
||||
mod fonts;
|
||||
mod image;
|
||||
mod input;
|
||||
mod input_widget;
|
||||
mod internal;
|
||||
mod io;
|
||||
mod menus;
|
||||
@ -84,31 +87,6 @@ pub fn get_version() -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents one of the buttons of the mouse
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum ImMouseButton {
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
Middle = 2,
|
||||
Extra1 = 3,
|
||||
Extra2 = 4,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct FrameSize {
|
||||
pub logical_size: (f64, f64),
|
||||
pub hidpi_factor: f64,
|
||||
}
|
||||
|
||||
impl FrameSize {
|
||||
pub fn new(width: f64, height: f64, hidpi_factor: f64) -> FrameSize {
|
||||
FrameSize {
|
||||
logical_size: (width, height),
|
||||
hidpi_factor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn fonts(&mut self) -> ImFontAtlas {
|
||||
unsafe { ImFontAtlas::from_ptr(self.io_mut().fonts) }
|
||||
@ -174,7 +152,10 @@ impl Context {
|
||||
}
|
||||
pub fn display_framebuffer_scale(&self) -> (f32, f32) {
|
||||
let io = self.io();
|
||||
(io.display_framebuffer_scale[0], io.display_framebuffer_scale[1])
|
||||
(
|
||||
io.display_framebuffer_scale[0],
|
||||
io.display_framebuffer_scale[1],
|
||||
)
|
||||
}
|
||||
pub fn mouse_pos(&self) -> (f32, f32) {
|
||||
let io = self.io();
|
||||
@ -206,7 +187,7 @@ impl Context {
|
||||
let io = self.io();
|
||||
io.mouse_wheel
|
||||
}
|
||||
pub fn mouse_drag_delta(&self, button: ImMouseButton) -> (f32, f32) {
|
||||
pub fn mouse_drag_delta(&self, button: MouseButton) -> (f32, f32) {
|
||||
let delta = unsafe { sys::igGetMouseDragDelta_nonUDT2(button as c_int, -1.0) };
|
||||
delta.into()
|
||||
}
|
||||
@ -220,38 +201,25 @@ impl Context {
|
||||
let io = self.io();
|
||||
io.mouse_draw_cursor
|
||||
}
|
||||
/// Set currently displayed cursor.
|
||||
/// Requires support in the windowing back-end if OS cursor is used.
|
||||
/// OS cursor is used if `mouse_draw_cursor` is set to `false` with
|
||||
/// [set_mouse_draw_cursor](#method.set_mouse_draw_cursor).
|
||||
pub fn set_mouse_cursor(&self, cursor: ImGuiMouseCursor) {
|
||||
unsafe {
|
||||
sys::igSetMouseCursor(cursor);
|
||||
}
|
||||
}
|
||||
/// Get currently displayed cursor.
|
||||
pub fn mouse_cursor(&self) -> ImGuiMouseCursor {
|
||||
unsafe { sys::igGetMouseCursor() }
|
||||
}
|
||||
/// Returns `true` if mouse is currently dragging with the `button` provided
|
||||
/// as argument.
|
||||
pub fn is_mouse_dragging(&self, button: ImMouseButton) -> bool {
|
||||
pub fn is_mouse_dragging(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDragging(button as c_int, -1.0) }
|
||||
}
|
||||
/// Returns `true` if the `button` provided as argument is currently down.
|
||||
pub fn is_mouse_down(&self, button: ImMouseButton) -> bool {
|
||||
pub fn is_mouse_down(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDown(button as c_int) }
|
||||
}
|
||||
/// Returns `true` if the `button` provided as argument is being clicked.
|
||||
pub fn is_mouse_clicked(&self, button: ImMouseButton) -> bool {
|
||||
pub fn is_mouse_clicked(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseClicked(button as c_int, false) }
|
||||
}
|
||||
/// Returns `true` if the `button` provided as argument is being double-clicked.
|
||||
pub fn is_mouse_double_clicked(&self, button: ImMouseButton) -> bool {
|
||||
pub fn is_mouse_double_clicked(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDoubleClicked(button as c_int) }
|
||||
}
|
||||
/// Returns `true` if the `button` provided as argument was released
|
||||
pub fn is_mouse_released(&self, button: ImMouseButton) -> bool {
|
||||
pub fn is_mouse_released(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseReleased(button as c_int) }
|
||||
}
|
||||
pub fn key_ctrl(&self) -> bool {
|
||||
@ -290,23 +258,23 @@ impl Context {
|
||||
let io = self.io_mut();
|
||||
io.keys_down[key as usize] = pressed;
|
||||
}
|
||||
pub fn set_imgui_key(&mut self, key: ImGuiKey, mapping: u8) {
|
||||
pub fn set_imgui_key(&mut self, key: Key, mapping: u8) {
|
||||
let io = self.io_mut();
|
||||
io.key_map[key as usize] = u32::from(mapping);
|
||||
}
|
||||
/// Map [`ImGuiKey`] values into user's key index
|
||||
pub fn get_key_index(&self, key: ImGuiKey) -> usize {
|
||||
unsafe { sys::igGetKeyIndex(key) as usize }
|
||||
/// Map [`Key`] values into user's key index
|
||||
pub fn get_key_index(&self, key: Key) -> usize {
|
||||
unsafe { sys::igGetKeyIndex(key as i32) as usize }
|
||||
}
|
||||
/// Return whether specific key is being held
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use imgui::{ImGuiKey, Ui};
|
||||
/// use imgui::{Key, Ui};
|
||||
///
|
||||
/// fn test(ui: &Ui) {
|
||||
/// let delete_key_index = ui.imgui().get_key_index(ImGuiKey::Delete);
|
||||
/// let delete_key_index = ui.imgui().get_key_index(Key::Delete);
|
||||
/// if ui.imgui().is_key_down(delete_key_index) {
|
||||
/// println!("Delete is being held!");
|
||||
/// }
|
||||
@ -339,23 +307,6 @@ impl Context {
|
||||
pub fn get_frame_rate(&self) -> f32 {
|
||||
self.io().framerate
|
||||
}
|
||||
pub fn frame<'ui, 'a: 'ui>(&'a mut self, frame_size: FrameSize, delta_time: f32) -> Ui<'ui> {
|
||||
{
|
||||
let io = self.io_mut();
|
||||
io.display_size[0] = frame_size.logical_size.0 as c_float;
|
||||
io.display_size[1] = frame_size.logical_size.1 as c_float;
|
||||
io.display_framebuffer_scale[0] = frame_size.hidpi_factor as c_float;
|
||||
io.display_framebuffer_scale[1] = frame_size.hidpi_factor as c_float;
|
||||
io.delta_time = delta_time;
|
||||
}
|
||||
unsafe {
|
||||
sys::igNewFrame();
|
||||
}
|
||||
Ui {
|
||||
imgui: self,
|
||||
frame_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DrawData<'a> {
|
||||
@ -435,8 +386,7 @@ pub struct DrawList<'a> {
|
||||
}
|
||||
|
||||
pub struct Ui<'ui> {
|
||||
imgui: &'ui Context,
|
||||
frame_size: FrameSize,
|
||||
ctx: &'ui Context,
|
||||
}
|
||||
|
||||
static FMT: &'static [u8] = b"%s\0";
|
||||
@ -446,18 +396,18 @@ fn fmt_ptr() -> *const c_char {
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
pub fn frame_size(&self) -> FrameSize {
|
||||
self.frame_size
|
||||
pub fn io(&self) -> &Io {
|
||||
unsafe { &*(sys::igGetIO() as *const Io) }
|
||||
}
|
||||
pub fn imgui(&self) -> &Context {
|
||||
self.imgui
|
||||
self.ctx
|
||||
}
|
||||
pub fn want_capture_mouse(&self) -> bool {
|
||||
let io = self.imgui.io();
|
||||
let io = self.io();
|
||||
io.want_capture_mouse
|
||||
}
|
||||
pub fn want_capture_keyboard(&self) -> bool {
|
||||
let io = self.imgui.io();
|
||||
let io = self.io();
|
||||
io.want_capture_keyboard
|
||||
}
|
||||
pub fn set_keyboard_focus_here(&self, offset: i32) {
|
||||
@ -466,19 +416,19 @@ impl<'ui> Ui<'ui> {
|
||||
}
|
||||
}
|
||||
pub fn framerate(&self) -> f32 {
|
||||
let io = self.imgui.io();
|
||||
let io = self.io();
|
||||
io.framerate
|
||||
}
|
||||
pub fn metrics_render_vertices(&self) -> i32 {
|
||||
let io = self.imgui.io();
|
||||
let io = self.io();
|
||||
io.metrics_render_vertices
|
||||
}
|
||||
pub fn metrics_render_indices(&self) -> i32 {
|
||||
let io = self.imgui.io();
|
||||
let io = self.io();
|
||||
io.metrics_render_indices
|
||||
}
|
||||
pub fn metrics_active_windows(&self) -> i32 {
|
||||
let io = self.imgui.io();
|
||||
let io = self.io();
|
||||
io.metrics_active_windows
|
||||
}
|
||||
pub fn render<F, E>(self, f: F) -> Result<(), E>
|
||||
@ -1157,7 +1107,7 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut imgui = Context::create();
|
||||
/// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1);
|
||||
/// # let ui = imgui.frame();
|
||||
/// if ui.button(im_str!("Show modal"), (0.0, 0.0)) {
|
||||
/// ui.open_popup(im_str!("modal"));
|
||||
/// }
|
||||
@ -1237,7 +1187,7 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut imgui = Context::create();
|
||||
/// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1);
|
||||
/// # let ui = imgui.frame();
|
||||
/// # let mut selected_radio_value = 2;
|
||||
/// ui.radio_button(im_str!("Item 1"), &mut selected_radio_value, 1);
|
||||
/// ui.radio_button(im_str!("Item 2"), &mut selected_radio_value, 2);
|
||||
@ -1254,7 +1204,7 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut imgui = Context::create();
|
||||
/// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1);
|
||||
/// # let ui = imgui.frame();
|
||||
/// # let mut radio_button_test = "cats".to_string();
|
||||
/// if ui.radio_button_bool(im_str!("Cats"), radio_button_test == "cats") {
|
||||
/// radio_button_test = "cats".to_string();
|
||||
@ -1347,7 +1297,7 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut imgui = Context::create();
|
||||
/// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1);
|
||||
/// # let ui = imgui.frame();
|
||||
/// ui.progress_bar(0.6)
|
||||
/// .size((100.0, 12.0))
|
||||
/// .overlay_text(im_str!("Progress!"))
|
||||
@ -1365,7 +1315,7 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut imgui = Context::create();
|
||||
/// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1);
|
||||
/// # let ui = imgui.frame();
|
||||
/// ui.window(im_str!("ChatWindow"))
|
||||
/// .title_bar(true)
|
||||
/// .scrollable(false)
|
||||
@ -1395,7 +1345,7 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut imgui = Context::create();
|
||||
/// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1);
|
||||
/// # let ui = imgui.frame();
|
||||
/// ui.with_style_var(StyleVar::Alpha(0.2), || {
|
||||
/// ui.text(im_str!("AB"));
|
||||
/// });
|
||||
@ -1413,7 +1363,7 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut imgui = Context::create();
|
||||
/// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1);
|
||||
/// # let ui = imgui.frame();
|
||||
/// # let styles = [StyleVar::Alpha(0.2), StyleVar::WindowPadding([1.0, 1.0])];
|
||||
/// ui.with_style_vars(&styles, || {
|
||||
/// ui.text(im_str!("A"));
|
||||
@ -1513,7 +1463,7 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut imgui = Context::create();
|
||||
/// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1);
|
||||
/// # let ui = imgui.frame();
|
||||
/// ui.with_color_var(StyleColor::Text, [1.0, 0.0, 0.0, 1.0], || {
|
||||
/// ui.text_wrapped(im_str!("AB"));
|
||||
/// });
|
||||
@ -1539,7 +1489,7 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut imgui = Context::create();
|
||||
/// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1);
|
||||
/// # let ui = imgui.frame();
|
||||
/// let red = [1.0, 0.0, 0.0, 1.0];
|
||||
/// let green = [0.0, 1.0, 0.0, 1.0];
|
||||
/// # let vars = [(StyleColor::Text, red), (StyleColor::TextDisabled, green)];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user