gui-branch
an 2019-05-13 22:03:09 -04:00
parent 36307aca0a
commit 56df373dc1
7 changed files with 504 additions and 800 deletions

View File

@ -1,129 +1,7 @@
//! Main map editor module.
//!
//! The entry point is responsible for maintaining the lifetime of the editor
//! and human interactions with it, but is otherwise not permitted to directly
//! edit it.
//! Map editor handling.
mod block;
pub use block::*;
use super::{color, draw::*};
use crate::{durandal::image::*, marathon::{machdr, map}};
impl MapEditor
{
/// Opens the editor with a new map.
pub fn open_new(&mut self)
{
*self = Self::default();
}
/// Opens the editor with an existing map.
pub fn open_buf(&mut self, b: &[u8])
{
// TODO: handle errors gracefully
let b = &b[machdr::try_mac_header(b)..];
let wad = map::read(b).expect("bad map file");
let ent = wad.entries.iter().nth(0).expect("no entries").1;
let info = ent.chunks.iter().find_map(|cnk| {
match cnk {
map::chnk::Chunk::Minf(info) => Some(info),
_ => None,
}
}).expect("no Minf chunk").clone();
let block = Block{info};
dbg!(&block);
*self = Self{blocks: vec![block],
tools: Self::default_tools()};
}
/// Draws the screen for this editor state.
pub fn draw<D, I>(&self, d: &mut D, im: &I)
where D: DrawArea<NativeImage = I>,
I: CacheImage
{
/*
let dw = d.w();
let dh = d.h();
let iw = im.w();
let ih = im.h();
let tx_top = "Map Required To Proceed";
let tx_bot = "CAS.qterm//CyberAcme Systems Inc.";
d.clear(Color16::new(0, 0, 0));
d.image((dw / 2 - iw / 2, dh / 2 - ih / 2), im);
d.rect(Rect{x: 0, y: 0, w: dw, h: 18}, color::DARK_RED);
d.text((4, 0), tx_top, color::RED);
d.rect(Rect{x: 0, y: dh - 18, w: dw, h: 18}, color::DARK_RED);
d.text((4, dh - 16), tx_bot, color::RED);
*/
let _ = im;
let text = &format!("{:#?}", &self);
d.clear(Color16::new(0, 0, 0));
d.text((0, 0), text, color::RED);
}
// Returns the default tools.
const fn default_tools() -> (Tool, Tool) {(Tool::Points, Tool::Lines)}
/// Returns a reference to the current block.
pub fn cur_block(&self) -> &Block {self.blocks.last().unwrap()}
/// Pushes a new block.
pub fn push_block(&mut self, blk: Block) {self.blocks.push(blk);}
/// Returns the current tool.
pub fn tool(&self) -> &Tool {&self.tools.0}
/// Sets the current tool, and returns the previous one.
pub fn set_tool(&mut self, t: Tool) -> &Tool
{
self.tools.1 = self.tools.0.clone();
self.tools.0 = t;
&self.tools.1
}
/// Returns true if the current map is unclean and needs to be saved.
pub fn unclean(&self) -> bool {true}
}
impl Default for MapEditor
{
#[inline]
fn default() -> Self
{
Self{blocks: vec![Block::default()], tools: Self::default_tools()}
}
}
/// The state of an opened map editor.
#[derive(Debug)]
pub struct MapEditor
{
blocks: Vec<Block>,
tools: (Tool, Tool),
}
/// A tool in the map editor.
#[derive(Clone, Debug)]
pub enum Tool
{
Points,
Lines,
Polygons,
}
pub mod record;
pub mod screen;
pub mod session;
// EOF

View File

