diff --git a/otg/gtk/src/components/goban.rs b/otg/gtk/src/components/goban.rs index c9500ea..c7cad2b 100644 --- a/otg/gtk/src/components/goban.rs +++ b/otg/gtk/src/components/goban.rs @@ -32,13 +32,23 @@ You should have received a copy of the GNU General Public License along with On // Okay, that wasn't so bad. I'm a little confused that I don't have a code action for renaming a // symbol, but I'll fix that some other time. Anyway, now let's focus on the goban. - // Now, we know what kind of object we have for the current board representation. Let's make use of // that. +use crate::perftrace; +use gio::resources_lookup_data; use glib::Object; -use gtk::{prelude::*, subclass::prelude::*}; -use std::{rc::Rc, cell::RefCell}; +use gtk::{ + gdk_pixbuf::{InterpType, Pixbuf}, + prelude::*, + subclass::prelude::*, +}; +use image::io::Reader as ImageReader; +use std::{cell::RefCell, io::Cursor, rc::Rc}; + +const WIDTH: i32 = 800; +const HEIGHT: i32 = 800; +const MARGIN: i32 = 20; // Internal representation of the Goban drawing area. #[derive(Default)] @@ -46,6 +56,8 @@ pub struct GobanPrivate { board_state: Rc>, } +impl GobanPrivate {} + #[glib::object_subclass] impl ObjectSubclass for GobanPrivate { const NAME: &'static str = "Goban"; @@ -57,28 +69,76 @@ impl ObjectImpl for GobanPrivate {} impl WidgetImpl for GobanPrivate {} impl DrawingAreaImpl for GobanPrivate {} -/// This Goban, being in the `components` crate, is merely the rendering of a board. This is not -/// the primary representation of the board. -/// -/// In a game of Go, there are certain rules about what are valid moves and what are not. -/// Internally, I want to keep track of those, and doing so requires a few things. -/// -/// - We can never repeat a game state (though I think maybe that is allowed in a few rulesets, but -/// I'm coding to the AGA ruleset) -/// - We can never play a suicidal move -/// -/// Finally, updating the board state is non-GUI logic. So, sorry, might be dropping away from GUI -/// code for a while to work on the backend representation, some of which already exists. +// This Goban, being in the `components` crate, is merely the rendering of a board. This is not +// the primary representation of the board. +// +// In a game of Go, there are certain rules about what are valid moves and what are not. +// Internally, I want to keep track of those, and doing so requires a few things. +// +// - We can never repeat a game state (though I think maybe that is allowed in a few rulesets, but +// I'm coding to the AGA ruleset) +// - We can never play a suicidal move +// +// Finally, updating the board state is non-GUI logic. So, sorry, might be dropping away from GUI +// code for a while to work on the backend representation, some of which already exists. glib::wrapper! { - pub struct Goban(ObjectSubclass) @extends gtk::Widget, gtk::DrawingArea; + pub struct Goban(ObjectSubclass) @extends gtk::DrawingArea, gtk::Widget; } impl Goban { pub fn new(board_state: otg_core::Goban) -> Self { - let s: Self = Object::new(); + let s: Self = Object::builder().build(); *s.imp().board_state.borrow_mut() = board_state; + s.set_width_request(WIDTH); + s.set_height_request(HEIGHT); + + s.set_draw_func({ + let s = s.clone(); + move |_, ctx, width, height| { + perftrace("render drawing area", || s.redraw(ctx, width, height)); + } + }); s } + + fn redraw(&self, ctx: &cairo::Context, width: i32, height: i32) { + println!("{} x {}", width, height); + /* + let wood_texture = resources_lookup_data( + "/com/luminescent-dreams/otg-gtk/wood_texture.jpg", + gio::ResourceLookupFlags::NONE, + ) + .unwrap(); + + let background = ImageReader::new(Cursor::new(wood_texture)) + .with_guessed_format() + .unwrap() + .decode(); + let background = background.map(|background| { + Pixbuf::from_bytes( + &glib::Bytes::from(background.as_bytes()), + gtk::gdk_pixbuf::Colorspace::Rgb, + false, + 8, + background.width() as i32, + background.height() as i32, + background.to_rgb8().sample_layout().height_stride as i32, + ) + .scale_simple(WIDTH, HEIGHT, InterpType::Nearest) + }); + + match background { + Ok(Some(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), + } + */ + + ctx.set_source_rgb(0.7, 0.7, 0.7); + let _ = ctx.paint(); + } } diff --git a/otg/gtk/src/views/game_review.rs b/otg/gtk/src/views/game_review.rs index d723c52..7c6ac42 100644 --- a/otg/gtk/src/views/game_review.rs +++ b/otg/gtk/src/views/game_review.rs @@ -38,15 +38,15 @@ impl Default for GameReviewPrivate { impl ObjectSubclass for GameReviewPrivate { const NAME: &'static str = "GameReview"; type Type = GameReview; - type ParentType = gtk::Grid; + type ParentType = gtk::Box; } impl ObjectImpl for GameReviewPrivate {} impl WidgetImpl for GameReviewPrivate {} -impl GridImpl for GameReviewPrivate {} +impl BoxImpl for GameReviewPrivate {} glib::wrapper! { - pub struct GameReview(ObjectSubclass) @extends gtk::Grid, gtk::Widget, @implements gtk::Accessible; + pub struct GameReview(ObjectSubclass) @extends gtk::Box, gtk::Widget, @implements gtk::Accessible; } impl GameReview { @@ -54,10 +54,14 @@ impl GameReview { let s: Self = Object::builder().build(); let board = Goban::new(otg_core::Goban::default()); + /* s.attach(&board, 0, 0, 2, 2); s.attach(>k::Label::new(Some("white player")), 0, 2, 1, 1); s.attach(>k::Label::new(Some("black player")), 0, 2, 1, 2); s.attach(>k::Label::new(Some("chat")), 1, 2, 2, 2); + */ + + s.append(&board); s }