vbAccelerator - Contents of code file: SkinnedListBar_SkinnedListBar.cs

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

using System.Diagnostics;

namespace vbAccelerator.Components.ListBarControl
{
   /// <summary>
   /// Defines the different button colours which can be set for
   /// a SkinnedListBarGroup item
   /// </summary>
   public enum ButtonPartColor : int
   {
      /// <summary>
      /// The default start color of the button gradient.
      /// </summary>
      buttonUpStartColor,
      /// <summary>
      /// The default end color of the button gradient.
      /// </summary>
      buttonUpEndColor,
      /// <summary>
      /// The start color of the button gradient when the mouse is over the
       button.
      /// </summary>
      buttonHotStartColor,
      /// <summary>
      /// The end color of the button gradient when the mouse is over the
       button.
      /// </summary>
      buttonHotEndColor,
      /// <summary>
      /// The start color of the button gradient when the mouse is down over
       the button.
      /// </summary>
      buttonDownStartColor,
      /// <summary>
      /// The end color of the button gradient when the mouse is down over the
       button.
      /// </summary>
      buttonDownEndColor
   }

   /// <summary>
   /// A class which subclasses the vbAccelerator .NET <c>ListBar</c> control
    to 
   /// modify its appearance.  This class overrides some of the class
    constructors
   /// to provide new scrolling buttons as well as drawing the border in
   /// a different style.
   /// </summary>
   public class SkinnedListBar : ListBar
   {
      /// <summary>
      /// Creates a new instance of a SkinnedListBarScrollButton used by this
       control
      /// to draw the scroll buttons.  Fired during control initialisation.
      /// </summary>
      /// <param name="buttonType">The type of scroll button (Up or Down)
      /// to create</param>
      /// <returns>A new ListBarScrollButton which is drawn when a ListBar
      /// contains more items than can be displayed.</returns>
      protected override ListBarScrollButton
       CreateListBarScrollButton(ListBarScrollButton.ListBarScrollButtonType
       buttonType)
      {
         return new SkinnedListBarScrollButton(buttonType);
      }

      /// <summary>
      /// Draw a border around the control.  This version draws an
      /// anti-aliased alpha blended thin border in a grey shade.
      /// </summary>
      /// <param name="gfx">The graphics object to drawn onto.</param>
      protected override void RenderControlBorder(
         Graphics gfx)
      {
         gfx.SmoothingMode = SmoothingMode.AntiAlias;

         Pen borderPen = new Pen(Color.FromArgb(128, 214, 220, 226), 1.5F);
         Rectangle borderRect = new Rectangle(
            this.ClientRectangle.Location, this.ClientRectangle.Size);
         borderRect.Width -= 1;
         borderRect.Height -= 1;
         gfx.DrawRectangle(borderPen, borderRect);
         borderPen.Dispose();
      }

      /// <summary>
      ///  Creates a new instance of the skinned list bar control.
      /// </summary>
      public SkinnedListBar() : base()
      {
         // intentionally blank
      }
   }

   /// <summary>
   /// An extended ListBarScrollButton which renders as a smooth
   /// circle with a shadow underneath.
   /// </summary>
   public class SkinnedListBarScrollButton : ListBarScrollButton
   {
      private Color[] buttonColor = new Color[6] 
         {
            Color.FromArgb(255, 255, 255), Color.FromArgb(234, 237, 240), 
            Color.FromArgb(243, 245, 247), Color.FromArgb(214, 220, 226),
            Color.FromArgb(214, 220, 226), Color.FromArgb(243, 245, 247)
         };

      /// <summary>
      /// Sets the color for the specified button part.
      /// </summary>
      /// <param name="color">The Color to set.</param>
      /// <param name="part">The part to set the color for.</param>
      public void SetButtonColor(ButtonPartColor part, Color color)
      {
         this.buttonColor[(int)part] = color;
      }
      /// <summary>
      /// Gets the color for the specified button part.
      /// </summary>
      /// <param name="part">The part to get the colour for.</param>
      /// <returns>The Color of the part</returns>
      public Color GetButtonColor(ButtonPartColor part)
      {
         return this.buttonColor[(int)part];
      }
      

