/* * Galaxium Messenger * Copyright (C) 2007 Ben Motmans <ben.motmans@gmail.com> * Copyright (C) 2007 Philippe Durand <draekz@gmail.com> * Copyright (C) 2007 Paul Burton <paulburton89@gmail.com> * * License: GNU General Public License (GPL) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; using System.Text; using Gdk; using Gtk; using Anculus.Core; using Galaxium.Core; using Galaxium.Gui; using Galaxium.Gui.GtkGui; using Galaxium.Protocol; using Galaxium.Protocol.Gui; namespace Galaxium.Gui.GtkGui { public class ContactCellRendererText: Gtk.CellRendererText { int _emoticonmargin = 1; string _text; string _markup = string.Empty; List<ITextChunk> _chunks = new List<ITextChunk> (); IProtocol _protocol; public new string Markup { get { return _markup; } set { if (_markup == value) return; //Log.Debug ("Old markup: {0}", _markup.Replace ("\n", "")); _markup = value; char accel_char; Pango.AttrList attrs; Pango.Global.ParseMarkup (_markup, char.MaxValue, out attrs, out _text, out accel_char); //Log.Debug ("New markup: {0}", _markup.Replace ("\n", "")); SplitMarkup (); } } public int EmoticonMargin { get { return _emoticonmargin; } set { _emoticonmargin = value; } } public ContactCellRendererText (IProtocol protocol) { _protocol = protocol; } void SplitMarkup () { lock (_chunks) { _chunks.Clear (); if (!string.IsNullOrEmpty (_text)) _chunks.AddRange (PangoUtility.SplitMarkup (_markup, _protocol, null)); } } protected override void Render (Drawable window, Gtk.Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gdk.Rectangle expose_area, Gtk.CellRendererState flags) { int xoffset, yoffset, width, height; GetSize (widget, ref cell_area, out xoffset, out yoffset, out width, out height); int y = (int) Ypad; int x = (int) Xpad; int pw, ph, lineheight = 0; Gtk.StateType state; if (!this.Sensitive) state = Gtk.StateType.Insensitive; else if ((flags & Gtk.CellRendererState.Selected) == Gtk.CellRendererState.Selected) state = (widget.HasFocus ? Gtk.StateType.Selected : Gtk.StateType.Active); else if (((flags & Gtk.CellRendererState.Prelit) == Gtk.CellRendererState.Prelit) && (widget.State == Gtk.StateType.Prelight)) state = Gtk.StateType.Prelight; else state = (widget.State == Gtk.StateType.Insensitive ? Gtk.StateType.Insensitive : Gtk.StateType.Normal); lock (_chunks) { int fontMaxHeight = 0; int fontHeight = 16; foreach (ITextChunk chunk in _chunks) { if (chunk.Type != TextChunkType.Emoticon) { char accel_char; Pango.AttrList attrs; string txt; Pango.Global.ParseMarkup (chunk.Text, char.MaxValue, out attrs, out txt, out accel_char); if (txt == "\n") { y += lineheight; x = (int)Xpad; lineheight = 0; fontMaxHeight = 0; attrs.Dispose (); continue; } if (string.IsNullOrEmpty (txt)) { Log.Warn ("No text in markup {0}", chunk.Text); foreach (ITextChunk c in _chunks) Log.Debug ("{0}: {1}", c.Type, c.Text); attrs.Dispose (); continue; } Pango.Layout lay = widget.CreatePangoLayout (txt); lay.FontDescription = this.FontDesc; lay.Wrap = this.WrapMode; lay.Ellipsize = this.Ellipsize; lay.Attributes = attrs; lay.GetPixelSize(out pw, out ph); Pango.Rectangle inkRect, logicalRect; lay.GetPixelExtents (out inkRect, out logicalRect); fontHeight = logicalRect.Height; if (fontHeight > fontMaxHeight) fontMaxHeight = fontHeight; if (ph > lineheight) lineheight = ph; //check if we need ellipsizing if (Ellipsize != Pango.EllipsizeMode.None && (cell_area.X + x + pw) > (cell_area.Width + cell_area.X)) lay.Width = Convert.ToInt32 ((cell_area.Width - xoffset - x - 2 * Xpad) * Pango.Scale.PangoScale); //paint the layout Gtk.Style.PaintLayout (widget.Style, window, state, true, cell_area, widget, "cellrenderertext", cell_area.X + x, cell_area.Y + y + ((fontMaxHeight - fontHeight) / 2), lay); lay.Dispose (); attrs.Dispose (); x += pw; } else { x += _emoticonmargin; IEmoticon emot = ((EmoticonTextChunk)chunk).Emoticon; Gdk.Pixbuf pixbuf = new Pixbuf (emot.Data); int newH = fontHeight; int newW = (int)(((double)pixbuf.Width / (double)pixbuf.Height) * newH); Gdk.Pixbuf scaled = pixbuf.ScaleSimple (newW, newH, InterpType.Bilinear); if (scaled != null) { if (cell_area.X + x < (cell_area.Width + cell_area.X)) window.DrawPixbuf (null, scaled, 0, 0, cell_area.X + x, cell_area.Y + y, scaled.Width, scaled.Height, RgbDither.None, 0, 0); x += scaled.Width + _emoticonmargin; scaled.Dispose (); } else Log.Error ("Unable to scale emoticon pixmap"); pixbuf.Dispose (); } } } } } }