diff --git a/source/leela/main.rs b/source/leela/main.rs index 142e12c..0c326cf 100644 --- a/source/leela/main.rs +++ b/source/leela/main.rs @@ -134,7 +134,7 @@ fn main() -> ResultS<()> use argparse::*; use memmap::Mmap; - let mut opt: Options = Default::default(); + let mut opt = Options::default(); { let mut ap = ArgumentParser::new(); diff --git a/source/marathon/map.rs b/source/marathon/map.rs index 2da456c..461d2af 100644 --- a/source/marathon/map.rs +++ b/source/marathon/map.rs @@ -178,7 +178,7 @@ fn read_poly_inter(b: &[u8]) -> ResultS } Ok(Polygon{tex_flr, tex_cei, hei_flr, hei_cei, lit_flr, lit_cei, xfr_flr, - xfr_cei, ..Default::default()}) + xfr_cei, ..Polygon::default()}) } /// Reads a `POLY` chunk. @@ -707,7 +707,7 @@ pub struct Note /// Static map information. #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct Minf { pub texture_id: u16, diff --git a/source/tycho/data/ui.xml b/source/tycho/data/ui.xml index 8650e5d..be86b96 100644 --- a/source/tycho/data/ui.xml +++ b/source/tycho/data/ui.xml @@ -948,124 +948,7 @@ Author: Alison Sanderson - - True - False - 24 - tycho-lines - - - True - False - 24 - tycho-points - - - True - False - 24 - tycho-polys - - - False - Tool Palette - 250 - True - - - - - - True - False - vertical - - - True - False - Geometry - - - True - False - Points - True - img-points - - - Points Tool - The tool that modifies points in the map. - push-button - - - - - True - - - - - True - False - Lines - True - img-lines - - - Lines Tool - The tool which modifies line segments on the map. - push-button - - - - - True - 1 - - - - - True - False - Polygons - True - img-polys - - - Polygon Tool - The tool which modifies polygon shapes on the map. - push-button - - - - - True - 2 - - - - - Geometry Collection - All of the tools which modify map geometry. - column-header - - - - - True - - - - - - - Tycho Tool Palette - Tycho's tool palette window. - window - - - - + False True dialog @@ -1226,13 +1109,130 @@ express Statement of Purpose. - + About Screen The about screen for Tycho. dialog + + True + False + 24 + tycho-lines + + + True + False + 24 + tycho-points + + + True + False + 24 + tycho-polys + + + False + Tool Palette + 250 + True + + + + + + True + False + vertical + + + True + False + Geometry + + + True + False + Points + True + img-points + + + Points Tool + The tool that modifies points in the map. + push-button + + + + + True + + + + + True + False + Lines + True + img-lines + + + Lines Tool + The tool which modifies line segments on the map. + push-button + + + + + True + 1 + + + + + True + False + Polygons + True + img-polys + + + Polygon Tool + The tool which modifies polygon shapes on the map. + push-button + + + + + True + 2 + + + + + Geometry Collection + All of the tools which modify map geometry. + column-header + + + + + True + + + + + + + Tycho Tool Palette + Tycho's tool palette window. + window + + + False Tycho diff --git a/source/tycho/editor.rs b/source/tycho/editor.rs index d84f40b..b12db60 100644 --- a/source/tycho/editor.rs +++ b/source/tycho/editor.rs @@ -13,11 +13,7 @@ impl MapEditorState /// Creates a new empty map. pub fn new() -> MapEditorState { - let info = Default::default(); - - let ed = MapEditorState{info}; - - ed + MapEditorState::default() } /// Draws the "no map" screen. @@ -35,17 +31,40 @@ impl MapEditorState d.rect(Rect{x: 0, y: d.h() - 18, w: d.w(), h: 18}, CR_DARK_RED); d.text((4, d.h() - 4), "CAS.qterm//CyberAcme Systems Inc.", CR_RED); } + + /// Draws the currently open map. + pub fn draw_some(&self, d: &impl DrawArea) + { + d.clear(Color16::new(0, 0, 0)); + } } -impl Drop for MapEditorState +impl Default for Tool { - fn drop(&mut self) {eprintln!("dropping MapEditorState");} + fn default() -> Tool {Tool::Points} } -/// The state of a single opened map. -pub struct MapEditorState +/// Copyable map state. +#[derive(Clone, Default)] +pub struct MapEditorStateBlock { info: map::Minf, } +/// The state of a map editor. +#[derive(Default)] +pub struct MapEditorState +{ + edit_stack: Vec, + tool: Tool, +} + +/// A tool in the map editor. +pub enum Tool +{ + Points, + Lines, + Polygons, +} + // EOF diff --git a/source/tycho/main.rs b/source/tycho/main.rs index f058550..a0ebaf1 100644 --- a/source/tycho/main.rs +++ b/source/tycho/main.rs @@ -24,7 +24,7 @@ unsafe extern "C" fn app_activate(app: *mut GtkApplication, edit: gpointer) let path = c_str!("/net/greyserv/maraiah/tycho/ui"); let b = gtk_builder_new_from_resource(path); - setup_draw_area(b); + setup_draw_area(b, edit.clone()); setup_win_map_view(b); setup_win_map_tools(b); setup_win_map_prop(b); @@ -35,15 +35,17 @@ unsafe extern "C" fn app_activate(app: *mut GtkApplication, edit: gpointer) } /// Sets up the map view window's drawing area. -unsafe fn setup_draw_area(b: *mut GtkBuilder) +unsafe fn setup_draw_area(b: *mut GtkBuilder, edit: Rc>) { struct RenderState { im_nomap: *mut GdkPixbuf, ax: *mut GtkAdjustment, ay: *mut GtkAdjustment, + edit: Rc>, } + /// Callback to finalize the drawing area. unsafe extern "C" fn c_done(_: *mut GtkWidget, rend: gpointer) { let rend = Box::from_raw(rend as *mut RenderState); @@ -55,6 +57,7 @@ unsafe fn setup_draw_area(b: *mut GtkBuilder) // data is dropped and freed here } + /// Callback to draw on the drawing area. unsafe extern "C" fn c_draw(wid: *mut GtkWidget, ctx: *mut cairo_sys::cairo_t, rend: gpointer) @@ -75,7 +78,10 @@ unsafe fn setup_draw_area(b: *mut GtkBuilder) let im = CrImage(rend.im_nomap); let dr = CrDrawArea::new(ctx, w, h); - MapEditorState::draw_none(&dr, &im); + match &*rend.edit { + Some(edit) => edit.draw_some(&dr), + None => MapEditorState::draw_none(&dr, &im), + } 1 } @@ -90,7 +96,7 @@ unsafe fn setup_draw_area(b: *mut GtkBuilder) let im_nomap = load_img(c_str!("/net/greyserv/maraiah/tycho/tycho1.png")); - let rend = RenderState{im_nomap, ax, ay}; + let rend = RenderState{im_nomap, ax, ay, edit}; let rend = Box::into_raw(Box::new(rend)); connect(wid as _, c_str!("destroy"), c_done as _, rend as _); @@ -156,6 +162,58 @@ unsafe fn setup_about_dlg(b: *mut GtkBuilder) g_object_unref(img as _); } +/// Sets up explicit window finalization for the main window. +unsafe fn setup_explicit_drop(b: *mut GtkBuilder, win: *mut GtkWindow) +{ + /// Callback to explicitly finalize all windows on exit. + unsafe extern "C" fn c_done(_: *mut GtkWidget, exp_del: gpointer) + { + let exp_del = Box::from_raw(exp_del as *mut Vec<*mut GtkWindow>); + + for win in *exp_del { + gtk_widget_destroy(win as _); + } + } + + // we need to explicitly drop other windows on exit, which means we need to + // create a list of them to send to the callback + let mut exp_del = Vec::new(); + + // so, we get all of the objects from the builder, and iterate through them + let head = gtk_builder_get_objects(b); + let mut lst = &*head; + + loop { + let obj = lst.data as *mut GObject; + + // while this is well-defined, it is a weird way of doing it, because + // this exact method of checking types isn't fully documented. we can't + // use the macros for this functionality because we're not using C, so we + // use the underlying function calls. again, get jacked, punk. + if g_type_check_instance_is_a(obj as _, gtk_window_get_type()) != 0 { + let owin = obj as *mut GtkWindow; + + if owin != win { + exp_del.push(owin); + } + } + + let nx = lst.next; + + if nx != ffi::null_mut() { + lst = &*nx; + } else { + break; + } + } + + g_slist_free(head); + + let exp_del = Box::into_raw(Box::new(exp_del)); + + connect(win as _, c_str!("destroy"), c_done as _, exp_del as _); +} + /// Sets up the main menu window. unsafe fn setup_win_main(b: *mut GtkBuilder, app: *mut GtkApplication, @@ -167,14 +225,6 @@ unsafe fn setup_win_main(b: *mut GtkBuilder, gtk_window_close(win as _); } - let win: *mut GtkWindow = get_obj(b, c_str!("win-main")); - let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-quit")); - - gtk_window_set_application(win, app); - gtk_widget_show_all(win as _); - - connect(btn as _, c_str!("activate"), c_quit_act as _, win as _); - /// Callback to create a new editor state when the "New" button is pressed. unsafe extern "C" fn c_new_act(_: *mut GtkWidget, edit: gpointer) { @@ -187,7 +237,7 @@ unsafe fn setup_win_main(b: *mut GtkBuilder, Data may be lost."); match run_ok_cancel_dlg(titl, text) { - true => {}, + true => {} false => return, } } @@ -201,12 +251,25 @@ unsafe fn setup_win_main(b: *mut GtkBuilder, Rc::from_raw(edit); } - let edit = Rc::into_raw(edit); + // set up main window + let win: *mut GtkWindow = get_obj(b, c_str!("win-main")); + + setup_explicit_drop(b, win); + + gtk_window_set_application(win, app); + gtk_widget_show_all(win as _); + + // set up buttons + let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-quit")); + + connect(btn as _, c_str!("activate"), c_quit_act as _, win as _); let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-new")); - connect(btn as _, c_str!("activate"), c_new_act as _, edit as _); - connect(btn as _, c_str!("destroy"), c_new_done as _, edit as _); + let eptr = Rc::into_raw(edit.clone()); + + connect(btn as _, c_str!("activate"), c_new_act as _, eptr as _); + connect(btn as _, c_str!("destroy"), c_new_done as _, eptr as _); } /// Sets up the CSS styling providers. @@ -227,14 +290,14 @@ unsafe fn setup_css() unsafe fn run_ok_cancel_dlg(title: ffi::NT, text: ffi::NT) -> bool { let flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT; - let dlg = gtk_dialog_new_with_buttons(title, - ffi::null_mut(), - flags, - c_str!("_OK"), - GTK_RESPONSE_ACCEPT, - c_str!("_Cancel"), - GTK_RESPONSE_REJECT, - ffi::null_mut::()); + let dlg = gtk_dialog_new_with_buttons(title, + ffi::null_mut(), + flags, + c_str!("_OK"), + GTK_RESPONSE_ACCEPT, + c_str!("_Cancel"), + GTK_RESPONSE_REJECT, + ffi::null_mut::()); let area = gtk_dialog_get_content_area(dlg as _); let labl = gtk_label_new(text); @@ -331,7 +394,7 @@ fn main() // ok, clean up all this crap now g_object_unref(app as _); - assert!(Rc::strong_count(&edit) == 1); + assert_eq!(Rc::strong_count(&edit), 1); drop(edit); // deinit the "static" data, and everything will be done