first steps

This commit is contained in:
2019-06-03 14:59:52 +02:00
commit ca3696f63f
6 changed files with 443 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
/target
**/*.rs.bk
Cargo.lock
**/*.glade~

14
Cargo.toml Normal file
View File

@@ -0,0 +1,14 @@
[package]
name = "playmat"
version = "0.1.0"
authors = ["Artus <artus@landoftheunicorn.ovh>"]
edition = "2018"
[dependencies]
gio = "*"
gdk = "*"
glib = "*"
[dependencies.gtk]
version = "^0.6.0"
features = ["v3_22"]

77
res/cell.glade Normal file
View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkEventBox" id="cell">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="button-press-event" handler="on_press_button" swapped="no"/>
<signal name="drag-begin" handler="on_drag_begin" swapped="no"/>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">3</property>
<property name="margin_right">3</property>
<property name="margin_bottom">2</property>
<property name="label_xalign">0.94999998807907104</property>
<property name="label_yalign">0.20000000298023224</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkBox" id="box">
<property name="width_request">128</property>
<property name="height_request">128</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="header">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK | GDK_VISIBILITY_NOTIFY_MASK | GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_SUBSTRUCTURE_MASK | GDK_SCROLL_MASK | GDK_TOUCH_MASK | GDK_SMOOTH_SCROLL_MASK | GDK_TOUCHPAD_GESTURE_MASK | GDK_TABLET_PAD_MASK</property>
<property name="label" translatable="yes">Cell</property>
<property name="justify">right</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="content">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Occupancy
Status</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="position">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_x_</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="variant" value="small-caps"/>
<attribute name="stretch" value="semi-expanded"/>
<attribute name="scale" value="1"/>
<attribute name="foreground" value="#88888a8a8585"/>
</attributes>
</object>
</child>
</object>
</child>
</object>
</interface>

123
res/main.glade Normal file
View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkApplicationWindow" id="app">
<property name="can_focus">False</property>
<property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK | GDK_VISIBILITY_NOTIFY_MASK | GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_SUBSTRUCTURE_MASK | GDK_SCROLL_MASK | GDK_TOUCH_MASK | GDK_SMOOTH_SCROLL_MASK | GDK_TOUCHPAD_GESTURE_MASK | GDK_TABLET_PAD_MASK</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Play Mat</property>
<property name="subtitle" translatable="yes">version 0.1</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Créatures</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">app.panel_switch</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPaned" id="panel">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="position">80</property>
<child>
<object class="GtkListBox" id="pawn_list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkListBoxRow">
<property name="width_request">100</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">True</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK | GDK_VISIBILITY_NOTIFY_MASK | GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_SUBSTRUCTURE_MASK | GDK_SCROLL_MASK | GDK_TOUCH_MASK | GDK_SMOOTH_SCROLL_MASK | GDK_TOUCHPAD_GESTURE_MASK | GDK_TABLET_PAD_MASK</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="shadow_type">out</property>
<property name="min_content_width">640</property>
<property name="min_content_height">480</property>
<property name="max_content_width">800</property>
<property name="max_content_height">600</property>
<property name="propagate_natural_width">True</property>
<property name="propagate_natural_height">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK | GDK_VISIBILITY_NOTIFY_MASK | GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_SUBSTRUCTURE_MASK | GDK_SCROLL_MASK | GDK_TOUCH_MASK | GDK_SMOOTH_SCROLL_MASK | GDK_TOUCHPAD_GESTURE_MASK | GDK_TABLET_PAD_MASK</property>
<property name="shadow_type">etched-in</property>
<child>
<object class="GtkGrid" id="map">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK | GDK_VISIBILITY_NOTIFY_MASK | GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_SUBSTRUCTURE_MASK | GDK_SCROLL_MASK | GDK_TOUCH_MASK | GDK_SMOOTH_SCROLL_MASK | GDK_TOUCHPAD_GESTURE_MASK | GDK_TABLET_PAD_MASK</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">True</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

104
src/grid.rs Normal file
View File

@@ -0,0 +1,104 @@
use crate::*;
pub struct Grid {
inner: gtk::Grid,
}
pub struct CellPosition(i32, i32);
impl Grid {
// Initialize a grid, populating its cells
// Only square grid for now
pub fn init(inner: gtk::Grid, size: i32) -> Self {
for i in 0..(size * size) {
let x = i % size;
let y = i / size;
let cell = grid::Cell::new(CellPosition(x,y));
inner.attach(cell.as_ref(), x, y, 1, 1);
// Signals
}
Grid { inner }
}
}
struct CellWidget {
eventbox: gtk::EventBox,
position: gtk::Label,
header : gtk::Label,
}
impl CellWidget {
fn new(pos: CellPosition, header_text: &str) -> Self {
let cell_src = include_str!("../res/cell.glade");
let builder = gtk::Builder::new_from_string(&cell_src);
let eventbox: gtk::EventBox =
builder
.get_object("cell")
.unwrap();
eventbox.set_events(gdk::EventMask::BUTTON_PRESS_MASK);
let header: gtk::Label =
builder
.get_object("header")
.unwrap();
header.set_text(header_text);
let position: gtk::Label =
builder
.get_object("position")
.unwrap();
position.set_text(&format!("{}x{}", pos.0, pos.1));
let header_clone = header.clone();
eventbox.connect_button_press_event(Self::on_click(header_clone));
CellWidget {
eventbox,
position,
header,
}
}
// Handler for button press events
fn on_click(
data: gtk::Label
) -> impl Fn(&gtk::EventBox, &gdk::EventButton) -> gtk::Inhibit
{
move |_,_| {
data.set_text("Clicked.");
gtk::Inhibit(true)
}
}
}
impl AsRef<gtk::EventBox> for CellWidget {
#[inline]
fn as_ref(&self) -> &gtk::EventBox {
&self.eventbox
}
}
pub struct Cell {
inner: CellWidget,
is_active: bool,
is_occupied: bool,
}
impl Cell {
pub fn new(pos: CellPosition) -> Self {
let inner = CellWidget::new(pos, "Empty cell");
Cell {
inner,
is_active: false,
is_occupied: false,
}
}
}
impl AsRef<gtk::EventBox> for Cell {
#[inline]
fn as_ref(&self) -> &gtk::EventBox {
self.inner.as_ref()
}
}

119
src/main.rs Normal file
View File

@@ -0,0 +1,119 @@
extern crate gtk;
extern crate gio;
extern crate gdk;
extern crate glib;
use gtk::BoxExt;
use gtk::prelude::*;
use gio::prelude::*;
use std::env::args;
use std::process;
mod grid;
mod pawn {
pub struct Pawn {
name: String
}
fn pawn_factory() -> Vec<Pawn> {
let mut pawns = Vec::with_capacity(3);
for name in &["Lomion", "Oilosse", "Fefi"] {
pawns.push(Pawn{ name: name.to_string() });
}
pawns
}
#[cfg(test)]
mod tests {
#[test]
fn test_pawn_factory() {}
}
}
struct App {
inner: gtk::Application,
pawns: Vec<pawn::Pawn>,
}
impl App {
fn new<'a>() -> Result<Self, &'a str> {
let app =
App {
inner: gtk::Application::new(
"home.local.PlayMat",
gio::ApplicationFlags::FLAGS_NONE
).expect("Failed to build Application"),
pawns: Vec::new(),
};
app.inner.connect_startup(|_| {});
app.inner.connect_activate(Self::on_activate);
Ok(app)
}
fn on_activate(app: &gtk::Application) {
println!("Activate App");
let main_src = include_str!("../res/main.glade");
let builder = gtk::Builder::new_from_string(main_src);
let win: gtk::ApplicationWindow =
builder
.get_object("app")
.unwrap();
win.set_application(app);
// Set up a simple switch for the Pawn list panel
let panel: gtk::Paned = builder.get_object("panel").unwrap();
Self::new_action(app, "panel_switch", move |_,_| {
if panel.get_position() == 0 {
panel.set_position(360);
} else {
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);
// TODO:
// * Display creature description when hovering over its position (cell)
// TODO: Pawn list
win.show_all();
}
/// 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>(
app: &gtk::Application,
name: &str,
f: F,
) {
let action = gio::SimpleAction::new(name, None);
action.connect_activate(f);
app.add_action(&action);
}
fn run(&self, args: &[String]) -> i32 {
self.inner.run(args)
}
}
fn main() {
if gtk::init().is_err() {
println!("Failed to initialize Gtk");
return
}
let exit_code = match App::new() {
Err(e) => {
println!("Error !\n{}", e);
1
},
Ok(app) => app.run(&args().collect::<Vec<_>>()),
};
process::exit(exit_code);
}