diff --git a/otg/gtk/src/app_window.rs b/otg/gtk/src/app_window.rs index 6ff129b..f393f59 100644 --- a/otg/gtk/src/app_window.rs +++ b/otg/gtk/src/app_window.rs @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with On the Grid. If not, see . */ -use crate::CoreApi; +use crate::{CoreApi, ResourceManager}; use adw::prelude::*; use otg_core::{ @@ -22,7 +22,7 @@ use otg_core::{ CoreRequest, CoreResponse, }; use sgf::GameRecord; -use std::sync::{Arc, RwLock}; +use std::{rc::Rc, sync::{Arc, RwLock}}; use crate::views::{GameReview, HomeView, SettingsView}; @@ -58,10 +58,12 @@ pub struct AppWindow { // Not liking this, but I have to keep track of the settings view model separately from // anything else. I'll have to look into this later. settings_view_model: Arc>>, + + resources: Rc, } impl AppWindow { - pub fn new(app: &adw::Application, core: CoreApi) -> Self { + pub fn new(app: &adw::Application, core: CoreApi, resources: ResourceManager) -> Self { let window = Self::setup_window(app); let overlay = Self::setup_overlay(); let stack = adw::NavigationView::new(); @@ -77,6 +79,7 @@ impl AppWindow { overlay, core, settings_view_model: Default::default(), + resources: Rc::new(resources), }; let home = s.setup_home(); diff --git a/otg/gtk/src/lib.rs b/otg/gtk/src/lib.rs index e36a2bb..817e066 100644 --- a/otg/gtk/src/lib.rs +++ b/otg/gtk/src/lib.rs @@ -21,10 +21,12 @@ pub use app_window::AppWindow; mod views; -use async_std::task::{yield_now}; -use otg_core::{Core, Observable, CoreRequest, CoreResponse}; -use std::{rc::Rc}; - +use async_std::task::yield_now; +use gio::resources_lookup_data; +use gtk::gdk_pixbuf::{Colorspace, InterpType, Pixbuf}; +use image::{io::Reader as ImageReader, ImageError}; +use otg_core::{Core, CoreRequest, CoreResponse, Observable}; +use std::{cell::RefCell, collections::HashMap, io::Cursor, rc::Rc}; #[derive(Clone)] pub struct CoreApi { @@ -37,6 +39,92 @@ impl CoreApi { } } +#[derive(Clone)] +pub enum Resource { + Image(Pixbuf), +} + +pub struct ResourceManager { + resources: Rc>>, +} + +impl ResourceManager { + pub fn new() -> Self { + let mut resources = HashMap::new(); + + for (path, xres, yres, transparency) in [ + ( + "/com/luminescent-dreams/otg-gtk/wood_texture.jpg", + 840, + 840, + false, + ), + ( + "/com/luminescent-dreams/otg-gtk/black_stone.png", + 40, + 40, + true, + ), + ( + "/com/luminescent-dreams/otg-gtk/white_stone.png", + 40, + 40, + true, + ), + ] { + match perftrace(&format!("loading {}", path), || { + Self::load_image(path, transparency, xres, yres) + }) { + Ok(Some(image)) => { + resources.insert(path.to_owned(), Resource::Image(image)); + } + Ok(None) => println!("no image in resource bundle for {}", path), + Err(err) => println!("failed to load image {}: {}", path, err), + } + } + + Self { + resources: Rc::new(RefCell::new(resources)), + } + } + + pub fn resource(&self, path: &str) -> Option { + self.resources.borrow().get(path).cloned() + } + + fn load_image( + path: &str, + transparency: bool, + width: i32, + height: i32, + ) -> Result, ImageError> { + let image_bytes = resources_lookup_data(path, gio::ResourceLookupFlags::NONE).unwrap(); + + let image = ImageReader::new(Cursor::new(image_bytes)) + .with_guessed_format() + .unwrap() + .decode(); + image.map(|image| { + let stride = if transparency { + image.to_rgba8().sample_layout().height_stride + } else { + image.to_rgb8().sample_layout().height_stride + }; + Pixbuf::from_bytes( + &glib::Bytes::from(image.as_bytes()), + Colorspace::Rgb, + transparency, + 8, + image.width() as i32, + image.height() as i32, + stride as i32, + ) + .scale_simple(width, height, InterpType::Nearest) + }) + } + +} + pub fn perftrace(trace_name: &str, f: F) -> A where F: FnOnce() -> A, diff --git a/otg/gtk/src/main.rs b/otg/gtk/src/main.rs index 5d0519b..6035d16 100644 --- a/otg/gtk/src/main.rs +++ b/otg/gtk/src/main.rs @@ -4,8 +4,7 @@ use async_std::task::spawn; use gio::ActionEntry; use otg_core::{Config, ConfigOption, Core, CoreNotification, LibraryPath, Observable}; use otg_gtk::{ - AppWindow, - CoreApi, + AppWindow, CoreApi, ResourceManager }; @@ -123,8 +122,9 @@ fn main() { app.connect_activate({ move |app| { + let resources = ResourceManager::new(); let core_api = CoreApi { core: core.clone() }; - let app_window = AppWindow::new(app, core_api); + let app_window = AppWindow::new(app, core_api, resources); setup_app_configuration_action(app, app_window.clone());