1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#![warn(missing_docs)]
#![allow(
    clippy::return_self_not_must_use,
    clippy::unit_arg,
    clippy::needless_doctest_main,
    clippy::too_many_arguments,
    clippy::collapsible_if
)]

//! This crate provides the ability to annotate structs with a `#[derive(Inspectable)]`,
//! which opens a debug interface using [egui](https://github.com/emilk/egui) where you can visually edit the values of your struct live.
//!
//! Your struct will then be available to you as a bevy resource.
//!
//! ## Example
//! ```rust
//! use bevy_inspector_egui::Inspectable;
//!
//! #[derive(Inspectable, Default)]
//! struct Data {
//!     should_render: bool,
//!     text: String,
//!     #[inspectable(min = 42.0, max = 100.0)]
//!     size: f32,
//! }
//! ```
//! Add the [`InspectorPlugin`] to your App.
//! ```rust,no_run
//! use bevy_inspector_egui::InspectorPlugin;
//! # use bevy::prelude::*;
//!
//! # #[derive(bevy_inspector_egui::Inspectable, Default)] struct Data {}
//! fn main() {
//!     App::new()
//!         .add_plugins(DefaultPlugins)
//!         .add_plugin(InspectorPlugin::<Data>::new())
//!         .run();
//! }
//! ```
//!
//! The list of built-in attributes is documented [here](trait.Inspectable.html#default-attributes).
//!
//! ## World Inspector
//!
//! If you want to display all world entities you can add the [`WorldInspectorPlugin`]:
//! ```rust,no_run
//! use bevy::prelude::*;
//! use bevy_inspector_egui::WorldInspectorPlugin;
//!
//! fn main() {
//!     App::new()
//!         .add_plugins(DefaultPlugins)
//!         .add_plugin(WorldInspectorPlugin::new())
//!         .add_startup_system(setup)
//!         .run();
//! }
//! # fn setup() {}
//! ```
//! You can configure it by inserting the [`WorldInspectorParams`] resource.
//! In order for custom components to be displayed in the world inspector, you'll need to [register](world_inspector::InspectableRegistry::register) it on the [`InspectableRegistry`](world_inspector::InspectableRegistry).
//!
//! # Features
//! - **clipboard** (enabled by default): enables `egui`'s clipboard integratoin
// //! - **rapier**: adds support for [bevy_rapier3d](https://docs.rs/bevy_rapier3d)
// //! - **rapier2d**: adds support for [bevy_rapier2d](https://docs.rs/bevy_rapier2d)

#[macro_use]
mod utils;

/// Utitly types implementing [`Inspectable`](crate::Inspectable)
pub mod widgets;

#[allow(missing_docs)]
mod impls;
/// Internals for the inspector plugins
pub mod plugin;

/// Configuration for the [`WorldInspectorPlugin`](crate::world_inspector::WorldInspectorPlugin)
pub mod world_inspector;

/// Commonly used imports
pub mod prelude {
    pub use crate::{Inspectable, InspectorPlugin, RegisterInspectable, WorldInspectorPlugin};
}

use std::hash::Hasher;
use std::marker::PhantomData;

use bevy::ecs::system::Resource;
use bevy::prelude::{App, Mut, World};
use egui::CtxRef;
use utils::error_label_needs_world;
#[doc(inline)]
pub use world_inspector::{InspectableRegistry, WorldInspectorParams, WorldInspectorPlugin};

/// [`Inspectable`] implementation for foreign types implementing [`Reflect`](bevy::reflect::Reflect)
pub mod reflect;

pub use bevy_egui;
pub use bevy_egui::egui;

/// Derives the [`Inspectable`](Inspectable) trait.
pub use bevy_inspector_egui_derive::Inspectable;
#[doc(inline)]
pub use plugin::InspectorPlugin;

/// Attributes for the built-in [`Inspectable`](Inspectable) implementations
pub mod options {
    pub use crate::impls::*;
    pub use crate::widgets::button::ButtonAttributes;
    pub use crate::widgets::new_window::WindowAttributes;
    pub use crate::world_inspector::impls::EntityAttributes;
}

