33
33
using MonoDevelop.Core;
34
34
using MonoDevelop.Components;
37
using MonoDevelop.Ide.Gui.Components;
37
39
namespace MonoDevelop.Ide
39
41
public static class ImageService
41
43
static Gtk.IconFactory iconFactory = new Gtk.IconFactory ();
45
// Mapping of icon spec to stock icon id.
42
46
static List<Dictionary<string, string>> addinIcons = new List<Dictionary<string, string>> ();
48
// Mapping of icon spec to stock icon id, but used only when the icon is not bound to a specific add-in
49
static Dictionary<string, string> iconSpecToStockId = new Dictionary<string, string> ();
51
// Map of all animations
52
static Dictionary<string, AnimatedIcon> animationFactory = new Dictionary<string, AnimatedIcon> ();
43
54
static List<RuntimeAddin> addins = new List<RuntimeAddin> ();
44
55
static Dictionary<string, string> composedIcons = new Dictionary<string, string> ();
45
56
static Dictionary<Gdk.Pixbuf, string> namedIcons = new Dictionary<Gdk.Pixbuf, string> ();
58
// Dictionary of extension nodes by stock icon id. It holds nodes that have not yet been loaded
46
59
static Dictionary<string, List<StockIconCodon>> iconStock = new Dictionary<string, List<StockIconCodon>> ();
48
61
static Gtk.Requisition[] iconSizes = new Gtk.Requisition[7];
98
113
pixbuf = new Gdk.Pixbuf (buffer);
99
114
} else if (!string.IsNullOrEmpty (iconCodon.IconId)) {
100
pixbuf = GetPixbuf (InternalGetStockId (iconCodon.Addin, iconCodon.IconId, iconCodon.IconSize), iconCodon.IconSize);
115
var id = GetStockIdForImageSpec (iconCodon.Addin, iconCodon.IconId, iconCodon.IconSize);
116
pixbuf = GetPixbuf (id, iconCodon.IconSize);
117
// This may be an animation, get it
118
animationFactory.TryGetValue (id, out animatedIcon);
119
} else if (!string.IsNullOrEmpty (iconCodon.Animation)) {
120
string id = GetStockIdForImageSpec (iconCodon.Addin, "animation:" + iconCodon.Animation, iconCodon.IconSize);
121
pixbuf = GetPixbuf (id, iconCodon.IconSize);
122
// This *should* be an animation
123
animationFactory.TryGetValue (id, out animatedIcon);
102
if (pixbuf != null) {
103
Gtk.IconSize size = forceWildcard? Gtk.IconSize.Invalid : iconCodon.IconSize;
126
Gtk.IconSize size = forceWildcard? Gtk.IconSize.Invalid : iconCodon.IconSize;
104
128
AddToIconFactory (iconCodon.StockId, pixbuf, size);
129
if (animatedIcon != null)
130
AddToAnimatedIconFactory (iconCodon.StockId, animatedIcon);
106
131
} catch (Exception ex) {
107
132
LoggingService.LogError (string.Format ("Error loading icon '{0}'", iconCodon.StockId), ex);
166
public static Gdk.Pixbuf MakeInverted (Gdk.Pixbuf icon)
168
if (icon.BitsPerSample != 8)
169
throw new NotSupportedException ();
170
Gdk.Pixbuf copy = icon.Copy ();
172
byte* pix = (byte*)copy.Pixels;
173
bool hasAlpha = copy.HasAlpha;
174
for (int y = 0; y < copy.Height; y++) {
176
for (int x = 0; x < copy.Width; x++) {
177
pix [0] = (byte)~pix [0];
178
pix [1] = (byte)~pix [1];
179
pix [2] = (byte)~pix [2];
180
pix += hasAlpha ? 4 : 3;
182
pix = start + copy.Rowstride;
141
188
public static Gdk.Pixbuf GetPixbuf (string name)
143
190
return GetPixbuf (name, Gtk.IconSize.Button);
154
201
LoggingService.LogWarning ("Empty icon requested. Stack Trace: " + Environment.NewLine + Environment.StackTrace);
155
202
return CreateColorBlock ("#FF0000", size);
205
// If this name refers to an icon defined in an extension point, the images for the icon will now be laoded
158
206
EnsureStockIconIsLoaded (name, size);
160
208
//if an icon name begins with '#', we assume it's a hex colour
161
209
if (name[0] == '#')
162
210
return CreateColorBlock (name, size);
164
string stockid = InternalGetStockId (name, size);
212
// Converts an image spec into a real stock icon id
213
string stockid = GetStockIdForImageSpec (name, size);
165
215
if (string.IsNullOrEmpty (stockid)) {
166
216
LoggingService.LogWarning ("Can't get stock id for " + name + " : " + Environment.NewLine + Environment.StackTrace);
167
217
return CreateColorBlock ("#FF0000", size);
374
427
public static string GetStockId (RuntimeAddin addin, string filename, Gtk.IconSize iconSize)
376
return InternalGetStockId (addin, filename, iconSize);
429
return GetStockIdForImageSpec (addin, filename, iconSize);
379
432
static void AddToIconFactory (string stockId, Gdk.Pixbuf pixbuf, Gtk.IconSize iconSize)
474
static string InternalGetStockIdFromAnimation (RuntimeAddin addin, string id, Gtk.IconSize size)
476
if (!id.StartsWith ("animation:"))
479
id = id.Substring (10);
480
Dictionary<string, string> hash;
484
addinId = GetAddinId (addin);
485
hash = addinIcons[addinId];
488
hash = iconSpecToStockId;
491
string stockId = "__asm" + addinId + "__" + id + "__" + size;
492
if (!hash.ContainsKey (stockId)) {
493
var aicon = new AnimatedIcon (addin, id, size);
494
AddToIconFactory (stockId, aicon.FirstFrame, size);
495
AddToAnimatedIconFactory (stockId, aicon);
496
hash[stockId] = stockId;
416
501
static int GetAddinId (RuntimeAddin addin)
418
503
int result = addins.IndexOf (addin);
472
static string InternalGetStockId (string filename, Gtk.IconSize size)
557
static string GetStockIdForImageSpec (string filename, Gtk.IconSize size)
474
return InternalGetStockId (null, filename, size);
559
return GetStockIdForImageSpec (null, filename, size);
477
static string InternalGetStockId (RuntimeAddin addin, string filename, Gtk.IconSize size)
562
static string GetStockIdForImageSpec (RuntimeAddin addin, string filename, Gtk.IconSize size)
479
564
if (filename.IndexOf ('|') == -1)
480
565
return PrivGetStockId (addin, filename, size);
491
576
if (addin != null && filename.StartsWith ("res:"))
492
577
return InternalGetStockIdFromResource (addin, filename, size);
579
if (filename.StartsWith ("animation:"))
580
return InternalGetStockIdFromAnimation (addin, filename, size);
585
public static bool IsAnimation (string iconId, Gtk.IconSize size)
587
EnsureStockIconIsLoaded (iconId, size);
588
string id = GetStockIdForImageSpec (iconId, size);
589
return animationFactory.ContainsKey (id);
592
public static AnimatedIcon GetAnimatedIcon (string iconId)
594
return GetAnimatedIcon (iconId, Gtk.IconSize.Button);
597
public static AnimatedIcon GetAnimatedIcon (string iconId, Gtk.IconSize size)
599
EnsureStockIconIsLoaded (iconId, size);
600
string id = GetStockIdForImageSpec (iconId, size);
603
animationFactory.TryGetValue (id, out aicon);
607
static List<WeakReference> animatedImages = new List<WeakReference> ();
609
class AnimatedImageInfo {
610
public Gtk.Image Image;
611
public AnimatedIcon AnimatedIcon;
612
public IDisposable Animation;
614
public AnimatedImageInfo (Gtk.Image img, AnimatedIcon anim)
618
img.Realized += HandleRealized;
619
img.Unrealized += HandleUnrealized;
620
img.Destroyed += HandleDestroyed;
625
void StartAnimation ()
627
if (Animation == null) {
628
Animation = AnimatedIcon.StartAnimation (delegate (Gdk.Pixbuf pix) {
634
void StopAnimation ()
636
if (Animation != null) {
637
Animation.Dispose ();
642
void HandleDestroyed (object sender, EventArgs e)
644
UnregisterImageAnimation (this);
647
void HandleUnrealized (object sender, EventArgs e)
652
void HandleRealized (object sender, EventArgs e)
657
public void Dispose ()
660
Image.Realized -= HandleRealized;
661
Image.Unrealized -= HandleUnrealized;
662
Image.Destroyed -= HandleDestroyed;
666
public static void LoadIcon (this Gtk.Image image, string iconId, Gtk.IconSize size)
668
AnimatedImageInfo ainfo = animatedImages.Select (a => (AnimatedImageInfo) a.Target).FirstOrDefault (a => a != null && a.Image == image);
670
if (ainfo.AnimatedIcon.AnimationSpec == iconId)
672
UnregisterImageAnimation (ainfo);
674
if (IsAnimation (iconId, size)) {
675
var anim = GetAnimatedIcon (iconId);
676
ainfo = new AnimatedImageInfo (image, anim);
677
ainfo.Animation = anim.StartAnimation (delegate (Gdk.Pixbuf pix) {
680
animatedImages.Add (new WeakReference (ainfo));
682
image.Pixbuf = GetPixbuf (iconId, size);
685
static void UnregisterImageAnimation (AnimatedImageInfo ainfo)
688
animatedImages.RemoveAll (a => (AnimatedImageInfo)a.Target == ainfo);