@ -1,6 +1,8 @@
//! Map editor records, or saved client state.
use crate::marathon::map;
impl Default for Block
impl Default for Record
{
#[inline]
fn default() -> Self {Self{info: map::minf::Minf::default()}}
@ -8,7 +10,7 @@ impl Default for Block
/// Copyable, versioned map state.
#[derive(Clone, Debug)]
pub struct Block
pub struct Record
{
pub info: map::minf::Minf,
}

View File

@ -0,0 +1,12 @@
//! Map editor screen, or current UI state.
pub trait Screen
{
/// Opens the editor with a new map.
fn open_new(&mut self);
/// Opens the editor with a new map.
fn open_buf(&mut self, b: &[u8]);
}
// EOF

View File

@ -0,0 +1,20 @@
//! Map editor session, or current client state.
impl Session
{
/// Opens the editor with a new map.
fn open_new(&mut self)
{
}
/// Opens the editor with a new map.
fn open_buf(&mut self, b: &[u8])
{
}
}
struct Session
{
}
// EOF

View File

@ -12,32 +12,333 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkWindow" id="win-map-view">
<object class="GtkAdjustment" id="adj-phys-id">
<property name="upper">65535</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAboutDialog" id="dlg-about">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Map View</property>
<property name="default_width">600</property>
<property name="default_height">400</property>
<child type="titlebar">
<property name="modal">True</property>
<property name="type_hint">dialog</property>
<property name="program_name">Tycho Map Editor</property>
<property name="copyright" translatable="yes">By Alison Sanderson. Public domain.</property>
<property name="comments" translatable="yes">greetigs i am tico the of superior ai to durdumbal go shoot my soldiers because its funny or ill put you in space</property>
<property name="website_label" translatable="yes">Home Page</property>
<property name="license" translatable="yes">To the extent possible under law, I, Alison Sanderson, have waived all
copyright and related or neighboring rights to this Document as described by
the Creative Commons Zero license as follows:
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
</property>
<property name="logo_icon_name">image-loading</property>
<property name="license_type">custom</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
<child internal-child="accessible">
<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-main">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Tycho</property>
<property name="resizable">False</property>
<property name="default_width">120</property>
<property name="default_height">250</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkScrolledWindow">
<object class="GtkMenuBar">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">always</property>
<property name="vscrollbar_policy">always</property>
<property name="window_placement">top-right</property>
<property name="overlay_scrolling">False</property>
<property name="can_focus">False</property>
<property name="pack_direction">ttb</property>
<child>
<object class="GtkViewport">
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hadjustment">adj-map-horz</property>
<property name="vadjustment">adj-map-vert</property>
<child>
<object class="GtkDrawingArea" id="draw-area">
<property name="label" translatable="yes">_File</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="btn-new">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Create a new project.</property>
<property name="label" translatable="yes">_New Project</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="btn-open">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Opens any type of project file.</property>
<property name="label" translatable="yes">_Open</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="btn-save">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Saves the currently open project.</property>
<property name="label" translatable="yes">_Save</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="btn-quit">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Quit the application.</property>
<property name="label" translatable="yes">_Quit</property>
<property name="use_underline">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_View</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="btn-show-map-view">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Opens the map view window.</property>
<property name="label" translatable="yes">Show _Map View</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="btn-show-map-tools">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Opens the map toolbox window.</property>
<property name="label" translatable="yes">Show Map _Tools</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="btn-show-map-prop">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Show Map _Properties</property>
<property name="use_underline">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="right_justified">True</property>
<property name="label" translatable="yes">_Info</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="btn-about">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Opens a window with information about this program.</property>
<property name="label" translatable="yes">_About</property>
<property name="use_underline">True</property>
</object>
</child>
</object>
</child>
</object>
@ -45,15 +346,12 @@
</object>
</child>
</object>
<object class="GtkAdjustment" id="adj-phys-id">
<property name="upper">65535</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkWindow" id="win-map-prop">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Map Properties</property>
<property name="transient_for">win-main</property>
<property name="attached_to">win-main</property>
<child>
<placeholder/>
</child>
@ -898,200 +1196,56 @@
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkAboutDialog" id="dlg-about">
<property name="can_focus">False</property>
<property name="modal">True</property>
<property name="type_hint">dialog</property>
<property name="program_name">Tycho Map Editor</property>
<property name="copyright" translatable="yes">By Alison Sanderson. Public domain.</property>
<property name="comments" translatable="yes">greetigs i am tico the of superior ai to durdumbal go shoot my soldiers because its funny or ill put you in space</property>
<property name="website_label" translatable="yes">Home Page</property>
<property name="license" translatable="yes">To the extent possible under law, I, Alison Sanderson, have waived all
copyright and related or neighboring rights to this Document as described by
the Creative Commons Zero license as follows:
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
</property>
<property name="logo_icon_name">image-loading</property>
<property name="license_type">custom</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<child>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">_Save</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">_Close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
<child internal-child="accessible">
<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>
<property name="transient_for">win-main</property>
<property name="attached_to">win-main</property>
<child>
<placeholder/>
</child>
@ -1186,142 +1340,34 @@ express Statement of Purpose.
</object>
</child>
</object>
<object class="GtkWindow" id="win-main">
<object class="GtkWindow" id="win-map-view">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Tycho</property>
<property name="resizable">False</property>
<property name="default_width">120</property>
<property name="default_height">250</property>
<child>
<property name="title" translatable="yes">Map View</property>
<property name="default_width">600</property>
<property name="default_height">400</property>
<property name="transient_for">win-main</property>
<property name="attached_to">win-main</property>
<child type="titlebar">
<placeholder/>
</child>
<child>
<object class="GtkMenuBar">
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pack_direction">ttb</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">always</property>
<property name="vscrollbar_policy">always</property>
<property name="window_placement">top-right</property>
<property name="overlay_scrolling">False</property>
<child>
<object class="GtkMenuItem">
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_File</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="hadjustment">adj-map-horz</property>
<property name="vadjustment">adj-map-vert</property>
<child>
<object class="GtkDrawingArea" id="draw-area">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="btn-new">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Create a new project.</property>
<property name="label" translatable="yes">_New Project</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="btn-open">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Opens any type of project file.</property>
<property name="label" translatable="yes">_Open</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="btn-save">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Saves the currently open project.</property>
<property name="label" translatable="yes">_Save</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="btn-quit">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Quit the application.</property>
<property name="label" translatable="yes">_Quit</property>
<property name="use_underline">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_View</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="btn-show-map-view">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Opens the map view window.</property>
<property name="label" translatable="yes">Show _Map View</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="btn-show-map-tools">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Opens the map toolbox window.</property>
<property name="label" translatable="yes">Show Map _Tools</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="btn-show-map-prop">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Show Map _Properties</property>
<property name="use_underline">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="right_justified">True</property>
<property name="label" translatable="yes">_Info</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="btn-about">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Opens a window with information about this program.</property>
<property name="label" translatable="yes">_About</property>
<property name="use_underline">True</property>
</object>
</child>
</object>
</child>
</object>

View File

@ -3,151 +3,47 @@
use super::glib::*;
use gobject_sys::*;
use gtk_sys::*;
use maraiah::{durandal::ffi, marathon::map, rozinante::editor};
use maraiah::{durandal::ffi, marathon::map};
use std::cell::RefCell;
// 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)
impl EditorModel
{
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)
pub fn new(view: EditorView) -> Self
{
self.cause_refresh_view();
self.cause_refresh_props();
Self{view}
}
/// Propagates updated map view information to widgets.
pub fn cause_refresh_view(&self)
pub fn open_new(&mut self)
{
unsafe {
gtk_widget_queue_draw(*self.draw);
}
eprintln!("open_new");
}
/// Propagates updated map property information to widgets.
pub fn cause_refresh_props(&self)
pub fn open_buf(&mut self, b: &[u8])
{
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();
eprintln!("open_buf");
}
}
impl std::ops::Deref for MapEditor
pub struct EditorPresenter
{
type Target = editor::MapEditor;
#[inline]
fn deref(&self) -> &Self::Target {&self.edit}
}
impl std::ops::DerefMut for MapEditor
pub struct EditorView
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {&mut self.edit}
pub prop: PropertiesWindow,
}
/// Specialized map editor which has callbacks for frontend purposes.
pub struct MapEditor
pub struct PropertiesWindow
{
pub edit: editor::MapEditor,
pub draw: Refc<'static, GtkWidget>,
pub fent: Vec<PropFlag>,
pub fenv: Vec<PropFlag>,
pub fmsn: Vec<PropFlag>,
pub flg_ent: Vec<Refc<'static, GtkToggleButton>>,
pub flg_env: Vec<Refc<'static, GtkToggleButton>>,
pub flg_msn: Vec<Refc<'static, GtkToggleButton>>,
}
/// A runtime reference to the map editor.
pub type MapEditorRef = std::cell::RefCell<MapEditor>;
pub struct PropFlag
pub struct EditorModel
{
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,
];
pub type EditorRef = std::cell::RefCell<EditorModel>;
// EOF