/// The context passed to [`Inspectable::ui`].
pub struct Context<'a> {
    /// egui ui context
    pub ui_ctx: Option<&'a CtxRef>,
    /// The world is only available when not using `InspectablePlugin::shared()`
    world: Option<*mut World>,
    _world_marker: PhantomData<&'a mut ()>,

    /// Something to distinguish between siblings.
    pub id: Option<u64>,
}

impl<'a> Context<'a> {
    /// Returns a reference to the world if the context has access to it
    pub fn world(&self) -> Option<&'a World> {
        self.world.map(|world| unsafe { &*world })
    }

    /// Get a mutable reference to the `world` if the inspector has access to it.
    ///
    /// # Safety
    /// Users of this function are only allowed to mutate resources and components,
    /// but can't do any changes that would result in changes of archetypes.
    pub unsafe fn world_mut(&mut self) -> Option<&'a mut World> {
        match self.world {
            Some(world) => Some(&mut *world),
            None => None,
        }
    }

    /// Returns the provided closure with mutable access to the world, and a context
    /// that has *no* access to the world.
    ///
    /// Will display an error message if the context doesn't have world access.
    pub fn world_scope(
        &mut self,
        ui: &mut egui::Ui,
        ty: &str,
        f: impl FnOnce(&mut World, &mut egui::Ui, &mut Context) -> bool,
    ) -> bool {
        let world = match self.world.take() {
            Some(world) => world,
            None => return error_label_needs_world(ui, ty),
        };
        let mut cx = Context {
            world: None,
            ..*self
        };
        let world = unsafe { &mut *world };
        let changed = f(world, ui, &mut cx);
        self.world = Some(world);

        changed
    }

    /// Like [`Context::world_scope`], but the context will have world access as well.
    ///
    /// # Safety
    /// The function must not use the world in ways that would invalidate archetypes, as
    /// types like the `InspectorQuery` will rely on them being the same before and after
    /// calling `Inspectable::ui`.
    pub unsafe fn world_scope_unchecked(
        &mut self,
        ui: &mut egui::Ui,
        ty: &str,
        f: impl FnOnce(&mut World, &mut egui::Ui, &mut Context) -> bool,
    ) -> bool {
        let world = match self.world {
            Some(world) => &mut *world,
            None => return error_label_needs_world(ui, ty),
        };
        let changed = f(world, ui, self);
        self.world = Some(world);

        changed
    }

    /// Temporarily removes a resource from the world and calls the provided closure with that resource
    /// while still having `&mut Context` available.
    ///
    /// Will display an error message if the context doesn't have world access.
    pub fn resource_scope<T: Resource, F: FnOnce(&mut egui::Ui, &mut Context, Mut<T>) -> bool>(
        &mut self,
        ui: &mut egui::Ui,
        ty: &str,
        f: F,
    ) -> bool {
        // Safety: the world is only used to modify a resource and doesn't change any archetypes
        unsafe {
            self.world_scope_unchecked(ui, ty, |world, ui, context| {
                world.resource_scope(|world, res: Mut<T>| {
                    let mut context = context.with_world(world);
                    f(ui, &mut context, res)
                })
            })
        }
    }

    fn take_world(&mut self) -> Option<(Context, &'a mut World)> {
        let world = self.world.take()?;
        let world = unsafe { &mut *world };
        let context = Context {
            world: None,
            ..*self
        };
        Some((context, world))
    }
}

impl<'a> Context<'a> {
    /// Create a new context with access to the world
    pub fn new_world_access(ui_ctx: Option<&'a CtxRef>, world: &'a mut World) -> Self {
        Context {
            ui_ctx,
            world: Some(world),
            _world_marker: PhantomData,
            id: None,
        }
    }

    /// Creates a context without access to `World`
    pub fn new_shared(ui_ctx: Option<&'a CtxRef>) -> Self {
        Context {
            ui_ctx,
            world: None,
            _world_marker: PhantomData,
            id: None,
        }
    }

    /// Same context but with different `world`
    pub fn with_world(&self, world: &'a mut World) -> Self {
        Context {
            world: Some(world),
            ..*self
        }
    }

