diff --git a/otg/gtk/src/app_window.rs b/otg/gtk/src/app_window.rs
index 6ff129b..b40c5e6 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: ResourceManager,
}
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,
};
let home = s.setup_home();
@@ -88,7 +91,7 @@ impl AppWindow {
pub fn open_game_review(&self, game_record: GameRecord) {
let header = adw::HeaderBar::new();
- let game_review = GameReview::new(self.core.clone(), game_record);
+ let game_review = GameReview::new(self.core.clone(), game_record, self.resources.clone());
let layout = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
diff --git a/otg/gtk/src/components/goban.rs b/otg/gtk/src/components/goban.rs
index 7d9958b..85d52fe 100644
--- a/otg/gtk/src/components/goban.rs
+++ b/otg/gtk/src/components/goban.rs
@@ -35,7 +35,7 @@ You should have received a copy of the GNU General Public License along with On
// Now, we know what kind of object we have for the current board representation. Let's make use of
// that.
-use crate::perftrace;
+use crate::{perftrace, Resource, ResourceManager};
use gio::resources_lookup_data;
use glib::Object;
@@ -56,6 +56,7 @@ const MARGIN: i32 = 20;
#[derive(Default)]
pub struct GobanPrivate {
board_state: Rc>,
+ resource_manager: Rc>>,
}
impl GobanPrivate {}
@@ -88,10 +89,11 @@ glib::wrapper! {
}
impl Goban {
- pub fn new(board_state: otg_core::Goban) -> Self {
+ pub fn new(board_state: otg_core::Goban, resources: ResourceManager) -> Self {
let s: Self = Object::builder().build();
*s.imp().board_state.borrow_mut() = board_state;
+ *s.imp().resource_manager.borrow_mut() = Some(resources);
s.set_width_request(WIDTH);
s.set_height_request(HEIGHT);
@@ -107,19 +109,42 @@ impl Goban {
fn redraw(&self, ctx: &cairo::Context, width: i32, height: i32) {
println!("{} x {}", width, height);
+ /*
let background = load_pixbuf(
"/com/luminescent-dreams/otg-gtk/wood_texture.jpg",
false,
WIDTH + 40,
HEIGHT + 40,
);
+ */
+
+ let background = self
+ .imp()
+ .resource_manager
+ .borrow()
+ .as_ref()
+ .and_then(|r| r.resource("/com/luminescent-dreams/otg-gtk/wood_texture.jpg"));
+
+ let black_texture = self
+ .imp()
+ .resource_manager
+ .borrow()
+ .as_ref()
+ .and_then(|r| r.resource("/com/luminescent-dreams/otg-gtk/black_stone.png"));
+
+ let white_texture = self
+ .imp()
+ .resource_manager
+ .borrow()
+ .as_ref()
+ .and_then(|r| r.resource("/com/luminescent-dreams/otg-gtk/white_stone.png"));
match background {
- Ok(Some(ref background)) => {
+ Some(Resource::Image(ref background)) => {
ctx.set_source_pixbuf(background, 0., 0.);
ctx.paint().expect("paint should never fail");
}
- Ok(None) | Err(_) => ctx.set_source_rgb(0.7, 0.7, 0.7),
+ None => ctx.set_source_rgb(0.7, 0.7, 0.7),
}
let board = self.imp().board_state.borrow();
@@ -129,7 +154,14 @@ impl Goban {
let hspace_between = ((width - 40) as f64) / ((board.size.width - 1) as f64);
let vspace_between = ((height - 40) as f64) / ((board.size.height - 1) as f64);
- let pen = Pen::new(MARGIN as f64, MARGIN as f64, hspace_between, vspace_between);
+ let pen = Pen::new(
+ MARGIN as f64,
+ MARGIN as f64,
+ hspace_between,
+ vspace_between,
+ black_texture,
+ white_texture,
+ );
(0..board.size.width).for_each(|col| {
ctx.move_to(
@@ -179,35 +211,27 @@ struct Pen {
y_offset: f64,
hspace_between: f64,
vspace_between: f64,
- black_stone: Pixbuf,
- white_stone: Pixbuf,
+ black_stone: Option,
+ white_stone: Option,
}
impl Pen {
- fn new(x_offset: f64, y_offset: f64, hspace_between: f64, vspace_between: f64) -> Self {
- let radius = (hspace_between / 2. - 2.) as i32;
- let black_stone = load_pixbuf(
- "/com/luminescent-dreams/otg-gtk/black_stone.png",
- true,
- 512,
- 512,
- )
- .unwrap()
- .unwrap();
- let black_stone = black_stone
- .scale_simple(radius * 2, radius * 2, InterpType::Nearest)
- .unwrap();
- let white_stone = load_pixbuf(
- "/com/luminescent-dreams/otg-gtk/white_stone.png",
- true,
- 512,
- 512,
- )
- .unwrap()
- .unwrap();
- let white_stone = white_stone
- .scale_simple(radius * 2, radius * 2, InterpType::Nearest)
- .unwrap();
+ fn new(
+ x_offset: f64,
+ y_offset: f64,
+ hspace_between: f64,
+ vspace_between: f64,
+ black_stone: Option,
+ white_stone: Option,
+ ) -> Self {
+ let black_stone = match black_stone {
+ Some(Resource::Image(img)) => Some(img),
+ _ => None,
+ };
+ let white_stone = match white_stone {
+ Some(Resource::Image(img)) => Some(img),
+ _ => None,
+ };
Pen {
x_offset,
y_offset,
@@ -232,8 +256,14 @@ impl Pen {
fn stone(&self, ctx: &cairo::Context, row: u8, col: u8, color: Color, _liberties: Option) {
let (x_loc, y_loc) = self.stone_location(row, col);
match color {
- Color::White => ctx.set_source_pixbuf(&self.white_stone, x_loc, y_loc),
- Color::Black => ctx.set_source_pixbuf(&self.black_stone, x_loc, y_loc),
+ Color::White => match self.white_stone {
+ Some(ref white_stone) => ctx.set_source_pixbuf(&white_stone, x_loc, y_loc),
+ None => ctx.set_source_rgb(0.9, 0.9, 0.9),
+ },
+ Color::Black => match self.black_stone {
+ Some(ref black_stone) => ctx.set_source_pixbuf(&black_stone, x_loc, y_loc),
+ None => ctx.set_source_rgb(0.0, 0.0, 0.0),
+ },
}
ctx.paint().expect("paint should never fail");
/*
diff --git a/otg/gtk/src/lib.rs b/otg/gtk/src/lib.rs
index e36a2bb..7fe1471 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,93 @@ impl CoreApi {
}
}
+#[derive(Clone)]
+pub enum Resource {
+ Image(Pixbuf),
+}
+
+#[derive(Clone)]
+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