Skip to content

Commit

Permalink
Added a dropdown allowing you to select from loaded images in the Ins…
Browse files Browse the repository at this point in the history
…pectorPrimitive implementation for Handle<Image>.
  • Loading branch information
eupraxia05 committed Mar 17, 2024
1 parent 1563fe9 commit f03903e
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 30 deletions.
2 changes: 2 additions & 0 deletions crates/bevy-inspector-egui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ once_cell = "1.16"
pretty-type-name = "1.0"
smallvec = "1.10"

egui-dropdown = "0.7.0"

[dev-dependencies]
bevy = { version = "0.13", default-features = false, features = [
"x11",
Expand Down
130 changes: 100 additions & 30 deletions crates/bevy-inspector-egui/src/inspector_egui_impls/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use pretty_type_name::pretty_type_name;

use crate::{
bevy_inspector::errors::{no_world_in_context, show_error},
reflect_inspector::InspectorUi,
reflect_inspector::InspectorUi, restricted_world_view::RestrictedWorldView,
};

use super::InspectorPrimitive;
Expand All @@ -25,57 +25,127 @@ impl InspectorPrimitive for Handle<Image> {
fn ui(
&mut self,
ui: &mut egui::Ui,
options: &dyn Any,
_: &dyn Any,
id: egui::Id,
env: InspectorUi<'_, '_>,
) -> bool {
self.ui_readonly(ui, options, id, env);
false
}

fn ui_readonly(&self, ui: &mut egui::Ui, _: &dyn Any, _: egui::Id, env: InspectorUi<'_, '_>) {
let Some(world) = &mut env.context.world else {
no_world_in_context(ui, self.reflect_short_type_path());
return;
//no_world_in_context(ui, self.reflect_short_type_path());
return false;
};
let (mut egui_user_textures, mut images) =
match world.get_two_resources_mut::<bevy_egui::EguiUserTextures, Assets<Image>>() {

update_and_show_image(self, world, ui);

let (asset_server, images) =
match world.get_two_resources_mut::<bevy_asset::AssetServer, Assets<Image>>() {
(Ok(a), Ok(b)) => (a, b),
(a, b) => {
if let Err(e) = a {
show_error(e, ui, &pretty_type_name::<bevy_egui::EguiContext>());
show_error(e, ui, &pretty_type_name::<bevy_asset::AssetServer>());
}
if let Err(e) = b {
show_error(e, ui, &pretty_type_name::<Assets<Image>>());
}
return;
return false;
}
};

// get all loaded image paths
let mut image_paths = Vec::new();
for image in images.iter() {
if let Some(image_path) = asset_server.get_path(image.0) {
image_paths.push(image_path.to_string());
}
}

let mut scaled_down_textures = SCALED_DOWN_TEXTURES.lock().unwrap();

// todo: read asset events to re-rescale images of they changed
let rescaled = rescaled_image(
self,
&mut scaled_down_textures,
&mut images,
&mut egui_user_textures,
);
let (rescaled_handle, texture_id) = match rescaled {
Some(it) => it,
None => {
ui.label("<texture>");
return;
// first, get the typed search text from a stored egui data value
let mut selected_path = None;
let mut image_picker_search_text = String::from("");
ui.data_mut(|data| {
image_picker_search_text = data.get_temp_mut_or_default::<String>(
id.with("image_picker_search_text")).clone();
});

// build and show the dropdown
let dropdown = egui_dropdown::DropDownBox::from_iter(
image_paths.iter(), id.with("image_picker"),
&mut image_picker_search_text,
|ui, path| {
let response = ui.selectable_label(false, path);
if response.clicked() {
selected_path = Some(path.to_string());
}
response
}
};
);
ui.add(dropdown);

// update the typed search text
ui.data_mut(|data| {
*data.get_temp_mut_or_default::<String>(
id.with("image_picker_search_text")) = image_picker_search_text;
});

let rescaled_image = images.get(&rescaled_handle).unwrap();
show_image(rescaled_image, texture_id, ui);
// if the user selected an option, update the image handle
if let Some(selected_path) = selected_path {
*self = asset_server.load(selected_path);
}

false
}

fn ui_readonly(&self, ui: &mut egui::Ui, _: &dyn Any, _: egui::Id, env: InspectorUi<'_, '_>) {
let Some(world) = &mut env.context.world else {
no_world_in_context(ui, self.reflect_short_type_path());
return;
};

update_and_show_image(self, world, ui);
}
}

static SCALED_DOWN_TEXTURES: Lazy<Mutex<ScaledDownTextures>> = Lazy::new(Default::default);

fn update_and_show_image(
image: &Handle<Image>,
world: &mut RestrictedWorldView,
ui: &mut egui::Ui
) {
let (mut egui_user_textures, mut images) =
match world.get_two_resources_mut::<bevy_egui::EguiUserTextures, Assets<Image>>() {
(Ok(a), Ok(b)) => (a, b),
(a, b) => {
if let Err(e) = a {
show_error(e, ui, &pretty_type_name::<bevy_egui::EguiContext>());
}
if let Err(e) = b {
show_error(e, ui, &pretty_type_name::<Assets<Image>>());
}
return;
}
};

let mut scaled_down_textures = SCALED_DOWN_TEXTURES.lock().unwrap();

// todo: read asset events to re-rescale images of they changed
let rescaled = rescaled_image(
image,
&mut scaled_down_textures,
&mut images,
&mut egui_user_textures,
);
let (rescaled_handle, texture_id) = match rescaled {
Some(it) => it,
None => {
ui.label("<texture>");
return;
}
};

let rescaled_image = images.get(&rescaled_handle).unwrap();
show_image(rescaled_image, texture_id, ui);
}

fn show_image(
image: &Image,
texture_id: egui::TextureId,
Expand Down

0 comments on commit f03903e

Please sign in to comment.