Logo Search packages:      
Sourcecode: galaxium version File versions  Download package

EntityTag.cs

/*
 * Galaxium Messenger
 * 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 Gdk;
using Gtk;

using Anculus.Core;

using Galaxium.Protocol;

namespace Galaxium.Gui.GtkGui
{
      public class EntityTag: TextTag
      {
            const uint MIN_BRIGHTNESS_CONTRAST = 75;
            const uint MIN_COLOR_CONTRAST = 200;
            
            static Gdk.Color _sendColor = new Gdk.Color(22, 86, 158);
            static List<Gdk.Color> _nickColors;
            static Gdk.Color[] _nickSeedColors = {
                  new Gdk.Color(252, 233, 79),  // Butter #1
                  new Gdk.Color(237, 212, 0),         // Butter #2
                  new Gdk.Color(196, 160, 0),         // Butter #3
                  new Gdk.Color(252, 175, 62),  // Orange #1
                  new Gdk.Color(245, 121, 0),         // Orange #2
                  new Gdk.Color(206, 92, 0),          // Orange #3
                  new Gdk.Color(233, 185, 110), // Chocolate #1
                  new Gdk.Color(193, 125, 17),  // Chocolate #2
                  new Gdk.Color(143, 89, 2),          // Chocolate #3
                  new Gdk.Color(138, 226, 52),  // Chameleon #1
                  new Gdk.Color(115, 210, 22),  // Chameleon #2
                  new Gdk.Color(78, 154, 6),          // Chameleon #3
                  new Gdk.Color(114, 159, 207), // Sky Blue #1
                  new Gdk.Color(52, 101, 164),  // Sky Blue #2
                  new Gdk.Color(32, 74, 135),         // Sky Blue #3
                  new Gdk.Color(173, 127, 168), // Plum #1
                  new Gdk.Color(117, 80, 123),  // Plum #2
                  new Gdk.Color(92, 53, 102),         // Plum #3
                  new Gdk.Color(239, 41, 41),         // Scarlet Red #1
                  new Gdk.Color(204, 0, 0),           // Scarlet Red #2
                  new Gdk.Color(164, 0, 0),           // Scarlet Red #3
                  new Gdk.Color(136, 138, 133), // Aluminium #4
                  new Gdk.Color(85, 87, 83),          // Aluminium #5
                  new Gdk.Color(46, 52, 54),          // Aluminium #6
            };

            TextTagTable _table;
            IEntity _entity;
            
            static EntityTag ()
            {
                  GenerateNickColors(200, new Gdk.Color(255, 255, 255));
            }
            
            public IEntity Entity
            {
                  get { return _entity; }
            }           
            
            public EntityTag (TextMessageDisplay display, IEntity entity): base (null)
            {
                  _table = display._tagTable;
                  _entity = entity;
                  
                  Weight = Pango.Weight.Bold;
                  PixelsAboveLines = 5;

                  if (entity.Local)
                        ForegroundGdk = _sendColor;
                  else
                  {
                        Gdk.Color col = _nickColors[(int)(GetStringHash(entity.UniqueIdentifier) % _nickColors.Count)];

                        float scale = ((1 - (Luminance (display.Style.Base (StateType.Normal)) / Luminance (display.Style.White))) *
                                       (Luminance (display.Style.White) / Math.Max (Math.Max (col.Red, col.Blue), col.Green)));

                        // Only lighten colors, we should never need to darken them
                        if (scale > 1)
                        {
                              col.Red   = (ushort)(scale * col.Red);
                              col.Green = (ushort)(scale * col.Green);
                              col.Blue  = (ushort)(scale * col.Blue);
                        }
                        
                        ForegroundGdk = col;
                  }
                  
                  _table.Add (this);
            }
            
            public override void Dispose()
            {
                  _table.Remove (this);
            }
            
            // Adapted from http://mail.gnome.org/archives/gtk-devel-list/2000-February/msg00045.html
            uint GetStringHash (string str)
            {
                  uint result = 0;
                  
                  foreach (char ch in str)
                        result += (result << 3) + ch;
                  
                  return result;
            }
            
            // Adapted from pidgin
            static void GenerateNickColors(uint count, Gdk.Color background)
            {
                  _nickColors = new List<Gdk.Color>();
                  
                  Random rand = new Random(background.Red + background.Green + background.Blue + 1);
                  DateTime breakoutTime = DateTime.Now.AddSeconds(3);
                  
                  // First check the seed colors
                  foreach (Gdk.Color seed in _nickSeedColors)
                  {
                        if (ColorIsVisible(seed, background, MIN_COLOR_CONTRAST, MIN_BRIGHTNESS_CONTRAST) &&
                            ColorIsVisible(seed, _sendColor, MIN_COLOR_CONTRAST / 4, 0))
                              _nickColors.Add(seed);
                        
                        if ((DateTime.Now > breakoutTime) || (_nickColors.Count >= count))
                              break;
                  }
                  
                  if (_nickColors.Count >= count)
                        return;
                  
                  // We don't have enough colors from the seed colors, try random ones
                  
                  while ((_nickColors.Count < count) && (DateTime.Now < breakoutTime))
                  {
                        Gdk.Color color = new Gdk.Color((byte)(rand.Next() * 255),
                                                        (byte)(rand.Next() * 255),
                                                        (byte)(rand.Next() * 255));
                        
                        if (ColorIsVisible(color, background, MIN_COLOR_CONTRAST, MIN_BRIGHTNESS_CONTRAST) &&
                            ColorIsVisible(color, _sendColor, MIN_COLOR_CONTRAST / 4, 0))
                              _nickColors.Add(color);
                  }
                  
                  // Check if we still don't have enough
                  
                  if (_nickColors.Count < count)
                        Log.Warn("Unable to generate enough suitable nickname colors ({0}/{1})", _nickColors.Count, count);
            }
            
            // Algorithm from http://www.w3.org/TR/AERT#color-contrast
            static bool ColorIsVisible(Gdk.Color foreground, Gdk.Color background, uint colorContrast, uint brightnessContrast)
            {
                  // Convert from 16 bit to 8 bit values
                  
                  byte fRed = (byte)(foreground.Red >> 8);
                  byte fGreen = (byte)(foreground.Green >> 8);
                  byte fBlue = (byte)(foreground.Blue >> 8);

                  byte bRed = (byte)(background.Red >> 8);
                  byte bGreen = (byte)(background.Green >> 8);
                  byte bBlue = (byte)(background.Blue >> 8);
                  
                  // Calculate brightness
                  
                  ulong fgBrightness = (ulong)((fRed * 299 + fGreen * 587 + fBlue * 114) / 1000);
                  ulong bgBrightness = (ulong)((bRed * 299 + bGreen * 587 + bBlue * 114) / 1000);

                  // Calculate differences
                  
                  ulong brDiff = (ulong)Math.Abs((long)(fgBrightness - bgBrightness));
                  ulong colDiff = (ulong)Math.Abs(fRed - bRed) + (ulong)Math.Abs(fGreen - bGreen) + (ulong)Math.Abs(fBlue - bBlue);
                  
                  return ((colDiff > colorContrast) && (brDiff > brightnessContrast));
            }

            static float Luminance(Gdk.Color col)
            {
                  return (float)((0.3 * col.Red) + (0.59 * col.Green) + (0.11 * col.Blue));
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index