      /// <summary>
      /// Draws the button onto the specified Graphics object.
      /// </summary>
      /// <param name="gfx">The graphics object to draw on.</param>
      /// <param name="defaultBackColor">The default background colour to
      /// draw the scroll bar using.</param>
      /// <param name="controlEnabled">Whether the button is enabled or
       not.</param>
      public override void DrawItem(
         Graphics gfx,
         Color defaultBackColor,
         bool controlEnabled
         )
      {   
         if ((this.Visible) && controlEnabled)
         {
            // Anti-alias for smoothness
            gfx.SmoothingMode = SmoothingMode.AntiAlias;
            // And half pixel offsetting
            gfx.PixelOffsetMode = PixelOffsetMode.Half;

            // Get the rectangle to draw the button into:
            Rectangle drawRect = this.Rectangle;
            drawRect.Width -= 4;
            drawRect.Height -= 4;

            // Draw a shadow:
            Rectangle shadowRect = new Rectangle(
               drawRect.Location, drawRect.Size);
            shadowRect.Offset(1, 1);
            SolidBrush shadowBrush = new SolidBrush(Color.FromArgb(128,
             Color.Black));
            gfx.FillEllipse(shadowBrush, shadowRect);
            shadowBrush.Dispose();
            if (! (this.MouseDown && this.MouseOver))
            {

               shadowRect = new Rectangle(
                  drawRect.Location, drawRect.Size);
               shadowRect.Offset(2, 2);
               shadowBrush = new SolidBrush(Color.FromArgb(64, Color.Black));
               gfx.FillEllipse(shadowBrush, shadowRect);            
               shadowBrush.Dispose();
            }

            // Get the colors to draw the brush
            Color startColor =
             this.buttonColor[(int)ButtonPartColor.buttonUpStartColor];
            Color endColor =
             this.buttonColor[(int)ButtonPartColor.buttonUpEndColor];

            if (this.MouseDown && this.MouseOver)
            {
               startColor =
                this.buttonColor[(int)ButtonPartColor.buttonDownStartColor];
               endColor =
                this.buttonColor[(int)ButtonPartColor.buttonDownEndColor];
            }
            else if (this.MouseOver || this.MouseDown)
            {
               startColor =
                this.buttonColor[(int)ButtonPartColor.buttonHotStartColor];
               endColor =
                this.buttonColor[(int)ButtonPartColor.buttonHotEndColor];
            }
            
            // Fill the background of the brush:
            LinearGradientBrush backBrush = new LinearGradientBrush(
               drawRect, startColor, endColor,
               90, false);   
            gfx.FillEllipse(backBrush, drawRect);
            backBrush.Dispose();

            // Draw the glyph:
            GraphicsPath glyph = new GraphicsPath();
            float glyphCentreX = ((float)(drawRect.Width + 1.0F) / 2.0F) +
             (float)drawRect.Left - 0.5F;
            float glyphCentreY = ((float)(drawRect.Height + 1.0F) / 2.0F) +
             (float)drawRect.Top - 0.5F;
            float glyphSize = 2.5F;
            if (this.MouseOver && this.MouseDown)
            {
               glyphCentreX += 0.5F;
               glyphCentreY += 0.5F;
            }
            if (this.ButtonType == ListBarScrollButtonType.Up)
            {
               glyphCentreY -= glyphSize / 3.0F;

               glyph.AddLine( 
                  glyphCentreX - glyphSize, glyphCentreY + glyphSize, 
                  glyphCentreX + glyphSize, glyphCentreY + glyphSize);
               glyph.AddLine(
                  glyphCentreX + glyphSize, glyphCentreY + glyphSize,
                  glyphCentreX, glyphCentreY - glyphSize);
               glyph.CloseFigure();
            }
            else
            {
               glyphCentreY += glyphSize / 3.0F;

               glyph.AddLine( 
                  glyphCentreX - glyphSize, glyphCentreY - glyphSize, 
                  glyphCentreX + glyphSize, glyphCentreY - glyphSize);
               glyph.AddLine(
                  glyphCentreX + glyphSize, glyphCentreY - glyphSize,
                  glyphCentreX, glyphCentreY + glyphSize);
               glyph.CloseFigure();
            }
            Brush glyphBrush = new SolidBrush(Color.FromArgb(128, Color.Black));
            gfx.FillPath(glyphBrush, glyph);
            glyphBrush.Dispose();
            glyph.Dispose();         
         }
      }

