view.rs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. use gtk::prelude::WidgetExtManual;
  2. use gtk::{
  3. BoxExt, ButtonExt, ContainerExt, DialogExt, EditableSignals, EntryExt, FileChooserExt,
  4. GtkWindowExt, LabelExt, WidgetExt,
  5. };
  6. use std::cell::RefCell;
  7. use std::collections::HashMap;
  8. use std::rc::Rc;
  9. use crate::{app, dmc};
  10. const SYMBOLS: &[char] = &['A', 'B', 'C', 'D'];
  11. #[derive(Clone)]
  12. struct App {
  13. data: Rc<RefCell<app::Data>>,
  14. }
  15. impl App {
  16. fn new() -> App {
  17. let app_data = app::Data {
  18. symbol: 'X',
  19. dmc: None,
  20. };
  21. let data = Rc::new(RefCell::new(app_data));
  22. App { data }
  23. }
  24. }
  25. #[derive(Clone)]
  26. pub struct View {
  27. app: App,
  28. window: gtk::Window,
  29. icon_buttons: HashMap<char, gtk::Button>,
  30. color_input: gtk::Entry,
  31. color_name: gtk::Label,
  32. submit: gtk::Button,
  33. canvas: gtk::DrawingArea,
  34. }
  35. impl View {
  36. pub fn create() -> View {
  37. let window = gtk::Window::new(gtk::WindowType::Toplevel);
  38. let app = App::new();
  39. // left pane: the icon choices
  40. let left_pane = gtk::Box::new(gtk::Orientation::Vertical, 4);
  41. // HKHK
  42. let mut icon_buttons = HashMap::new();
  43. for ch in SYMBOLS {
  44. let button = gtk::Button::with_label(&ch.to_string());
  45. left_pane.pack_start(&button, false, true, 0);
  46. icon_buttons.insert(*ch, button);
  47. }
  48. // center pane
  49. let center_pane = gtk::Box::new(gtk::Orientation::Vertical, 2);
  50. let color_input = gtk::Entry::new();
  51. let color_name = gtk::Label::new(None);
  52. let submit = gtk::Button::with_label("EXPORT IT");
  53. center_pane.pack_start(&color_input, false, true, 0);
  54. center_pane.pack_start(&color_name, false, true, 0);
  55. center_pane.pack_start(&submit, false, true, 0);
  56. let canvas = gtk::DrawingArea::new();
  57. // the overall container
  58. let flow = gtk::Box::new(gtk::Orientation::Horizontal, 2);
  59. flow.pack_start(&left_pane, false, true, 0);
  60. flow.pack_start(&center_pane, false, true, 0);
  61. flow.pack_start(&canvas, true, true, 0);
  62. window.add(&flow);
  63. View {
  64. app,
  65. window,
  66. icon_buttons,
  67. color_input,
  68. color_name,
  69. submit,
  70. canvas,
  71. }
  72. }
  73. pub fn setup(&self) -> &Self {
  74. // setup window properties and callbacks
  75. self.window.connect_delete_event(move |_, _| {
  76. gtk::main_quit();
  77. gtk::Inhibit(false)
  78. });
  79. self.window.set_title("I Am Legend");
  80. self.window.set_default_size(500, 200);
  81. self.window.set_resizable(false);
  82. // setup all the icon button callbacks
  83. for (ch, button) in self.icon_buttons.iter() {
  84. self.clone().icon_button_clicked(*ch, button);
  85. }
  86. self.clone().color_entry_changed(&self.color_input);
  87. self.clone().submit_clicked(&self.submit);
  88. self.clone().canvas_draw(&self.canvas);
  89. self
  90. }
  91. pub fn icon_button_clicked(self, ch: char, button: &gtk::Button) {
  92. button.connect_clicked(move |_| {
  93. self.app.data.borrow_mut().symbol = ch;
  94. self.window.queue_draw_area(0, 0, 500, 200);
  95. });
  96. }
  97. pub fn color_entry_changed(self, entry: &gtk::Entry) {
  98. entry.connect_changed(move |s| {
  99. let str = s.get_text();
  100. if let Some(color) = dmc::LOOKUP.get(str.as_str()) {
  101. self.app.data.borrow_mut().dmc = Some(*color.clone());
  102. self.color_name.set_text(color.name);
  103. self.submit.set_sensitive(true);
  104. } else {
  105. self.app.data.borrow_mut().dmc = None;
  106. self.color_name.set_text("");
  107. self.submit.set_sensitive(false);
  108. }
  109. self.window.queue_draw_area(0, 0, 500, 200);
  110. });
  111. }
  112. pub fn submit_clicked(self, button: &gtk::Button) {
  113. button.connect_clicked(move |_| {
  114. let dialog = gtk::FileChooserDialog::with_buttons(
  115. Some("Select filename"),
  116. Some(&self.window),
  117. gtk::FileChooserAction::Save,
  118. &[
  119. ("_Cancel", gtk::ResponseType::Cancel),
  120. ("_Open", gtk::ResponseType::Ok),
  121. ],
  122. );
  123. let filter = gtk::FileFilter::new();
  124. filter.add_mime_type("image/svg+xml");
  125. filter.add_pattern("*.svg");
  126. filter.set_name(Some("SVG image"));
  127. dialog.add_filter(&filter);
  128. if dialog.run() == gtk::ResponseType::Ok {
  129. if let Some(tgt) = dialog.get_filename() {
  130. let mut tgt = tgt.to_owned();
  131. if !tgt.ends_with(".svg") {
  132. tgt.set_extension("svg");
  133. }
  134. if let Err(err) = self.app.data.borrow_mut().draw_to_file(tgt) {
  135. eprintln!("Error in rendering: {}", err);
  136. }
  137. }
  138. }
  139. unsafe {
  140. dialog.destroy();
  141. }
  142. });
  143. }
  144. pub fn canvas_draw(self, canvas: &gtk::DrawingArea) {
  145. canvas.connect_draw(move |cv, ctx| {
  146. println!("drawing");
  147. let w = cv.get_allocated_width();
  148. let h = cv.get_allocated_height();
  149. if let Err(err) = self.app.data.borrow_mut().render(ctx, w as f64, h as f64) {
  150. eprintln!("Error in rendering: {}", err);
  151. }
  152. gtk::Inhibit(false)
  153. });
  154. }
  155. pub fn show(&self) {
  156. self.window.show_all();
  157. }
  158. }