View File

@ -7,66 +7,38 @@ use gio_sys::*;
use glib_sys::*;
use gobject_sys::*;
use gtk_sys::*;
use maraiah::{c_str, durandal::ffi};
use maraiah::{c_str,
durandal::{err::*, ffi}};
use std::{cell::RefCell, rc::Rc};
const APP_ID: ffi::NT = c_str!("net.greyserv.maraiah.tycho");
const B_ADJ_M_HORZ: ffi::NT = c_str!("adj-map-horz");
const B_ADJ_M_VERT: ffi::NT = c_str!("adj-map-vert");
const B_BTN_ABOUT: ffi::NT = c_str!("btn-about");
const B_BTN_M_PROP: ffi::NT = c_str!("btn-show-map-prop");
const B_BTN_M_TOOL: ffi::NT = c_str!("btn-show-map-tools");
const B_BTN_M_VIEW: ffi::NT = c_str!("btn-show-map-view");
const B_BTN_NEW: ffi::NT = c_str!("btn-new");
const B_BTN_OPEN: ffi::NT = c_str!("btn-open");
const B_BTN_QUIT: ffi::NT = c_str!("btn-quit");
const B_CON_F_ENT: ffi::NT = c_str!("con-f-ent");
const B_CON_F_ENV: ffi::NT = c_str!("con-f-env");
const B_CON_F_MSN: ffi::NT = c_str!("con-f-msn");
const B_DLG_ABOUT: ffi::NT = c_str!("dlg-about");
const B_DRAW_AREA: ffi::NT = c_str!("draw-area");
const B_WIN_MAIN: ffi::NT = c_str!("win-main");
const B_WIN_M_PROP: ffi::NT = c_str!("win-map-prop");
const B_WIN_M_TOOL: ffi::NT = c_str!("win-map-tools");
const B_WIN_M_VIEW: ffi::NT = c_str!("win-map-view");
const E_ACTIVATE: ffi::NT = c_str!("activate");
const E_DELETE: ffi::NT = c_str!("delete-event");
const E_DESTROY: ffi::NT = c_str!("destroy");
const E_DRAW: ffi::NT = c_str!("draw");
const E_SHUTDOWN: ffi::NT = c_str!("shutdown");
const E_TOGGLE: ffi::NT = c_str!("toggled");
const IM_ABOUT: ffi::NT = c_str!("/net/greyserv/maraiah/tycho/tycho2.png");
const IM_NOMAP: ffi::NT = c_str!("/net/greyserv/maraiah/tycho/tycho1.png");
const PATH_BUILDER: ffi::NT = c_str!("/net/greyserv/maraiah/tycho/ui");
const PATH_CSS: ffi::NT = c_str!("/net/greyserv/maraiah/tycho/css");
// Called when the application activates in order to set everything up.
unsafe extern "C" fn app_activate(app: *mut GtkApplication, _: gpointer)
{
// Callback to finalize the reference.
unsafe extern "C" fn c_done(_: *mut GApplication, ptr: gpointer)
{
let edit = Rc::from_raw(ptr as *const MapEditorRef);
let edit = Rc::from_raw(ptr as *const EditorRef);
assert_eq!(Rc::strong_count(&edit), 1);
}
let b = Refc::new(gtk_builder_new_from_resource(PATH_BUILDER));
let edit = MapEditor{edit: Default::default(),
draw: Refc::own(get_obj(&b, B_DRAW_AREA)),
fent: get_flag_fields(&b, B_CON_F_ENT),
fenv: get_flag_fields(&b, B_CON_F_ENV),
fmsn: get_flag_fields(&b, B_CON_F_MSN)};
let prop = PropertiesWindow{flg_ent: get_flag_fields(&b, B_CON_F_ENT),
flg_env: get_flag_fields(&b, B_CON_F_ENV),
flg_msn: get_flag_fields(&b, B_CON_F_MSN)};
let edit = EditorModel::new(EditorView{prop});
let edit = RefCell::new(edit);
let edit = Rc::new(edit);
setup_css();
setup_toggles(edit.clone());
setup_draw_area(&b, edit.clone());
setup_win_map_view(&b);
setup_win_map_tools(&b);
setup_win_map_prop(&b);
//setup_draw_area(&b, edit.clone());
let wv = setup_win(&b, B_WIN_M_VIEW, B_BTN_M_VIEW);
let wt = setup_win(&b, B_WIN_M_TOOL, B_BTN_M_TOOL);
let _ = setup_win(&b, B_WIN_M_PROP, B_BTN_M_PROP);
gtk_widget_show_all(wv);
gtk_widget_show_all(wt);
setup_about_dlg(&b);
setup_win_main(&b, app, edit.clone());
@ -74,7 +46,8 @@ unsafe extern "C" fn app_activate(app: *mut GtkApplication, _: gpointer)
}
// Gets all of the toggle buttons from a container.
unsafe fn get_flag_fields(b: &Refc<GtkBuilder>, name: ffi::NT) -> Vec<PropFlag>
unsafe fn get_flag_fields(b: &Refc<GtkBuilder>, name: ffi::NT)
-> Vec<Refc<'static, GtkToggleButton>>
{
let mut flags = Vec::new();
@ -82,127 +55,28 @@ unsafe fn get_flag_fields(b: &Refc<GtkBuilder>, name: ffi::NT) -> Vec<PropFlag>
let head = ListD::new(gtk_container_get_children(head));
let gtyp = gtk_toggle_button_get_type();
get_typed_from(head, gtyp, |obj| {
flags.push(PropFlag{w: Refc::own(obj as _), h: 0});
});
get_typed_from(head, gtyp, |obj| flags.push(Refc::own(obj as _)));
flags
}
// Connects toggle events to every flag in the map properties window.
unsafe fn setup_toggles(edit: Rc<MapEditorRef>)
{
let mut ed = edit.borrow_mut();
connect_toggle(edit.clone(), ed.fent.iter_mut());
connect_toggle(edit.clone(), ed.fenv.iter_mut());
connect_toggle(edit.clone(), ed.fmsn.iter_mut());
}
// Connects toggle events to each of the widgets in `it`.
unsafe fn connect_toggle<'a, I>(edit: Rc<MapEditorRef>, it: I)
where I: Iterator<Item = &'a mut PropFlag>
{
// Callback for when the button is toggled, which causates an update.
unsafe extern "C" fn c_toggled(_: *mut GtkToggleButton, edit: gpointer)
{
let edit = &*(edit as *const MapEditorRef);
edit.borrow_mut().cause_update_props();
}
// go over each widget, set its object and callback handle
for flg in it {
let erf = connect_ref(*flg.w, edit.clone());
flg.h = connect(*flg.w, E_TOGGLE, c_toggled as _, erf);
}
}
// Sets up the map view window's drawing area.
unsafe fn setup_draw_area(b: &Refc<GtkBuilder>, edit: Rc<MapEditorRef>)
{
// All of the state necessary for the drawing area.
struct RenderState
{
im_nomap: Refc<'static, GdkPixbuf>,
ax: Refc<'static, GtkAdjustment>,
ay: Refc<'static, GtkAdjustment>,
edit: Rc<MapEditorRef>,
}
// Callback to finalize the drawing area.
unsafe extern "C" fn c_done(_: *mut GtkWidget, rend: gpointer)
{
Box::from_raw(rend as *mut RenderState);
}
// Callback to draw on the drawing area.
unsafe extern "C" fn c_draw(wid: *mut GtkWidget,
ctx: *mut cairo_sys::cairo_t,
rend: gpointer)
-> gboolean
{
let rend = &mut *(rend as *mut RenderState);
let w = f64::from(gtk_widget_get_allocated_width(wid));
let h = f64::from(gtk_widget_get_allocated_height(wid));
gtk_adjustment_set_lower(*rend.ax, 0.0);
gtk_adjustment_set_upper(*rend.ax, w);
gtk_adjustment_set_lower(*rend.ay, 0.0);
gtk_adjustment_set_upper(*rend.ay, h);
let im = CrImage(*rend.im_nomap);
let mut dr = CrDrawArea::new(ctx, w, h);
rend.edit.borrow().draw(&mut dr, &im);
1
}
let wid = get_obj::<GtkDrawingArea>(b, B_DRAW_AREA);
// get all of the necessary state and related objects
let ax = Refc::own(get_obj(b, B_ADJ_M_HORZ));
let ay = Refc::own(get_obj(b, B_ADJ_M_VERT));
let im_nomap = Refc::new(load_img(IM_NOMAP));
let rend = RenderState{im_nomap, ax, ay, edit};
let rend = Box::into_raw(Box::new(rend));
connect(wid, E_DESTROY, c_done as _, rend);
connect(wid, E_DRAW, c_draw as _, rend);
}
// Sets up the map view window.
unsafe fn setup_win_map_view(b: &Refc<GtkBuilder>)
unsafe fn setup_win(b: &Refc<GtkBuilder>, win: ffi::NT, btn: ffi::NT)
-> *mut GtkWidget
{
let win = get_obj::<GtkWindow >(b, B_WIN_M_VIEW);
let btn = get_obj::<GtkMenuItem>(b, B_BTN_M_VIEW);
// Callback to show the widget.
unsafe extern "C" fn c_show_act(_: *mut GtkWidget, wid: gpointer)
{
gtk_widget_show_all(wid as _);
}
let win = get_obj::<GtkWindow >(b, win);
let btn = get_obj::<GtkMenuItem>(b, btn);
connect_hide(win);
connect_show(btn, win);
}
connect(btn, E_ACTIVATE, c_show_act as _, win);
// Sets up the map tools window.
unsafe fn setup_win_map_tools(b: &Refc<GtkBuilder>)
{
let win = get_obj::<GtkWindow >(b, B_WIN_M_TOOL);
let btn = get_obj::<GtkMenuItem>(b, B_BTN_M_TOOL);
connect_hide(win);
connect_show(btn, win);
}
// Sets up the map properties window.
unsafe fn setup_win_map_prop(b: &Refc<GtkBuilder>)
{
let win = get_obj::<GtkWindow >(b, B_WIN_M_PROP);
let btn = get_obj::<GtkMenuItem>(b, B_BTN_M_PROP);
connect_hide(win);
connect_show(btn, win);
win as *mut GtkWidget
}
// Sets up the about dialogue.
@ -284,7 +158,7 @@ unsafe fn get_typed_from<I, F>(it: I, ty: GType, mut f: F)
// Sets up the main menu window.
unsafe fn setup_win_main(b: &Refc<GtkBuilder>,
app: *mut GtkApplication,
edit: Rc<MapEditorRef>)
edit: Rc<EditorRef>)
{
// Callback to close the window when the "Quit" button is pressed.
unsafe extern "C" fn c_quit_act(_: *mut GtkWidget, win: gpointer)
@ -295,45 +169,30 @@ unsafe fn setup_win_main(b: &Refc<GtkBuilder>,
// Callback to create a new map when the "New" button is pressed.
unsafe extern "C" fn c_new_act(_: *mut GtkWidget, edit: gpointer)
{
let edit = &*(edit as *const MapEditorRef);
let mut edit = edit.borrow_mut();
let edit = &*(edit as *const EditorRef);
if edit.unclean() {
let titl = c_str!("Confirm");
let text = c_str!("Are you sure you want to create a new project? \
Unsaved data may be lost.");
edit.borrow_mut().open_new();
}
if !run_ok_cancel_dlg(titl, text) {
return;
}
}
// Opens the map editor with a buffer.
unsafe fn open_buf(path: &str, edit: &mut EditorModel) -> ResultS<()>
{
let fp = std::fs::File::open(&path)?;
let mm = memmap::Mmap::map(&fp)?;
edit.open_new();
edit.cause_refresh();
edit.open_buf(&mm);
Ok(())
}
// Callback to open an existing map when the "Open" button is pressed.
unsafe extern "C" fn c_open_act(_: *mut GtkWidget, edit: gpointer)
{
let edit = &*(edit as *const MapEditorRef);
let mut edit = edit.borrow_mut();
if edit.unclean() {
let titl = c_str!("Confirm");
let text = c_str!("Are you sure you want to open this project? \
Unsaved data may be lost.");
if !run_ok_cancel_dlg(titl, text) {
return;
}
}
let edit = &*(edit as *const EditorRef);
if let Some(path) = run_file_chooser_open() {
// TODO: handle errors gracefully
let fp = std::fs::File::open(&path).unwrap();
let mm = memmap::Mmap::map(&fp).unwrap();
edit.open_buf(&mm);
edit.cause_refresh();
open_buf(&path, &mut edit.borrow_mut()).unwrap();
}
}
@ -367,32 +226,6 @@ unsafe fn setup_css()
gtk_style_context_add_provider_for_screen(scr, *css as _, pri);
}
// Runs a modal OK/Cancel dialogue.
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_void());
let area = gtk_dialog_get_content_area(dlg as _);
let labl = gtk_label_new(text);
gtk_container_add(area as _, labl);
gtk_widget_show_all(area as _);
let res = gtk_dialog_run(dlg as _);
gtk_widget_destroy(dlg);
res == GTK_RESPONSE_ACCEPT
}
// Runs a modal Open File dialogue.
unsafe fn run_file_chooser_open() -> Option<String>
{
@ -440,26 +273,13 @@ unsafe fn connect_hide<T>(wid: *mut T)
connect(wid, E_DELETE, c_hide_del as _, ffi::null_void());
}
// Connects a handler that shows a widget when activated.
unsafe fn connect_show<T, U>(btn: *mut T, wid: *mut U)
{
// Callback to show the widget.
unsafe extern "C" fn c_show_act(_: *mut GtkWidget, wid: gpointer)
{
gtk_widget_show_all(wid as _);
}
connect(btn, E_ACTIVATE, c_show_act as _, wid);
}
// Connects the map editor reference to a widget.
unsafe fn connect_ref<T>(obj: *mut T, rc: Rc<MapEditorRef>)
-> *const MapEditorRef
unsafe fn connect_ref<T>(obj: *mut T, rc: Rc<EditorRef>) -> *const EditorRef
{
// Callback to finalize the reference.
unsafe extern "C" fn c_done(_: *mut GtkWidget, ptr: gpointer)
{
Rc::from_raw(ptr as *const MapEditorRef);
Rc::from_raw(ptr as *const EditorRef);
}
let ptr = Rc::into_raw(rc);
@ -521,4 +341,34 @@ fn main()
}
}
const APP_ID: ffi::NT = c_str!("net.greyserv.maraiah.tycho");
const B_ADJ_M_HORZ: ffi::NT = c_str!("adj-map-horz");
const B_ADJ_M_VERT: ffi::NT = c_str!("adj-map-vert");
const B_BTN_ABOUT: ffi::NT = c_str!("btn-about");
const B_BTN_M_PROP: ffi::NT = c_str!("btn-show-map-prop");
const B_BTN_M_TOOL: ffi::NT = c_str!("btn-show-map-tools");
const B_BTN_M_VIEW: ffi::NT = c_str!("btn-show-map-view");
const B_BTN_NEW: ffi::NT = c_str!("btn-new");
const B_BTN_OPEN: ffi::NT = c_str!("btn-open");
const B_BTN_QUIT: ffi::NT = c_str!("btn-quit");
const B_CON_F_ENT: ffi::NT = c_str!("con-f-ent");
const B_CON_F_ENV: ffi::NT = c_str!("con-f-env");
const B_CON_F_MSN: ffi::NT = c_str!("con-f-msn");
const B_DLG_ABOUT: ffi::NT = c_str!("dlg-about");
const B_DRAW_AREA: ffi::NT = c_str!("draw-area");
const B_WIN_MAIN: ffi::NT = c_str!("win-main");
const B_WIN_M_PROP: ffi::NT = c_str!("win-map-prop");
const B_WIN_M_TOOL: ffi::NT = c_str!("win-map-tools");
const B_WIN_M_VIEW: ffi::NT = c_str!("win-map-view");
const E_ACTIVATE: ffi::NT = c_str!("activate");
const E_DELETE: ffi::NT = c_str!("delete-event");
const E_DESTROY: ffi::NT = c_str!("destroy");
const E_DRAW: ffi::NT = c_str!("draw");
const E_SHUTDOWN: ffi::NT = c_str!("shutdown");
const E_TOGGLE: ffi::NT = c_str!("toggled");
const IM_ABOUT: ffi::NT = c_str!("/net/greyserv/maraiah/tycho/tycho2.png");
const IM_NOMAP: ffi::NT = c_str!("/net/greyserv/maraiah/tycho/tycho1.png");
const PATH_BUILDER: ffi::NT = c_str!("/net/greyserv/maraiah/tycho/ui");
const PATH_CSS: ffi::NT = c_str!("/net/greyserv/maraiah/tycho/css");
// EOF