explicit window finalization etc

gui-branch
an 2019-03-27 05:32:25 -04:00
parent 46ad94bdf0
commit 2cd5be77d3
5 changed files with 238 additions and 156 deletions

View File

@ -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();

View File

@ -178,7 +178,7 @@ fn read_poly_inter(b: &[u8]) -> ResultS<Polygon>
}
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,

View File

@ -948,124 +948,7 @@ Author: Alison Sanderson
</object>
</child>
</object>
<object class="GtkImage" id="img-lines">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">24</property>
<property name="icon_name">tycho-lines</property>
</object>
<object class="GtkImage" id="img-points">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">24</property>
<property name="icon_name">tycho-points</property>
</object>
<object class="GtkImage" id="img-polys">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">24</property>
<property name="icon_name">tycho-polys</property>
</object>
<object class="GtkWindow" id="win-map-tools">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Tool Palette</property>
<property name="default_height">250</property>
<property name="skip_taskbar_hint">True</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkToolPalette">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToolItemGroup">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Geometry</property>
<child>
<object class="GtkToolButton" id="btn-point">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Points</property>
<property name="use_underline">True</property>
<property name="icon_widget">img-points</property>
<child internal-child="accessible">
<object class="AtkObject" id="btn-point-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">Points Tool</property>
<property name="AtkObject::accessible-description" translatable="yes">The tool that modifies points in the map.</property>
<property name="AtkObject::accessible-role" translatable="yes">push-button</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="btn-lines">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Lines</property>
<property name="use_underline">True</property>
<property name="icon_widget">img-lines</property>
<child internal-child="accessible">
<object class="AtkObject" id="btn-lines-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">Lines Tool</property>
<property name="AtkObject::accessible-description" translatable="yes">The tool which modifies line segments on the map.</property>
<property name="AtkObject::accessible-role" translatable="yes">push-button</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="btn-polys">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Polygons</property>
<property name="use_underline">True</property>
<property name="icon_widget">img-polys</property>
<child internal-child="accessible">
<object class="AtkObject" id="btn-polys-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">Polygon Tool</property>
<property name="AtkObject::accessible-description" translatable="yes">The tool which modifies polygon shapes on the map.</property>
<property name="AtkObject::accessible-role" translatable="yes">push-button</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="position">2</property>
</packing>
</child>
<child internal-child="accessible">
<object class="AtkObject">
<property name="AtkObject::accessible-name" translatable="yes">Geometry Collection</property>
<property name="AtkObject::accessible-description" translatable="yes">All of the tools which modify map geometry.</property>
<property name="AtkObject::accessible-role" translatable="yes">column-header</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
</packing>
</child>
</object>
</child>
<child internal-child="accessible">
<object class="AtkObject" id="win-map-tools-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">Tycho Tool Palette</property>
<property name="AtkObject::accessible-description" translatable="yes">Tycho's tool palette window.</property>
<property name="AtkObject::accessible-role" translatable="yes">window</property>
</object>
</child>
</object>
<object class="GtkAboutDialog" id="win-about">
<object class="GtkAboutDialog" id="dlg-about">
<property name="can_focus">False</property>
<property name="modal">True</property>
<property name="type_hint">dialog</property>
@ -1226,13 +1109,130 @@ express Statement of Purpose.
</object>
</child>
<child internal-child="accessible">
<object class="AtkObject" id="win-about-atkobject">
<object class="AtkObject" id="dlg-about-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">About Screen</property>
<property name="AtkObject::accessible-description" translatable="yes">The about screen for Tycho.</property>
<property name="AtkObject::accessible-role" translatable="yes">dialog</property>
</object>
</child>
</object>
<object class="GtkImage" id="img-lines">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">24</property>
<property name="icon_name">tycho-lines</property>
</object>
<object class="GtkImage" id="img-points">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">24</property>
<property name="icon_name">tycho-points</property>
</object>
<object class="GtkImage" id="img-polys">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">24</property>
<property name="icon_name">tycho-polys</property>
</object>
<object class="GtkWindow" id="win-map-tools">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Tool Palette</property>
<property name="default_height">250</property>
<property name="skip_taskbar_hint">True</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkToolPalette">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToolItemGroup">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Geometry</property>
<child>
<object class="GtkToolButton" id="btn-point">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Points</property>
<property name="use_underline">True</property>
<property name="icon_widget">img-points</property>
<child internal-child="accessible">
<object class="AtkObject" id="btn-point-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">Points Tool</property>
<property name="AtkObject::accessible-description" translatable="yes">The tool that modifies points in the map.</property>
<property name="AtkObject::accessible-role" translatable="yes">push-button</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="btn-lines">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Lines</property>
<property name="use_underline">True</property>
<property name="icon_widget">img-lines</property>
<child internal-child="accessible">
<object class="AtkObject" id="btn-lines-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">Lines Tool</property>
<property name="AtkObject::accessible-description" translatable="yes">The tool which modifies line segments on the map.</property>
<property name="AtkObject::accessible-role" translatable="yes">push-button</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="btn-polys">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Polygons</property>
<property name="use_underline">True</property>
<property name="icon_widget">img-polys</property>
<child internal-child="accessible">
<object class="AtkObject" id="btn-polys-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">Polygon Tool</property>
<property name="AtkObject::accessible-description" translatable="yes">The tool which modifies polygon shapes on the map.</property>
<property name="AtkObject::accessible-role" translatable="yes">push-button</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="position">2</property>
</packing>
</child>
<child internal-child="accessible">
<object class="AtkObject">
<property name="AtkObject::accessible-name" translatable="yes">Geometry Collection</property>
<property name="AtkObject::accessible-description" translatable="yes">All of the tools which modify map geometry.</property>
<property name="AtkObject::accessible-role" translatable="yes">column-header</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
</packing>
</child>
</object>
</child>
<child internal-child="accessible">
<object class="AtkObject" id="win-map-tools-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">Tycho Tool Palette</property>
<property name="AtkObject::accessible-description" translatable="yes">Tycho's tool palette window.</property>
<property name="AtkObject::accessible-role" translatable="yes">window</property>
</object>
</child>
</object>
<object class="GtkWindow" id="win-main">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Tycho</property>

View File

@ -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<MapEditorStateBlock>,
tool: Tool,
}
/// A tool in the map editor.
pub enum Tool
{
Points,
Lines,
Polygons,
}
// EOF

View File

@ -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<Option<MapEditorState>>)
{
struct RenderState
{
im_nomap: *mut GdkPixbuf,
ax: *mut GtkAdjustment,
ay: *mut GtkAdjustment,
edit: Rc<Option<MapEditorState>>,
}
/// 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::<gpointer>());
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::<gpointer>());
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