adds basics of pawn's placement

This commit is contained in:
2019-06-05 16:20:23 +02:00
parent 525babba5b
commit 9b79004b54
3 changed files with 207 additions and 156 deletions

View File

@@ -4,18 +4,21 @@ pub struct Grid {
inner: gtk::Grid, inner: gtk::Grid,
} }
#[derive(Debug,Copy,Clone)]
pub struct CellPosition(i32, i32); pub struct CellPosition(i32, i32);
impl Grid { impl Grid {
// Initialize a grid, populating its cells /// Initialize a grid, populating its cells
// Only square grid for now /// Only square grid for now
pub fn init(inner: gtk::Grid, size: i32) -> Self { pub(crate) fn init(inner: gtk::Grid, size: i32, app_state: AppState) -> Self {
for i in 0..(size * size) { for i in 0..(size * size) {
let x = i % size; let x = i % size;
let y = i / size; let y = i / size;
let cell = grid::Cell::new(CellPosition(x,y)); let cell = grid::Cell::new(
CellPosition(x,y)
);
cell.connect_clicked(app_state.clone());
inner.attach(cell.as_ref(), x, y, 1, 1); inner.attach(cell.as_ref(), x, y, 1, 1);
// Signals
} }
Grid { inner } Grid { inner }
} }
@@ -26,6 +29,7 @@ struct CellWidget {
eventbox: gtk::EventBox, eventbox: gtk::EventBox,
position: gtk::Label, position: gtk::Label,
header : gtk::Label, header : gtk::Label,
content: gtk::Label,
} }
impl CellWidget { impl CellWidget {
@@ -68,25 +72,28 @@ impl CellWidget {
.unwrap(); .unwrap();
position.set_text(&format!("{}x{}", pos.0, pos.1)); position.set_text(&format!("{}x{}", pos.0, pos.1));
let header_clone = header.clone(); let cell = CellWidget {
eventbox.connect_button_press_event(Self::on_click(header_clone));
CellWidget {
eventbox, eventbox,
position, position,
header, header,
} content: builder.get_object("content").unwrap(),
};
cell
} }
// Handler for button press events pub fn connect_clicked(&self, state: AppState) {
fn on_click( let header = self.header.clone();
data: gtk::Label let content = self.content.clone();
) -> impl Fn(&gtk::EventBox, &gdk::EventButton) -> gtk::Inhibit self.eventbox
{ .connect_button_press_event(move |_,_| {
move |_,_| { let mut state = state.borrow_mut();
data.set_text("Clicked."); if let Some(data) = state.pending.take() {
gtk::Inhibit(true) println!("{:?}", data);
} content.set_text(&data.name);
};
header.set_text("Is Clicked.");
gtk::Inhibit(true)
});
} }
} }
@@ -97,21 +104,22 @@ impl AsRef<gtk::EventBox> for CellWidget {
} }
} }
pub struct Cell { struct Cell {
inner: CellWidget, inner: CellWidget,
is_active: bool, position: CellPosition,
is_occupied: bool,
} }
impl Cell { impl Cell {
pub fn new(pos: CellPosition) -> Self { fn new(position: CellPosition) -> Self {
let inner = CellWidget::new(pos, "Empty cell");
Cell { Cell {
inner, inner: CellWidget::new(position, ""),
is_active: false, position
is_occupied: false,
} }
} }
fn connect_clicked(&self, state: AppState) {
self.inner.connect_clicked(state);
}
} }
impl AsRef<gtk::EventBox> for Cell { impl AsRef<gtk::EventBox> for Cell {

View File

@@ -3,109 +3,44 @@ extern crate gio;
extern crate gdk; extern crate gdk;
extern crate glib; extern crate glib;
use gtk::BoxExt; use std::cell::RefCell;
use std::rc::Rc;
use gtk::prelude::*; use gtk::prelude::*;
use gio::prelude::*; use gio::prelude::*;
use std::env::args; use std::env::args;
use std::process; use std::process;
mod grid; mod grid;
mod pawn;
mod pawn { /// Content of the Application state
use super::*; ///
#[derive(Debug,Clone,Default)]
#[derive(Debug,Clone)] pub struct AppData {
pub struct PawnList { /// A slot for any pawn waiting for placement
inner: gtk::ListBox, pending: Option<pawn::PawnData>,
} /// Owned list of pawns
pawns: Vec<pawn::Pawn>,
impl PawnList {
pub fn init(inner: gtk::ListBox) -> Self {
PawnList{ inner }
}
pub fn add(&self, pawn: &Pawn) {
let row = gtk::ListBoxRow::new();
row.add(pawn.as_ref());
self.inner.add(&row);
}
}
struct PawnData {
name: String,
}
pub struct Pawn {
data: PawnData,
widget: gtk::Box,
}
impl Pawn {
pub fn new<S: Into<String>>(name: S) -> Self {
let pawn_src = include_str!("../res/pawn.glade");
let builder = gtk::Builder::new_from_string(pawn_src);
let name = name.into();
let label: gtk::Label =
builder
.get_object("name")
.unwrap();
label.set_text(&name);
let place_btn: gtk::Button =
builder
.get_object("place_btn")
.unwrap();
place_btn.connect_clicked(|_| {
println!("Placing...");
});
let stats_btn: gtk::Button =
builder
.get_object("stats_btn")
.unwrap();
stats_btn.connect_clicked(|_| {
println!("Showing stats...");
});
let widget: gtk::Box = builder.get_object("pawn").unwrap();
Pawn {
data: PawnData{ name },
widget,
}
}
}
impl AsRef<gtk::Box> for Pawn {
fn as_ref(&self) -> &gtk::Box {
&self.widget
}
}
pub fn pawn_factory() -> Vec<Pawn> {
let mut pawns = Vec::with_capacity(3);
for name in &["Lomion", "Oilosse", "Fefi"] {
pawns.push(Pawn::new(*name));
}
pawns
}
#[cfg(test)]
mod tests {
#[test]
fn test_pawn_factory() {
let pawns = pawn_factory();
assert_eq!(pawns.len(), 3);
assert_eq!(pawns.get(2).unwrap(), "Fefi");
}
}
} }
/// A sharable state for the whole application
#[derive(Debug,Clone,Default)]
pub struct AppState(Rc<RefCell<AppData>>);
impl std::ops::Deref for AppState {
type Target = Rc<RefCell<AppData>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
struct App { struct App {
inner: gtk::Application, inner: gtk::Application,
pawns: Vec<pawn::Pawn>, state: AppState,
} }
impl App { impl App {
fn new<'a>() -> Result<Self, &'a str> { fn new<'a>() -> Result<Self, &'a str> {
let app = let app =
@@ -114,55 +49,63 @@ impl App {
"home.local.PlayMat", "home.local.PlayMat",
gio::ApplicationFlags::FLAGS_NONE gio::ApplicationFlags::FLAGS_NONE
).expect("Failed to build Application"), ).expect("Failed to build Application"),
pawns: Vec::new(), state: Default::default(),
}; };
app.inner.connect_startup(|_| {}); app.connect_all();
app.inner.connect_activate(Self::on_activate);
Ok(app) Ok(app)
} }
fn on_activate(app: &gtk::Application) { fn connect_all(&self) {
println!("Activate App"); let app_state = self.state.clone();
let main_src = include_str!("../res/main.glade"); self.inner.connect_startup(|_| {});
let builder = gtk::Builder::new_from_string(main_src); self.inner.connect_activate(
let win: gtk::ApplicationWindow = move |app| {
builder println!("Activate App");
.get_object("app") let main_src = include_str!("../res/main.glade");
.unwrap(); let builder = gtk::Builder::new_from_string(main_src);
win.set_application(app); let win: gtk::ApplicationWindow =
builder
.get_object("app")
.unwrap();
win.set_application(app);
// Set up a simple switch for the Pawn list panel // Set up a simple switch for the Pawn list panel
let panel: gtk::Paned = builder.get_object("panel").unwrap(); let panel: gtk::Paned = builder.get_object("panel").unwrap();
Self::new_action(app, "panel_switch", move |_,_| { Self::new_action(app, "panel_switch", move |_,_| {
if panel.get_position() == 0 { if panel.get_position() == 0 {
panel.set_position(360); panel.set_position(360);
} else { } else {
panel.set_position(0); panel.set_position(0);
}
});
// Initialize grid
let grid: gtk::Grid = builder.get_object("map").unwrap();
// TODO: implement drag-drop events
// * From pawn_list to cell : place pawn on dest cell
// * From cell to cell : move pawn from source to dest cell
let _grid = grid::Grid::init(grid, 10, app_state.clone());
// TODO:
// * Display creature description when hovering over its position (cell)
// TODO: Pawn list
let pawn_list = builder.get_object("pawn_list").unwrap();
let pawn_list = pawn::PawnList::init(pawn_list);
for pawn in pawn::pawn_factory() {
pawn_list.add(&pawn);
pawn.connect_place(app_state.clone());
pawn.connect_stats();
app_state.borrow_mut().pawns.push(pawn);
}
win.show_all();
} }
}); );
// Initialize grid
let grid: gtk::Grid = builder.get_object("map").unwrap();
// TODO: implement drag-drop events
// * From pawn_list to cell : place pawn on dest cell
// * From cell to cell : move pawn from source to dest cell
let _grid = grid::Grid::init(grid, 10);
// TODO:
// * Display creature description when hovering over its position (cell)
// TODO: Pawn list
let pawn_list = builder.get_object("pawn_list").unwrap();
let pawn_list = pawn::PawnList::init(pawn_list);
for pawn in &pawn::pawn_factory() {
pawn_list.add(pawn);
}
win.show_all();
} }
/// Creates a simple action and connects the given handler to its activate signal. /// Creates a simple action and connects the given handler to its activate signal.
pub fn new_action<F: Fn(&gio::SimpleAction, &Option<glib::Variant>) + 'static>( fn new_action<F: Fn(&gio::SimpleAction, &Option<glib::Variant>) + 'static>(
app: &gtk::Application, app: &gtk::Application,
name: &str, name: &str,
f: F, f: F,
@@ -173,6 +116,7 @@ impl App {
} }
fn run(&self, args: &[String]) -> i32 { fn run(&self, args: &[String]) -> i32 {
println!("{:#?}", &self.state);
self.inner.run(args) self.inner.run(args)
} }
} }

