diff options
| author | MichaelTheShifter <[email protected]> | 2016-07-20 09:40:36 -0400 |
|---|---|---|
| committer | MichaelTheShifter <[email protected]> | 2016-07-20 09:40:36 -0400 |
| commit | d40fed5ce2bc806a91245adb18039634eac13ed0 (patch) | |
| tree | f1d7168aee6db109ac2c738ad18c9db667a6ba69 /source/ShiftUI/Internal/ImageList.cs | |
| parent | f1856e8ed30ed882229fd3fa2a4038122a5fb441 (diff) | |
| download | shiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.tar.gz shiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.tar.bz2 shiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.zip | |
Move ShiftUI source code to ShiftOS
This'll be a lot easier to work on.
Diffstat (limited to 'source/ShiftUI/Internal/ImageList.cs')
| -rw-r--r-- | source/ShiftUI/Internal/ImageList.cs | 1073 |
1 files changed, 1073 insertions, 0 deletions
diff --git a/source/ShiftUI/Internal/ImageList.cs b/source/ShiftUI/Internal/ImageList.cs new file mode 100644 index 0000000..b983455 --- /dev/null +++ b/source/ShiftUI/Internal/ImageList.cs @@ -0,0 +1,1073 @@ +// +// ShiftUI.ImageList.cs +// +// Authors: +// Peter Bartok <[email protected]> +// Kornél Pál <http://www.kornelpal.hu/> +// +// Copyright (C) 2004-2005 Novell, Inc. +// Copyright (C) 2005 Kornél Pál +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +// COMPLETE + +// +// Differences between MS.NET ImageList and this implementation: +// +// This is a fully managed image list implementation. +// +// Images are stored as Format32bppArgb internally but ColorDepth is applied +// to the colors of images. Images[index] returns a Format32bppArgb copy of +// the image so this difference is only internal. +// +// MS.NET has no alpha channel support (except for icons in 32-bit mode with +// comctl32.dll version 6.0) but this implementation has full alpha channel +// support in 32-bit mode. +// +// Handle should be an HIMAGELIST returned by ImageList_Create. This +// implementation uses (IntPtr)(-1) that is a non-zero but invalid handle. +// +// MS.NET destroys handles using the garbage collector this implementation +// does the same with Image objects stored in an ArrayList. +// +// MS.NET 1.x shares the same HIMAGELIST between ImageLists that were +// initialized from the same ImageListStreamer and doesn't update ImageSize +// and ColorDepth that are treated as bugs and MS.NET 2.0 behavior is +// implemented. +// +// MS.NET 2.0 does not clear keys when handle is destroyed that is treated as +// a bug. +// + +using System.Collections; +using System.Collections.Specialized; +using System.ComponentModel; +using System.ComponentModel.Design.Serialization; +using System.Drawing; +using System.Drawing.Design; +using System.Drawing.Imaging; +using System.Globalization; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [DefaultProperty("Images")] + //[Designer("ShiftUI.Design.ImageListDesigner, " + Consts.AssemblySystem_Design)] + //[DesignerSerializer("ShiftUI.Design.ImageListCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)] + [ToolboxItemFilter("ShiftUI")] + [TypeConverter(typeof(ImageListConverter))] + public sealed class ImageList : System.ComponentModel.Component + { + #region Private Fields + private const ColorDepth DefaultColorDepth = ColorDepth.Depth8Bit; + private static readonly Size DefaultImageSize = new Size(16, 16); + private static readonly Color DefaultTransparentColor = Color.Transparent; + private object tag; + private readonly ImageCollection images; + #endregion // Private Fields + + #region Sub-classes + //[Editor("ShiftUI.Design.ImageCollectionEditor, " + Consts.AssemblySystem_Design, typeof(UITypeEditor))] + public sealed class ImageCollection : IList, ICollection, IEnumerable + { + private const int AlphaMask = unchecked((int)0xFF000000); + + private static class IndexedColorDepths + { + internal static readonly ColorPalette Palette4Bit; + internal static readonly ColorPalette Palette8Bit; + private static readonly int[] squares; + + static IndexedColorDepths() + { + Bitmap bitmap; + int index; + + bitmap = new Bitmap(1, 1, PixelFormat.Format4bppIndexed); + Palette4Bit = bitmap.Palette; + bitmap.Dispose(); + + bitmap = new Bitmap(1, 1, PixelFormat.Format8bppIndexed); + Palette8Bit = bitmap.Palette; + bitmap.Dispose(); + + squares = new int[511]; + for (index = 0; index < 256; index++) + squares[255 + index] = squares[255 - index] = index * index; + } + + internal static int GetNearestColor(Color[] palette, int color) + { + int index; + int count; + int red; + int green; + int blue; + int nearestColor; + int minDistance; + int distance; + + count = palette.Length; + for (index = 0; index < count; index++) + if (palette[index].ToArgb() == color) + return color; + + red = unchecked((int)(unchecked((uint)color) >> 16) & 0xFF); + green = unchecked((int)(unchecked((uint)color) >> 8) & 0xFF); + blue = color & 0xFF; + nearestColor = AlphaMask; + minDistance = int.MaxValue; + + for (index = 0; index < count; index++) + if ((distance = squares[255 + palette[index].R - red] + squares[255 + palette[index].G - green] + squares[255 + palette[index].B - blue]) < minDistance) { + nearestColor = palette[index].ToArgb(); + minDistance = distance; + } + + return nearestColor; + } + } + + [Flags()] + private enum ItemFlags + { + None = 0, + UseTransparentColor = 1, + ImageStrip = 2 + } + + private sealed class ImageListItem + { + internal readonly object Image; + internal readonly ItemFlags Flags; + internal readonly Color TransparentColor; + internal readonly int ImageCount = 1; + + internal ImageListItem(Icon value) + { + if (value == null) + throw new ArgumentNullException("value"); + + // Icons are cloned. + this.Image = (Icon)value.Clone(); + } + + internal ImageListItem(Image value) + { + if (value == null) + throw new ArgumentNullException("value"); + + if (!(value is Bitmap)) + throw new ArgumentException("Image must be a Bitmap."); + + // Images are not cloned. + this.Image = value; + } + + internal ImageListItem(Image value, Color transparentColor) : this(value) + { + this.Flags = ItemFlags.UseTransparentColor; + this.TransparentColor = transparentColor; + } + + internal ImageListItem(Image value, int imageCount) : this(value) + { + this.Flags = ItemFlags.ImageStrip; + this.ImageCount = imageCount; + } + } + + #region ImageCollection Private Fields + private ColorDepth colorDepth = DefaultColorDepth; + private Size imageSize = DefaultImageSize; + private Color transparentColor = DefaultTransparentColor; + private ArrayList list = new ArrayList(); + private ArrayList keys = new ArrayList(); + private int count; + private bool handleCreated; + private int lastKeyIndex = -1; + private readonly ImageList owner; + #endregion // ImageCollection Private Fields + + #region ImageCollection Internal Constructors + // For use in ImageList + internal ImageCollection(ImageList owner) + { + this.owner = owner; + } + #endregion // ImageCollection Internal Constructor + + #region ImageCollection Internal Instance Properties + // For use in ImageList + internal ColorDepth ColorDepth { + get { + return this.colorDepth; + } + + set { + if (!Enum.IsDefined(typeof(ColorDepth), value)) + throw new InvalidEnumArgumentException("value", (int)value, typeof(ColorDepth)); + + if (this.colorDepth != value) { + this.colorDepth = value; + RecreateHandle(); + } + } + } + + // For use in ImageList + internal IntPtr Handle { + get { + CreateHandle(); + return (IntPtr)(-1); + } + } + + // For use in ImageList + internal bool HandleCreated { + get { + return this.handleCreated; + } + } + + // For use in ImageList + internal Size ImageSize { + get { + return this.imageSize; + } + + set { + if (value.Width < 1 || value.Width > 256 || value.Height < 1 || value.Height > 256) + throw new ArgumentException("ImageSize.Width and Height must be between 1 and 256", "value"); + + if (this.imageSize != value) { + this.imageSize = value; + RecreateHandle(); + } + } + } + + // For use in ImageList + internal ImageListStreamer ImageStream { + get { + return this.Empty ? null : new ImageListStreamer(this); + } + + set { + int index; + Image[] streamImages; + + if (value == null) { + if (this.handleCreated) + DestroyHandle(); + else + this.Clear(); + } + // Only deserialized ImageListStreamers are used. + else if ((streamImages = value.Images) != null) { + this.list = new ArrayList(streamImages.Length); + this.count = 0; + this.handleCreated = true; + this.keys = new ArrayList(streamImages.Length); + + for (index = 0; index < streamImages.Length; index++) { + list.Add((Image)streamImages[index].Clone()); + keys.Add(null); + } + + // Invalid ColorDepth values are ignored. + if (Enum.IsDefined(typeof(ColorDepth), value.ColorDepth)) + this.colorDepth = (ColorDepth)value.ColorDepth; + this.imageSize = value.ImageSize; + + // Event is raised even when handle was not created yet. + owner.OnRecreateHandle(); + } + } + } + + // For use in ImageList + internal Color TransparentColor { + get { + return this.transparentColor; + } + + set { + this.transparentColor = value; + } + } + #endregion // ImageCollection Internal Instance Properties + + #region ImageCollection Public Instance Properties + [Browsable(false)] + public int Count { + get { + return this.handleCreated ? list.Count : this.count; + } + } + + public bool Empty { + get { + return this.Count == 0; + } + } + + public bool IsReadOnly { + get { + return false; + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Image this[int index] { + get { + return (Image)GetImage(index).Clone(); + } + + set { + Image image; + + if (index < 0 || index >= this.Count) + throw new ArgumentOutOfRangeException("index"); + + if (value == null) + throw new ArgumentNullException("value"); + + if (!(value is Bitmap)) + throw new ArgumentException("Image must be a Bitmap."); + + image = CreateImage(value, this.transparentColor); + CreateHandle(); + list[index] = image; + } + } + + public Image this[string key] { + get { + int index; + + return (index = IndexOfKey(key)) == -1 ? null : this[index]; + } + } + + public StringCollection Keys { + get { + int index; + string key; + StringCollection keyCollection; + + // Returns all keys even when there are more keys than + // images. Null keys are returned as empty strings. + + keyCollection = new StringCollection(); + for (index = 0; index < keys.Count; index++) + keyCollection.Add(((key = (string)keys[index]) == null || key.Length == 0) ? string.Empty : key); + + return keyCollection; + } + } + #endregion // ImageCollection Public Instance Properties + + #region ImageCollection Private Static Methods + private static bool CompareKeys(string key1, string key2) + { + // Keys are case-insensitive and keys with different length + // are not equal even when string.Compare treats them equal. + + if (key1 == null || key2 == null || key1.Length != key2.Length) + return false; + + return string.Compare(key1, key2, true, CultureInfo.InvariantCulture) == 0; + } + #endregion // ImageCollection Private Static Methods + + #region ImageCollection Private Instance Methods + private int AddItem(string key, ImageListItem item) + { + int itemIndex; + int index; + + if (this.handleCreated) + itemIndex = AddItemInternal(item); + else { + // Image strips are counted as a single item in the return + // value of Add and AddStrip until handle is created. + + itemIndex = list.Add(item); + this.count += item.ImageCount; + } + + if ((item.Flags & ItemFlags.ImageStrip) == 0) + keys.Add(key); + else + for (index = 0; index < item.ImageCount; index++) + keys.Add(null); + + return itemIndex; + } + + internal event EventHandler Changed; + + private int AddItemInternal(ImageListItem item) + { + if (Changed != null) + Changed (this, EventArgs.Empty); + + if (item.Image is Icon) { + int imageWidth; + int imageHeight; + Bitmap bitmap; + Graphics graphics; + + bitmap = new Bitmap(imageWidth = this.imageSize.Width, imageHeight = this.imageSize.Height, PixelFormat.Format32bppArgb); + graphics = Graphics.FromImage(bitmap); + graphics.DrawIcon((Icon)item.Image, new Rectangle(0, 0, imageWidth, imageHeight)); + graphics.Dispose(); + + ReduceColorDepth(bitmap); + return list.Add(bitmap); + } + else if ((item.Flags & ItemFlags.ImageStrip) == 0) + return list.Add(CreateImage((Image)item.Image, (item.Flags & ItemFlags.UseTransparentColor) == 0 ? this.transparentColor : item.TransparentColor)); + else { + int imageX; + int width; + int imageWidth; + int imageHeight; + int index; + Image image; + Bitmap bitmap; + Graphics graphics; + Rectangle imageRect; + ImageAttributes imageAttributes; + + // When ImageSize was changed after adding image strips + // Count will return invalid values based on old ImageSize + // but when creating handle either ArgumentException will + // be thrown or image strip will be added according to the + // new ImageSize. This can result in image count + // difference that can result in exceptions in methods + // that use Count before creating handle. In addition this + // can result in the loss of sync with keys. When doing + // the same after handle was created there are no problems + // as handle will be recreated after changing ImageSize + // that results in the loss of images added previously. + + if ((width = (image = (Image)item.Image).Width) == 0 || (width % (imageWidth = this.imageSize.Width)) != 0) + throw new ArgumentException("Width of image strip must be a positive multiple of ImageSize.Width.", "value"); + + if (image.Height != (imageHeight = this.imageSize.Height)) + throw new ArgumentException("Height of image strip must be equal to ImageSize.Height.", "value"); + + imageRect = new Rectangle(0, 0, imageWidth, imageHeight); + if (this.transparentColor.A == 0) + imageAttributes = null; + else { + imageAttributes = new ImageAttributes(); + imageAttributes.SetColorKey(this.transparentColor, this.transparentColor); + } + + index = list.Count; + for (imageX = 0; imageX < width; imageX += imageWidth) { + bitmap = new Bitmap(imageWidth, imageHeight, PixelFormat.Format32bppArgb); + graphics = Graphics.FromImage(bitmap); + graphics.DrawImage(image, imageRect, imageX, 0, imageWidth, imageHeight, GraphicsUnit.Pixel, imageAttributes); + graphics.Dispose(); + + ReduceColorDepth(bitmap); + list.Add(bitmap); + } + + if (imageAttributes != null) + imageAttributes.Dispose(); + + return index; + } + } + + private void CreateHandle() + { + int index; + ArrayList items; + + if (!this.handleCreated) { + items = this.list; + this.list = new ArrayList(this.count); + this.count = 0; + this.handleCreated = true; + + for (index = 0; index < items.Count; index++) + AddItemInternal((ImageListItem)items[index]); + } + } + + private Image CreateImage(Image value, Color transparentColor) + { + int imageWidth; + int imageHeight; + ImageAttributes imageAttributes; + + if (transparentColor.A == 0) + imageAttributes = null; + else { + imageAttributes = new ImageAttributes(); + imageAttributes.SetColorKey (transparentColor, transparentColor); + } + + var bitmap = new Bitmap (imageWidth = this.imageSize.Width, imageHeight = this.imageSize.Height, PixelFormat.Format32bppArgb); + using (var graphics = Graphics.FromImage (bitmap)) + graphics.DrawImage (value, new Rectangle(0, 0, imageWidth, imageHeight), 0, 0, value.Width, value.Height, GraphicsUnit.Pixel, imageAttributes); + + if (imageAttributes != null) + imageAttributes.Dispose (); + + ReduceColorDepth (bitmap); + return bitmap; + } + + private void RecreateHandle() + { + if (this.handleCreated) { + DestroyHandle(); + this.handleCreated = true; + owner.OnRecreateHandle(); + } + } + + private unsafe void ReduceColorDepth(Bitmap bitmap) + { + byte* pixelPtr; + byte* lineEndPtr; + byte* linePtr; + int line; + int pixel; + int height; + int widthBytes; + int stride; + BitmapData bitmapData; + Color[] palette; + + if (this.colorDepth < ColorDepth.Depth32Bit) { + bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + try { + linePtr = (byte*)bitmapData.Scan0; + height = bitmapData.Height; + widthBytes = bitmapData.Width << 2; + stride = bitmapData.Stride; + + if (this.colorDepth < ColorDepth.Depth16Bit) { + palette = (this.colorDepth < ColorDepth.Depth8Bit ? IndexedColorDepths.Palette4Bit : IndexedColorDepths.Palette8Bit).Entries; + + for (line = 0; line < height; line++) { + lineEndPtr = linePtr + widthBytes; + for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4) + *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : IndexedColorDepths.GetNearestColor(palette, pixel | AlphaMask); + linePtr += stride; + } + } + else if (this.colorDepth < ColorDepth.Depth24Bit) { + for (line = 0; line < height; line++) { + lineEndPtr = linePtr + widthBytes; + for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4) + *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : (pixel & 0x00F8F8F8) | AlphaMask; + linePtr += stride; + } + } + else { + for (line = 0; line < height; line++) { + lineEndPtr = linePtr + widthBytes; + for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4) + *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : pixel | AlphaMask; + linePtr += stride; + } + } + } + finally { + bitmap.UnlockBits(bitmapData); + } + } + } + #endregion // ImageCollection Private Instance Methods + + #region ImageCollection Internal Instance Methods + // For use in ImageList + internal void DestroyHandle() + { + if (this.handleCreated) { + this.list = new ArrayList(); + this.count = 0; + this.handleCreated = false; + keys = new ArrayList(); + } + } + + // For use in ImageList + internal Image GetImage(int index) + { + if (index < 0 || index >= this.Count) + throw new ArgumentOutOfRangeException("index"); + + CreateHandle(); + return (Image)list[index]; + } + + // For use in ImageListStreamer + internal Image[] ToArray() + { + Image[] images; + + // Handle is created even when the list is empty. + CreateHandle(); + images = new Image[list.Count]; + list.CopyTo(images); + return images; + } + #endregion // ImageCollection Internal Instance Methods + + #region ImageCollection Public Instance Methods + public void Add(Icon value) + { + Add(null, value); + } + + public void Add(Image value) + { + Add(null, value); + } + + public int Add(Image value, Color transparentColor) + { + return AddItem(null, new ImageListItem(value, transparentColor)); + } + + public void Add(string key, Icon icon) + { + // Argument has name icon but exceptions use name value. + AddItem(key, new ImageListItem(icon)); + } + + public void Add(string key, Image image) + { + // Argument has name image but exceptions use name value. + AddItem(key, new ImageListItem(image)); + } + + public void AddRange(Image[] images) + { + int index; + + if (images == null) + throw new ArgumentNullException("images"); + + for (index = 0; index < images.Length; index++) + Add(images[index]); + } + + public int AddStrip(Image value) + { + int width; + int imageWidth; + + if (value == null) + throw new ArgumentNullException("value"); + + if ((width = value.Width) == 0 || (width % (imageWidth = this.imageSize.Width)) != 0) + throw new ArgumentException("Width of image strip must be a positive multiple of ImageSize.Width.", "value"); + + if (value.Height != this.imageSize.Height) + throw new ArgumentException("Height of image strip must be equal to ImageSize.Height.", "value"); + + return AddItem(null, new ImageListItem(value, width / imageWidth)); + } + + public void Clear() + { + list.Clear(); + if (!this.handleCreated) + this.count = 0; + keys.Clear(); + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public bool Contains(Image image) + { + throw new NotSupportedException(); + } + + public bool ContainsKey(string key) + { + return IndexOfKey(key) != -1; + } + + public IEnumerator GetEnumerator() + { + Image[] images = new Image[this.Count]; + int index; + + if (images.Length != 0) { + // Handle is created only when there are images. + CreateHandle(); + + for (index = 0; index < images.Length; index++) + images[index] = (Image)((Image)list[index]).Clone(); + } + + return images.GetEnumerator(); + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public int IndexOf(Image image) + { + throw new NotSupportedException(); + } + + public int IndexOfKey(string key) + { + int index; + + if (key != null && key.Length != 0) { + // When last IndexOfKey was successful and the same key was + // assigned to an image with a lower index than the last + // result and the key of the last result equals to key + // argument the last result is returned. + + if (this.lastKeyIndex >= 0 && this.lastKeyIndex < this.Count && CompareKeys((string)keys[this.lastKeyIndex], key)) + return this.lastKeyIndex; + + // Duplicate keys are allowed and first match is returned. + for (index = 0; index < this.Count; index++) + if (CompareKeys((string)keys[index], key)) + return this.lastKeyIndex = index; + } + + return this.lastKeyIndex = -1; + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public void Remove(Image image) + { + throw new NotSupportedException(); + } + + public void RemoveAt(int index) + { + if (index < 0 || index >= this.Count) + throw new ArgumentOutOfRangeException("index"); + + CreateHandle(); + list.RemoveAt(index); + keys.RemoveAt(index); + if (Changed != null) + Changed (this, EventArgs.Empty); + } + + public void RemoveByKey(string key) + { + int index; + + if ((index = IndexOfKey(key)) != -1) + RemoveAt(index); + } + + public void SetKeyName(int index, string name) + { + // Only SetKeyName throws IndexOutOfRangeException. + if (index < 0 || index >= this.Count) + throw new IndexOutOfRangeException(); + + keys[index] = name; + } + #endregion // ImageCollection Public Instance Methods + + #region ImageCollection Interface Properties + object IList.this[int index] { + get { + return this[index]; + } + + set { + if (!(value is Image)) + throw new ArgumentException("value"); + + this[index] = (Image)value; + } + } + + bool IList.IsFixedSize { + get { + return false; + } + } + + bool ICollection.IsSynchronized { + get { + return false; + } + } + + object ICollection.SyncRoot { + get { + return this; + } + } + #endregion // ImageCollection Interface Properties + + #region ImageCollection Interface Methods + int IList.Add(object value) + { + int index; + + if (!(value is Image)) + throw new ArgumentException("value"); + + index = this.Count; + this.Add((Image)value); + return index; + } + + bool IList.Contains(object image) + { + return image is Image ? this.Contains ((Image) image) : false; + } + + int IList.IndexOf (object image) + { + return image is Image ? this.IndexOf ((Image) image) : -1; + } + + void IList.Insert(int index, object value) + { + throw new NotSupportedException(); + } + + void IList.Remove (object image) + { + if (image is Image) + this.Remove ((Image) image); + } + + void ICollection.CopyTo(Array dest, int index) + { + for (int imageIndex = 0; imageIndex < this.Count; imageIndex++) + dest.SetValue (this[imageIndex], index++); + } + #endregion // ImageCollection Interface Methods + } + #endregion // Sub-classes + + #region Public Constructors + public ImageList() + { + images = new ImageCollection(this); + } + + public ImageList(System.ComponentModel.IContainer container) : this() + { + container.Add(this); + } + #endregion // Public Constructors + + #region Private Instance Methods + private void OnRecreateHandle() + { + EventHandler eh = (EventHandler)(Events [RecreateHandleEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + // MS's TypeDescriptor stuff apparently uses + // non-public ShouldSerialize* methods, because it + // picks up this behavior even though the methods + // aren't public. we can't make them private, though, + // without adding compiler warnings. so, make then + // internal instead. + + internal bool ShouldSerializeTransparentColor () + { + return this.TransparentColor != Color.LightGray; + } + + internal bool ShouldSerializeColorDepth() + { + // ColorDepth is serialized in ImageStream when non-empty. + // It is serialized even if it has its default value when empty. + return images.Empty; + } + + internal bool ShouldSerializeImageSize() + { + // ImageSize is serialized in ImageStream when non-empty. + // It is serialized even if it has its default value when empty. + return images.Empty; + } + + internal void ResetColorDepth () + { + this.ColorDepth = DefaultColorDepth; + } + + internal void ResetImageSize () + { + this.ImageSize = DefaultImageSize; + } + + internal void ResetTransparentColor () + { + this.TransparentColor = Color.LightGray; + } + #endregion // Private Instance Methods + + #region Public Instance Properties + public ColorDepth ColorDepth { + get { + return images.ColorDepth; + } + + set { + images.ColorDepth = value; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IntPtr Handle { + get { + return images.Handle; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool HandleCreated { + get { + return images.HandleCreated; + } + } + + [DefaultValue(null)] + [MergableProperty(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ImageCollection Images { + get { + return this.images; + } + } + + [Localizable(true)] + public Size ImageSize { + get { + return images.ImageSize; + } + + set { + images.ImageSize = value; + } + } + + [Browsable(false)] + [DefaultValue(null)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public ImageListStreamer ImageStream { + get { + return images.ImageStream; + } + + set { + images.ImageStream = value; + } + } + + [Bindable(true)] + [DefaultValue(null)] + [Localizable(false)] + [TypeConverter(typeof(StringConverter))] + public object Tag { + get { + return this.tag; + } + + set { + this.tag = value; + } + } + + public Color TransparentColor { + get { + return images.TransparentColor; + } + + set { + images.TransparentColor = value; + } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + public void Draw(Graphics g, Point pt, int index) + { + this.Draw(g, pt.X, pt.Y, index); + } + + public void Draw(Graphics g, int x, int y, int index) + { + g.DrawImage(images.GetImage(index), x, y); + } + + public void Draw(Graphics g, int x, int y, int width, int height, int index) + { + g.DrawImage(images.GetImage(index), x, y, width, height); + } + + public override string ToString() + { + return base.ToString() + " Images.Count: " + images.Count.ToString() + ", ImageSize: " + this.ImageSize.ToString(); + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override void Dispose(bool disposing) + { + if (disposing) + images.DestroyHandle(); + + base.Dispose(disposing); + } + #endregion // Protected Instance Methods + + #region Events + static object RecreateHandleEvent = new object (); + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public event EventHandler RecreateHandle { + add { Events.AddHandler (RecreateHandleEvent, value); } + remove { Events.RemoveHandler (RecreateHandleEvent, value); } + } + #endregion // Events + } +} |
