Skip to content

Commit

Permalink
remove last remanant of RawImage
Browse files Browse the repository at this point in the history
  • Loading branch information
jprochazk committed Sep 13, 2023
1 parent cb5e3c4 commit 63d6d31
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 230 deletions.
101 changes: 5 additions & 96 deletions crates/egui/src/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
//! For example, a loader may determine that it doesn't support loading a specific URI
//! if the protocol does not match what it expects.
mod bytes_loader;
mod texture_loader;

use self::bytes_loader::DefaultBytesLoader;
use self::texture_loader::DefaultTextureLoader;
use crate::Context;
use ahash::HashMap;
use epaint::mutex::Mutex;
Expand Down Expand Up @@ -458,102 +463,6 @@ pub trait TextureLoader {
fn byte_size(&self) -> usize;
}

#[derive(Default)]
pub(crate) struct DefaultBytesLoader {
cache: Mutex<HashMap<Cow<'static, str>, Bytes>>,
}

impl DefaultBytesLoader {
pub(crate) fn insert(&self, uri: impl Into<Cow<'static, str>>, bytes: impl Into<Bytes>) {
self.cache
.lock()
.entry(uri.into())
.or_insert_with(|| bytes.into());
}
}

impl BytesLoader for DefaultBytesLoader {
fn id(&self) -> &str {
generate_loader_id!(DefaultBytesLoader)
}

fn load(&self, _: &Context, uri: &str) -> BytesLoadResult {
match self.cache.lock().get(uri).cloned() {
Some(bytes) => Ok(BytesPoll::Ready {
size: None,
bytes,
mime: None,
}),
None => Err(LoadError::NotSupported),
}
}

fn forget(&self, uri: &str) {
let _ = self.cache.lock().remove(uri);
}

fn forget_all(&self) {
self.cache.lock().clear();
}

fn byte_size(&self) -> usize {
self.cache.lock().values().map(|bytes| bytes.len()).sum()
}
}

#[derive(Default)]
struct DefaultTextureLoader {
cache: Mutex<HashMap<(String, TextureOptions), TextureHandle>>,
}

impl TextureLoader for DefaultTextureLoader {
fn id(&self) -> &str {
generate_loader_id!(DefaultTextureLoader)
}

fn load(
&self,
ctx: &Context,
uri: &str,
texture_options: TextureOptions,
size_hint: SizeHint,
) -> TextureLoadResult {
let mut cache = self.cache.lock();
if let Some(handle) = cache.get(&(uri.into(), texture_options)) {
let texture = SizedTexture::from_handle(handle);
Ok(TexturePoll::Ready { texture })
} else {
match ctx.try_load_image(uri, size_hint)? {
ImagePoll::Pending { size } => Ok(TexturePoll::Pending { size }),
ImagePoll::Ready { image } => {
let handle = ctx.load_texture(uri, image, texture_options);
let texture = SizedTexture::from_handle(&handle);
cache.insert((uri.into(), texture_options), handle);
Ok(TexturePoll::Ready { texture })
}
}
}
}

fn forget(&self, uri: &str) {
self.cache.lock().retain(|(u, _), _| u != uri);
}

fn forget_all(&self) {
self.cache.lock().clear();
}

fn end_frame(&self, _: usize) {}

fn byte_size(&self) -> usize {
self.cache
.lock()
.values()
.map(|texture| texture.byte_size())
.sum()
}
}

type BytesLoaderImpl = Arc<dyn BytesLoader + Send + Sync + 'static>;
type ImageLoaderImpl = Arc<dyn ImageLoader + Send + Sync + 'static>;
type TextureLoaderImpl = Arc<dyn TextureLoader + Send + Sync + 'static>;
Expand Down
57 changes: 57 additions & 0 deletions crates/egui/src/load/bytes_loader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use super::*;

#[derive(Default)]
pub struct DefaultBytesLoader {
cache: Mutex<HashMap<Cow<'static, str>, Bytes>>,
}

impl DefaultBytesLoader {
pub fn insert(&self, uri: impl Into<Cow<'static, str>>, bytes: impl Into<Bytes>) {
self.cache
.lock()
.entry(uri.into())
.or_insert_with_key(|uri| {
let bytes: Bytes = bytes.into();

#[cfg(feature = "log")]
log::trace!("loaded {} bytes for uri {uri:?}", bytes.len());

bytes
});
}
}

impl BytesLoader for DefaultBytesLoader {
fn id(&self) -> &str {
generate_loader_id!(DefaultBytesLoader)
}

fn load(&self, _: &Context, uri: &str) -> BytesLoadResult {
match self.cache.lock().get(uri).cloned() {
Some(bytes) => Ok(BytesPoll::Ready {
size: None,
bytes,
mime: None,
}),
None => Err(LoadError::NotSupported),
}
}

fn forget(&self, uri: &str) {
#[cfg(feature = "log")]
log::trace!("forget {uri:?}");

let _ = self.cache.lock().remove(uri);
}

fn forget_all(&self) {
#[cfg(feature = "log")]
log::trace!("forget all");

self.cache.lock().clear();
}

fn byte_size(&self) -> usize {
self.cache.lock().values().map(|bytes| bytes.len()).sum()
}
}
60 changes: 60 additions & 0 deletions crates/egui/src/load/texture_loader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use super::*;

#[derive(Default)]
pub struct DefaultTextureLoader {
cache: Mutex<HashMap<(String, TextureOptions), TextureHandle>>,
}

