| 1 |
use failure::Error;
|
| 2 |
use image;
|
| 3 |
use serde_json;
|
| 4 |
use std::io::{Read, Write, Seek};
|
| 5 |
use zip::{ZipArchive, ZipWriter};
|
| 6 |
|
1 | 7 |
pub struct State {
|
2 | |
pub document: Option<Document>,
|
| 8 |
pub document: Document,
|
| 9 |
pub save_state: SaveState,
|
| 10 |
}
|
| 11 |
|
| 12 |
#[derive(Debug)]
|
| 13 |
pub enum SaveState {
|
| 14 |
Unsaved,
|
| 15 |
Modified,
|
| 16 |
Saved,
|
3 | 17 |
}
|
4 | 18 |
|
5 | 19 |
pub struct Document {
|
| 20 |
pub tilesheet: image::DynamicImage,
|
| 21 |
pub metadata: Metadata,
|
| 22 |
pub rules: (),
|
6 | 23 |
}
|
| 24 |
|
| 25 |
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
| 26 |
pub struct Metadata {
|
| 27 |
pub tile_width: u16,
|
| 28 |
pub tile_height: u16,
|
| 29 |
pub config_loop_forever: bool,
|
| 30 |
}
|
| 31 |
|
| 32 |
impl Document {
|
| 33 |
pub fn open_from_file<R: Read + Seek>(r: &mut R) -> Result<Document, Error> {
|
| 34 |
let mut archive = ZipArchive::new(r)?;
|
| 35 |
let tilesheet = {
|
| 36 |
let mut buf = Vec::new();
|
| 37 |
archive.by_name("tilesheet.png")?.read_to_end(&mut buf)?;
|
| 38 |
image::load_from_memory(&buf)?
|
| 39 |
};
|
| 40 |
let metadata = {
|
| 41 |
let file = archive.by_name("metadata.json")?;
|
| 42 |
serde_json::from_reader(file)?
|
| 43 |
};
|
| 44 |
let rules = {
|
| 45 |
let file = archive.by_name("rules.json")?;
|
| 46 |
serde_json::from_reader(file)?
|
| 47 |
};
|
| 48 |
Ok(Document{ tilesheet, metadata, rules })
|
| 49 |
}
|
| 50 |
|
| 51 |
pub fn save_to_file<W: Write + Seek>(&self, w: &mut W) -> Result<(), Error> {
|
| 52 |
use zip::write::FileOptions;
|
| 53 |
|
| 54 |
let mut zip = ZipWriter::new(w);
|
| 55 |
zip.start_file("tilesheet.png", FileOptions::default())?;
|
| 56 |
self.tilesheet.write_to(&mut zip, image::ImageOutputFormat::PNG)?;
|
| 57 |
|
| 58 |
zip.start_file("metadata.json", FileOptions::default())?;
|
| 59 |
serde_json::to_writer(&mut zip, &self.metadata)?;
|
| 60 |
|
| 61 |
zip.start_file("rules.json", FileOptions::default())?;
|
| 62 |
serde_json::to_writer(&mut zip, &self.rules)?;
|
| 63 |
|
| 64 |
zip.start_file("info.txt", FileOptions::default())?;
|
| 65 |
writeln!(
|
| 66 |
&mut zip,
|
| 67 |
"Created by {} v{}",
|
| 68 |
::constants::PROGRAM_NAME,
|
| 69 |
::constants::PROGRAM_VERSION,
|
| 70 |
)?;
|
| 71 |
|
| 72 |
zip.finish()?;
|
| 73 |
Ok(())
|
| 74 |
}
|
| 75 |
|
| 76 |
pub fn dummy() -> Document {
|
| 77 |
Document {
|
| 78 |
tilesheet: image::DynamicImage::new_rgb8(32, 32),
|
| 79 |
metadata: Metadata {
|
| 80 |
tile_width: 16,
|
| 81 |
tile_height: 16,
|
| 82 |
config_loop_forever: false,
|
| 83 |
},
|
| 84 |
rules: (),
|
| 85 |
}
|
| 86 |
}
|
| 87 |
}
|
| 88 |
|
| 89 |
#[cfg(test)]
|
| 90 |
mod tests {
|
| 91 |
use super::Document;
|
| 92 |
use std::io::{BufReader, Cursor};
|
| 93 |
|
| 94 |
#[test]
|
| 95 |
fn round_trip() {
|
| 96 |
let mut buf = Cursor::new(Vec::new());
|
| 97 |
let doc1 = Document::dummy();
|
| 98 |
doc1.save_to_file(&mut buf).unwrap();
|
| 99 |
let buf = buf.into_inner();
|
| 100 |
let doc2 = Document::open_from_file(&mut BufReader::new(Cursor::new(buf))).unwrap();
|
| 101 |
assert!(doc1.metadata == doc2.metadata);
|
| 102 |
}
|
| 103 |
}
|