void AddEmoji(Gtk.TextBuffer buffer, ref Gtk.TextIter iter, ImageMessagePartModel imgPart, string shortName) { var unicode = Emojione.ShortnameToUnicode(shortName); if (unicode == null) { AddAlternativeText(buffer, ref iter, imgPart); return; } int width, height; int widthPango, heightPango; int descent; using (var layout = CreatePangoLayout(null)) { layout.GetPixelSize(out width, out height); layout.GetSize(out widthPango, out heightPango); descent = layout.Context.GetMetrics(layout.FontDescription, null).Descent; } // A mark here serves two pusposes. One is to allow us to apply the // tag across the pixbuf. It also lets us know later where to put // the pixbuf if we need to load it from the network var mark = new Gtk.TextMark(null, true); buffer.AddMark(mark, iter); var emojiName = unicode + ".png"; string emojiPath; if (EmojiCache.TryGetIcon("emojione", emojiName, out emojiPath)) { var emojiFile = new FileInfo(emojiPath); if (emojiFile.Exists && emojiFile.Length > 0) { var pix = new Gdk.Pixbuf(emojiPath, -1, height); buffer.InsertPixbuf(ref iter, pix); var beforeIter = buffer.GetIterAtMark(mark); var imgTag = new EmojiTag(mark, emojiFile.FullName); imgTag.Rise = - descent; _MessageTextTagTable.Add(imgTag); buffer.ApplyTag(imgTag, beforeIter, iter); } else { AddAlternativeText(buffer, ref iter, imgPart); } return; } var emojiUrl = Emojione.UnicodeToUrl(unicode); EmojiCache.BeginDownloadFile("emojione", emojiName, emojiUrl, (path) => { GLib.Idle.Add(delegate { var afterIter = buffer.GetIterAtMark(mark); buffer.InsertPixbuf(ref afterIter, new Gdk.Pixbuf(path, -1, height)); var beforeIter = buffer.GetIterAtMark(mark); var emojiTag = new EmojiTag(mark, path); _MessageTextTagTable.Add(emojiTag); emojiTag.Rise = - descent; buffer.ApplyTag(emojiTag, beforeIter, afterIter); return false; }); }, (ex) => { GLib.Idle.Add(delegate { var markIter = buffer.GetIterAtMark(mark); buffer.DeleteMark(mark); AddAlternativeText(buffer, ref markIter, imgPart); return false; }); } ); }
public static void Deserialize (Gtk.TextBuffer buffer, Gtk.TextIter start, XmlTextReader xml) { int offset = start.Offset; Stack<TagStart> stack = new Stack<TagStart> (); TagStart tag_start; NoteTagTable note_table = buffer.TagTable as NoteTagTable; int curr_depth = -1; // A stack of boolean values which mark if a // list-item contains content other than another list Stack<bool> list_stack = new Stack<bool> (); while (xml.Read ()) { switch (xml.NodeType) { case XmlNodeType.Element: if (xml.Name == "note-content") break; tag_start = new TagStart (); tag_start.Start = offset; if (note_table != null && note_table.IsDynamicTagRegistered (xml.Name)) { tag_start.Tag = note_table.CreateDynamicTag (xml.Name); } else if (xml.Name == "list") { curr_depth++; break; } else if (xml.Name == "list-item") { if (curr_depth >= 0) { if (xml.GetAttribute ("dir") == "rtl") { tag_start.Tag = note_table.GetDepthTag (curr_depth, Pango.Direction.Rtl); } else { tag_start.Tag = note_table.GetDepthTag (curr_depth, Pango.Direction.Ltr); } list_stack.Push (false); } else { Logger.Error("</list> tag mismatch"); } } else { tag_start.Tag = buffer.TagTable.Lookup (xml.Name); } if (tag_start.Tag is NoteTag) { ((NoteTag) tag_start.Tag).Read (xml, true); } stack.Push (tag_start); break; case XmlNodeType.Text: case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: Gtk.TextIter insert_at = buffer.GetIterAtOffset (offset); buffer.Insert (ref insert_at, xml.Value); offset += xml.Value.Length; // If we are inside a <list-item> mark off // that we have encountered some content if (list_stack.Count > 0) { list_stack.Pop (); list_stack.Push (true); } break; case XmlNodeType.EndElement: if (xml.Name == "note-content") break; if (xml.Name == "list") { curr_depth--; break; } tag_start = stack.Pop (); if (tag_start.Tag == null) break; Gtk.TextIter apply_start, apply_end; apply_start = buffer.GetIterAtOffset (tag_start.Start); apply_end = buffer.GetIterAtOffset (offset); if (tag_start.Tag is NoteTag) { ((NoteTag) tag_start.Tag).Read (xml, false); } // Insert a bullet if we have reached a closing // <list-item> tag, but only if the <list-item> // had content. DepthNoteTag depth_tag = tag_start.Tag as DepthNoteTag; if (depth_tag != null && list_stack.Pop ()) { ((NoteBuffer) buffer).InsertBullet (ref apply_start, depth_tag.Depth, depth_tag.Direction); buffer.RemoveAllTags (apply_start, apply_start); offset += 2; } else if (depth_tag == null) { buffer.ApplyTag (tag_start.Tag, apply_start, apply_end); } break; default: Logger.Warn ("Unhandled element {0}. Value: '{1}'", xml.NodeType, xml.Value); break; } } }
public void Undo (Gtk.TextBuffer buffer) { Gtk.TextIter start_iter, end_iter; start_iter = buffer.GetIterAtOffset (start); end_iter = buffer.GetIterAtOffset (end); buffer.MoveMark (buffer.SelectionBound, start_iter); buffer.ApplyTag (tag, start_iter, end_iter); buffer.MoveMark (buffer.InsertMark, end_iter); }
public static void Deserialize (Gtk.TextBuffer buffer, Gtk.TextIter start, string content) { StringReader reader = new StringReader(content); int intCharacter; char convertedCharacter; int offset = start.Offset; string sbuffer = String.Empty; Stack<TagStart> stack = new Stack<TagStart> (); TagStart tag_start; while (true) { intCharacter = reader.Read (); if (intCharacter == -1) break; convertedCharacter = Convert.ToChar (intCharacter); if (sbuffer != String.Empty || convertedCharacter == '<') { sbuffer += convertedCharacter; if (sbuffer == "<bold>") { tag_start = new TagStart (); tag_start.Start = offset; tag_start.Tag = buffer.TagTable.Lookup ("bold"); stack.Push (tag_start); sbuffer = String.Empty; } else if (sbuffer == "<italic>") { tag_start = new TagStart (); tag_start.Start = offset; tag_start.Tag = buffer.TagTable.Lookup ("italic"); stack.Push (tag_start); sbuffer = String.Empty; } else if (sbuffer == "</bold>" || sbuffer == "</italic>") { if (stack.Count > 0) { tag_start = stack.Pop (); Gtk.TextIter apply_start, apply_end; apply_start = buffer.GetIterAtOffset (tag_start.Start); apply_end = buffer.GetIterAtOffset (offset); buffer.ApplyTag (tag_start.Tag, apply_start, apply_end); sbuffer = String.Empty; } } else if (sbuffer.Length > 9) { Gtk.TextIter insert_at = buffer.GetIterAtOffset(offset); buffer.Insert (ref insert_at, sbuffer); offset += sbuffer.Length; sbuffer = String.Empty; } } else { Gtk.TextIter insert_at = buffer.GetIterAtOffset(offset); buffer.Insert (ref insert_at, convertedCharacter.ToString ()); offset += 1; } } }
protected void ApplySplitTags (Gtk.TextBuffer buffer) { foreach (TagData tag in splitTags) { int offset = GetSplitOffset (); Gtk.TextIter start = buffer.GetIterAtOffset (tag.start - offset); Gtk.TextIter end = buffer.GetIterAtOffset (tag.end - offset); buffer.ApplyTag(tag.tag, start, end); } }