From f92387cdddd1daf3e1cc0c9a3bfe500510236fee Mon Sep 17 00:00:00 2001 From: Julian Sparber Date: Thu, 26 Apr 2018 14:47:18 +0200 Subject: [PATCH] mention: highlight own username in mentions using pango attributes --- fractal-gtk/src/widgets/message.rs | 96 ++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/fractal-gtk/src/widgets/message.rs b/fractal-gtk/src/widgets/message.rs index 966fbf0b..0247d024 100644 --- a/fractal-gtk/src/widgets/message.rs +++ b/fractal-gtk/src/widgets/message.rs @@ -219,10 +219,38 @@ impl<'a> MessageBox<'a> { fn build_room_msg_body(&self, body: &str) -> gtk::Box { let bx = gtk::Box::new(gtk::Orientation::Horizontal, 0); let msg = gtk::Label::new(""); + let uname = self.op.username.clone().unwrap_or_default(); msg.set_markup(&markup_text(body)); self.set_label_styles(&msg); + if String::from(body).contains(&uname) { + + let name = uname.clone(); + msg.connect_property_cursor_position_notify(move |w| { + if let Some(text) = w.get_text() { + if let Some(attr) = highlight_username(w.clone(), &name, text) { + w.set_attributes(&attr); + } + } + }); + + let name = uname.clone(); + msg.connect_property_selection_bound_notify(move |w| { + if let Some(text) = w.get_text() { + if let Some(attr) = highlight_username(w.clone(), &name, text) { + w.set_attributes(&attr); + } + } + }); + + if let Some(text) = msg.get_text() { + if let Some(attr) = highlight_username(msg.clone(), &uname, text) { + msg.set_attributes(&attr); + } + } + } + bx.add(&msg); bx } @@ -336,3 +364,71 @@ impl<'a> MessageBox<'a> { bx } } + +fn highlight_username(label: gtk::Label, alias: &String, input: String) -> Option { + fn contains((start, end): (i32, i32), item: i32) -> bool { + match start <= end { + true => start <= item && end > item, + false => start <= item || end > item, + } + } + + let input = input.to_lowercase(); + let bounds = label.get_selection_bounds(); + let context = gtk::Widget::get_style_context (&label.clone().upcast::())?; + let fg = gtk::StyleContext::lookup_color (&context, "theme_selected_bg_color")?; + let red = fg.red * 65535. + 0.5; + let green = fg.green * 65535. + 0.5; + let blue = fg.blue * 65535. + 0.5; + let color = pango::Attribute::new_foreground(red as u16, green as u16, blue as u16)?; + + let attr = pango::AttrList::new(); + let mut input = input.clone(); + let alias = &alias.to_lowercase(); + let mut removed_char = 0; + while input.contains(alias) { + let pos = { + let start = input.find(alias)? as i32; + (start, start + alias.len() as i32) + }; + let mut color = color.clone(); + let mark_start = removed_char as i32 + pos.0; + let mark_end = removed_char as i32 + pos.1; + let mut final_pos = Some((mark_start, mark_end)); + /* exclude selected text */ + if let Some((bounds_start, bounds_end)) = bounds { + /* If the selection is within the alias */ + if contains((mark_start, mark_end), bounds_start) && + contains((mark_start, mark_end), bounds_end) { + final_pos = Some((mark_start, bounds_start)); + /* Add blue color after a selection */ + let mut color = color.clone(); + color.set_start_index(bounds_end as u32); + color.set_end_index(mark_end as u32); + attr.insert(color); + } else { + /* The alias starts inside a selection */ + if contains(bounds?, mark_start) { + final_pos = Some((bounds_end, final_pos?.1)); + } + /* The alias ends inside a selection */ + if contains(bounds?, mark_end - 1) { + final_pos = Some((final_pos?.0, bounds_start)); + } + } + } + + if let Some((start, end)) = final_pos { + color.set_start_index(start as u32); + color.set_end_index(end as u32); + attr.insert(color); + } + { + let end = pos.1 as usize; + input.drain(0..end); + } + removed_char = removed_char + pos.1 as u32; + } + + Some(attr) +}