mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-11 21:48:36 +00:00
Support multiple simultaneous winit versions in imgui-winit-support
- Resolve conflicts in favor of latest. - Warn at runtime if more than one is enabled and its a debug build (but support turning that off via yet another feature) - Document all of this, including examples and (rough) support policy.
This commit is contained in:
parent
eea1f4ca3d
commit
54ab45b15c
@ -18,3 +18,9 @@ winit-23 = { version = "0.23", package = "winit", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["winit-23"]
|
||||
|
||||
# This is phrased as a negative (unlike most features) so that it needs to be
|
||||
# explicitly disabled (and `default-features = false` won't do it). To avoid
|
||||
# problems from this we don't expose this in the public API in any way, keeping
|
||||
# things additive.
|
||||
no-warn-on-multiple = []
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
//! This crate provides a winit-based backend platform for imgui-rs.
|
||||
//!
|
||||
//! A backend platform handles window/input device events and manages their state.
|
||||
//! A backend platform handles window/input device events and manages their
|
||||
//! state.
|
||||
//!
|
||||
//! # Using the library
|
||||
//!
|
||||
@ -70,24 +71,92 @@
|
||||
//! }
|
||||
//! })
|
||||
//! ```
|
||||
|
||||
#[cfg(feature = "winit-19")]
|
||||
use winit_19 as winit;
|
||||
|
||||
#[cfg(feature = "winit-20")]
|
||||
use winit_20 as winit;
|
||||
|
||||
#[cfg(feature = "winit-22")]
|
||||
use winit_22 as winit;
|
||||
//!
|
||||
//! ## `winit` versions and features.
|
||||
//!
|
||||
//! This crate has several features which control the version of winit which is
|
||||
//! used.
|
||||
//!
|
||||
//! The following versions are supported, controlled by the listed feature.
|
||||
//!
|
||||
//! - The `winit-23` feature uses winit versions compatible with `0.23`. This is
|
||||
//! on by default, so to use any other version you need to disable this crates
|
||||
//! default features.
|
||||
//! - The `winit-22` feature uses winit versions compatible with `0.22`.
|
||||
//! - The `winit-20` feature should support winit either `0.20` or winit `0.21`.
|
||||
//! - The `winit-19` feature should support winits older than `0.19` (possibly
|
||||
//! back to winit 0.16.*, but this isn't regularly tested and may not work).
|
||||
//!
|
||||
//! If multiple `winit-*` features are enabled, and it is a debug build (as
|
||||
//! determined by `debug_assertions`), we will log a warning to stderr during
|
||||
//! init. This can be disabled by either turning on the `no-warn-on-multiple`
|
||||
//! feature, fixing the configuration, or disabling `debug_assertions`.
|
||||
//!
|
||||
//! Conversely, if no `winit-*` features are enabled, we will fail to compile.
|
||||
//! This is not an issue generally, as by default we turn on `winit-23`.
|
||||
//!
|
||||
//! All of this is in attempt to preserve the additive nature of features (while
|
||||
//! still helping users notice project configuration issues), however it's done
|
||||
//! fairly weakly as our this crate's API isn't 100% identical across winit
|
||||
//! versions.
|
||||
//!
|
||||
//! ### Using an older `winit` version
|
||||
//!
|
||||
//! To use an older version, you must configure `default-features = false` in
|
||||
//! your `Cargo.toml`:
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies.imgui-winit-support]
|
||||
//! version = "0.6"
|
||||
//! features = ["winit-$YOUR_VERSION_HERE"]
|
||||
//! default-features = false
|
||||
//! ```
|
||||
//!
|
||||
//! ### Old `winit` compatibility
|
||||
//!
|
||||
//! No guarantee is made on how long this crate will support legacy versions of
|
||||
//! `winit`, but we'll try to follow these rules:
|
||||
//!
|
||||
//! - Versions which are still in widespread use in the ecosystem will be
|
||||
//! supported while that is true (for example, 0.19 at the time of writing is
|
||||
//! quite old, but used by the most recent version of several popular crates).
|
||||
//!
|
||||
//! - Versions which are not a significant maintenance burden will be supported
|
||||
//! (for example, supporting versions older than winit 0.19 given that we
|
||||
//! support 0.19).
|
||||
//!
|
||||
//! - Explicitly removing support for a feature-indicated version will be
|
||||
//! considered a breaking change.
|
||||
//!
|
||||
//! - Changing the default feature to the new latest `winit` version is *not* a
|
||||
//! breaking change.
|
||||
|
||||
#[cfg(feature = "winit-23")]
|
||||
use winit_23 as winit;
|
||||
|
||||
#[cfg(all(not(feature = "winit-23"), feature = "winit-22"))]
|
||||
use winit_22 as winit;
|
||||
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22")),
|
||||
feature = "winit-20",
|
||||
))]
|
||||
use winit_20 as winit;
|
||||
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22", feature = "winit-20")),
|
||||
feature = "winit-19",
|
||||
))]
|
||||
use winit_19 as winit;
|
||||
|
||||
use imgui::{self, BackendFlags, ConfigFlags, Context, ImString, Io, Key, Ui};
|
||||
use std::cmp::Ordering;
|
||||
use winit::dpi::{LogicalPosition, LogicalSize};
|
||||
|
||||
#[cfg(feature = "winit-19")]
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22", feature = "winit-20")),
|
||||
feature = "winit-19",
|
||||
))]
|
||||
use winit::{
|
||||
DeviceEvent, ElementState, Event, KeyboardInput, MouseButton, MouseCursor, MouseScrollDelta,
|
||||
TouchPhase, VirtualKeyCode, Window, WindowEvent,
|
||||
@ -103,6 +172,69 @@ use winit::{
|
||||
window::{CursorIcon as MouseCursor, Window},
|
||||
};
|
||||
|
||||
// Ensure at least one is enabled
|
||||
#[cfg(not(any(
|
||||
feature = "winit-19",
|
||||
feature = "winit-20",
|
||||
feature = "winit-22",
|
||||
feature = "winit-23",
|
||||
)))]
|
||||
compile_error!("Please enable at least one version of `winit` (see documentation for details).");
|
||||
|
||||
fn check_multiple_winits() {
|
||||
use std::io::Write as _;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
// bail out for release builds or if we've been explicitly disabled.
|
||||
if cfg!(any(not(debug_assertions), feature = "no-warn-on-multiple")) {
|
||||
return;
|
||||
}
|
||||
let winits_enabled = cfg!(feature = "winit-23") as usize
|
||||
+ cfg!(feature = "winit-22") as usize
|
||||
+ cfg!(feature = "winit-20") as usize
|
||||
+ cfg!(feature = "winit-19") as usize;
|
||||
|
||||
// Only complain once even if we're called multiple times.
|
||||
static COMPLAINED: AtomicBool = AtomicBool::new(false);
|
||||
// Note that the `Ordering` basically doesn't matter here, but even if it
|
||||
// did, `Relaxed` is still correct because we're only interested in the
|
||||
// effects on a single atomic variable.
|
||||
if winits_enabled <= 1 || COMPLAINED.compare_and_swap(false, true, Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
let mut err = Vec::with_capacity(512);
|
||||
|
||||
// Log the complaint into a buffer first — in practice this is enough to
|
||||
// ensure atomicity.
|
||||
let _ = writeln!(
|
||||
err,
|
||||
"Warning (imgui-winit-support): More than one `winit-*` version feature is enabled \
|
||||
(this likely indicates misconfiguration, see documentation for details)."
|
||||
);
|
||||
let feats = [
|
||||
("winit-23", cfg!(feature = "winit-23"), " (default)"),
|
||||
("winit-22", cfg!(feature = "winit-22"), ""),
|
||||
("winit-20", cfg!(feature = "winit-20"), ""),
|
||||
("winit-19", cfg!(feature = "winit-19"), ""),
|
||||
];
|
||||
for &(name, enabled, extra) in &feats {
|
||||
if enabled {
|
||||
let _ = writeln!(err, " `feature = {:?}` is enabled{}", name, extra);
|
||||
}
|
||||
}
|
||||
if cfg!(feature = "winit-23") && winits_enabled == 2 {
|
||||
let _ = writeln!(
|
||||
err,
|
||||
" Perhaps you are missing a `default-features = false`?",
|
||||
);
|
||||
}
|
||||
let _ = writeln!(
|
||||
err,
|
||||
" (Note: This warning is only present in debug builds, and \
|
||||
can be disabled using the \"no-warn-on-multiple\" feature)"
|
||||
);
|
||||
let _ = std::io::stderr().write_all(&err);
|
||||
}
|
||||
|
||||
/// winit backend platform state
|
||||
#[derive(Debug)]
|
||||
pub struct WinitPlatform {
|
||||
@ -132,7 +264,10 @@ fn to_winit_cursor(cursor: imgui::MouseCursor) -> MouseCursor {
|
||||
}
|
||||
|
||||
impl CursorSettings {
|
||||
#[cfg(feature = "winit-19")]
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22", feature = "winit-20")),
|
||||
feature = "winit-19",
|
||||
))]
|
||||
fn apply(&self, window: &Window) {
|
||||
match self.cursor {
|
||||
Some(mouse_cursor) if !self.draw_cursor => {
|
||||
@ -203,6 +338,8 @@ impl WinitPlatform {
|
||||
/// * keys are configured
|
||||
/// * platform name is set
|
||||
pub fn init(imgui: &mut Context) -> WinitPlatform {
|
||||
// noop in non-debug builds, if disabled, or if called a second time.
|
||||
check_multiple_winits();
|
||||
let io = imgui.io_mut();
|
||||
io.backend_flags.insert(BackendFlags::HAS_MOUSE_CURSORS);
|
||||
io.backend_flags.insert(BackendFlags::HAS_SET_MOUSE_POS);
|
||||
@ -244,7 +381,10 @@ impl WinitPlatform {
|
||||
///
|
||||
/// * framebuffer scale (= DPI factor) is set
|
||||
/// * display size is set
|
||||
#[cfg(feature = "winit-19")]
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22", feature = "winit-20")),
|
||||
feature = "winit-19",
|
||||
))]
|
||||
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;
|
||||
@ -281,7 +421,10 @@ impl WinitPlatform {
|
||||
///
|
||||
/// 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.
|
||||
#[cfg(feature = "winit-19")]
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22", feature = "winit-20")),
|
||||
feature = "winit-19",
|
||||
))]
|
||||
pub fn scale_size_from_winit(&self, window: &Window, logical_size: LogicalSize) -> LogicalSize {
|
||||
match self.hidpi_mode {
|
||||
ActiveHiDpiMode::Default => logical_size,
|
||||
@ -311,7 +454,10 @@ impl WinitPlatform {
|
||||
///
|
||||
/// 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.
|
||||
#[cfg(feature = "winit-19")]
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22", feature = "winit-20")),
|
||||
feature = "winit-19",
|
||||
))]
|
||||
pub fn scale_pos_from_winit(
|
||||
&self,
|
||||
window: &Window,
|
||||
@ -345,7 +491,10 @@ impl WinitPlatform {
|
||||
///
|
||||
/// 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.
|
||||
#[cfg(feature = "winit-19")]
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22", feature = "winit-20")),
|
||||
feature = "winit-19",
|
||||
))]
|
||||
pub fn scale_pos_for_winit(
|
||||
&self,
|
||||
window: &Window,
|
||||
@ -382,7 +531,10 @@ impl WinitPlatform {
|
||||
/// * window size / dpi factor changes are applied
|
||||
/// * keyboard state is updated
|
||||
/// * mouse state is updated
|
||||
#[cfg(feature = "winit-19")]
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22", feature = "winit-20")),
|
||||
feature = "winit-19",
|
||||
))]
|
||||
pub fn handle_event(&mut self, io: &mut Io, window: &Window, event: &Event) {
|
||||
match *event {
|
||||
Event::WindowEvent {
|
||||
@ -421,7 +573,10 @@ impl WinitPlatform {
|
||||
/// * window size / dpi factor changes are applied
|
||||
/// * keyboard state is updated
|
||||
/// * mouse state is updated
|
||||
#[cfg(feature = "winit-20")]
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22")),
|
||||
feature = "winit-20",
|
||||
))]
|
||||
pub fn handle_event<T>(&mut self, io: &mut Io, window: &Window, event: &Event<T>) {
|
||||
match *event {
|
||||
Event::WindowEvent {
|
||||
@ -501,7 +656,10 @@ impl WinitPlatform {
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "winit-19")]
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22", feature = "winit-20")),
|
||||
feature = "winit-19",
|
||||
))]
|
||||
fn handle_window_event(&mut self, io: &mut Io, window: &Window, event: &WindowEvent) {
|
||||
match *event {
|
||||
WindowEvent::Resized(logical_size) => {
|
||||
@ -587,7 +745,10 @@ impl WinitPlatform {
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "winit-20", feature = "winit-22"))]
|
||||
#[cfg(all(
|
||||
not(feature = "winit-23"),
|
||||
any(feature = "winit-20", feature = "winit-22")
|
||||
))]
|
||||
fn handle_window_event(&mut self, io: &mut Io, window: &Window, event: &WindowEvent) {
|
||||
match *event {
|
||||
WindowEvent::Resized(physical_size) => {
|
||||
@ -687,6 +848,7 @@ impl WinitPlatform {
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "winit-23")]
|
||||
fn handle_window_event(&mut self, io: &mut Io, window: &Window, event: &WindowEvent) {
|
||||
match *event {
|
||||
@ -794,7 +956,10 @@ impl WinitPlatform {
|
||||
/// This function performs the following actions:
|
||||
///
|
||||
/// * mouse cursor is repositioned (if requested by imgui-rs)
|
||||
#[cfg(feature = "winit-19")]
|
||||
#[cfg(all(
|
||||
not(any(feature = "winit-23", feature = "winit-22", feature = "winit-20")),
|
||||
feature = "winit-19",
|
||||
))]
|
||||
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(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user