      /// <summary>
      /// Creates a new instance of this class with the specified
      /// button type (Up or Down)
      /// </summary>
      /// <param name="buttonType">The scroll button type to create.</param>
      public SkinnedListBarScrollButton(ListBarScrollButtonType buttonType) :
       base(buttonType)
      {
         // intentionally blank
      }

   }

   /// <summary>
   /// An extended ListBarGroup which renders with a gradient skin
   /// appearance.
   /// </summary>
   public class SkinnedListBarGroup : ListBarGroup
   {
      private Color[] buttonColor = new Color[6] 
         {
            Color.FromArgb(255, 255, 255), Color.FromArgb(234, 237, 240), 
            Color.FromArgb(243, 245, 247), Color.FromArgb(214, 220, 226),
            Color.FromArgb(214, 220, 226), Color.FromArgb(243, 245, 247)
         };
   
      /// <summary>
      /// Sets the color for the specified button part.
      /// </summary>
      /// <param name="color">The Color to set.</param>
      /// <param name="part">The part to set the color for.</param>
      public void SetButtonColor(ButtonPartColor part, Color color)
      {
         this.buttonColor[(int)part] = color;
      }
      /// <summary>
      /// Gets the color for the specified button part.
      /// </summary>
      /// <param name="part">The part to get the colour for.</param>
      /// <returns>The Color of the part</returns>
      public Color GetButtonColor(ButtonPartColor part)
      {
         return this.buttonColor[(int)part];
      }
      

      /// <summary>
      /// Draws the button for this group bar onto the control.
      /// </summary>
      /// <param name="gfx">The graphics object to draw onto.</param>
      /// <param name="font">The Font to draw with</param>
      /// <param name="enabled">Whether the control is enabled or not.</param>
      public override void DrawButton(
         Graphics gfx,
         Font font,
         bool enabled
         )
      {   
         gfx.SmoothingMode = SmoothingMode.AntiAlias;

         // Fill the background of the button:
         Color startColor =
          this.buttonColor[(int)ButtonPartColor.buttonUpStartColor];
         Color endColor =
          this.buttonColor[(int)ButtonPartColor.buttonUpEndColor];

         if (this.MouseDown && this.MouseOver)
         {
            startColor =
             this.buttonColor[(int)ButtonPartColor.buttonDownStartColor];
            endColor =
             this.buttonColor[(int)ButtonPartColor.buttonDownEndColor];
         }
         else if (this.MouseOver || this.MouseDown)
         {
            startColor =
             this.buttonColor[(int)ButtonPartColor.buttonHotStartColor];
            endColor = this.buttonColor[(int)ButtonPartColor.buttonHotEndColor];
         }

         Rectangle drawRect = new Rectangle(this.ButtonLocation, 
            new Size(this.ButtonWidth, this.ButtonHeight));
         LinearGradientBrush backBrush = new LinearGradientBrush(
            drawRect, startColor, endColor,
            90, false);
         gfx.FillRectangle(backBrush, drawRect);
         backBrush.Dispose();

         // Draw the text:
         StringFormat format = new StringFormat(StringFormatFlags.NoWrap |
          StringFormatFlags.LineLimit);
         Font drawFont = this.Font;
         if (drawFont == null)
         {
            drawFont = font;
         }
         RectangleF textRect = new RectangleF(
            this.ButtonLocation.X, this.ButtonLocation.Y,
            this.ButtonWidth, this.ButtonHeight);
         textRect.Inflate(-2, -2);
         if (this.MouseDown && this.MouseOver)
         {
            textRect.Offset(1, 1);
         }
         format.Alignment = StringAlignment.Near;
         format.LineAlignment = StringAlignment.Center;
         Brush textBrush = new SolidBrush(this.ForeColor);
         gfx.DrawString(this.Caption, drawFont, textBrush, textRect, format);
         textBrush.Dispose();
         format.Dispose();

      }

