diff --git a/rust-toolchain b/rust-toolchain index 2bf5ad0..bf867e0 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -stable +nightly diff --git a/src/main.rs b/src/main.rs index 0dcb19d..7141284 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,15 @@ //! (c) 2020–2021 Fredrick R. Brennan, Matthew Blanchard & MFEK Authors //! Apache 2.0 licensed. See AUTHORS. #![allow(non_snake_case)] // for our name MFEKglif +#![allow(incomplete_features)] +#![feature( + type_alias_impl_trait, + local_key_cell_methods, + trait_alias, + const_trait_impl, + generic_const_exprs, + adt_const_params +)] use crate::command::{Command, CommandInfo, CommandMod}; use crate::editor::{ @@ -21,6 +30,8 @@ use tool_behaviors::pan::PanBehavior; use user_interface::egui_manager::EguiManager; use user_interface::gui::window::WindowManager; +#[macro_use] +extern crate lazy_static; #[macro_use] extern crate pub_mod; diff --git a/src/tools/guidelines/dialog.rs b/src/tools/guidelines/dialog.rs index 874d065..7ddc566 100644 --- a/src/tools/guidelines/dialog.rs +++ b/src/tools/guidelines/dialog.rs @@ -1,67 +1,227 @@ use super::super::prelude::*; use super::{Guidelines, SplitGuidelines}; use crate::tool_behaviors::add_guideline::AddGuideline; -use crate::user_interface::gui::windows::egui_parsed_textfield; +use crate::user_interface::{self, gui::{build_and_add_icon_button, icons}, InputPrompt}; +use glifparser::IntegerOrFloat; +use std::rc::Rc; + +lazy_static! { + static ref PLUS_GLOBE: String = format!("{}{}", icons::_PLUS, icons::_GLOBE); +} impl Guidelines { pub fn tool_dialog(&mut self, v: &mut Editor, i: &mut Interface, ui: &mut egui::Ui) { let (mut guidelines, _, local_guidelines_len, _) = SplitGuidelines::new(v).as_tuple(); - ui.horizontal(|ui| { - if ui.button("➕").clicked() { - v.push_behavior(Box::new(AddGuideline::new(0., false))); - } - - if ui.button("🌏").clicked() { - v.push_behavior(Box::new(AddGuideline::new(0., true))); - } - - if ui.button("🌐").clicked() { - v.write_metrics(i); - } - - if let Some(selected) = self.selected_idx { - //log::trace!("Selected {}; global len {}", selected, global_guidelines_len); - let selected_i = if guidelines[selected].1 {selected - local_guidelines_len} else {selected}; - //log::trace!("Selected index {}", selected_i); - - if guidelines[selected].1 && guidelines[selected].0.data.as_guideline().format { - ui.label("Format defined."); - } else { - if ui.button("➖").clicked() { - v.begin_modification(&format!("Remove {} guideline.", if guidelines[selected].1 { "global" } else { "local" }), false); - self.selected_idx = None; - if guidelines[selected].1 { - v.guidelines.remove(selected_i); + for (gidx, (guideline, is_global)) in guidelines.iter_mut().enumerate() { + ui.vertical(|ui| { + ui.horizontal(|ui| { + let ( + mut guidelines, + _guidelines_len, + local_guidelines_len, + _global_guidelines_len, + ) = SplitGuidelines::new(v).as_tuple(); + + if build_and_add_icon_button::<"icons_small">(v, ui, icons::_PLUS).clicked() { + v.push_behavior(Box::new(AddGuideline::new(0., false))); + } + + if build_and_add_icon_button::<"icons_small">(v, ui, &*PLUS_GLOBE).clicked() { + v.push_behavior(Box::new(AddGuideline::new(0., true))); + } + + if build_and_add_icon_button::<"icons_small">(v, ui, icons::_GLOBE).clicked() { + v.write_metrics(i); + } + + if let Some(selected) = self.selected_idx { + //log::trace!("Selected {}; global len {}", selected, global_guidelines_len); + let selected_i = if guidelines[selected].1 { + selected - local_guidelines_len } else { - v.with_glyph_mut(|glyph| { - glyph.guidelines.remove(selected_i); + selected + }; + //log::trace!("Selected index {}", selected_i); + + if guidelines[selected].1 + && guidelines[selected].0.data.as_guideline().format + { + ui.label("Format defined."); + } else { + let mb = build_and_add_icon_button::<"icons_small">(v, ui, icons::_MINUS); + if mb.clicked() { + v.begin_modification( + &format!( + "Remove {} guideline.", + if guidelines[selected].1 { + "global" + } else { + "local" + } + ), + false, + ); + self.selected_idx = None; + if guidelines[selected].1 { + v.guidelines.remove(selected_i); + } else { + v.with_glyph_mut(|glyph| { + glyph.guidelines.remove(selected_i); + }); + } + v.end_modification(); + } + } + } + + let is_global = *is_global; + let guideline_name = guideline.name.clone().unwrap_or_else(|| { + if gidx == 0 { + String::from("Unnamed") + } else { + format!("Unnamed {}", gidx + 1) + } + }); + + let guideline_display = guideline_name.clone(); + let mut im_str = guideline_display; + + if !(is_global && guideline.data.as_guideline().format) { + let rb = build_and_add_icon_button::<"icons_small">(v, ui, icons::_RENAME); + if rb.clicked() { + i.push_prompt(InputPrompt::Text { + label: "Guideline name:".to_string(), + default: guideline_name, + func: Rc::new(move |editor, string| { + let gidx = if is_global { + gidx - local_guidelines_len + } else { + gidx + }; + editor.begin_modification("Change guideline name.", false); + if is_global { + editor.guidelines[gidx].name = Some(string.clone()); + } else { + editor.with_glyph_mut(move |glyph| { + glyph.guidelines[gidx].name = Some(string.clone()) + }); + } + editor.end_modification(); + }), }); } - v.end_modification(); } - } - } else { - ui.label("No guideline selected."); - } - }); + + if is_global { + let label = if guideline.data.as_guideline().format { + icons::_UFO + } else { + icons::_GLOBE + }; + build_and_add_icon_button::<"icons_small">(v, ui, label); + } + + let name_b = ui.button(&im_str); + if name_b.clicked() { + self.selected_idx = Some(gidx); + } + }); + }); + } + if let Some(selected) = self.selected_idx { - ui.label("Position"); - ui.vertical(|ui| { - if guidelines[selected].1 { - /*v.begin_modification("Move guideline.", false); - v.with_glyph_mut(|glyph| { - let mut guidelinex = &mut glyph.guidelines[selected].at.x; - *guidelinex = egui_parsed_textfield(ui, "ax", *guidelinex, &mut self.edit_buf); - let mut guideliney = &mut glyph.guidelines[selected].at.y; - *guideliney = egui_parsed_textfield(ui, "ay", *guideliney, &mut self.edit_buf); - }); - v.end_modification();*/ + ui.horizontal(|ui| { + let (guidelines, _guidelines_len, local_guidelines_len, _global_guidelines_len) = + SplitGuidelines::new(v).as_tuple(); + if guidelines.is_empty() { + return; + } + + let (mut at, mut angle) = { + let at = guidelines[selected].0.at; + let angle = guidelines[selected].0.angle.into(); + + (at, angle) + }; + + let (old_at, old_angle) = (at, angle); + if !guidelines[selected].0.data.as_guideline().fixed { + user_interface::gui::windows::egui_parsed_textfield( + ui, + "X", + at.x, + &mut self.edit_buf, + ); + user_interface::gui::windows::egui_parsed_textfield( + ui, + "Y", + at.y, + &mut self.edit_buf, + ); + } else { + ui.label(format!( + "Position of {} is fixed.", + guidelines[selected] + .0 + .name + .as_ref() + .unwrap_or(&format!("Unnamed {}", selected + 1)) + )); + } + if !(guidelines[selected].1 && guidelines[selected].0.data.as_guideline().format) { + user_interface::gui::windows::egui_parsed_textfield( + ui, + "Angle", + angle, + &mut self.edit_buf, + ); } else { - let mut guidelinex = &mut v.guidelines[selected].at.x; - *guidelinex = egui_parsed_textfield(ui, "ax", *guidelinex, &mut self.edit_buf); - let mut guideliney = &mut v.guidelines[selected].at.y; - *guideliney = egui_parsed_textfield(ui, "ay", *guideliney, &mut self.edit_buf); + ui.label(format!( + "Angle of {} is fixed.", + guidelines[selected] + .0 + .name + .as_ref() + .unwrap_or(&format!("Unnamed {}", selected + 1)) + )); + } + + if at != old_at + || (!guidelines[selected].0.data.as_guideline().format && angle != old_angle) + { + let selected_i = if guidelines[selected].1 { + selected - local_guidelines_len + } else { + selected + }; + + v.begin_modification( + &format!( + "Modify {} guideline.", + if guidelines[selected].1 { + "global" + } else { + "local" + } + ), + false, + ); + if guidelines[selected].1 { + v.guidelines[selected_i].at = at; + v.guidelines[selected_i].angle = IntegerOrFloat::Float(angle); + } else { + v.with_glyph_mut(|glyph| { + glyph.guidelines[selected_i].at = at; + glyph.guidelines[selected_i].angle = IntegerOrFloat::Float(angle); + }); + } + if guidelines[selected].0.data.as_guideline().right { + v.with_glyph_mut(|glyph| { + glyph.width = Some(at.x as u64); + }); + } + v.end_modification(); } }); } diff --git a/src/tools/mod.rs b/src/tools/mod.rs index 69e3436..a5eb76c 100644 --- a/src/tools/mod.rs +++ b/src/tools/mod.rs @@ -51,7 +51,7 @@ pub enum ToolEnum { Dash, Shapes, Image, - Guidelines + Guidelines, } impl Display for ToolEnum { diff --git a/src/user_interface/egui_manager/fonts.rs b/src/user_interface/egui_manager/fonts.rs index 8fd8266..7d768bc 100644 --- a/src/user_interface/egui_manager/fonts.rs +++ b/src/user_interface/egui_manager/fonts.rs @@ -12,7 +12,7 @@ fn tweak(font: FontData) -> FontData { }) } -fn tweak_icons(font: FontData) -> FontData { +fn tweak_enlarge(font: FontData) -> FontData { font.tweak(FontTweak { scale: 1.4 * constants::FONT_SCALE_FACTOR, ..Default::default() @@ -28,10 +28,12 @@ impl EguiManager { fonts.font_data.insert("sans".to_owned(), tweak(egui::FontData::from_static(&SYSTEMSANS.data))); fonts.font_data.insert("serif".to_owned(), tweak(egui::FontData::from_static(&SYSTEMSERIF.data))); fonts.font_data.insert("mono".to_owned(), tweak(egui::FontData::from_static(&SYSTEMMONO.data))); - fonts.font_data.insert("icons".to_owned(), tweak_icons(egui::FontData::from_static(&ICONSFONT.data))); + fonts.font_data.insert("icons".to_owned(), tweak_enlarge(egui::FontData::from_static(&ICONSFONT.data))); + fonts.font_data.insert("icons_small".to_owned(), tweak(egui::FontData::from_static(&ICONSFONT.data))); fonts.families.get_mut(&egui::FontFamily::Proportional).unwrap().insert(0, "sans".to_owned()); fonts.families.get_mut(&egui::FontFamily::Monospace).unwrap().insert(0, "mono".to_owned()); fonts.families.insert(egui::FontFamily::Name("icons".into()), vec!["icons".to_owned(), "mono".to_owned()]); + fonts.families.insert(egui::FontFamily::Name("icons_small".into()), vec!["icons_small".to_owned(), "mono".to_owned()]); ctx.set_fonts(fonts); } } diff --git a/src/user_interface/gui/icons/button.rs b/src/user_interface/gui/icons/button.rs new file mode 100644 index 0000000..e7c63d8 --- /dev/null +++ b/src/user_interface/gui/icons/button.rs @@ -0,0 +1,85 @@ +use crate::{constants::*, editor::Editor}; +use egui::{Button, Response, Ui}; + +use std::cell::RefCell; + +struct IconButton { + button: Option