mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 14:20:04 -04:00
Merge branch 'main' into ime-preedit-visuals
This commit is contained in:
25
.github/workflows/taplo.yml
vendored
Normal file
25
.github/workflows/taplo.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Checks that all TOML files are formatted with taplo.
|
||||||
|
name: Taplo
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
taplo:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Taplo
|
||||||
|
uses: taiki-e/install-action@v2.48.7
|
||||||
|
with:
|
||||||
|
tool: taplo-cli@0.9.3
|
||||||
|
|
||||||
|
- name: Check TOML formatting
|
||||||
|
run: |
|
||||||
|
taplo fmt --check
|
||||||
@@ -1337,7 +1337,7 @@ dependencies = [
|
|||||||
"image",
|
"image",
|
||||||
"jiff",
|
"jiff",
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
"rand 0.9.2",
|
"rand 0.9.3",
|
||||||
"serde",
|
"serde",
|
||||||
"unicode_names2",
|
"unicode_names2",
|
||||||
]
|
]
|
||||||
@@ -3657,9 +3657,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.9.2"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_chacha 0.9.0",
|
"rand_chacha 0.9.0",
|
||||||
"rand_core 0.9.3",
|
"rand_core 0.9.3",
|
||||||
|
|||||||
@@ -134,12 +134,16 @@ syntect = { version = "5.3.0", default-features = false }
|
|||||||
tempfile = "3.23.0"
|
tempfile = "3.23.0"
|
||||||
thiserror = "2.0.17"
|
thiserror = "2.0.17"
|
||||||
tokio = "1.49"
|
tokio = "1.49"
|
||||||
toml = {version = "1.0.0", default-features = false }
|
toml = { version = "1.0.0", default-features = false }
|
||||||
type-map = "0.5.1"
|
type-map = "0.5.1"
|
||||||
unicode_names2 = { version = "2.0.0", default-features = false }
|
unicode_names2 = { version = "2.0.0", default-features = false }
|
||||||
unicode-general-category = "1.1.0"
|
unicode-general-category = "1.1.0"
|
||||||
unicode-segmentation = "1.12.0"
|
unicode-segmentation = "1.12.0"
|
||||||
vello_cpu = { version = "0.0.7", default-features = false, features = ["std", "u8_pipeline", "f32_pipeline"] }
|
vello_cpu = { version = "0.0.7", default-features = false, features = [
|
||||||
|
"std",
|
||||||
|
"u8_pipeline",
|
||||||
|
"f32_pipeline",
|
||||||
|
] }
|
||||||
wasm-bindgen = "0.2.108" # Keep wasm-bindgen version in sync in: setup_web.sh, Cargo.toml, Cargo.lock, rust.yml. Don't update this spuriously, because of https://github.com/rerun-io/rerun/issues/8766
|
wasm-bindgen = "0.2.108" # Keep wasm-bindgen version in sync in: setup_web.sh, Cargo.toml, Cargo.lock, rust.yml. Don't update this spuriously, because of https://github.com/rerun-io/rerun/issues/8766
|
||||||
wasm-bindgen-futures = "0.4.58"
|
wasm-bindgen-futures = "0.4.58"
|
||||||
wayland-cursor = { version = "0.31.11", default-features = false }
|
wayland-cursor = { version = "0.31.11", default-features = false }
|
||||||
|
|||||||
@@ -722,6 +722,7 @@ impl WgpuWinitRunning<'_> {
|
|||||||
&clipped_primitives,
|
&clipped_primitives,
|
||||||
&textures_delta,
|
&textures_delta,
|
||||||
screenshot_commands,
|
screenshot_commands,
|
||||||
|
window,
|
||||||
);
|
);
|
||||||
|
|
||||||
for action in viewport.actions_requested.drain(..) {
|
for action in viewport.actions_requested.drain(..) {
|
||||||
@@ -1111,6 +1112,7 @@ fn render_immediate_viewport(
|
|||||||
&clipped_primitives,
|
&clipped_primitives,
|
||||||
&textures_delta,
|
&textures_delta,
|
||||||
vec![],
|
vec![],
|
||||||
|
window,
|
||||||
);
|
);
|
||||||
|
|
||||||
egui_winit.handle_platform_output(window, platform_output);
|
egui_winit.handle_platform_output(window, platform_output);
|
||||||
|
|||||||
@@ -56,8 +56,13 @@ impl TextAgent {
|
|||||||
let input = input.clone();
|
let input = input.clone();
|
||||||
move |event: web_sys::InputEvent, runner: &mut AppRunner| {
|
move |event: web_sys::InputEvent, runner: &mut AppRunner| {
|
||||||
let text = input.value();
|
let text = input.value();
|
||||||
// Fix android virtual keyboard Gboard
|
// Workaround for an Android Gboard issue: after typing a word,
|
||||||
// This removes the virtual keyboard's suggestion.
|
// the user has to delete invisible characters (whose count
|
||||||
|
// matches the length of the current suggestion) before actual
|
||||||
|
// characters are deleted, unless the focus has been reset.
|
||||||
|
//
|
||||||
|
// this issue appears to have been fixed in Gboard sometime
|
||||||
|
// between versions 14.7.09 and 17.0.12.
|
||||||
if !event.is_composing() {
|
if !event.is_composing() {
|
||||||
input.blur().ok();
|
input.blur().ok();
|
||||||
input.focus().ok();
|
input.focus().ok();
|
||||||
@@ -164,6 +169,12 @@ impl TextAgent {
|
|||||||
|
|
||||||
let Some(ime) = ime else { return Ok(()) };
|
let Some(ime) = ime else { return Ok(()) };
|
||||||
|
|
||||||
|
if ime.should_interrupt_composition {
|
||||||
|
// no-op for now: currently, the text agent is sizeless, so any
|
||||||
|
// click shifts focus to the canvas, which naturally interrupts the
|
||||||
|
// composition.
|
||||||
|
}
|
||||||
|
|
||||||
let mut canvas_rect = super::canvas_content_rect(canvas);
|
let mut canvas_rect = super::canvas_content_rect(canvas);
|
||||||
// Fix for safari with virtual keyboard flapping position
|
// Fix for safari with virtual keyboard flapping position
|
||||||
if is_mobile_safari() {
|
if is_mobile_safari() {
|
||||||
|
|||||||
@@ -411,6 +411,7 @@ impl Painter {
|
|||||||
/// and the captures captured screenshot if it was requested.
|
/// and the captures captured screenshot if it was requested.
|
||||||
///
|
///
|
||||||
/// If `capture_data` isn't empty, a screenshot will be captured.
|
/// If `capture_data` isn't empty, a screenshot will be captured.
|
||||||
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub fn paint_and_update_textures(
|
pub fn paint_and_update_textures(
|
||||||
&mut self,
|
&mut self,
|
||||||
viewport_id: ViewportId,
|
viewport_id: ViewportId,
|
||||||
@@ -419,6 +420,7 @@ impl Painter {
|
|||||||
clipped_primitives: &[epaint::ClippedPrimitive],
|
clipped_primitives: &[epaint::ClippedPrimitive],
|
||||||
textures_delta: &epaint::textures::TexturesDelta,
|
textures_delta: &epaint::textures::TexturesDelta,
|
||||||
capture_data: Vec<UserData>,
|
capture_data: Vec<UserData>,
|
||||||
|
window: &winit::window::Window,
|
||||||
) -> f32 {
|
) -> f32 {
|
||||||
profiling::function_scope!();
|
profiling::function_scope!();
|
||||||
|
|
||||||
@@ -654,6 +656,8 @@ impl Painter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.pre_present_notify();
|
||||||
|
|
||||||
{
|
{
|
||||||
profiling::scope!("present");
|
profiling::scope!("present");
|
||||||
// wgpu doesn't document where vsync can happen. Maybe here?
|
// wgpu doesn't document where vsync can happen. Maybe here?
|
||||||
|
|||||||
@@ -1057,7 +1057,8 @@ impl State {
|
|||||||
self.set_cursor_icon(window, cursor_icon);
|
self.set_cursor_icon(window, cursor_icon);
|
||||||
|
|
||||||
let allow_ime = ime.is_some();
|
let allow_ime = ime.is_some();
|
||||||
if self.allow_ime != allow_ime {
|
let is_toggling_ime = self.allow_ime != allow_ime;
|
||||||
|
if is_toggling_ime {
|
||||||
self.allow_ime = allow_ime;
|
self.allow_ime = allow_ime;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
if !self.allow_ime {
|
if !self.allow_ime {
|
||||||
@@ -1074,6 +1075,14 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ime) = ime {
|
if let Some(ime) = ime {
|
||||||
|
if !is_toggling_ime && ime.should_interrupt_composition {
|
||||||
|
// TODO(umajho): use a more proper way to interrupt composition
|
||||||
|
// if `winit` provides one in the future.
|
||||||
|
|
||||||
|
window.set_ime_allowed(false);
|
||||||
|
window.set_ime_allowed(true);
|
||||||
|
}
|
||||||
|
|
||||||
let pixels_per_point = pixels_per_point(&self.egui_ctx, window);
|
let pixels_per_point = pixels_per_point(&self.egui_ctx, window);
|
||||||
let ime_rect_px = pixels_per_point * ime.rect;
|
let ime_rect_px = pixels_per_point * ime.rect;
|
||||||
if self.ime_rect_px != Some(ime_rect_px)
|
if self.ime_rect_px != Some(ime_rect_px)
|
||||||
|
|||||||
@@ -793,7 +793,7 @@ impl Context {
|
|||||||
let plugins = self.read(|ctx| ctx.plugins.ordered_plugins());
|
let plugins = self.read(|ctx| ctx.plugins.ordered_plugins());
|
||||||
#[expect(deprecated)]
|
#[expect(deprecated)]
|
||||||
self.run(new_input, |ctx| {
|
self.run(new_input, |ctx| {
|
||||||
let mut top_ui = Ui::new(
|
let mut root_ui = Ui::new(
|
||||||
ctx.clone(),
|
ctx.clone(),
|
||||||
Id::new((ctx.viewport_id(), "__top_ui")),
|
Id::new((ctx.viewport_id(), "__top_ui")),
|
||||||
UiBuilder::new()
|
UiBuilder::new()
|
||||||
@@ -802,14 +802,15 @@ impl Context {
|
|||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
plugins.on_begin_pass(&mut top_ui);
|
plugins.on_begin_pass(&mut root_ui);
|
||||||
run_ui(&mut top_ui);
|
run_ui(&mut root_ui);
|
||||||
plugins.on_end_pass(&mut top_ui);
|
plugins.on_end_pass(&mut root_ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inform ctx about what we actually used, so we can shrink the native window to fit.
|
ctx.pass_state_mut(|state| {
|
||||||
// TODO(emilk): make better use of this somehow
|
state.root_ui_available_rect = Some(root_ui.available_rect_before_wrap());
|
||||||
ctx.pass_state_mut(|state| state.allocate_central_panel(top_ui.min_rect()));
|
state.root_ui_min_rect = Some(root_ui.min_rect());
|
||||||
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2611,6 +2612,12 @@ impl ContextImpl {
|
|||||||
|
|
||||||
let mut platform_output: PlatformOutput = std::mem::take(&mut viewport.output);
|
let mut platform_output: PlatformOutput = std::mem::take(&mut viewport.output);
|
||||||
|
|
||||||
|
if self.memory.should_interrupt_ime()
|
||||||
|
&& let Some(ime) = &mut platform_output.ime
|
||||||
|
{
|
||||||
|
ime.should_interrupt_composition = true;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
profiling::scope!("accesskit");
|
profiling::scope!("accesskit");
|
||||||
let state = viewport.this_pass.accesskit_state.take();
|
let state = viewport.this_pass.accesskit_state.take();
|
||||||
@@ -2853,13 +2860,21 @@ impl Context {
|
|||||||
/// How much space is still available after panels have been added.
|
/// How much space is still available after panels have been added.
|
||||||
#[deprecated = "Use content_rect (or viewport_rect) instead"]
|
#[deprecated = "Use content_rect (or viewport_rect) instead"]
|
||||||
pub fn available_rect(&self) -> Rect {
|
pub fn available_rect(&self) -> Rect {
|
||||||
|
#[expect(deprecated)] // legacy
|
||||||
self.pass_state(|s| s.available_rect()).round_ui()
|
self.pass_state(|s| s.available_rect()).round_ui()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How much space is used by windows and the top-level [`Ui`].
|
/// How much space is used by windows and the top-level [`Ui`].
|
||||||
pub fn globally_used_rect(&self) -> Rect {
|
pub fn globally_used_rect(&self) -> Rect {
|
||||||
self.write(|ctx| {
|
self.write(|ctx| {
|
||||||
let mut used = ctx.viewport().this_pass.used_by_panels;
|
let viewport = ctx.viewport();
|
||||||
|
let root_ui_min_rect =
|
||||||
|
(viewport.this_pass.root_ui_min_rect).or(viewport.prev_pass.root_ui_min_rect);
|
||||||
|
|
||||||
|
let mut used = root_ui_min_rect.unwrap_or_else(|| {
|
||||||
|
#[expect(deprecated)] // legacy
|
||||||
|
ctx.viewport().this_pass.used_by_panels
|
||||||
|
});
|
||||||
for (_id, window) in ctx.memory.areas().visible_windows() {
|
for (_id, window) in ctx.memory.areas().visible_windows() {
|
||||||
used |= window.rect();
|
used |= window.rect();
|
||||||
}
|
}
|
||||||
@@ -2886,18 +2901,27 @@ impl Context {
|
|||||||
/// Is the pointer (mouse/touch) over any egui area?
|
/// Is the pointer (mouse/touch) over any egui area?
|
||||||
pub fn is_pointer_over_egui(&self) -> bool {
|
pub fn is_pointer_over_egui(&self) -> bool {
|
||||||
let pointer_pos = self.input(|i| i.pointer.interact_pos());
|
let pointer_pos = self.input(|i| i.pointer.interact_pos());
|
||||||
if let Some(pointer_pos) = pointer_pos {
|
let Some(pointer_pos) = pointer_pos else {
|
||||||
if let Some(layer) = self.layer_id_at(pointer_pos) {
|
return false;
|
||||||
if layer.order == Order::Background {
|
};
|
||||||
!self.pass_state(|state| state.unused_rect.contains(pointer_pos))
|
let Some(layer) = self.layer_id_at(pointer_pos) else {
|
||||||
} else {
|
return false;
|
||||||
true
|
};
|
||||||
}
|
if layer.order == Order::Background {
|
||||||
|
let root_ui_available_rect = self
|
||||||
|
.pass_state(|state| state.root_ui_available_rect)
|
||||||
|
.or_else(|| self.prev_pass_state(|state| state.root_ui_available_rect));
|
||||||
|
|
||||||
|
if let Some(root_ui_available_rect) = root_ui_available_rect {
|
||||||
|
// Modern `run_ui` code
|
||||||
|
!root_ui_available_rect.contains(pointer_pos)
|
||||||
} else {
|
} else {
|
||||||
false
|
// Legacy code
|
||||||
|
#[expect(deprecated)]
|
||||||
|
!self.pass_state(|state| state.unused_rect.contains(pointer_pos))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ pub struct IMEOutput {
|
|||||||
///
|
///
|
||||||
/// This is a very thin rectangle.
|
/// This is a very thin rectangle.
|
||||||
pub cursor_rect: crate::Rect,
|
pub cursor_rect: crate::Rect,
|
||||||
|
|
||||||
|
/// Whether any ongoing IME composition should be interrupted.
|
||||||
|
pub should_interrupt_composition: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commands that the egui integration should execute at the end of a frame.
|
/// Commands that the egui integration should execute at the end of a frame.
|
||||||
|
|||||||
@@ -117,21 +117,10 @@ pub struct Memory {
|
|||||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||||
popups: ViewportIdMap<OpenPopup>,
|
popups: ViewportIdMap<OpenPopup>,
|
||||||
|
|
||||||
/// When the last IME interruption was made.
|
/// Whether to inform the backend to interrupt any ongoing IME composition
|
||||||
|
/// this pass.
|
||||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||||
ime_interruption_time: ImeInterruptionTime,
|
requested_interrupt_ime: bool,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
enum ImeInterruptionTime {
|
|
||||||
#[default]
|
|
||||||
None,
|
|
||||||
|
|
||||||
/// The IME was interrupted in the current frame.
|
|
||||||
ThisFrame,
|
|
||||||
|
|
||||||
/// The IME was interrupted in the previous frame.
|
|
||||||
LastFrame,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Memory {
|
impl Default for Memory {
|
||||||
@@ -149,7 +138,7 @@ impl Default for Memory {
|
|||||||
popups: Default::default(),
|
popups: Default::default(),
|
||||||
everything_is_visible: Default::default(),
|
everything_is_visible: Default::default(),
|
||||||
add_fonts: Default::default(),
|
add_fonts: Default::default(),
|
||||||
ime_interruption_time: Default::default(),
|
requested_interrupt_ime: Default::default(),
|
||||||
};
|
};
|
||||||
slf.interactions.entry(slf.viewport_id).or_default();
|
slf.interactions.entry(slf.viewport_id).or_default();
|
||||||
slf.areas.entry(slf.viewport_id).or_default();
|
slf.areas.entry(slf.viewport_id).or_default();
|
||||||
@@ -778,15 +767,7 @@ impl Memory {
|
|||||||
|
|
||||||
self.areas.entry(self.viewport_id).or_default();
|
self.areas.entry(self.viewport_id).or_default();
|
||||||
|
|
||||||
match self.ime_interruption_time {
|
self.requested_interrupt_ime = false;
|
||||||
ImeInterruptionTime::ThisFrame => {
|
|
||||||
self.ime_interruption_time = ImeInterruptionTime::LastFrame;
|
|
||||||
}
|
|
||||||
ImeInterruptionTime::LastFrame => {
|
|
||||||
self.ime_interruption_time = ImeInterruptionTime::None;
|
|
||||||
}
|
|
||||||
ImeInterruptionTime::None => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// self.interactions is handled elsewhere
|
// self.interactions is handled elsewhere
|
||||||
|
|
||||||
@@ -1028,30 +1009,22 @@ impl Memory {
|
|||||||
///
|
///
|
||||||
/// A widget should only consume IME events if this returns `true`. At most
|
/// A widget should only consume IME events if this returns `true`. At most
|
||||||
/// one widget can own IME events for each frame.
|
/// one widget can own IME events for each frame.
|
||||||
|
#[inline(always)]
|
||||||
pub fn owns_ime_events(&self, id: Id) -> bool {
|
pub fn owns_ime_events(&self, id: Id) -> bool {
|
||||||
let Some(focus) = self.focus() else {
|
// Note: Even if the IME is being interrupted in the current frame, we
|
||||||
return false;
|
// should not return `false` here, since we still need
|
||||||
};
|
// `PlatformOutput::ime` to be set in such cases.
|
||||||
// We check across two frames because the widget that called
|
|
||||||
// `interrupt_ime` may run after other widgets that call this method
|
self.has_focus(id)
|
||||||
// within the same frame.
|
|
||||||
if matches!(
|
|
||||||
self.ime_interruption_time,
|
|
||||||
ImeInterruptionTime::ThisFrame | ImeInterruptionTime::LastFrame
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
focus.focused() == Some(id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interrupt the current IME composition, if any.
|
/// Interrupt the current IME composition, if any.
|
||||||
///
|
|
||||||
/// This causes [`Self::owns_ime_events`] to return `false` for all widgets
|
|
||||||
/// for the remainder of this frame and the next frame, giving time
|
|
||||||
/// for the IME to be dismissed (by making `platform_output.ime` be `None`
|
|
||||||
/// for at least one frame).
|
|
||||||
pub fn interrupt_ime(&mut self) {
|
pub fn interrupt_ime(&mut self) {
|
||||||
self.ime_interruption_time = ImeInterruptionTime::ThisFrame;
|
self.requested_interrupt_ime = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn should_interrupt_ime(&self) -> bool {
|
||||||
|
self.requested_interrupt_ime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#![expect(deprecated)] // TODO(emilk): Remove legacy panels
|
||||||
|
|
||||||
use ahash::HashMap;
|
use ahash::HashMap;
|
||||||
|
|
||||||
use crate::{Align, Id, IdMap, LayerId, Rangef, Rect, Vec2, WidgetRects, id::IdSet, style};
|
use crate::{Align, Id, IdMap, LayerId, Rangef, Rect, Vec2, WidgetRects, id::IdSet, style};
|
||||||
@@ -199,15 +201,28 @@ pub struct PassState {
|
|||||||
|
|
||||||
pub tooltips: TooltipPassState,
|
pub tooltips: TooltipPassState,
|
||||||
|
|
||||||
|
/// What the root UI had available at the end of the previous pass.
|
||||||
|
///
|
||||||
|
/// Only set if [`crate::Context::run_ui`] has been called.
|
||||||
|
pub root_ui_available_rect: Option<Rect>,
|
||||||
|
|
||||||
|
/// What the root UI had used at the end of the previous pass.
|
||||||
|
///
|
||||||
|
/// Only set if [`crate::Context::run_ui`] has been called.
|
||||||
|
pub root_ui_min_rect: Option<Rect>,
|
||||||
|
|
||||||
/// Starts off as the `screen_rect`, shrinks as panels are added.
|
/// Starts off as the `screen_rect`, shrinks as panels are added.
|
||||||
/// The [`crate::CentralPanel`] does not change this.
|
/// The [`crate::CentralPanel`] does not change this.
|
||||||
|
#[deprecated = "Only used by legacy Context-Panels"]
|
||||||
pub available_rect: Rect,
|
pub available_rect: Rect,
|
||||||
|
|
||||||
/// Starts off as the `screen_rect`, shrinks as panels are added.
|
/// Starts off as the `screen_rect`, shrinks as panels are added.
|
||||||
/// The [`crate::CentralPanel`] retracts from this.
|
/// The [`crate::CentralPanel`] retracts from this.
|
||||||
|
#[deprecated = "Only used by legacy Context-Panels"]
|
||||||
pub unused_rect: Rect,
|
pub unused_rect: Rect,
|
||||||
|
|
||||||
/// How much space is used by panels.
|
/// How much space is used by panels.
|
||||||
|
#[deprecated = "Only used by legacy Context-Panels"]
|
||||||
pub used_by_panels: Rect,
|
pub used_by_panels: Rect,
|
||||||
|
|
||||||
/// The current scroll area should scroll to this range (horizontal, vertical).
|
/// The current scroll area should scroll to this range (horizontal, vertical).
|
||||||
@@ -240,6 +255,8 @@ impl Default for PassState {
|
|||||||
widgets: Default::default(),
|
widgets: Default::default(),
|
||||||
layers: Default::default(),
|
layers: Default::default(),
|
||||||
tooltips: Default::default(),
|
tooltips: Default::default(),
|
||||||
|
root_ui_available_rect: None,
|
||||||
|
root_ui_min_rect: None,
|
||||||
available_rect: Rect::NAN,
|
available_rect: Rect::NAN,
|
||||||
unused_rect: Rect::NAN,
|
unused_rect: Rect::NAN,
|
||||||
used_by_panels: Rect::NAN,
|
used_by_panels: Rect::NAN,
|
||||||
@@ -262,6 +279,8 @@ impl PassState {
|
|||||||
widgets,
|
widgets,
|
||||||
tooltips,
|
tooltips,
|
||||||
layers,
|
layers,
|
||||||
|
root_ui_available_rect,
|
||||||
|
root_ui_min_rect,
|
||||||
available_rect,
|
available_rect,
|
||||||
unused_rect,
|
unused_rect,
|
||||||
used_by_panels,
|
used_by_panels,
|
||||||
@@ -278,6 +297,8 @@ impl PassState {
|
|||||||
widgets.clear();
|
widgets.clear();
|
||||||
tooltips.clear();
|
tooltips.clear();
|
||||||
layers.clear();
|
layers.clear();
|
||||||
|
*root_ui_available_rect = None;
|
||||||
|
*root_ui_min_rect = None;
|
||||||
*available_rect = content_rect;
|
*available_rect = content_rect;
|
||||||
*unused_rect = content_rect;
|
*unused_rect = content_rect;
|
||||||
*used_by_panels = Rect::NOTHING;
|
*used_by_panels = Rect::NOTHING;
|
||||||
@@ -295,6 +316,7 @@ impl PassState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// How much space is still available after panels has been added.
|
/// How much space is still available after panels has been added.
|
||||||
|
#[deprecated = "Only used by legacy Context-Panels"]
|
||||||
pub(crate) fn available_rect(&self) -> Rect {
|
pub(crate) fn available_rect(&self) -> Rect {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.available_rect.is_finite(),
|
self.available_rect.is_finite(),
|
||||||
@@ -304,6 +326,7 @@ impl PassState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shrink `available_rect`.
|
/// Shrink `available_rect`.
|
||||||
|
#[deprecated = "Only used by legacy Context-Panels"]
|
||||||
pub(crate) fn allocate_left_panel(&mut self, panel_rect: Rect) {
|
pub(crate) fn allocate_left_panel(&mut self, panel_rect: Rect) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
panel_rect.min.distance(self.available_rect.min) < 0.1,
|
panel_rect.min.distance(self.available_rect.min) < 0.1,
|
||||||
@@ -315,6 +338,7 @@ impl PassState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shrink `available_rect`.
|
/// Shrink `available_rect`.
|
||||||
|
#[deprecated = "Only used by legacy Context-Panels"]
|
||||||
pub(crate) fn allocate_right_panel(&mut self, panel_rect: Rect) {
|
pub(crate) fn allocate_right_panel(&mut self, panel_rect: Rect) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
panel_rect.max.distance(self.available_rect.max) < 0.1,
|
panel_rect.max.distance(self.available_rect.max) < 0.1,
|
||||||
@@ -326,6 +350,7 @@ impl PassState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shrink `available_rect`.
|
/// Shrink `available_rect`.
|
||||||
|
#[deprecated = "Only used by legacy Context-Panels"]
|
||||||
pub(crate) fn allocate_top_panel(&mut self, panel_rect: Rect) {
|
pub(crate) fn allocate_top_panel(&mut self, panel_rect: Rect) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
panel_rect.min.distance(self.available_rect.min) < 0.1,
|
panel_rect.min.distance(self.available_rect.min) < 0.1,
|
||||||
@@ -337,6 +362,7 @@ impl PassState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shrink `available_rect`.
|
/// Shrink `available_rect`.
|
||||||
|
#[deprecated = "Only used by legacy Context-Panels"]
|
||||||
pub(crate) fn allocate_bottom_panel(&mut self, panel_rect: Rect) {
|
pub(crate) fn allocate_bottom_panel(&mut self, panel_rect: Rect) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
panel_rect.max.distance(self.available_rect.max) < 0.1,
|
panel_rect.max.distance(self.available_rect.max) < 0.1,
|
||||||
@@ -347,6 +373,7 @@ impl PassState {
|
|||||||
self.used_by_panels |= panel_rect;
|
self.used_by_panels |= panel_rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deprecated = "Only used by legacy Context-Panels"]
|
||||||
pub(crate) fn allocate_central_panel(&mut self, panel_rect: Rect) {
|
pub(crate) fn allocate_central_panel(&mut self, panel_rect: Rect) {
|
||||||
// Note: we do not shrink `available_rect`, because
|
// Note: we do not shrink `available_rect`, because
|
||||||
// we allow windows to cover the CentralPanel.
|
// we allow windows to cover the CentralPanel.
|
||||||
|
|||||||
@@ -894,6 +894,7 @@ impl TextEdit<'_> {
|
|||||||
o.ime = Some(crate::output::IMEOutput {
|
o.ime = Some(crate::output::IMEOutput {
|
||||||
rect: to_global * inner_rect,
|
rect: to_global * inner_rect,
|
||||||
cursor_rect: to_global * primary_cursor_rect,
|
cursor_rect: to_global * primary_cursor_rect,
|
||||||
|
should_interrupt_composition: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,13 @@ readme = "README.md"
|
|||||||
repository = "https://github.com/emilk/egui/tree/main/crates/egui_glow"
|
repository = "https://github.com/emilk/egui/tree/main/crates/egui_glow"
|
||||||
categories = ["gui", "game-development"]
|
categories = ["gui", "game-development"]
|
||||||
keywords = ["glow", "egui", "gui", "gamedev"]
|
keywords = ["glow", "egui", "gui", "gamedev"]
|
||||||
include = ["../../LICENSE-APACHE", "../../LICENSE-MIT", "**/*.rs", "Cargo.toml", "src/shader/*.glsl"]
|
include = [
|
||||||
|
"../../LICENSE-APACHE",
|
||||||
|
"../../LICENSE-MIT",
|
||||||
|
"**/*.rs",
|
||||||
|
"Cargo.toml",
|
||||||
|
"src/shader/*.glsl",
|
||||||
|
]
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
@@ -65,7 +71,6 @@ winit = { workspace = true, optional = true, default-features = false, features
|
|||||||
web-sys = { workspace = true, features = ["console"] }
|
web-sys = { workspace = true, features = ["console"] }
|
||||||
wasm-bindgen.workspace = true
|
wasm-bindgen.workspace = true
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
glutin = { workspace = true, default-features = true } # examples/pure_glow
|
glutin = { workspace = true, default-features = true } # examples/pure_glow
|
||||||
glutin-winit = { workspace = true, default-features = true }
|
glutin-winit = { workspace = true, default-features = true }
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ egui.workspace = true
|
|||||||
eframe = { workspace = true, optional = true }
|
eframe = { workspace = true, optional = true }
|
||||||
kittest.workspace = true
|
kittest.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
toml = {workspace = true, features = ["parse", "serde"] }
|
toml = { workspace = true, features = ["parse", "serde"] }
|
||||||
|
|
||||||
# wgpu dependencies
|
# wgpu dependencies
|
||||||
egui-wgpu = { workspace = true, optional = true }
|
egui-wgpu = { workspace = true, optional = true }
|
||||||
|
|||||||
@@ -48,7 +48,14 @@ mint = ["emath/mint"]
|
|||||||
rayon = ["dep:rayon"]
|
rayon = ["dep:rayon"]
|
||||||
|
|
||||||
## Allow serialization using [`serde`](https://docs.rs/serde).
|
## Allow serialization using [`serde`](https://docs.rs/serde).
|
||||||
serde = ["dep:serde", "ahash/serde", "emath/serde", "ecolor/serde", "font-types/serde", "smallvec/serde"]
|
serde = [
|
||||||
|
"dep:serde",
|
||||||
|
"ahash/serde",
|
||||||
|
"ecolor/serde",
|
||||||
|
"emath/serde",
|
||||||
|
"font-types/serde",
|
||||||
|
"smallvec/serde",
|
||||||
|
]
|
||||||
|
|
||||||
## Change Vertex layout to be compatible with unity
|
## Change Vertex layout to be compatible with unity
|
||||||
unity = []
|
unity = []
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ workspace = true
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
eframe = { workspace = true, features = [
|
eframe = { workspace = true, default_features = false, features = [
|
||||||
|
"glow",
|
||||||
"default",
|
"default",
|
||||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||||
] }
|
] }
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ struct MyTestApp {}
|
|||||||
|
|
||||||
impl eframe::App for MyTestApp {
|
impl eframe::App for MyTestApp {
|
||||||
fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
||||||
|
egui::Panel::top("top").show_inside(ui, |ui| {
|
||||||
|
ui.label("This is a test of painting directly with glow.");
|
||||||
|
});
|
||||||
|
|
||||||
use glow::HasContext as _;
|
use glow::HasContext as _;
|
||||||
let gl = frame.gl().unwrap();
|
let gl = frame.gl().unwrap();
|
||||||
|
|
||||||
@@ -43,6 +47,21 @@ impl eframe::App for MyTestApp {
|
|||||||
|
|
||||||
egui::Window::new("Floating Window").show(ui.ctx(), |ui| {
|
egui::Window::new("Floating Window").show(ui.ctx(), |ui| {
|
||||||
ui.label("The background should be purple.");
|
ui.label("The background should be purple.");
|
||||||
|
ui.label(format!(
|
||||||
|
"is_pointer_over_egui: {}",
|
||||||
|
ui.is_pointer_over_egui()
|
||||||
|
));
|
||||||
|
ui.label(format!(
|
||||||
|
"egui_wants_pointer_input: {}",
|
||||||
|
ui.egui_wants_pointer_input()
|
||||||
|
));
|
||||||
|
ui.label(format!(
|
||||||
|
"egui_is_using_pointer: {}",
|
||||||
|
ui.egui_is_using_pointer()
|
||||||
|
));
|
||||||
|
if let Some(pos) = ui.pointer_latest_pos() {
|
||||||
|
ui.label(format!("layer_id_at: {:?}", ui.layer_id_at(pos)));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user