123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- 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 {
- /// Setup and run the program
- pub fn run() {
- View::create().setup().show()
- }
- /// Create and arrange the widgets that will be used for drawing
- /// the UI
- 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(¢er_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,
- }
- }
- /// Bind callbacks and set up default configuration values for the
- /// provided widgets
- 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
- }
- /// Setup the callback for an icon-chooser button
- fn icon_button_clicked(self, ch: char, button: >k::Button) {
- button.connect_clicked(move |_| {
- self.app.data.borrow_mut().symbol = ch;
- self.window.queue_draw_area(0, 0, 500, 200);
- });
- }
- /// Setup the callback that fires when the text changes for the
- /// DMC thread input box
- fn color_entry_changed(self, entry: >k::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);
- });
- }
- /// Setup the callback that fires when the 'EXPORT IT' button is
- /// clicked
- fn submit_clicked(self, button: >k::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();
- }
- });
- }
- /// Setup the callback that handles drawing the canvas
- fn canvas_draw(self, canvas: >k::DrawingArea) {
- canvas.connect_draw(move |cv, ctx| {
- 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)
- });
- }
- /// Show the whole thing
- fn show(&self) {
- self.window.show_all();
- }
- }
|