impl TextureLoader for DefaultTextureLoader {
fn id(&self) -> &str {
crate::generate_loader_id!(DefaultTextureLoader)
}

fn load(
&self,
ctx: &Context,
uri: &str,
texture_options: TextureOptions,
size_hint: SizeHint,
) -> TextureLoadResult {
let mut cache = self.cache.lock();
if let Some(handle) = cache.get(&(uri.into(), texture_options)) {
let texture = SizedTexture::from_handle(handle);
Ok(TexturePoll::Ready { texture })
} else {
match ctx.try_load_image(uri, size_hint)? {
ImagePoll::Pending { size } => Ok(TexturePoll::Pending { size }),
ImagePoll::Ready { image } => {
let handle = ctx.load_texture(uri, image, texture_options);
let texture = SizedTexture::from_handle(&handle);
cache.insert((uri.into(), texture_options), handle);
Ok(TexturePoll::Ready { texture })
}
}
}
}

fn forget(&self, uri: &str) {
#[cfg(feature = "log")]
log::trace!("forget {uri:?}");

self.cache.lock().retain(|(u, _), _| u != uri);
}

fn forget_all(&self) {
#[cfg(feature = "log")]
log::trace!("forget all");

self.cache.lock().clear();
}

fn end_frame(&self, _: usize) {}

fn byte_size(&self) -> usize {
self.cache
.lock()
.values()
.map(|texture| texture.byte_size())
.sum()
}
}
53 changes: 33 additions & 20 deletions crates/egui/src/widgets/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::*;
/// # });
/// ```
#[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
pub struct Button {
pub struct Button<'a> {
text: WidgetText,
shortcut_text: WidgetText,
wrap: Option<bool>,
Expand All @@ -34,10 +34,10 @@ pub struct Button {
frame: Option<bool>,
min_size: Vec2,
rounding: Option<Rounding>,
image: Option<widgets::RawImage>,
image: Option<Image<'a>>,
}

impl Button {
impl<'a> Button<'a> {
pub fn new(text: impl Into<WidgetText>) -> Self {
Self {
text: text.into(),
Expand All @@ -57,15 +57,11 @@ impl Button {
/// Creates a button with an image to the left of the text. The size of the image as displayed is defined by the provided size.
#[allow(clippy::needless_pass_by_value)]
pub fn image_and_text(
texture_id: TextureId,
image_size: impl Into<Vec2>,
image_source: impl Into<ImageSource<'a>>,
text: impl Into<WidgetText>,
) -> Self {
Self {
image: Some(widgets::RawImage::new(SizedTexture {
id: texture_id,
size: image_size.into(),
})),
image: Some(Image::new(image_source)),
..Self::new(text)
}
}
Expand Down Expand Up @@ -142,7 +138,7 @@ impl Button {
}
}

impl Widget for Button {
impl Widget for Button<'_> {
fn ui(self, ui: &mut Ui) -> Response {
let Button {
text,
Expand All @@ -158,6 +154,11 @@ impl Widget for Button {
image,
} = self;

let image_size = image
.as_ref()
.and_then(|image| image.size())
.unwrap_or(Vec2::splat(0.0));

let frame = frame.unwrap_or_else(|| ui.visuals().button_frame);

let mut button_padding = ui.spacing().button_padding;
Expand All @@ -166,8 +167,8 @@ impl Widget for Button {
}

let mut text_wrap_width = ui.available_width() - 2.0 * button_padding.x;
if let Some(image) = &image {
text_wrap_width -= image.size().x + ui.spacing().icon_spacing;
if image.is_some() {
text_wrap_width -= image_size.x + ui.spacing().icon_spacing;
}
if !shortcut_text.is_empty() {
text_wrap_width -= 60.0; // Some space for the shortcut text (which we never wrap).
Expand All @@ -178,9 +179,9 @@ impl Widget for Button {
.then(|| shortcut_text.into_galley(ui, Some(false), f32::INFINITY, TextStyle::Button));

let mut desired_size = text.size();
if let Some(image) = &image {
desired_size.x += image.size().x + ui.spacing().icon_spacing;
desired_size.y = desired_size.y.max(image.size().y);
if image.is_some() {
desired_size.x += image_size.x + ui.spacing().icon_spacing;
desired_size.y = desired_size.y.max(image_size.y);
}
if let Some(shortcut_text) = &shortcut_text {
desired_size.x += ui.spacing().item_spacing.x + shortcut_text.size().x;
Expand All @@ -206,10 +207,10 @@ impl Widget for Button {
.rect(rect.expand(visuals.expansion), rounding, fill, stroke);
}

let text_pos = if let Some(image) = &image {
let text_pos = if image.is_some() {
let icon_spacing = ui.spacing().icon_spacing;
pos2(
rect.min.x + button_padding.x + image.size().x + icon_spacing,
rect.min.x + button_padding.x + image_size.x + icon_spacing,
rect.center().y - 0.5 * text.size().y,
)
} else {
Expand All @@ -235,11 +236,23 @@ impl Widget for Button {
let image_rect = Rect::from_min_size(
pos2(
rect.min.x + button_padding.x,
rect.center().y - 0.5 - (image.size().y / 2.0),
rect.center().y - 0.5 - (image_size.y / 2.0),
),
image.size(),
image_size,
);
image.paint_at(ui, image_rect);
match image.load(ui) {
Ok(TexturePoll::Ready { texture }) => {
image.paint_at(ui, image_rect, &texture);
}
Ok(TexturePoll::Pending { .. }) => {
ui.add(Spinner::new().size(image_rect.size().min_elem()))
.on_hover_text(format!("Loading {:?}…", image.uri()));
}
Err(err) => {
ui.colored_label(ui.visuals().error_fg_color, "⚠")
.on_hover_text(err.to_string());
}
};
}
}

Expand Down
Loading

0 comments on commit 63d6d31

Please sign in to comment.