Skip to content

Commit 5911e42

Browse files
committed
Add glyphkind field in new glyph window
1 parent 9aa173b commit 5911e42

File tree

5 files changed

+171
-9
lines changed

5 files changed

+171
-9
lines changed

src/glyphs/obj.rs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -273,18 +273,54 @@ impl GlyphMetadata {
273273
Some("text"),
274274
clone!(@strong self as obj => move |entry, _| {
275275
let mut unicodes = obj.imp().unicode.borrow_mut();
276+
let mut kinds = obj.imp().kinds.borrow_mut();
276277
let text = entry.text();
277-
if let Some(t) = text.strip_prefix("u+") {
278-
unicodes.clear();
279-
unicodes.push(Unicode::new(t.to_string()));
280-
} else if let Some(t) = text.strip_prefix("U+") {
281-
unicodes.clear();
282-
unicodes.push(Unicode::new(t.to_string()));
278+
if let Some(t) = text.strip_prefix("u+").or_else(|| text.strip_prefix("U+")) {
279+
let val = Unicode::new(t.to_string());
280+
// TODO show error to user
281+
if let Ok(kind) = GlyphKind::try_from(&val) {
282+
kinds.0 = kind;
283+
unicodes.clear();
284+
unicodes.push(val);
285+
}
283286
}
284287
}),
285288
);
289+
let codepoint =
290+
PropertyChoice::new("codepoint", gtk::RadioButton::new(), unicode_entry.upcast());
291+
let name_entry = gtk::Entry::builder()
292+
.visible(true)
293+
.expand(false)
294+
.placeholder_text("component name")
295+
.build();
296+
name_entry.buffer().connect_notify_local(
297+
Some("text"),
298+
clone!(@strong self as obj => move |entry, _| {
299+
let mut unicodes = obj.imp().unicode.borrow_mut();
300+
unicodes.clear();
301+
let mut kinds = obj.imp().kinds.borrow_mut();
302+
let text = entry.text();
303+
kinds.0 = GlyphKind::from(text);
304+
}),
305+
);
306+
307+
let component = PropertyChoice::new(
308+
"component",
309+
gtk::RadioButton::from_widget(codepoint.button()),
310+
name_entry.upcast(),
311+
);
312+
let kind_box = gtk::Box::builder()
313+
.orientation(gtk::Orientation::Vertical)
314+
.spacing(5)
315+
.expand(true)
316+
.visible(true)
317+
.can_focus(true)
318+
.build();
319+
kind_box.pack_start(&codepoint, false, false, 5);
320+
kind_box.pack_start(&component, false, false, 5);
321+
kind_box.show_all();
286322
w.add_separator();
287-
w.add("unicode", unicode_label, unicode_entry.upcast());
323+
w.add("unicode", unicode_label, kind_box.upcast());
288324
}
289325
w
290326
}

src/ufo/glif.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,45 @@ impl Unicode {
276276
pub fn new(hex: String) -> Self {
277277
Self { hex }
278278
}
279+
280+
#[inline(always)]
281+
pub fn hex(&self) -> &str {
282+
self.hex.as_str()
283+
}
284+
}
285+
286+
/// ```
287+
/// # use gerb::glyphs::GlyphKind;
288+
/// # use gerb::ufo::glif::Unicode;
289+
///
290+
/// assert_eq!(GlyphKind::try_from(&Unicode::new("0062".to_string())).unwrap(), GlyphKind::from('b'));
291+
/// assert_eq!(GlyphKind::try_from(&Unicode::new("0041".to_string())).unwrap(), GlyphKind::from('A'));
292+
/// assert_eq!(GlyphKind::try_from(&Unicode::new("00E6".to_string())).unwrap(), GlyphKind::from('æ'));
293+
/// assert_eq!(GlyphKind::try_from(&Unicode::new("0021".to_string())).unwrap(), GlyphKind::from('!'));
294+
/// ```
295+
impl TryFrom<&Unicode> for crate::glyphs::GlyphKind {
296+
type Error = String;
297+
298+
fn try_from(val: &Unicode) -> Result<crate::glyphs::GlyphKind, Self::Error> {
299+
let num = u32::from_str_radix(val.hex(), 16)
300+
.map_err(|err| format!("{} is not a valid hex value: {err}.", val.hex()))?;
301+
Ok(crate::glyphs::GlyphKind::Char(
302+
char::from_u32(num)
303+
.ok_or_else(|| format!("{} = {num} is not a valid codepoint value.", val.hex()))?,
304+
))
305+
}
306+
}
307+
308+
impl From<char> for crate::glyphs::GlyphKind {
309+
fn from(val: char) -> crate::glyphs::GlyphKind {
310+
crate::glyphs::GlyphKind::Char(val)
311+
}
312+
}
313+
314+
impl From<String> for crate::glyphs::GlyphKind {
315+
fn from(val: String) -> crate::glyphs::GlyphKind {
316+
crate::glyphs::GlyphKind::Component(val)
317+
}
279318
}
280319