    /// Same context but with a derived `id`
    pub fn with_id(&mut self, id: u64) -> Context<'_> {
        let mut hasher = std::collections::hash_map::DefaultHasher::default();
        if let Some(id) = self.id {
            hasher.write_u64(id);
        }
        hasher.write_u64(id);
        let id = hasher.finish();

        Context {
            id: Some(id),
            world: self.world.as_mut().map(|world| *world),
            _world_marker: PhantomData,
            ui_ctx: self.ui_ctx,
        }
    }

    /// Returns the [id](struct.Context.html#structfield.id) if present, otherwise a dummy id.
    pub fn id(&self) -> egui::Id {
        let dummy_id = egui::Id::new(42);
        match self.id {
            Some(id) => egui::Id::new(id),
            None => dummy_id,
        }
    }
}

/// This trait describes how a struct should be displayed.
/// It can be derived for structs and enums, see the [crate-level docs](index.html) for how to do that.
///
/// ## Default attributes
/// - **ignore**: hides the field in the inspector
/// - **label**: provides a label instead of using the field name
/// - **read_only**: disables the UI
/// - **collapse**: wraps the ui in an [`egui::CollapsingHeader`].
/// - **default**: only for enums, specifies the default value when selecting a new variant
/// - **wrapper**: wrap field UI in a custom function. Demo in the [rust_types example](https://github.com/jakobhellermann/bevy-inspector-egui/blob/main/examples/rust_types.rs#L20).
/// - **override_where_clause**: specifies which type bounds should be used for generics. For example `#[inspectable(override_where_clause = "") struct Struct(PhantomData<M>)` won't include a `M: Inspectable` bound.
pub trait Inspectable {
    /// The `Attributes` associated type specifies what attributes can be passed to a field.
    /// See the following snippet for an example:
    /// ```rust,no_run
    /// # use bevy_inspector_egui::{egui, Inspectable, Context};
    /// struct MyCustomType;
    /// # #[derive(Clone, Default)]
    /// struct MyWidgetAttributes { a: f32, b: Option<String> }
    ///
    /// impl Inspectable for MyCustomType {
    ///   type Attributes = MyWidgetAttributes;
    ///
    ///   fn ui(&mut self, _: &mut egui::Ui, options: MyWidgetAttributes, context: &mut Context) -> bool {
    ///     println!("a = {}, b = {:?}", options.a, options.b);
    ///     false
    ///   }
    /// }
    ///
    /// // ...
    ///
    /// #[derive(Inspectable)]
    /// struct InspectorData {
    ///   #[inspectable(a = 10.0, b = None)]
    ///   value: MyCustomType,
    /// }
    /// ```
    type Attributes: Default + Clone;

    /// This methods is responsible for building the egui ui.
    /// Returns whether any data was modified.
    fn ui(&mut self, ui: &mut egui::Ui, options: Self::Attributes, context: &mut Context) -> bool;

    /// Displays the value without any context. Useful for usage outside of the plugins, where
    /// there is no access to the world or [`EguiContext`](bevy_egui::EguiContext).
    fn ui_raw(&mut self, ui: &mut egui::Ui, options: Self::Attributes) {
        let mut empty_context = Context::new_shared(None);
        self.ui(ui, options, &mut empty_context);
    }

    /// Required setup for the bevy application, e.g. registering events. Note that this method will run for every instance of a type.
    #[allow(unused_variables)]
    fn setup(app: &mut App) {}
}

/// Helper trait for enabling `app.register_inspectable::<T>()`
pub trait RegisterInspectable {
    /// Register type `T` so that it can be displayed by the [`WorldInspectorPlugin`](crate::WorldInspectorPlugin).
    /// Forwards to [`InspectableRegistry::register`].
    fn register_inspectable<T: Inspectable + 'static>(&mut self) -> &mut Self;
}

impl RegisterInspectable for App {
    fn register_inspectable<T: Inspectable + 'static>(&mut self) -> &mut Self {
        self.world
            .get_resource_mut::<InspectableRegistry>()
            .unwrap()
            .register::<T>();
        self
    }
}