ImageStrip.cs :  » GUI » Paint.net » PaintDotNet » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » GUI » Paint.net 
Paint.net » PaintDotNet » ImageStrip.cs
/////////////////////////////////////////////////////////////////////////////////
// Paint.NET                                                                   //
// Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors.     //
// Portions Copyright (C) Microsoft Corporation. All Rights Reserved.          //
// See src/Resources/Files/License.txt for full licensing and attribution      //
// details.                                                                    //
// .                                                                           //
/////////////////////////////////////////////////////////////////////////////////

using PaintDotNet.SystemLayer;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

namespace PaintDotNet{
    /*
     * Coordinate spaces:
     * 
     * - Client -- This is the same as the Windows client space.
     * - Screen -- This is the same as the Windows screen space.
     * - View   -- This is a virtual coordinate in the viewable, scrollable area. Client->View is defined as Client.X+ScrollOffset. View->Client is View.X-ScrollOffset
     * - Item   -- This is relative to an item. Item->View is Item.X+(itemIndex * ItemViewSize.Width)
     * 
     * */

    public class ImageStrip
        : Control
    {
        public enum ItemPart
        {
            None,
            Image,
            CloseButton
        }

        public sealed class Item
        {
            private PushButtonState imageRenderState;
            private Image image;

            private bool selected;

            private PushButtonState checkRenderState;
            private CheckState checkState;

            private PushButtonState closeRenderState;

            private bool dirty;

            private bool lockedDirtyValue;
            private int dirtyValueLockCount = 0;

            private object tag;

            public event EventHandler Changed;
            private void OnChanged()
            {
                if (Changed != null)
                {
                    Changed(this, EventArgs.Empty);
                }
            }

            public Image Image
            {
                get
                {
                    return this.image;
                }

                set
                {
                    this.image = value;
                    OnChanged();
                }
            }

            public PushButtonState ImageRenderState
            {
                get
                {
                    return this.imageRenderState;
                }

                set
                {
                    if (this.imageRenderState != value)
                    {
                        this.imageRenderState = value;
                        OnChanged();
                    }
                }
            }

            public bool Selected
            {
                get
                {
                    return this.selected;
                }

                set
                {
                    if (this.selected != value)
                    {
                        this.selected = value;
                        OnChanged();
                    }
                }
            }

            public bool Dirty
            {
                get
                {
                    if (this.dirtyValueLockCount > 0)
                    {
                        return this.lockedDirtyValue;
                    }
                    else
                    {
                        return this.dirty;
                    }
                }

                set
                {
                    if (this.dirty != value)
                    {
                        this.dirty = value;

                        if (this.dirtyValueLockCount <= 0)
                        {
                            OnChanged();
                        }
                    }
                }
            }

            public void LockDirtyValue(bool forceValue)
            {
                ++this.dirtyValueLockCount;

                if (this.dirtyValueLockCount == 1)
                {
                    this.lockedDirtyValue = forceValue;
                }
            }

            public void UnlockDirtyValue()
            {
                --this.dirtyValueLockCount;

                if (this.dirtyValueLockCount == 0)
                {
                    OnChanged();
                }
                else if (this.dirtyValueLockCount < 0)
                {
                    throw new InvalidOperationException("Calls to UnlockDirtyValue() must be matched by a preceding call to LockDirtyValue()");
                }
            }

            public bool Checked
            {
                get
                {
                    return (CheckState == CheckState.Checked);
                }

                set
                {
                    if (value)
                    {
                        CheckState = CheckState.Checked;
                    }
                    else
                    {
                        CheckState = CheckState.Unchecked;
                    }
                }
            }

            public CheckState CheckState
            {
                get
                {
                    return this.checkState;
                }

                set
                {
                    if (this.checkState != value)
                    {
                        this.checkState = value;
                        OnChanged();
                    }
                }
            }

            public PushButtonState CheckRenderState
            {
                get
                {
                    return this.checkRenderState;
                }

                set
                {
                    if (this.checkRenderState != value)
                    {
                        this.checkRenderState = value;
                        OnChanged();
                    }
                }
            }

            public PushButtonState CloseRenderState
            {
                get
                {
                    return this.closeRenderState;
                }

                set
                {
                    if (this.closeRenderState != value)
                    {
                        this.closeRenderState = value;
                        OnChanged();
                    }
                }
            }

            public void SetPartRenderState(ItemPart itemPart, PushButtonState renderState)
            {
                switch (itemPart)
                {
                    case ItemPart.None:
                        break;

                    case ItemPart.CloseButton:
                        CloseRenderState = renderState;
                        break;

                    case ItemPart.Image:
                        ImageRenderState = renderState;
                        break;

                    default:
                        throw new InvalidEnumArgumentException();
                }
            }

            public object Tag
            {
                get
                {
                    return this.tag;
                }

                set
                {
                    this.tag = value;
                    OnChanged();
                }
            }

            public void Update()
            {
                OnChanged();
            }

            public Item()
            {
            }

            public Item(Image image)
            {
                this.image = image;
            }
        }

        private bool managedFocus = false;
        private bool showScrollButtons = false;
        private ArrowButton leftScrollButton;
        private ArrowButton rightScrollButton;

        private int scrollOffset = 0;
        private bool showCloseButtons = false;
        private const int closeButtonLength = 13;
        private int imagePadding = 2;
        private int closeButtonPadding = 2;

        private int mouseOverIndex = -1;
        private ItemPart mouseOverItemPart = ItemPart.None;
        private bool mouseOverApplyRendering = false;

        private int mouseDownIndex = -1;
        private MouseButtons mouseDownButton = MouseButtons.None;
        private ItemPart mouseDownItemPart = ItemPart.None;
        private bool mouseDownApplyRendering = false;

        private bool drawShadow = true;
        private bool drawDirtyOverlay = true;

        public bool DrawShadow
        {
            get
            {
                return this.drawShadow;
            }

            set
            {
                if (this.drawShadow != value)
                {
                    this.drawShadow = value;
                    Refresh();
                }
            }
        }

        public bool DrawDirtyOverlay
        {
            get
            {
                return this.drawDirtyOverlay;
            }

            set
            {
                if (this.drawDirtyOverlay != value)
                {
                    this.drawDirtyOverlay = value;
                    Refresh();
                }
            }
        }

        // This is done as an optimization: otherwise we're getting flooded with MouseMove events
        // and constantly refreshing our rendering. So CPU usage goes to heck.
        private Point lastMouseMovePt = new Point(-32000, -32000); 

        private List<Item> items = new List<Item>();

        protected ArrowButton LeftScrollButton
        {
            get
            {
                return this.leftScrollButton;
            }
        }

        protected ArrowButton RightScrollButton
        {
            get
            {
                return this.rightScrollButton;
            }
        }

        private void MouseStatesToItemStates()
        {
            UI.SuspendControlPainting(this);

            for (int i = 0; i < this.items.Count; ++i)
            {
                this.items[i].CheckRenderState = PushButtonState.Normal;
                this.items[i].CloseRenderState = PushButtonState.Normal;
                this.items[i].ImageRenderState = PushButtonState.Normal;
                this.items[i].Selected = false;
            }

            if (this.mouseDownApplyRendering)
            {
                if (this.mouseDownIndex < 0 || this.mouseDownIndex >= this.items.Count)
                {
                    this.mouseDownApplyRendering = false;
                }
                else
                {
                    this.items[this.mouseDownIndex].SetPartRenderState(this.mouseDownItemPart, PushButtonState.Pressed);
                    this.items[this.mouseDownIndex].Selected = true;
                }
            }
            else if (this.mouseOverApplyRendering)
            {
                if (this.mouseOverIndex < 0 || this.mouseOverIndex >= this.items.Count)
                {
                    this.mouseOverApplyRendering = false;
                }
                else
                {
                    this.items[this.mouseOverIndex].SetPartRenderState(this.mouseOverItemPart, PushButtonState.Hot);
                    this.items[this.mouseOverIndex].Selected = true;
                }
            }

            UI.ResumeControlPainting(this);
            Invalidate();
        }

        public ImageStrip()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.Selectable, false);