99
src/pawn.rs Normal file
View File

@@ -0,0 +1,99 @@
use super::*;
#[derive(Debug,Clone)]
pub struct PawnList {
inner: gtk::ListBox,
}
impl PawnList {
pub fn init(inner: gtk::ListBox) -> Self {
PawnList{ inner }
}
pub fn add(&self, pawn: &Pawn) {
let row = gtk::ListBoxRow::new();
row.add(pawn.as_ref());
self.inner.add(&row);
}
}
#[derive(Debug,Clone)]
pub struct PawnData {
pub name: String,
pub position: Option<String>, // Content of label from CellWidget
}
#[derive(Debug, Clone)]
pub struct Pawn {
data: PawnData,
widget: gtk::Box,
place_btn: gtk::Button,
stats_btn: gtk::Button,
}
impl Pawn {
pub fn new<S: Into<String>>(name: S) -> Self {
let pawn_src = include_str!("../res/pawn.glade");
let builder = gtk::Builder::new_from_string(pawn_src);
let name = name.into();
let label: gtk::Label =
builder
.get_object("name")
.unwrap();
label.set_text(&name);
let widget: gtk::Box = builder.get_object("pawn").unwrap();
Pawn {
data: PawnData{ name, position: None, },
widget,
place_btn: builder.get_object("place_btn").unwrap(),
stats_btn: builder.get_object("stats_btn").unwrap(),
}
}
pub fn connect_place(&self, state: AppState) {
let name = self.data.name.clone();
let data = self.data.clone();
self.place_btn
.connect_clicked(
move |_| {
println!("Placing {}...", name);
let mut state = state.0.borrow_mut();
state.pending = Some(data.clone()); // ???
}
);
}
pub fn connect_stats(&self) {
self.stats_btn
.connect_clicked(
move |_| {
println!("Showing stats...");
}
);
}
}
impl AsRef<gtk::Box> for Pawn {
fn as_ref(&self) -> &gtk::Box {
&self.widget
}
}
pub fn pawn_factory() -> Vec<Pawn> {
let mut pawns = Vec::with_capacity(3);
for name in &["Lomion", "Oilosse", "Fefi"] {
pawns.push(Pawn::new(*name));
}
pawns
}
#[cfg(test)]
mod tests {
#[test]
fn test_pawn_factory() {
let pawns = pawn_factory();
assert_eq!(pawns.len(), 3);
assert_eq!(pawns.get(2).unwrap(), "Fefi");
}
}