Maraiah/source/tycho/interfaces/editor.rs

154 lines
4.1 KiB
Rust

//! Map editor interface.
use super::glib::*;
use gobject_sys::*;
use gtk_sys::*;
use maraiah::{durandal::ffi, marathon::map, rozinante::editor};
// Iterates over each flag widget with its respective ordered flag object.
fn each_flag<T, F>(buttons: &[PropFlag], ordering: &[T], mut f: F)
where F: FnMut(&PropFlag, &T)
{
for (flg, ord) in buttons.iter().zip(ordering) {
f(flg, ord);
}
}
// Creates a closure which sets if a button is toggled.
fn r_flg<T, F>(mut f: F) -> impl FnMut(&PropFlag, &T)
where F: FnMut(&T) -> bool
{
move |flg, ord| {
unsafe {
// we have to block the signal handler so that it doesn't cause an
// infinite recursion of updating
g_signal_handler_block(*flg.w as _, flg.h);
gtk_toggle_button_set_active(*flg.w, f(ord).into());
g_signal_handler_unblock(*flg.w as _, flg.h);
}
}
}
// Creates a closure which checks if a button is toggled.
fn s_flg<T, F>(mut f: F) -> impl FnMut(&PropFlag, &T)
where F: FnMut(&T, bool)
{
move |flg, ord| f(ord, unsafe {gtk_toggle_button_get_active(*flg.w)} != 0)
}
impl MapEditor
{
/// Propagates all updated map information to widgets.
pub fn cause_refresh(&self)
{
self.cause_refresh_view();
self.cause_refresh_props();
}
/// Propagates updated map view information to widgets.
pub fn cause_refresh_view(&self)
{
unsafe {
gtk_widget_queue_draw(*self.draw);
}
}
/// Propagates updated map property information to widgets.
pub fn cause_refresh_props(&self)
{
let inf = &self.cur_block().info;
each_flag(&self.fent, &O_ENT, r_flg(|&f| inf.entr_flags.contains(f)));
each_flag(&self.fenv, &O_ENV, r_flg(|&f| inf.envi_flags.contains(f)));
each_flag(&self.fmsn, &O_MSN, r_flg(|&f| inf.miss_flags.contains(f)));
}
/// Propagates updated map property information to the editor state.
pub fn cause_update_props(&mut self)
{
let mut blk = self.cur_block().clone();
let inf = &mut blk.info;
each_flag(&self.fent, &O_ENT, s_flg(|&f, s| inf.entr_flags.set(f, s)));
each_flag(&self.fenv, &O_ENV, s_flg(|&f, s| inf.envi_flags.set(f, s)));
each_flag(&self.fmsn, &O_MSN, s_flg(|&f, s| inf.miss_flags.set(f, s)));
self.push_block(blk);
self.cause_refresh_view();
}
}
impl std::ops::Deref for MapEditor
{
type Target = editor::MapEditor;
#[inline]
fn deref(&self) -> &Self::Target {&self.edit}
}
impl std::ops::DerefMut for MapEditor
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {&mut self.edit}
}
/// Specialized map editor which has callbacks for frontend purposes.
pub struct MapEditor
{
pub edit: editor::MapEditor,
pub draw: Refc<'static, GtkWidget>,
pub fent: Vec<PropFlag>,
pub fenv: Vec<PropFlag>,
pub fmsn: Vec<PropFlag>,
}
/// A runtime reference to the map editor.
pub type MapEditorRef = std::cell::RefCell<MapEditor>;
pub struct PropFlag
{
pub w: Refc<'static, GtkToggleButton>,
pub h: ffi::c_ulong,
}
// NOTE: this is flipped because of GTK weirdness. don't touch
const O_ENT: [map::minf::EntFlags; 8] = [
map::minf::EntFlags::CTF,
map::minf::EntFlags::RUGBY,
map::minf::EntFlags::DEFENSE,
map::minf::EntFlags::KOTH,
map::minf::EntFlags::KTMWTB,
map::minf::EntFlags::CARNAGE,
map::minf::EntFlags::CO_OP,
map::minf::EntFlags::SOLO,
];
const O_ENV: [map::minf::EnvFlags; 11] = [
map::minf::EnvFlags::VACUUM,
map::minf::EnvFlags::MAGNETIC,
map::minf::EnvFlags::REBELLION,
map::minf::EnvFlags::LOW_GRAV,
map::minf::EnvFlags::M1_GLUE,
map::minf::EnvFlags::LAVA_FLOOR,
map::minf::EnvFlags::REBELLION2,
map::minf::EnvFlags::MUSIC,
map::minf::EnvFlags::TERM_PAUSE,
map::minf::EnvFlags::M1_MONSTER,
map::minf::EnvFlags::M1_WEPS,
];
const O_MSN: [map::minf::MsnFlags; 8] = [
map::minf::MsnFlags::EXTERMINATION,
map::minf::MsnFlags::EXPLORATION,
map::minf::MsnFlags::RETRIEVAL,
map::minf::MsnFlags::REPAIR,
map::minf::MsnFlags::RESCUE,
map::minf::MsnFlags::M1_EXPLORATION,
map::minf::MsnFlags::M1_RESCUE,
map::minf::MsnFlags::M1_REPAIR,
];
// EOF