@@ -97,8 +97,8 @@ pub struct ImageMeta {
9797 pub metadata : HashMap < String , String > ,
9898 /// EXIF metadata (key-value pairs), stored separately from regular metadata
9999 pub exif_data : Option < HashMap < String , String > > ,
100- /// Image source (can be texture handle or URI for animated images)
101- pub image_source : egui:: widgets :: ImageSource < ' static > ,
100+ /// Pre-constructed image widget ready for rendering
101+ pub image : egui:: Image < ' static > ,
102102 /// Keep the texture handle alive to prevent GPU texture from being freed
103103 pub _texture_handle : Option < egui:: TextureHandle > ,
104104}
@@ -110,7 +110,7 @@ impl std::fmt::Debug for ImageMeta {
110110 . field ( "title" , & self . title )
111111 . field ( "metadata" , & self . metadata )
112112 . field ( "exif_data" , & self . exif_data )
113- . field ( "image_source " , & "ImageSource " )
113+ . field ( "image " , & "Image " )
114114 . field (
115115 "_texture_handle" ,
116116 & self . _texture_handle . as_ref ( ) . map ( |_| "TextureHandle" ) ,
@@ -130,9 +130,7 @@ pub enum PreviewContent {
130130 language : & ' static str ,
131131 } ,
132132 /// Plugin-generated preview content
133- PluginPreview {
134- components : Vec < kiorg_plugin:: Component > ,
135- } ,
133+ PluginPreview { components : Vec < RenderedComponent > } ,
136134 /// Image content with metadata
137135 Image ( ImageMeta ) ,
138136 /// Zip file content with a list of entries
@@ -182,15 +180,134 @@ pub struct TarEntry {
182180 pub permissions : String ,
183181}
184182
183+ fn load_into_texture (
184+ ctx : & egui:: Context ,
185+ dynamic_image : image:: DynamicImage ,
186+ name : String ,
187+ ) -> ( egui:: Image < ' static > , Option < egui:: TextureHandle > ) {
188+ let rgba8 = dynamic_image. to_rgba8 ( ) ;
189+ let size = [ rgba8. width ( ) as usize , rgba8. height ( ) as usize ] ;
190+ let color_image =
191+ egui:: ColorImage :: from_rgba_unmultiplied ( size, rgba8. as_flat_samples ( ) . as_slice ( ) ) ;
192+ let texture = ctx. load_texture ( name, color_image, Default :: default ( ) ) ;
193+ let image = egui:: Image :: new ( & texture) ;
194+ ( image, Some ( texture) )
195+ }
196+
197+ /// Rendered version of plugin components that can hold processed data like textures
198+ #[ derive( Clone , Debug ) ]
199+ pub enum RenderedComponent {
200+ Title ( kiorg_plugin:: TitleComponent ) ,
201+ Text ( kiorg_plugin:: TextComponent ) ,
202+ Image ( RenderedImageComponent ) ,
203+ Table ( kiorg_plugin:: TableComponent ) ,
204+ }
205+
206+ #[ derive( Clone ) ]
207+ pub struct RenderedImageComponent {
208+ pub image : egui:: Image < ' static > ,
209+ pub interactive : bool ,
210+ pub _texture_handle : Option < egui:: TextureHandle > ,
211+ }
212+
213+ impl std:: fmt:: Debug for RenderedImageComponent {
214+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
215+ f. debug_struct ( "RenderedImageComponent" )
216+ . field ( "image" , & "Image" )
217+ . field ( "interactive" , & self . interactive )
218+ . field (
219+ "_texture_handle" ,
220+ & self . _texture_handle . as_ref ( ) . map ( |_| "TextureHandle" ) ,
221+ )
222+ . finish ( )
223+ }
224+ }
225+
185226impl PreviewContent {
186227 /// Creates a new text preview content
187228 pub fn text ( content : impl Into < String > ) -> Self {
188229 Self :: Text ( content. into ( ) )
189230 }
190231
191- /// Creates a new plugin preview content
192- pub fn plugin_preview ( components : Vec < kiorg_plugin:: Component > ) -> Self {
193- Self :: PluginPreview { components }
232+ /// Creates a new plugin preview content by processing plugin components
233+ pub fn plugin_preview_from_components (
234+ components : Vec < kiorg_plugin:: Component > ,
235+ ctx : & egui:: Context ,
236+ ) -> Self {
237+ let mut rendered_components = Vec :: with_capacity ( components. len ( ) ) ;
238+
239+ for component in components {
240+ match component {
241+ kiorg_plugin:: Component :: Title ( t) => {
242+ rendered_components. push ( RenderedComponent :: Title ( t) )
243+ }
244+ kiorg_plugin:: Component :: Text ( t) => {
245+ rendered_components. push ( RenderedComponent :: Text ( t) )
246+ }
247+ kiorg_plugin:: Component :: Table ( t) => {
248+ rendered_components. push ( RenderedComponent :: Table ( t) )
249+ }
250+ kiorg_plugin:: Component :: Image ( img) => match img. source {
251+ kiorg_plugin:: ImageSource :: Path ( path) => match image:: open ( & path) {
252+ Ok ( dynamic_image) => {
253+ let ( image, texture_handle) = load_into_texture (
254+ ctx,
255+ dynamic_image,
256+ format ! ( "plugin_preview_path_{}" , path) ,
257+ ) ;
258+ rendered_components. push ( RenderedComponent :: Image (
259+ RenderedImageComponent {
260+ image,
261+ interactive : img. interactive ,
262+ _texture_handle : texture_handle,
263+ } ,
264+ ) ) ;
265+ }
266+ Err ( e) => {
267+ rendered_components. push ( RenderedComponent :: Text (
268+ kiorg_plugin:: TextComponent {
269+ text : format ! (
270+ "Failed to load image from path: {}\n Error: {}" ,
271+ path, e
272+ ) ,
273+ } ,
274+ ) ) ;
275+ }
276+ } ,
277+ kiorg_plugin:: ImageSource :: Bytes { format, data, uid } => {
278+ match image:: load_from_memory_with_format ( & data, format) {
279+ Ok ( dynamic_image) => {
280+ let ( image, texture_handle) = load_into_texture (
281+ ctx,
282+ dynamic_image,
283+ format ! ( "plugin_preview_bytes_{}" , uid) ,
284+ ) ;
285+ rendered_components. push ( RenderedComponent :: Image (
286+ RenderedImageComponent {
287+ image,
288+ interactive : img. interactive ,
289+ _texture_handle : texture_handle,
290+ } ,
291+ ) ) ;
292+ }
293+ Err ( e) => {
294+ rendered_components. push ( RenderedComponent :: Text (
295+ kiorg_plugin:: TextComponent {
296+ text : format ! (
297+ "Failed to decode image (format: {:?}, uid: {}\n Error: {}" ,
298+ format, uid, e
299+ ) ,
300+ } ,
301+ ) ) ;
302+ }
303+ }
304+ }
305+ } ,
306+ }
307+ }
308+ Self :: PluginPreview {
309+ components : rendered_components,
310+ }
194311 }
195312
196313 /// Creates a new image preview content with a texture handle
@@ -200,11 +317,12 @@ impl PreviewContent {
200317 texture : egui:: TextureHandle ,
201318 exif_data : Option < HashMap < String , String > > ,
202319 ) -> Self {
320+ let image = egui:: Image :: new ( & texture) ;
203321 Self :: Image ( ImageMeta {
204322 title : title. into ( ) ,
205323 metadata,
206324 exif_data,
207- image_source : egui :: widgets :: ImageSource :: from ( & texture ) ,
325+ image ,
208326 _texture_handle : Some ( texture) ,
209327 } )
210328 }
@@ -216,12 +334,13 @@ impl PreviewContent {
216334 uri : String ,
217335 exif_data : Option < HashMap < String , String > > ,
218336 ) -> Self {
337+ let image = egui:: Image :: new ( egui:: widgets:: ImageSource :: Uri ( uri. into ( ) ) ) ;
219338 Self :: Image ( ImageMeta {
220339 title : title. into ( ) ,
221340 metadata,
222341 exif_data,
223- image_source : egui :: widgets :: ImageSource :: Uri ( uri . into ( ) ) ,
224- _texture_handle : None , // No texture handle for URI-based images//
342+ image ,
343+ _texture_handle : None , // No texture handle for URI-based images
225344 } )
226345 }
227346
0 commit comments