      private void newDefaults()
      {
         this.rectangle.Height = 28;
         this.ForeColor = Color.FromArgb(77, 89, 103);
         this.BackColor = Color.White;
      }

      /// <summary>
      /// Constructs a new, blank instance of a ListBarGroup.
      /// </summary>
      public SkinnedListBarGroup() : base()
      {         
         newDefaults();
      }

      /// <summary>
      /// Constructs a new instance of a ListBarGroup with the specified
      /// caption.
      /// </summary>
      /// <param name="caption">Caption for the group's control button.</param>
      public SkinnedListBarGroup(
         string caption
         ) : base(caption)
      {
         newDefaults();
      }
      /// <summary>
      /// Constructs a new instance of a ListBarGroup with the specified
      /// caption and items.
      /// </summary>
      /// <param name="caption">Caption for the group's control button.</param>
      /// <param name="subItems">The array of items to add to the group's
      /// collection of items.</param>
      public SkinnedListBarGroup(
         string caption,
         ListBarItem[] subItems
         ) : base(caption, subItems)
      {
         newDefaults();
      }

      /// <summary>
      /// Constructs a new instance of a ListBarGroup with the specified
      /// caption and tooltip text.
      /// </summary>
      /// <param name="caption">Caption for the group's control button.</param>
      /// <param name="toolTipText">ToolTip text to show when hovering over
      /// the group.</param>
      public SkinnedListBarGroup(
         string caption, 
         string toolTipText
         ) : base(caption, toolTipText)
      {
         newDefaults();
      }

      /// <summary>
      /// Constructs a new instance of a ListBarGroup with the specified
      /// caption, tooltip text and user-defined data.
      /// </summary>
      /// <param name="caption">Caption for the group's control button.</param>
      /// <param name="toolTipText">ToolTip text to show when hovering over
      /// the group.</param>
      /// <param name="tag">User-defined object data which is associated with
      /// the group.</param>
      public SkinnedListBarGroup(
         string caption, 
         string toolTipText,
         object tag
         ) : base(caption, toolTipText, tag)
      {
         newDefaults();
      }
   }

   /// <summary>
   /// An extended ListBarItem which renders with an alpha-blended shadow
   /// appearance.
   /// </summary>
   public class SkinnedListBarItem : ListBarItem
   {

      /// <summary>
      /// Draws this item into the specified graphics object.
      /// </summary>
      /// <param name="gfx">The graphics object to draw onto.</param>
      /// <param name="ils">The ImageList to source icons from.</param>
      /// <param name="defaultFont">The default Font to draw the item
       with</param>
      /// <param name="style">The style (Outlook version) to draw using.</param>
      /// <param name="view">The view (large or small icons) to draw
       using.</param>
      /// <param name="scrollOffset">The offset of the first item from the 
      /// (0,0) point in the graphics object.</param>
      /// <param name="controlEnabled">Whether the control is enabled or
       not.</param>
      /// <param name="skipDrawText">Whether to skip drawing text or not
      /// (the item is being edited)</param>
      public override void DrawButton(
         Graphics gfx, 
         ImageList ils, 
         Font defaultFont, 
         ListBarDrawStyle style, 
         ListBarGroupView view,
         int scrollOffset,
         bool controlEnabled,
         bool skipDrawText
         )
      {

         gfx.SmoothingMode = SmoothingMode.AntiAlias;

         bool rightToLeft = false;
         if (this.Owner != null)
         {
            if (this.Owner.RightToLeft == RightToLeft.Yes)
            {
               rightToLeft = true;
            }
         }

         // Work out the icon & text rectangles:         
         textRectangle = new Rectangle(this.Location, new Size(this.Width,
          this.Height));
         textRectangle.Offset(0, scrollOffset);
         if (view == ListBarGroupView.SmallIcons)
         {
            textRectangle.Y += 1;
            textRectangle.Height -= 1;
         }
         iconRectangle = new Rectangle(textRectangle.Location,
          textRectangle.Size);
         
         if (view == ListBarGroupView.SmallIcons)
         {
            if (ils != null)
            {
               if (rightToLeft)
               {
                  iconRectangle.X = iconRectangle.Right - ils.ImageSize.Width -
                   4;
                  iconRectangle.Width = ils.ImageSize.Width;
               }
               else
               {
                  iconRectangle.X += 4;
                  iconRectangle.Width = ils.ImageSize.Width;
                  textRectangle.X += ils.ImageSize.Width + 8;
               }
               textRectangle.Width -= (iconRectangle.Width + 8);
               iconRectangle.Height = ils.ImageSize.Height;
               iconRectangle.Y += (this.Height - iconRectangle.Height) / 2;
            }
            else
            {
               textRectangle.Inflate(-2,-2);
            }
         }
         else
         {
            if (ils != null)
            {
               iconRectangle.Y += 7;
               iconRectangle.Height = ils.ImageSize.Height;
               iconRectangle.Width = ils.ImageSize.Width;
               iconRectangle.X = iconRectangle.Left + (this.Width -
                iconRectangle.Width) / 2;
               
               textRectangle.Y += ils.ImageSize.Height + 11;
               textRectangle.Height -= (ils.ImageSize.Height + 11);
            }
            else
            {
               textRectangle.Inflate(-2,-2);
            }
         }

         int iconX = iconRectangle.X;
         int iconY = iconRectangle.Y;


         if (this.MouseDown && this.MouseOver)
         {
            iconX++;
            iconY++;
         }

         // If we're drawing using XP style and the button is
         // hot or down then we draw the background:
         Rectangle rcHighlight = new Rectangle(iconRectangle.Location,
          iconRectangle.Size);               
         rcHighlight.Inflate(2,2);

         if ((this.Enabled) && (this.MouseOver || this.MouseDown))
         {
            Color highlightColor;
            if (this.MouseDown && this.MouseOver)
            {
               highlightColor = Color.FromArgb(128, 230, 230, 230);
                //Utility.BlendColor(Color.FromKnownColor(KnownColor.Highlight),
                Color.FromKnownColor(KnownColor.Window), 224);
            }
            else
            {
               highlightColor = Color.FromArgb(64, 230, 230, 230);
                //highlightColor =
                Utility.BlendColor(Color.FromKnownColor(KnownColor.Highlight),
                Color.FromKnownColor(KnownColor.Window), 128);
            }
            SolidBrush highlight = new SolidBrush(Color.FromArgb(128,
             highlightColor));
            gfx.FillRectangle(highlight, rcHighlight);
            highlight.Dispose();
            
            Pen highlightPen = new Pen(Color.FromArgb(142, 154, 170));
            gfx.DrawRectangle(highlightPen, rcHighlight);
            highlightPen.Dispose();

         }

         
         // Draw the icon if necessary:
         if (ils != null)
         {
            if (this.IconIndex >= 0 && this.IconIndex <= ils.Images.Count)
            {

               if ((this.Enabled) && (this.MouseOver || this.MouseDown ||
                this.Selected))
               {
                  ControlPaint.DrawImageDisabled(gfx, 
                     ils.Images[this.IconIndex], 
                     iconX + 1, iconY + 1, Color.Black);
                  ils.Draw(gfx, iconX, iconY, this.IconIndex);
               }
               else
               {
                  ControlPaint.DrawImageDisabled(gfx,
                   ils.Images[this.IconIndex], iconX, iconY, Color.Aqua);
               }

            }
            else
            {
               // We don't want an exception in a paint event
               Trace.WriteLine(
                  String.Format("Icon {0} doesn't exist in ImageList {1}", 
                  this.IconIndex,
                  ils));
            }
         }
         // We do this to make the hit testing more usable:
         iconRectangle.Inflate(4, 4);

         // Draw the text:
         // Get the font to draw with:
         Font drawFont = this.Font;
         if (drawFont  == null)
         {
            drawFont = defaultFont;
         }
         // Set up format:
         StringFormat format = new StringFormat(StringFormatFlags.LineLimit);
         format.Trimming = StringTrimming.EllipsisCharacter;
         if (view == ListBarGroupView.SmallIcons)
         {            
            format.Alignment = StringAlignment.Near;
            format.LineAlignment = StringAlignment.Center;
            format.FormatFlags = format.FormatFlags | StringFormatFlags.NoWrap;
         }
         else
         {
            format.Alignment = StringAlignment.Center;
         }
         format.LineAlignment = StringAlignment.Near;
         format.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show;
         // Bounding rectangle:
         RectangleF rectF = new RectangleF(textRectangle.X, textRectangle.Y,
            textRectangle.Width, textRectangle.Height);
         if (view == ListBarGroupView.SmallIcons)
         {
            SizeF textSize = gfx.MeasureString(this.Caption, drawFont,
             textRectangle.Width, format);
            rectF.Y += (rectF.Height - textSize.Height) / 2;
         }
         // Color:
         SolidBrush br = new SolidBrush(this.ForeColor);
         // Finally...
         if (this.Enabled)
         {
            gfx.DrawString(this.Caption, drawFont, br, rectF, format);
         }
         else
         {
            ControlPaint.DrawStringDisabled(gfx, 
               this.Caption, drawFont, 
               Color.FromKnownColor(KnownColor.Control), 
               rectF, format);
         }
         br.Dispose();
         format.Dispose();

      }

      private void newDefaults()
      {
         this.ForeColor = Color.FromArgb(77, 89, 103);
      }

      /// <summary>
      /// Constructs a new, empty instance of a ListBarItem.
      /// </summary>
      public SkinnedListBarItem() : base()
      {         
         newDefaults();
      }
      /// <summary>
      ///  Constructs a new instance of a ListBarItem, specifying
      ///  the caption to display.
      /// </summary>
      /// <param name="caption">The caption for this item.</param>
      public SkinnedListBarItem(string caption) : base(caption)
      {
         newDefaults();
      }
      /// <summary>
      ///  Constructs a new instance of a ListBarItem, specifying
      ///  the caption and the index of the icon to display.
      /// </summary>
      /// <param name="caption">The caption for this item.</param>
      /// <param name="iconIndex">The 0-based index of the icon
      /// to display</param>
      public SkinnedListBarItem(
            string caption, 
            int iconIndex
         ) : base(caption, iconIndex)
      {
         newDefaults();
      }

      /// <summary>
      ///  Constructs a new instance of a ListBarItem, specifying
      ///  the caption, the index of the icon and the 
      ///  tooltip text.
      /// </summary>
      /// <param name="caption">The caption for this item.</param>
      /// <param name="iconIndex">The 0-based index of the icon
      /// to display</param>
      /// <param name="toolTipText">The tooltip text to show
      /// when the mouse hovers over this item.</param>
      public SkinnedListBarItem(
         string caption,
         int iconIndex,
         string toolTipText
         ) : base(caption, iconIndex, toolTipText)
      {
         newDefaults();
      }
      /// <summary>
      ///  Constructs a new instance of a ListBarItem, specifying
      ///  the caption, the index of the icon, the 
      ///  tooltip text and the tag.
      /// </summary>
      /// <param name="caption">The caption for this item.</param>
      /// <param name="iconIndex">The 0-based index of the icon
      /// to display</param>
      /// <param name="toolTipText">The tooltip text to show
      /// when the mouse hovers over this item.</param>
      /// <param name="tag">An object which can be used to 
      /// associate user-defined data with the item.</param>
      public SkinnedListBarItem(
         string caption,
         int iconIndex,
         string toolTipText,
         object tag
         ) : base (caption, iconIndex, toolTipText, tag)
      {
         newDefaults();
      }
      /// <summary>
      ///  Constructs a new instance of a ListBarItem, specifying
      ///  the caption, the index of the icon, the 
      ///  tooltip text, the tag and the key.
      /// </summary>
      /// <param name="caption">The caption for this item.</param>
      /// <param name="iconIndex">The 0-based index of the icon
      /// to display</param>
      /// <param name="toolTipText">The tooltip text to show
      /// when the mouse hovers over this item.</param>
      /// <param name="tag">An object which can be used to 
      /// associate user-defined data with the item.</param>
      /// <param name="key">A user-defined string which is 
      /// associated with the item.</param>
      public SkinnedListBarItem(
         string caption,
         int iconIndex,
         string toolTipText,
         object tag,
         string key
         ) : base(caption, iconIndex, toolTipText, tag, key)
      {
         newDefaults();
      }

   }
}