281320
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Default)]

src/utils.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,16 @@ macro_rules! impl_modified {
236236
}
237237
};
238238
}
239+
240+
#[macro_export]
241+
macro_rules! impl_deref {
242+
($ty:ty, $inner:ty) => {
243+
impl std::ops::Deref for $ty {
244+
type Target = $inner;
245+
246+
fn deref(&self) -> &Self::Target {
247+
self.imp()
248+
}
249+
}
250+
};
251+
}

src/utils/property_window.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ pub fn get_widget_for_value(
547547
.sensitive(readwrite)
548548
.visible(true)
549549
.halign(gtk::Align::Start)
550-
.valign(gtk::Align::Start)
550+
.valign(gtk::Align::Center)
551551
.use_alpha(true)
552552
.show_editor(true)
553553
.build();
@@ -828,3 +828,78 @@ pub fn new_property_window(
828828
w.set_child(Some(&scrolled_window));
829829
w
830830
}
831+
832+
#[derive(Default, Debug)]
833+
pub struct PropertyChoiceInner {
834+
pub btn: OnceCell<gtk::RadioButton>,
835+
pub widget: OnceCell<gtk::Widget>,
836+
}
837+
838+
#[glib::object_subclass]
839+
impl ObjectSubclass for PropertyChoiceInner {
840+
const NAME: &'static str = "PropertyChoice";
841+
type Type = PropertyChoice;
842+
type ParentType = gtk::Box;
843+
}
844+
845+
impl ObjectImpl for PropertyChoiceInner {
846+
fn constructed(&self, obj: &Self::Type) {
847+
self.parent_constructed(obj);
848+
obj.upcast_ref::<gtk::Box>()
849+
.set_orientation(gtk::Orientation::Horizontal);
850+
obj.set_spacing(1);
851+
obj.set_expand(false);
852+
obj.set_visible(true);
853+
obj.set_can_focus(true);
854+
}
855+
}
856+
857+
impl WidgetImpl for PropertyChoiceInner {}
858+
impl ContainerImpl for PropertyChoiceInner {}
859+
impl BoxImpl for PropertyChoiceInner {}
860+
861+
glib::wrapper! {
862+
pub struct PropertyChoice(ObjectSubclass<PropertyChoiceInner>)
863+
@extends gtk::Widget, gtk::Container, gtk::Box;
864+
}
865+
866+
impl PropertyChoice {
867+
pub fn new(label: &str, btn: gtk::RadioButton, widget: gtk::Widget) -> Self {
868+
let ret: PropertyChoice = glib::Object::new(&[]).unwrap();
869+
let label = gtk::Label::builder()
870+
.label(label)
871+
.visible(true)
872+
.selectable(false)
873+
.max_width_chars(30)
874+
.halign(gtk::Align::Start)
875+
.wrap(true)
876+
.expand(false)
877+
.build();
878+
let event_box = gtk::EventBox::builder()
879+
.events(gtk::gdk::EventMask::BUTTON_PRESS_MASK)
880+
.above_child(true)
881+
.child(&label)
882+
.visible(true)
883+
.build();
884+
ret.pack_start(&event_box, false, false, 5);
885+
ret.pack_start(&btn, false, false, 5);
886+
ret.pack_start(&widget, false, false, 5);
887+
btn.bind_property("active", &widget, "sensitive")
888+
.flags(glib::BindingFlags::SYNC_CREATE)
889+
.build();
890+
event_box.connect_button_press_event(clone!(@weak btn => @default-return Inhibit(false), move |_, event| {
891+
if event.button() == gtk::gdk::BUTTON_PRIMARY && event.event_type() == gtk::gdk::EventType::ButtonPress {
892+
btn.set_active(true);
893+
}
894+
Inhibit(false)
895+
}));
896+
ret.btn.set(btn).unwrap();
897+
ret
898+
}
899+
900+
pub fn button(&self) -> &gtk::RadioButton {
901+
self.btn.get().unwrap()
902+
}
903+
}
904+
905+
impl_deref!(PropertyChoice, PropertyChoiceInner);

src/views/collection.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ impl ObjectImpl for CollectionInner {
173173
save.connect_clicked(clone!(@weak metadata, @weak w, @weak obj => move |_| {
174174
let project = obj.project();
175175
let name = metadata.name().to_string();
176-
//FIXME: set GlyphKind
177176
let glyph = Rc::new(RefCell::new(metadata.clone().into()));
178177
metadata.glyph_ref.set(glyph.clone()).unwrap();
179178
//FIXME: show err msg

0 commit comments

Comments
 (0)