Browse Source

fractal-gtk: Use `msg_entry` as a GtkSourceView

This modifies `msg_entry` to be a GtkSourceView in order to support
multiline message input. Messages are still sent by simply pressing the
enter key but there is also the possibility to insert line returns
within the message with Shift-Enter.

See https://gitlab.gnome.org/World/fractal/issues/154
environments/review-jsparber-h-cxnwl8/deployments/1
Eisha Chen-yen-su 8 years ago committed by Daniel García Moreno
parent
commit
f49f6be6cc
  1. 43
      Cargo.lock
  2. 3
      fractal-gtk/Cargo.toml
  3. 29
      fractal-gtk/src/app/connect/send.rs
  4. 80
      fractal-gtk/src/appop/member.rs
  5. 12
      fractal-gtk/src/appop/message.rs
  6. 35
      fractal-gtk/src/appop/room.rs

43
Cargo.lock generated

@ -376,6 +376,7 @@ dependencies = [
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
"sourceview 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tree_magic 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -762,6 +763,23 @@ dependencies = [
"pango 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gtk-source-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gtk-sys"
version = "0.6.0"
@ -1687,6 +1705,29 @@ name = "smallvec"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "sourceview"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk-source-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"pango 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "string_cache"
version = "0.7.3"
@ -2272,6 +2313,7 @@ dependencies = [
"checksum gstreamer-video 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75300cf1ed8d8d65811349fc755fac22be05ea55df551ab29e43664d4a575c92"
"checksum gstreamer-video-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed798787e78a0f1c8be06bd3adcab03f962f049a820743aae9f690f56a0d538"
"checksum gtk 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d695d6be4110618a97c19cd068e8a00e53e33b87e3c65cdc5397667498b1bc24"
"checksum gtk-source-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3b11e821fccfa5c1cf8bec9a0084629f465d18e54cf2bea1eb73dc5b8a3bb2"
"checksum gtk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d9554cf5b3a85a13fb39258c65b04b262989c1d7a758f8f555b77a478621a91"
"checksum html2pango 0.1.0 (git+https://gitlab.gnome.org/World/html2pango)" = "<none>"
"checksum html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b04478cf718862650a0bf66acaf8f2f8c906fbc703f35c916c1f4211b069a364"
@ -2376,6 +2418,7 @@ dependencies = [
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
"checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d"
"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013"
"checksum sourceview 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2ceb81d91628bedb8aaabad6dd5e39a663bbf42994ac2d03fd2d8cf9466fc0f4"
"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"
"checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191"
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"

3
fractal-gtk/Cargo.toml

@ -50,3 +50,6 @@ git = "https://gitlab.gnome.org/jsparber/gspell-rs"
[dependencies.gtk]
features = ["v3_22"]
version = "0.4.0"
[dependencies.sourceview]
version = "0.4.0"

29
fractal-gtk/src/app/connect/send.rs

@ -1,19 +1,38 @@
extern crate gdk;
extern crate gtk;
extern crate sourceview;
use self::gtk::prelude::*;
use app::App;
impl App {
pub fn connect_send(&self) {
let msg_entry: gtk::Entry = self.ui.builder
let msg_entry: sourceview::View = self.ui.builder
.get_object("msg_entry")
.expect("Couldn't find msg_entry in ui file.");
let mut op = self.op.clone();
msg_entry.connect_activate(move |entry| if let Some(text) = entry.get_text() {
let mut mut_text = text;
op.lock().unwrap().send_message(mut_text);
entry.set_text("");
msg_entry.connect_key_press_event(move |entry, key| {
match key.get_keyval() {
gdk::enums::key::Return | gdk::enums::key::KP_Enter
if !key.get_state().contains(gdk::ModifierType::SHIFT_MASK) => {
if let Some(buffer) = entry.get_buffer() {
let start = buffer.get_start_iter();
let end = buffer.get_end_iter();
if let Some(text) = buffer.get_text(&start, &end, false) {
let mut mut_text = text;
op.lock().unwrap().send_message(mut_text);
}
buffer.set_text("");
}
Inhibit(true)
},
_ => Inhibit(false)
}
});
op = self.op.clone();

80
fractal-gtk/src/appop/member.rs

@ -1,4 +1,7 @@
#![deny(unused)]
extern crate gtk;
extern crate sourceview;
use self::gtk::prelude::*;
@ -31,6 +34,83 @@ impl AppOp {
0
}
pub fn show_members(&self, members: Vec<Member>) {
self.clean_member_list();
let mlist: gtk::ListBox = self.ui.builder
.get_object("member_list")
.expect("Couldn't find member_list in ui file.");
let msg_entry: sourceview::View = self.ui.builder
.get_object("msg_entry")
.expect("Couldn't find msg_entry in ui file.");
// limiting the number of members to show in the list
for member in members.iter().take(self.member_limit) {
let w;
let m = member.clone();
{
let mb = widgets::MemberBox::new(&m, &self);
w = mb.widget(false);
}
w.connect_button_press_event(clone!( msg_entry => move |_, _| {
if let Some(ref a) = m.alias {
if let Some(buffer) = msg_entry.get_buffer() {
buffer.insert_at_cursor(&a.clone());
}
msg_entry.grab_focus();
}
glib::signal::Inhibit(true)
}));
let p = mlist.get_children().len() - 1;
mlist.insert(&w, p as i32);
}
if members.len() > self.member_limit {
let n = (members.len() - self.member_limit) as u32;
let newlabel = ni18n_k("and one more", "and {member_count} more", n,
&[("member_count", &n.to_string())]);
self.more_members_btn.set_label(&newlabel);
self.more_members_btn.show();
} else {
self.more_members_btn.hide();
}
let members_count = self.ui.builder
.get_object::<gtk::Label>("members_count")
.expect("Can't find member_count in ui file.");
members_count.set_text(&format!("{}", members.len()));
}
pub fn show_all_members(&self) {
let inp: gtk::SearchEntry = self.ui.builder
.get_object("members_search")
.expect("Couldn't find members_searcn in ui file.");
let text = inp.get_text();
if let Some(r) = self.rooms.get(&self.active_room.clone().unwrap_or_default()) {
let mut members: Vec<Member> = match text {
// all members if no search text
None => r.members.values().cloned().collect(),
Some(t) => {
// members with the text in the alias
r.members.values().filter(move |x| {
match x.alias {
None => false,
Some(ref a) => a.to_lowercase().contains(&t.to_lowercase())
}
}).cloned().collect()
}
};
members.sort_by_key(|m| {
-r.power_levels.get(&m.uid).unwrap_or(&0)
});
self.show_members(members);
}
}
pub fn set_room_members(&mut self, roomid: String, members: Vec<Member>) {
if let Some(r) = self.rooms.get_mut(&roomid) {
r.members = HashMap::new();

12
fractal-gtk/src/appop/message.rs

@ -1,4 +1,5 @@
extern crate comrak;
extern crate sourceview;
extern crate tree_magic;
use i18n::i18n;
@ -149,7 +150,7 @@ impl AppOp {
prev: Option<Message>,
force_full: bool,
first_new: bool) {
let msg_entry: gtk::Entry = self.ui.builder
let msg_entry: sourceview::View = self.ui.builder
.get_object("msg_entry")
.expect("Couldn't find msg_entry in ui file.");
let messages = self.ui.builder
@ -177,11 +178,10 @@ impl AppOp {
if let Some(label) = eb.get_children().iter().next() {
if let Ok(l) = label.clone().downcast::<gtk::Label>() {
if let Some(t) = l.get_text() {
let mut pos = entry.get_position();
entry.insert_text(&t[..], &mut pos);
pos = entry.get_text_length() as i32;
entry.set_position(pos);
entry.grab_focus_without_selecting();
if let Some(buffer) = entry.get_buffer() {
buffer.insert_at_cursor(&t[..]);
}
entry.grab_focus();
}
}
}

35
fractal-gtk/src/appop/room.rs

@ -1,5 +1,6 @@
extern crate gtk;
extern crate rand;
extern crate sourceview;
use i18n::{i18n, i18n_k};
@ -164,15 +165,25 @@ impl AppOp {
self.member_limit = 50;
self.room_panel(RoomPanel::Loading);
let msg_entry: gtk::Entry = self.ui.builder
let msg_entry: sourceview::View = self.ui.builder
.get_object("msg_entry")
.expect("Couldn't find msg_entry in ui file.");
if let Some(msg) = msg_entry.get_text() {
let active_room_id = self.active_room.clone().unwrap_or_default();
if msg.len() > 0 {
self.unsent_messages.insert(active_room_id, (msg, msg_entry.get_position()));
} else {
self.unsent_messages.remove(&active_room_id);
if let Some(buffer) = msg_entry.get_buffer() {
let start = buffer.get_start_iter();
let end = buffer.get_end_iter();
if let Some(msg) = buffer.get_text(&start, &end, false) {
let active_room_id = self.active_room.clone().unwrap_or_default();
if msg.len() > 0 {
if let Some(mark) = buffer.get_insert() {
let iter = buffer.get_iter_at_mark(&mark);
let msg_position = iter.get_offset();
self.unsent_messages.insert(active_room_id, (msg, msg_position));
}
} else {
self.unsent_messages.remove(&active_room_id);
}
}
}
@ -310,7 +321,7 @@ impl AppOp {
ch.show();
}
let msg_entry: gtk::Entry = self.ui.builder
let msg_entry: sourceview::View = self.ui.builder
.get_object("msg_entry")
.expect("Couldn't find msg_entry in ui file.");
msg_entry.grab_focus();
@ -319,8 +330,12 @@ impl AppOp {
let msg = self.unsent_messages
.get(&active_room_id).cloned()
.unwrap_or((String::new(), 0));
msg_entry.set_text(&msg.0);
msg_entry.set_position(msg.1);
if let Some(buffer) = msg_entry.get_buffer() {
buffer.set_text(&msg.0);
let iter = buffer.get_iter_at_offset(msg.1);
buffer.place_cursor(&iter);
}
},
_ => {
for ch in headerbar.get_children().iter() {

Loading…
Cancel
Save