            DoubleBuffered = true;
            ResizeRedraw = true;

            InitializeComponent();
        }

        private void InitializeComponent()
        {
            this.leftScrollButton = new ArrowButton();
            this.rightScrollButton = new ArrowButton();
            SuspendLayout();
            //
            // leftScrollButton
            //
            this.leftScrollButton.Name = "leftScrollButton";
            this.leftScrollButton.ArrowDirection = ArrowDirection.Left;
            this.leftScrollButton.ArrowOutlineWidth = 1.0f;
            this.leftScrollButton.Click += new EventHandler(LeftScrollButton_Click);
            this.leftScrollButton.DrawWithGradient = true;
            //
            // rightScrollButton
            //
            this.rightScrollButton.Name = "rightScrollButton";
            this.rightScrollButton.ArrowDirection = ArrowDirection.Right;
            this.rightScrollButton.ArrowOutlineWidth = 1.0f;
            this.rightScrollButton.Click += new EventHandler(RightScrollButton_Click);
            this.rightScrollButton.DrawWithGradient = true;
            //
            // ImageStrip
            //
            this.Name = "ImageStrip";
            this.TabStop = false;
            this.Controls.Add(this.leftScrollButton);
            this.Controls.Add(this.rightScrollButton);
            ResumeLayout();
            PerformLayout();
        }

        public event EventHandler<EventArgs<ArrowDirection>> ScrollArrowClicked;
        protected virtual void OnScrollArrowClicked(ArrowDirection arrowDirection)
        {
            if (ScrollArrowClicked != null)
            {
                ScrollArrowClicked(this, new EventArgs<ArrowDirection>(arrowDirection));
            }
        }

        private void LeftScrollButton_Click(object sender, EventArgs e)
        {
            Focus();
            OnScrollArrowClicked(ArrowDirection.Left);
        }

        private void RightScrollButton_Click(object sender, EventArgs e)
        {
            Focus();
            OnScrollArrowClicked(ArrowDirection.Right);
        }

        /// <summary>
        /// This event is raised when this control wishes to relinquish focus.
        /// </summary>
        public event EventHandler RelinquishFocus;

        private void OnRelinquishFocus()
        {
            if (RelinquishFocus != null)
            {
                RelinquishFocus(this, EventArgs.Empty);
            }
        }   
        
        /// <summary>
        /// Gets or sets whether the control manages focus.
        /// </summary>
        /// <remarks>
        /// If this is true, the toolstrip will capture focus when the mouse enters its client area. It will then
        /// relinquish focus (via the RelinquishFocus event) when the mouse leaves. It will not capture or
        /// attempt to relinquish focus if MenuStripEx.IsAnyMenuActive returns true.
        /// </remarks>
        public bool ManagedFocus
        {
            get
            {
                return this.managedFocus;
            }

            set
            {
                this.managedFocus = value;
            }
        }

        public void AddItem(Item newItem)
        {
            if (this.items.Contains(newItem))
            {
                throw new ArgumentException("newItem was already added to this control");
            }

            newItem.Changed += Item_Changed;
            this.items.Add(newItem);

            PerformLayout();
            Invalidate();
        }

        public void RemoveItem(Item item)
        {
            if (!this.items.Contains(item))
            {
                throw new ArgumentException("item was never added to this control");
            }

            item.Changed -= Item_Changed;
            this.items.Remove(item);

            PerformLayout();
            Invalidate();
        }

        public void ClearItems()
        {
            SuspendLayout();
            UI.SuspendControlPainting(this);

            while (this.items.Count > 0)
            {
                RemoveItem(this.items[this.items.Count - 1]);
            }

            UI.ResumeControlPainting(this);
            ResumeLayout(true);

            Invalidate();
        }

        private void Item_Changed(object sender, EventArgs e)
        {
            Invalidate();
        }

        /// <summary>
        /// Raised when an item is clicked on.
        /// </summary>
        /// <remarks>
        /// e.Data.First is a reference to the Item. 
        /// e.Data.Second is the ItemPart.
        /// e.Data.Third is the MouseButtons that was used to click on the ItemPart.
        /// </remarks>
        public event EventHandler<EventArgs<Triple<Item, ItemPart, MouseButtons>>> ItemClicked;
        protected virtual void OnItemClicked(Item item, ItemPart itemPart, MouseButtons mouseButtons)
        {
            if (ItemClicked != null)
            {
                ItemClicked(this, new EventArgs<Triple<Item, ItemPart, MouseButtons>>(
                    Triple.Create(item, itemPart, mouseButtons)));
            }
        }

        public void PerformItemClick(int itemIndex, ItemPart itemPart, MouseButtons mouseButtons)
        {
            PerformItemClick(this.items[itemIndex], itemPart, mouseButtons);
        }

        public void PerformItemClick(Item item, ItemPart itemPart, MouseButtons mouseButtons)
        {
            OnItemClicked(item, itemPart, mouseButtons);
        }

        public Item[] Items
        {
            get
            {
                return this.items.ToArray();
            }
        }

        public int ItemCount
        {
            get
            {
                return this.items.Count;
            }
        }

        public bool ShowScrollButtons
        {
            get
            {
                return this.showScrollButtons;
            }

            set
            {
                if (this.showScrollButtons != value)
                {
                    this.showScrollButtons = value;
                    PerformLayout();
                    Invalidate(true);
                }
            }
        }

        public int MinScrollOffset
        {
            get
            {
                return 0;
            }
        }

        public int MaxScrollOffset
        {
            get
            {
                Size itemSize = ItemSize;

                int itemsLength = itemSize.Width * this.items.Count;
                int viewLength = itemsLength - ClientSize.Width;
                int maxScrollOffset = Math.Max(0, viewLength);
                return maxScrollOffset;
            }
        }

        public int ScrollOffset
        {
            get
            {
                return this.scrollOffset;
            }

            set
            {
                int clampedValue = Utility.Clamp(value, MinScrollOffset, MaxScrollOffset);

                if (this.scrollOffset != clampedValue)
                {
                    this.scrollOffset = clampedValue;
                    OnScrollOffsetChanged();
                    Invalidate(true);
                }
            }
        }

        public event EventHandler ScrollOffsetChanged;
        protected virtual void OnScrollOffsetChanged()
        {
            PerformLayout();

            if (ScrollOffsetChanged != null)
            {
                ScrollOffsetChanged(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Gets the viewable area, in View coordinate space.
        /// </summary>
        public Rectangle ViewRectangle
        {
            get
            {
                Size itemSize = ItemSize;
                return new Rectangle(0, 0, itemSize.Width * ItemCount, itemSize.Height);
            }
        }

        protected override void OnLayout(LayoutEventArgs levent)
        {
            int arrowWidth = UI.ScaleWidth(16);

            ScrollOffset = Utility.Clamp(this.scrollOffset, MinScrollOffset, MaxScrollOffset);

            // Determine arrow visibility / position
            this.leftScrollButton.Size = new Size(arrowWidth, ClientSize.Height);
            this.leftScrollButton.Location = new Point(0, 0);

            this.rightScrollButton.Size = new Size(arrowWidth, ClientSize.Height);
            this.rightScrollButton.Location = new Point(ClientSize.Width - this.rightScrollButton.Width, 0);

            bool showEitherButton = this.showScrollButtons && (this.ViewRectangle.Width > ClientRectangle.Width);
            bool showRightButton = (this.scrollOffset < MaxScrollOffset) && showEitherButton;
            bool showLeftButton = (this.scrollOffset > MinScrollOffset) && showEitherButton;

            this.rightScrollButton.Enabled = showRightButton;
            this.rightScrollButton.Visible = showRightButton;
            this.leftScrollButton.Enabled = showLeftButton;
            this.leftScrollButton.Visible = showLeftButton;

            base.OnLayout(levent);
        }

        public bool ShowCloseButtons
        {
            get
            {
                return this.showCloseButtons;
            }

            set
            {
                if (this.showCloseButtons != value)
                {
                    this.showCloseButtons = value;
                    PerformLayout();
                    Invalidate();
                }
            }
        }

        public int PreferredMinClientWidth
        {
            get
            {
                if (this.items.Count == 0)
                {
                    return 0;
                }

                int minWidth = ItemSize.Width;

                if (this.leftScrollButton.Visible || this.rightScrollButton.Visible)
                {
                    minWidth += this.leftScrollButton.Width;
                    minWidth += this.rightScrollButton.Width;
                }

                minWidth = Math.Min(minWidth, ViewRectangle.Width);

                return minWidth;
            }
        }

        public Size PreferredImageSize
        {
            get
            {
                Rectangle itemRect;
                Rectangle imageRect;

                MeasureItemPartRectangles(out itemRect, out imageRect);
                return new Size(imageRect.Width - imagePadding * 2, imageRect.Height - imagePadding * 2);
            }
        }

        public Size ItemSize
        {
            get
            {
                Rectangle itemRect;
                Rectangle imageRect;

                MeasureItemPartRectangles(out itemRect, out imageRect);
                return itemRect.Size;
            }
        }

        protected virtual void DrawItemBackground(Graphics g, Item item, Rectangle itemRect)
        {
        }

        protected virtual void DrawItemHighlight(
            Graphics g, 
            Item item, 
            Rectangle itemRect, 
            Rectangle highlightRect)
        {
            Color backFillColor;
            Color outlineColor;

            if (item.Checked)
            {
                backFillColor = Color.FromArgb(192, SystemColors.Highlight);
                outlineColor = backFillColor;
            }
            else if (item.Selected)
            {
                backFillColor = Color.FromArgb(64, SystemColors.HotTrack);
                outlineColor = Color.FromArgb(64, SystemColors.HotTrack);
            }
            else
            {
                backFillColor = Color.Transparent;
                outlineColor = Color.Transparent;
            }

            using (SolidBrush backFillBrush = new SolidBrush(backFillColor))
            {
                g.FillRectangle(backFillBrush, highlightRect);
            }

            using (Pen outlinePen = new Pen(outlineColor))
            {
                g.DrawRectangle(outlinePen, highlightRect.X, highlightRect.Y, highlightRect.Width - 1, highlightRect.Height - 1);
            }
        }

        protected virtual void DrawItemCloseButton(
            Graphics g, 
            Item item, 
            Rectangle itemRect, 
            Rectangle closeButtonRect)
        {
            if (item.Checked && item.Selected)
            {
                const string resourceNamePrefix = "Images.ImageStrip.CloseButton.";
                const string resourceNameSuffix = ".png";
                string resourceNameInfix = item.CloseRenderState.ToString();

                string resourceName = resourceNamePrefix + resourceNameInfix + resourceNameSuffix;

                ImageResource imageResource = PdnResources.GetImageResource(resourceName);
                Image image = imageResource.Reference;

                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;

                g.DrawImage(image, closeButtonRect, new Rectangle(0, 0, image.Width, image.Width), GraphicsUnit.Pixel);
            }
        }

        protected virtual void DrawItemDirtyOverlay(
            Graphics g,
            Item item,
            Rectangle itemRect,
            Rectangle dirtyOverlayRect)
        {
            Color outerPenColor = Color.White;
            Color innerPenColor = Color.Orange;

            const int xInset = 2;
            int scaledXInset = UI.ScaleWidth(xInset);

            const float outerPenWidth = 4.0f;
            const float innerPenWidth = 2.0f;

            float scaledOuterPenWidth = UI.ScaleWidth(outerPenWidth);
            float scaledInnerPenWidth = UI.ScaleWidth(innerPenWidth);

            SmoothingMode oldSM = g.SmoothingMode;
            g.SmoothingMode = SmoothingMode.AntiAlias;

            int left = dirtyOverlayRect.Left + scaledXInset;
            int top = dirtyOverlayRect.Top + scaledXInset;
            int right = dirtyOverlayRect.Right - scaledXInset;
            int bottom = dirtyOverlayRect.Bottom - scaledXInset;

            float r = Math.Min((right - left) / 2.0f, (bottom - top) / 2.0f);

            PointF centerPt = new PointF((left + right) / 2.0f, (top + bottom) / 2.0f);
            float twoPiOver5 = (float)(Math.PI * 0.4);

            PointF a = new PointF(centerPt.X + r * (float)Math.Sin(twoPiOver5), centerPt.Y - r * (float)Math.Cos(twoPiOver5));
            PointF b = new PointF(centerPt.X + r * (float)Math.Sin(2 * twoPiOver5), centerPt.Y - r * (float)Math.Cos(2 * twoPiOver5));
            PointF c = new PointF(centerPt.X + r * (float)Math.Sin(3 * twoPiOver5), centerPt.Y - r * (float)Math.Cos(3 * twoPiOver5));
            PointF d = new PointF(centerPt.X + r * (float)Math.Sin(4 * twoPiOver5), centerPt.Y - r * (float)Math.Cos(4 * twoPiOver5));
            PointF e = new PointF(centerPt.X + r * (float)Math.Sin(5 * twoPiOver5), centerPt.Y - r * (float)Math.Cos(5 * twoPiOver5));

            PointF[] lines =
                new PointF[]
                {
                    centerPt, a,
                    centerPt, b,
                    centerPt, c,
                    centerPt, d,
                    centerPt, e
                }; 

            using (Pen outerPen = new Pen(outerPenColor, scaledOuterPenWidth))
            {
                for (int i = 0; i < lines.Length; i += 2)
                {
                    g.DrawLine(outerPen, lines[i], lines[i + 1]);
                }
            }

            using (Pen innerPen = new Pen(innerPenColor, scaledInnerPenWidth))
            {
                for (int i = 0; i < lines.Length; i += 2)
                {
                    g.DrawLine(innerPen, lines[i], lines[i + 1]);
                }
            }

            g.SmoothingMode = oldSM;
        }

        protected virtual void DrawItemImageShadow(
            Graphics g,
            Item item,
            Rectangle itemRect,
            Rectangle imageRect,
            Rectangle imageInsetRect)
        {
            Rectangle shadowRect = Rectangle.Inflate(imageInsetRect, 1, 1);
            Utility.DrawDropShadow1px(g, shadowRect);
        }

        protected virtual void DrawItemImage(
            Graphics g, 
            Item item, 
            Rectangle itemRect, 
            Rectangle imageRect, 
            Rectangle imageInsetRect)
        {
            // Draw the image
            if (item.Image != null)
            {
                g.DrawImage(
                    item.Image,
                    imageInsetRect,
                    new Rectangle(0, 0, item.Image.Width, item.Image.Height),
                    GraphicsUnit.Pixel);
            }
        }

        private void DrawItem(Graphics g, Item item, Point offset)
        {
            Rectangle itemRect;
            Rectangle imageRect;
            Rectangle imageInsetRect;
            Rectangle closeButtonRect;
            Rectangle dirtyOverlayRect;

            MeasureItemPartRectangles(
                item, 
                out itemRect, 
                out imageRect, 
                out imageInsetRect,
                out closeButtonRect,
                out dirtyOverlayRect);

            itemRect.X += offset.X;
            itemRect.Y += offset.Y;

            imageRect.X += offset.X;
            imageRect.Y += offset.Y;

            imageInsetRect.X += offset.X;
            imageInsetRect.Y += offset.Y;

            closeButtonRect.X += offset.X;
            closeButtonRect.Y += offset.Y;

            dirtyOverlayRect.X += offset.X;
            dirtyOverlayRect.Y += offset.Y;

            DrawItemBackground(g, item, itemRect);

            Rectangle highlightRect = itemRect;
            DrawItemHighlight(g, item, itemRect, highlightRect);

            // Fill background and draw outline
            if (this.drawShadow)
            {
                DrawItemImageShadow(g, item, itemRect, imageRect, imageInsetRect);
            }

            DrawItemImage(g, item, itemRect, imageRect, imageInsetRect);

            if (this.showCloseButtons)
            {
                DrawItemCloseButton(g, item, itemRect, closeButtonRect);
            }

            if (this.drawDirtyOverlay && item.Dirty)
            {
                DrawItemDirtyOverlay(g, item, itemRect, dirtyOverlayRect);
            }
        }

        public Point ClientPointToViewPoint(Point clientPt)
        {
            int viewX = clientPt.X + this.scrollOffset;
            return new Point(viewX, clientPt.Y);
        }

        public Rectangle ClientRectangleToViewRectangle(Rectangle clientRect)
        {
            Point viewPt = ClientPointToViewPoint(clientRect.Location);
            return new Rectangle(viewPt, clientRect.Size);
        }

        public Point ViewPointToClientPoint(Point viewPt)
        {
            int clientX = viewPt.X - this.scrollOffset;
            return new Point(clientX, viewPt.Y);
        }

        public Rectangle ViewRectangleToClientRectangle(Rectangle viewRect)
        {
            Point clientPt = ViewPointToClientPoint(viewRect.Location);
            return new Rectangle(clientPt, viewRect.Size);
        }

        private Point ViewPointToItemPoint(int itemIndex, Point viewPt)
        {
            Rectangle itemRect = ItemIndexToItemViewRectangle(itemIndex);
            Point itemPt = new Point(viewPt.X - itemRect.X, viewPt.Y);
            return itemPt;
        }

        private Rectangle ItemIndexToItemViewRectangle(int itemIndex)
        {
            Size itemSize = ItemSize;
            return new Rectangle(itemSize.Width * itemIndex, itemSize.Height, itemSize.Width, itemSize.Height);
        }

        public int ViewPointToItemIndex(Point viewPt)
        {
            if (!ViewRectangle.Contains(viewPt))
            {
                return -1;
            }

            Size itemSize = ItemSize;
            int index = viewPt.X / itemSize.Width;

            return index;
        }

        private void MeasureItemPartRectangles(
            out Rectangle itemRect,
            out Rectangle imageRect)
        {
            itemRect = new Rectangle(
                0,
                0,
                ClientSize.Height,
                ClientSize.Height);

            imageRect = new Rectangle(
                itemRect.Left,
                itemRect.Top,
                itemRect.Width,
                itemRect.Width);
        }

        private void MeasureItemPartRectangles(
            Item item,
            out Rectangle itemRect,
            out Rectangle imageRect,
            out Rectangle imageInsetRect,
            out Rectangle closeButtonRect,
            out Rectangle dirtyOverlayRect)
        {
            MeasureItemPartRectangles(out itemRect, out imageRect);

            Rectangle imageInsetRectMax = new Rectangle(
                imageRect.Left + imagePadding,
                imageRect.Top + imagePadding,
                imageRect.Width - imagePadding * 2,
                imageRect.Height - imagePadding * 2);

            Size imageInsetSize;
            
            if (item.Image == null)
            {
                imageInsetSize = imageRect.Size;
            }
            else
            {
                imageInsetSize = Utility.ComputeThumbnailSize(item.Image.Size, imageInsetRectMax.Width);
            }

            int scaledCloseButtonLength = UI.ScaleWidth(closeButtonLength);
            int scaledCloseButtonPadding = UI.ScaleWidth(closeButtonPadding);

            imageInsetRect = new Rectangle(
                imageInsetRectMax.Left + (imageInsetRectMax.Width - imageInsetSize.Width) / 2,
                imageInsetRectMax.Bottom - imageInsetSize.Height,
                imageInsetSize.Width,
                imageInsetSize.Height);

            closeButtonRect = new Rectangle(
                imageInsetRectMax.Right - scaledCloseButtonLength - scaledCloseButtonPadding,
                imageInsetRectMax.Top + scaledCloseButtonPadding,
                scaledCloseButtonLength,
                scaledCloseButtonLength);

            dirtyOverlayRect = new Rectangle(
                imageInsetRectMax.Left + scaledCloseButtonPadding,
                imageInsetRectMax.Top + scaledCloseButtonPadding,
                scaledCloseButtonLength,
                scaledCloseButtonLength);
        }

        private ItemPart ItemPointToItemPart(Item item, Point pt)
        {
            Rectangle itemRect;
            Rectangle imageRect;
            Rectangle imageInsetRect;
            Rectangle closeButtonRect;
            Rectangle dirtyOverlayRect;

            MeasureItemPartRectangles(
                item,
                out itemRect,
                out imageRect,
                out imageInsetRect,
                out closeButtonRect,
                out dirtyOverlayRect);

            if (closeButtonRect.Contains(pt))
            {
                return ItemPart.CloseButton;
            }

            if (imageRect.Contains(pt))
            {
                return ItemPart.Image;
            }

            return ItemPart.None;
        }

        private Rectangle ItemIndexToClientRect(int itemIndex)
        {
            Size itemSize = ItemSize;

            Rectangle clientRect = new Rectangle(
                itemSize.Width * itemIndex,
                0,
                itemSize.Width,
                itemSize.Height);

            return clientRect;
        }

        private void CalculateVisibleScrollOffsets(
            int itemIndex,
            out int minOffset, 
            out int maxOffset,
            out int minFullyShownOffset,
            out int maxFullyShownOffset)
        {
            Rectangle itemClientRect = ItemIndexToClientRect(itemIndex);

            minOffset = itemClientRect.Left + 1 - ClientSize.Width;
            maxOffset = itemClientRect.Right - 1;
            minFullyShownOffset = itemClientRect.Right - ClientSize.Width;
            maxFullyShownOffset = itemClientRect.Left;

            if (this.leftScrollButton.Visible)
            {
                maxOffset -= this.leftScrollButton.Width;
                maxFullyShownOffset -= this.leftScrollButton.Width;
            }

            if (this.rightScrollButton.Visible)
            {
                minOffset += this.rightScrollButton.Width;
                minFullyShownOffset += this.rightScrollButton.Width;
            }
        }

        public Rectangle ScrolledViewRect
        {
            get
            {
                return new Rectangle(this.scrollOffset, 0, ClientSize.Width, ClientSize.Height);
            }
        }

        public bool IsItemVisible(int index)
        {
            Rectangle itemRect = ItemIndexToClientRect(index);
            Rectangle intersect = Rectangle.Intersect(itemRect, ScrolledViewRect);
            return (intersect.Width > 0 || intersect.Height > 0);
        }

        public bool IsItemFullyVisible(int index)
        {
            Rectangle itemRect = ItemIndexToClientRect(index);
            Rectangle svRect = ScrolledViewRect;

            if (this.leftScrollButton.Visible)
            {
                svRect.X += this.leftScrollButton.Width;
                svRect.Width -= this.leftScrollButton.Width;
            }

            if (this.rightScrollButton.Visible)
            {
                svRect.Width -= this.rightScrollButton.Width;
            }

            Rectangle intersect = Rectangle.Intersect(itemRect, svRect);
            return (intersect == itemRect);
        }

        public void EnsureItemFullyVisible(Item item)
        {
            int index = this.items.IndexOf(item);
            EnsureItemFullyVisible(index);
        }

        public void EnsureItemFullyVisible(int index)
        {
            if (IsItemFullyVisible(index))
            {
                return;
            }

            int minOffset;
            int maxOffset;
            int minFullyShownOffset;
            int maxFullyShownOffset;

            CalculateVisibleScrollOffsets(index, out minOffset, out maxOffset, 
                out minFullyShownOffset, out maxFullyShownOffset);

            // Pick the offset that moves the image the fewest number of pixels
            int oldOffset = this.scrollOffset;
            int dxMin = Math.Abs(oldOffset - minFullyShownOffset);
            int dxMax = Math.Abs(oldOffset - maxFullyShownOffset);

            if (dxMin <= dxMax)
            {
                this.ScrollOffset = minFullyShownOffset;
            }
            else
            {
                this.ScrollOffset = maxFullyShownOffset;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (UI.IsControlPaintingEnabled(this))
            {
                Size itemSize = ItemSize;
                Rectangle firstItemRect = new Rectangle(-this.scrollOffset, 0, itemSize.Width, itemSize.Height);

                for (int i = 0; i < this.items.Count; ++i)
                {
                    if (IsItemVisible(i))
                    {
                        Point itemOffset = new Point(firstItemRect.X + itemSize.Width * i, firstItemRect.Y);
                        DrawItem(e.Graphics, this.items[i], itemOffset);
                    }
                }
            }

            base.OnPaint(e);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (this.mouseDownButton == MouseButtons.None)
            {
                Point clientPt = new Point(e.X, e.Y);
                Point viewPt = ClientPointToViewPoint(clientPt);
                int itemIndex = ViewPointToItemIndex(viewPt);

                if (itemIndex >= 0 && itemIndex < this.items.Count)
                {
                    Item item = this.items[itemIndex];
                    Point itemPt = ViewPointToItemPoint(itemIndex, viewPt);
                    ItemPart itemPart = ItemPointToItemPart(item, itemPt);

                    if (itemPart == ItemPart.Image)
                    {
                        OnItemClicked(item, itemPart, e.Button);

                        this.mouseDownApplyRendering = false;
                        this.mouseOverIndex = itemIndex;
                        this.mouseOverItemPart = itemPart;
                        this.mouseOverApplyRendering = true;
                    }
                    else
                    {
                        this.mouseDownIndex = itemIndex;
                        this.mouseDownItemPart = itemPart;
                        this.mouseDownButton = e.Button;
                        this.mouseDownApplyRendering = true;
                        this.mouseOverApplyRendering = false;
                    }

                    MouseStatesToItemStates();
                    Refresh();
                }
            }

            base.OnMouseDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            GetFocus();

            Point clientPt = new Point(e.X, e.Y);

            if (clientPt != this.lastMouseMovePt)
            {
                Point viewPt = ClientPointToViewPoint(clientPt);
                int itemIndex = ViewPointToItemIndex(viewPt);

                if (this.mouseDownButton == MouseButtons.None)
                {
                    if (itemIndex >= 0 && itemIndex < this.items.Count)
                    {
                        Item item = this.items[itemIndex];
                        Point itemPt = ViewPointToItemPoint(itemIndex, viewPt);
                        ItemPart itemPart = ItemPointToItemPart(item, itemPt);

                        this.mouseOverIndex = itemIndex;
                        this.mouseOverItemPart = itemPart;
                        this.mouseOverApplyRendering = true;
                    }
                    else
                    {
                        this.mouseOverApplyRendering = false;
                    }
                }
                else
                {
                    this.mouseOverApplyRendering = false;

                    if (itemIndex != this.mouseDownIndex)
                    {
                        this.mouseDownApplyRendering = false;
                    }
                    else if (itemIndex < 0 || itemIndex >= this.items.Count)
                    {
                        this.mouseDownApplyRendering = false;
                    }
                    else
                    {
                        Item item = this.Items[itemIndex];
                        Point itemPt = ViewPointToItemPoint(itemIndex, viewPt);

                        ItemPart itemPart = ItemPointToItemPart(item, itemPt);

                        if (itemPart != this.mouseDownItemPart)
                        {
                            this.mouseDownApplyRendering = false;
                        }
                    }
                }

                MouseStatesToItemStates();
                Refresh();
            }

            this.lastMouseMovePt = clientPt;
            base.OnMouseMove(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            bool raisedClickEvent = false;

            if (this.mouseDownButton == e.Button)
            {
                Point clientPt = new Point(e.X, e.Y);
                Point viewPt = ClientPointToViewPoint(clientPt);
                int itemIndex = ViewPointToItemIndex(viewPt);

                if (itemIndex >= 0 && itemIndex < this.items.Count)
                {
                    Item item = this.items[itemIndex];
                    Point itemPt = ViewPointToItemPoint(itemIndex, viewPt);
                    ItemPart itemPart = ItemPointToItemPart(item, itemPt);

                    if (itemIndex == this.mouseDownIndex && itemPart == this.mouseDownItemPart)
                    {
                        if (itemPart == ItemPart.CloseButton && !item.Checked)
                        {
                            // Can only close 'checked' images, just like how tab switching+closing works in IE7
                            itemPart = ItemPart.Image;
                        }

                        OnItemClicked(item, itemPart, this.mouseDownButton);
                        raisedClickEvent = true;
                    }

                    this.mouseOverApplyRendering = true;
                    this.mouseOverItemPart = itemPart;
                    this.mouseOverIndex = itemIndex;
                }

                this.mouseDownApplyRendering = false;
                this.mouseDownButton = MouseButtons.None;

                MouseStatesToItemStates();
                Refresh();
            }

            if (raisedClickEvent)
            {
                ForceMouseMove();
            }

            base.OnMouseUp(e);
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            float count = (float)e.Delta / SystemInformation.MouseWheelScrollDelta;
            int pixels = (int)(count * ItemSize.Width);
            int newSO = ScrollOffset - pixels;
            ScrollOffset = newSO;

            ForceMouseMove();

            base.OnMouseWheel(e);
        }

        private void ForceMouseMove()
        {
            Point clientPt = PointToClient(Control.MousePosition);
            this.lastMouseMovePt = new Point(this.lastMouseMovePt.X + 1, this.lastMouseMovePt.Y + 1);
            MouseEventArgs me = new MouseEventArgs(MouseButtons.None, 0, clientPt.X, clientPt.Y, 0);
            OnMouseMove(me);
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            GetFocus();
            base.OnMouseEnter(e);
        }

        private void GetFocus()
        {
            if (this.managedFocus && !MenuStripEx.IsAnyMenuActive && UI.IsOurAppActive)
            {
                this.Focus();
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            this.mouseDownApplyRendering = false;
            this.mouseOverApplyRendering = false;

            MouseStatesToItemStates();
            Refresh();

            if (this.managedFocus && !MenuStripEx.IsAnyMenuActive && UI.IsOurAppActive)
            {
                OnRelinquishFocus();
            }

            base.OnMouseLeave(e);
        }       
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.