|  | @@ -1,198 +1,13 @@
 | 
	
		
			
				|  |  | -use anyhow::{anyhow, bail, Result};
 | 
	
		
			
				|  |  | -use gtk::prelude::WidgetExtManual;
 | 
	
		
			
				|  |  | -use gtk::{
 | 
	
		
			
				|  |  | -    BoxExt, ButtonExt, ContainerExt, DialogExt, EditableSignals, EntryExt, FileChooserExt,
 | 
	
		
			
				|  |  | -    GtkWindowExt, LabelExt, WidgetExt,
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -use std::cell::RefCell;
 | 
	
		
			
				|  |  | -use std::rc::Rc;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +mod app;
 | 
	
		
			
				|  |  |  mod dmc;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -struct AppData {
 | 
	
		
			
				|  |  | -    symbol: char,
 | 
	
		
			
				|  |  | -    dmc: Option<dmc::DMC>,
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -impl AppData {
 | 
	
		
			
				|  |  | -    fn draw_to_file<P: AsRef<std::path::Path>>(&self, path: P) -> Result<()> {
 | 
	
		
			
				|  |  | -        let f = std::fs::File::create(path)?;
 | 
	
		
			
				|  |  | -        let surf = cairo::SvgSurface::for_stream(100.0, 100.0, f)?;
 | 
	
		
			
				|  |  | -        self.render(&cairo::Context::new(&surf), 100.0, 100.0)?;
 | 
	
		
			
				|  |  | -        if let Err(err) = surf.finish_output_stream() {
 | 
	
		
			
				|  |  | -            bail!(err.error);
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        Ok(())
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    fn render(&self, ctx: &cairo::Context, w: f64, h: f64) -> Result<()> {
 | 
	
		
			
				|  |  | -        let off_x = (w - 100.) / 2.0;
 | 
	
		
			
				|  |  | -        let off_y = (h - 100.) / 2.0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        let color = self.color();
 | 
	
		
			
				|  |  | -        ctx.set_source_rgb(color.0, color.1, color.2);
 | 
	
		
			
				|  |  | -        ctx.paint();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        ctx.set_source_rgb(0., 0., 0.);
 | 
	
		
			
				|  |  | -        ctx.rectangle(off_x, off_y, 100., 100.);
 | 
	
		
			
				|  |  | -        ctx.stroke();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        ctx.move_to(off_x, off_y - 23.0);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        let layout = pangocairo::functions::create_layout(&ctx)
 | 
	
		
			
				|  |  | -            .ok_or_else(|| anyhow!("Could not create layout"))?;
 | 
	
		
			
				|  |  | -        layout.set_width(100 * 1024);
 | 
	
		
			
				|  |  | -        layout.set_alignment(pango::Alignment::Center);
 | 
	
		
			
				|  |  | -        let font = pango::FontDescription::from_string("Fira Sans 92");
 | 
	
		
			
				|  |  | -        layout.set_font_description(Some(&font));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        layout.set_text(&self.symbol.to_string());
 | 
	
		
			
				|  |  | -        pangocairo::functions::show_layout(&ctx, &layout);
 | 
	
		
			
				|  |  | -        Ok(())
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    fn color(&self) -> (f64, f64, f64) {
 | 
	
		
			
				|  |  | -        self.dmc
 | 
	
		
			
				|  |  | -            .map(|dmc| dmc.color)
 | 
	
		
			
				|  |  | -            .unwrap_or_else(|| (0.5, 0.5, 0.5))
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#[derive(Clone)]
 | 
	
		
			
				|  |  | -struct App {
 | 
	
		
			
				|  |  | -    data: Rc<RefCell<AppData>>,
 | 
	
		
			
				|  |  | -    window: gtk::Window,
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -impl App {
 | 
	
		
			
				|  |  | -    fn new(window: gtk::Window) -> App {
 | 
	
		
			
				|  |  | -        let app_data = AppData {
 | 
	
		
			
				|  |  | -            symbol: 'X',
 | 
	
		
			
				|  |  | -            dmc: None,
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        let data = Rc::new(RefCell::new(app_data));
 | 
	
		
			
				|  |  | -        App { data, window }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -fn mk_app() {
 | 
	
		
			
				|  |  | -    let window = gtk::Window::new(gtk::WindowType::Toplevel);
 | 
	
		
			
				|  |  | -    let app = App::new(window.clone());
 | 
	
		
			
				|  |  | -    window.connect_delete_event(move |_, _| {
 | 
	
		
			
				|  |  | -        gtk::main_quit();
 | 
	
		
			
				|  |  | -        gtk::Inhibit(false)
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    window.set_title("I Am Legend");
 | 
	
		
			
				|  |  | -    window.set_default_size(500, 200);
 | 
	
		
			
				|  |  | -    window.set_resizable(false);
 | 
	
		
			
				|  |  | -    let container = gtk::Box::new(gtk::Orientation::Vertical, 4);
 | 
	
		
			
				|  |  | -    container.pack_start(&mk_icon_choice('A', app.clone()), false, true, 0);
 | 
	
		
			
				|  |  | -    container.pack_start(&mk_icon_choice('B', app.clone()), false, true, 0);
 | 
	
		
			
				|  |  | -    container.pack_start(&mk_icon_choice('C', app.clone()), false, true, 0);
 | 
	
		
			
				|  |  | -    container.pack_start(&mk_icon_choice('D', app.clone()), false, true, 0);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    let flow = gtk::Box::new(gtk::Orientation::Horizontal, 2);
 | 
	
		
			
				|  |  | -    flow.pack_start(&container, false, true, 0);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    let container = gtk::Box::new(gtk::Orientation::Vertical, 2);
 | 
	
		
			
				|  |  | -    let label = gtk::Label::new(None);
 | 
	
		
			
				|  |  | -    let button = gtk::Button::with_label("EXPORT IT");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        let color = gtk::Entry::new();
 | 
	
		
			
				|  |  | -        let app = app.clone();
 | 
	
		
			
				|  |  | -        let window = window.clone();
 | 
	
		
			
				|  |  | -        let label = label.clone();
 | 
	
		
			
				|  |  | -        let button = button.clone();
 | 
	
		
			
				|  |  | -        color.connect_changed(move |s| {
 | 
	
		
			
				|  |  | -            let str = s.get_text();
 | 
	
		
			
				|  |  | -            if let Some(color) = dmc::LOOKUP.get(str.as_str()) {
 | 
	
		
			
				|  |  | -                app.data.borrow_mut().dmc = Some(*color.clone());
 | 
	
		
			
				|  |  | -                label.set_text(color.name);
 | 
	
		
			
				|  |  | -                button.set_sensitive(true);
 | 
	
		
			
				|  |  | -            } else {
 | 
	
		
			
				|  |  | -                app.data.borrow_mut().dmc = None;
 | 
	
		
			
				|  |  | -                label.set_text("");
 | 
	
		
			
				|  |  | -                button.set_sensitive(false);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            window.queue_draw_area(0, 0, 500, 200);
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -        container.pack_start(&color, false, true, 0);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        button.set_sensitive(false);
 | 
	
		
			
				|  |  | -        let app = app.clone();
 | 
	
		
			
				|  |  | -        let window = window.clone();
 | 
	
		
			
				|  |  | -        button.connect_clicked(move |_| {
 | 
	
		
			
				|  |  | -            let dialog = gtk::FileChooserDialog::with_buttons(
 | 
	
		
			
				|  |  | -                Some("Select filename"),
 | 
	
		
			
				|  |  | -                Some(&window),
 | 
	
		
			
				|  |  | -                gtk::FileChooserAction::Save,
 | 
	
		
			
				|  |  | -                &[
 | 
	
		
			
				|  |  | -                    ("_Cancel", gtk::ResponseType::Cancel),
 | 
	
		
			
				|  |  | -                    ("_Open", gtk::ResponseType::Ok),
 | 
	
		
			
				|  |  | -                ],
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | -            let filter = gtk::FileFilter::new();
 | 
	
		
			
				|  |  | -            filter.add_mime_type("image/svg+xml");
 | 
	
		
			
				|  |  | -            filter.add_pattern("*.svg");
 | 
	
		
			
				|  |  | -            filter.set_name(Some("SVG image"));
 | 
	
		
			
				|  |  | -            dialog.add_filter(&filter);
 | 
	
		
			
				|  |  | -            if dialog.run() == gtk::ResponseType::Ok {
 | 
	
		
			
				|  |  | -                if let Some(tgt) = dialog.get_filename() {
 | 
	
		
			
				|  |  | -                    let mut tgt = tgt.to_owned();
 | 
	
		
			
				|  |  | -                    if !tgt.ends_with(".svg") {
 | 
	
		
			
				|  |  | -                        tgt.set_extension("svg");
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    println!("saving to {:?}", tgt);
 | 
	
		
			
				|  |  | -                    if let Err(err) = app.data.borrow_mut().draw_to_file(tgt) {
 | 
	
		
			
				|  |  | -                        eprintln!("Error in rendering: {}", err);
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            unsafe {
 | 
	
		
			
				|  |  | -                dialog.destroy();
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -        container.pack_start(&button, false, true, 0);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    container.pack_start(&label, false, true, 0);
 | 
	
		
			
				|  |  | -    flow.pack_start(&container, false, true, 0);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        let canvas = gtk::DrawingArea::new();
 | 
	
		
			
				|  |  | -        canvas.connect_draw(move |cv, ctx| {
 | 
	
		
			
				|  |  | -            let w = cv.get_allocated_width();
 | 
	
		
			
				|  |  | -            let h = cv.get_allocated_height();
 | 
	
		
			
				|  |  | -            if let Err(err) = app.data.borrow_mut().render(ctx, w as f64, h as f64) {
 | 
	
		
			
				|  |  | -                eprintln!("Error in rendering: {}", err);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            gtk::Inhibit(false)
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -        flow.pack_start(&canvas, true, true, 0);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    window.add(&flow);
 | 
	
		
			
				|  |  | -    window.show_all();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -fn mk_icon_choice(choice: char, cell: App) -> gtk::Button {
 | 
	
		
			
				|  |  | -    let button = gtk::Button::with_label(&choice.to_string());
 | 
	
		
			
				|  |  | -    button.connect_clicked(move |_| {
 | 
	
		
			
				|  |  | -        cell.data.borrow_mut().symbol = choice;
 | 
	
		
			
				|  |  | -        cell.window.queue_draw_area(0, 0, 500, 200);
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -    button
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +mod view;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  fn main() {
 | 
	
		
			
				|  |  |      if gtk::init().is_err() {
 | 
	
		
			
				|  |  |          eprintln!("Failed to initialize GTK application");
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  | -        mk_app();
 | 
	
		
			
				|  |  | +        view::View::create().setup().show();
 | 
	
		
			
				|  |  | +        // view::mk_app();
 | 
	
		
			
				|  |  |          gtk::main();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |