Browse Source

Refactor a bit

Getty Ritter 3 years ago
parent
commit
d681f03d39
3 changed files with 233 additions and 189 deletions
  1. 51 0
      src/app.rs
  2. 4 189
      src/main.rs
  3. 178 0
      src/view.rs

+ 51 - 0
src/app.rs

@@ -0,0 +1,51 @@
+use crate::dmc;
+use anyhow::{anyhow, bail, Result};
+
+pub struct Data {
+    pub symbol: char,
+    pub dmc: Option<dmc::DMC>,
+}
+
+impl Data {
+    pub 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(())
+    }
+
+    pub 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))
+    }
+}

+ 4 - 189
src/main.rs

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

+ 178 - 0
src/view.rs

@@ -0,0 +1,178 @@
+use gtk::prelude::WidgetExtManual;
+use gtk::{
+    BoxExt, ButtonExt, ContainerExt, DialogExt, EditableSignals, EntryExt, FileChooserExt,
+    GtkWindowExt, LabelExt, WidgetExt,
+};
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::rc::Rc;
+
+use crate::{app, dmc};
+
+const SYMBOLS: &[char] = &['A', 'B', 'C', 'D'];
+
+#[derive(Clone)]
+struct App {
+    data: Rc<RefCell<app::Data>>,
+}
+
+impl App {
+    fn new() -> App {
+        let app_data = app::Data {
+            symbol: 'X',
+            dmc: None,
+        };
+        let data = Rc::new(RefCell::new(app_data));
+        App { data }
+    }
+}
+
+#[derive(Clone)]
+pub struct View {
+    app: App,
+    window: gtk::Window,
+    icon_buttons: HashMap<char, gtk::Button>,
+    color_input: gtk::Entry,
+    color_name: gtk::Label,
+    submit: gtk::Button,
+    canvas: gtk::DrawingArea,
+}
+
+impl View {
+    pub fn create() -> View {
+        let window = gtk::Window::new(gtk::WindowType::Toplevel);
+        let app = App::new();
+        // left pane: the icon choices
+        let left_pane = gtk::Box::new(gtk::Orientation::Vertical, 4);
+        // HKHK
+        let mut icon_buttons = HashMap::new();
+        for ch in SYMBOLS {
+            let button = gtk::Button::with_label(&ch.to_string());
+            left_pane.pack_start(&button, false, true, 0);
+            icon_buttons.insert(*ch, button);
+        }
+
+        // center pane
+        let center_pane = gtk::Box::new(gtk::Orientation::Vertical, 2);
+        let color_input = gtk::Entry::new();
+        let color_name = gtk::Label::new(None);
+        let submit = gtk::Button::with_label("EXPORT IT");
+        center_pane.pack_start(&color_input, false, true, 0);
+        center_pane.pack_start(&color_name, false, true, 0);
+        center_pane.pack_start(&submit, false, true, 0);
+
+        let canvas = gtk::DrawingArea::new();
+
+        // the overall container
+        let flow = gtk::Box::new(gtk::Orientation::Horizontal, 2);
+        flow.pack_start(&left_pane, false, true, 0);
+        flow.pack_start(&center_pane, false, true, 0);
+        flow.pack_start(&canvas, true, true, 0);
+
+        window.add(&flow);
+
+        View {
+            app,
+            window,
+            icon_buttons,
+            color_input,
+            color_name,
+            submit,
+            canvas,
+        }
+    }
+
+    pub fn setup(&self) -> &Self {
+        // setup window properties and callbacks
+        self.window.connect_delete_event(move |_, _| {
+            gtk::main_quit();
+            gtk::Inhibit(false)
+        });
+        self.window.set_title("I Am Legend");
+        self.window.set_default_size(500, 200);
+        self.window.set_resizable(false);
+
+        // setup all the icon button callbacks
+        for (ch, button) in self.icon_buttons.iter() {
+            self.clone().icon_button_clicked(*ch, button);
+        }
+
+        self.clone().color_entry_changed(&self.color_input);
+        self.clone().submit_clicked(&self.submit);
+        self.clone().canvas_draw(&self.canvas);
+
+        self
+    }
+
+    pub fn icon_button_clicked(self, ch: char, button: &gtk::Button) {
+        button.connect_clicked(move |_| {
+            self.app.data.borrow_mut().symbol = ch;
+            self.window.queue_draw_area(0, 0, 500, 200);
+        });
+    }
+
+    pub fn color_entry_changed(self, entry: &gtk::Entry) {
+        entry.connect_changed(move |s| {
+            let str = s.get_text();
+            if let Some(color) = dmc::LOOKUP.get(str.as_str()) {
+                self.app.data.borrow_mut().dmc = Some(*color.clone());
+                self.color_name.set_text(color.name);
+                self.submit.set_sensitive(true);
+            } else {
+                self.app.data.borrow_mut().dmc = None;
+                self.color_name.set_text("");
+                self.submit.set_sensitive(false);
+            }
+            self.window.queue_draw_area(0, 0, 500, 200);
+        });
+    }
+
+    pub fn submit_clicked(self, button: &gtk::Button) {
+        button.connect_clicked(move |_| {
+            let dialog = gtk::FileChooserDialog::with_buttons(
+                Some("Select filename"),
+                Some(&self.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");
+                    }
+                    if let Err(err) = self.app.data.borrow_mut().draw_to_file(tgt) {
+                        eprintln!("Error in rendering: {}", err);
+                    }
+                }
+            }
+            unsafe {
+                dialog.destroy();
+            }
+        });
+    }
+
+    pub fn canvas_draw(self, canvas: &gtk::DrawingArea) {
+        canvas.connect_draw(move |cv, ctx| {
+            println!("drawing");
+            let w = cv.get_allocated_width();
+            let h = cv.get_allocated_height();
+            if let Err(err) = self.app.data.borrow_mut().render(ctx, w as f64, h as f64) {
+                eprintln!("Error in rendering: {}", err);
+            }
+            gtk::Inhibit(false)
+        });
+    }
+
+    pub fn show(&self) {
+        self.window.show_all();
+    }
+}