use std::io::Write;
use gtk::prelude::*;
use gtk::DrawingArea;
pub fn main() {
env_logger::Builder::from_env(
env_logger::Env::default().default_filter_or("info"),
)
.format(|buf, record| {
writeln!(
buf,
"{} [{}] {}",
chrono::Local::now().format("%Y-%m-%dT%H:%M:%S"),
record.level(),
record.args()
)
})
.init();
let application =
gtk::Application::new(Some("rusty_train.bin"), Default::default());
application.connect_activate(|app| {
build(app);
});
application.run();
}
pub enum UiEvent {
ButtonPress(navig18xx::ui::ButtonPress),
KeyPress(navig18xx::ui::KeyPress),
PingCurrentState(navig18xx::ui::PingDest),
}
pub fn build(application: >k::Application) {
let games = navig18xx::game::games();
let window = gtk::ApplicationWindow::new(application);
let bar = gtk::HeaderBar::new();
let adj: Option<>k::Adjustment> = None;
let scrolled_win = gtk::ScrolledWindow::new(adj, adj);
let drawing_area = Box::new(DrawingArea::new)();
scrolled_win.set_child(Some(&drawing_area));
let (ping_tx, ping_rx) =
glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let win = window.clone().upcast::<gtk::Window>();
let controller = navig18xx::ui::control::Gtk3Controller::new(
win,
drawing_area.clone(),
ping_tx,
);
let mut ui = navig18xx::ui::UserInterface::new(
games,
controller,
Default::default(),
);
ui.draw();
bar.set_title(Some("Rusty Train"));
bar.set_decoration_layout(Some("menu:close"));
bar.set_show_close_button(true);
window.set_titlebar(Some(&bar));
let (tx, rx) =
glib::MainContext::sync_channel(glib::PRIORITY_DEFAULT, 100);
let surface = ui.canvas.surface();
drawing_area.connect_draw(move |_da, ctx| {
let surf = surface.read().expect("Could not access drawing surface");
ctx.set_source_surface(&surf, 0.0, 0.0).unwrap();
ctx.paint().unwrap();
Inhibit(false)
});
let tx_ = tx.clone();
drawing_area.connect_button_press_event(move |_widget, event| {
tx_.send(UiEvent::ButtonPress(event.into()))
.expect("Could not send ButtonPress event");
Inhibit(false)
});
window.add_events(gdk::EventMask::BUTTON_PRESS_MASK);
scrolled_win.add_events(gdk::EventMask::BUTTON_PRESS_MASK);
drawing_area.add_events(gdk::EventMask::BUTTON_PRESS_MASK);
let tx_ = tx.clone();
window.connect_key_press_event(move |_widget, event| {
tx_.send(UiEvent::KeyPress(event.into()))
.expect("Could not send KeyPress event");
Inhibit(false)
});
window.add_events(gdk::EventMask::KEY_PRESS_MASK);
ping_rx.attach(None, move |dest| {
tx.send(UiEvent::PingCurrentState(dest))
.expect("Could not send Ping event");
glib::source::Continue(true)
});
let mut start_visible = true;
let start_widget = start_message();
window.set_child(Some(&start_widget));
let _window = window.clone();
rx.attach(None, move |event| {
let response = match event {
UiEvent::ButtonPress(event) => ui.handle_button_press(&event),
UiEvent::KeyPress(event) => ui.handle_key_press(&event),
UiEvent::PingCurrentState(dest) => ui.ping(dest),
};
ui.respond(response);
if start_visible && ui.state.as_start().is_none() {
_window.remove(&start_widget);
_window.add(&scrolled_win);
_window.show_all();
start_visible = false;
}
glib::source::Continue(true)
});
window.show_all();
}
fn start_message() -> gtk::Grid {
let grid = gtk::Grid::builder()
.expand(true)
.halign(gtk::Align::Center)
.valign(gtk::Align::Center)
.build();
["Ctrl+N", "Ctrl+O", "Q"]
.iter()
.enumerate()
.for_each(|(ix, text)| {
let label = gtk::Label::builder()
.use_markup(true)
.selectable(false)
.label(&format!("<b>{}:</b> ", text))
.expand(true)
.halign(gtk::Align::End)
.build();
grid.attach(&label, 0, ix as i32, 1, 1);
});
["Start a new game", "Load a saved game", "Quit"]
.iter()
.enumerate()
.for_each(|(ix, text)| {
let label = gtk::Label::builder()
.selectable(false)
.label(text)
.expand(true)
.halign(gtk::Align::Start)
.build();
grid.attach(&label, 1, ix as i32, 1, 1);
});
grid
}