Click here to Skip to main content
15,884,472 members
Articles / Containers / Docker

Visual Studio IDE like Dock Container - Second Version

Rate me:
Please Sign up or sign in to vote.
4.96/5 (70 votes)
2 Oct 2009CPOL4 min read 307.3K   16.2K   276  
Second version of Visual Studio IDE like dock container
/***************************************************************************
 *   CopyRight (C) 2009 by Cristinel Mazarine                              *
 *   Author:   Cristinel Mazarine                                          *
 *   Contact:  cristinel@osec.ro                                           *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the Crom Free License as published by           *
 *   the SC Crom-Osec SRL; version 1 of the License                        *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   Crom Free License for more details.                                   *
 *                                                                         *
 *   You should have received a copy of the Crom Free License along with   *
 *   this program; if not, write to the contact@osec.ro                    *
 ***************************************************************************/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace Crom.Controls.TabbedDocument
{
   /// <summary>
   /// Renderer for bottom tab button
   /// </summary>
   public class BottomTabButtonRenderer : TabButtonRenderer
   {
      #region Fields

      private const int                ButtonBottomMargin                  = 2;
      private const int                PanelMargin                         = 0;
      private const int                ButtonHorizontalMargins             = 16;
      private const int                ButtonHeight                        = 16;

      #endregion Fields

      #region Instance

      /// <summary>
      /// Default constructor
      /// </summary>
      public BottomTabButtonRenderer()
      {
      }

      #endregion Instance

      #region Public section

      /// <summary>
      /// Draw the button
      /// </summary>
      /// <param name="bounds">button bounds</param>
      /// <param name="text">button text</param>
      /// <param name="selected">flag indicating that should use selected colors</param>
      /// <param name="font">font used to draw the text</param>
      /// <param name="graphics">graphics</param>
      public override void Draw(Rectangle bounds, string text, bool selected, Font font, Graphics graphics)
      {
         using (GraphicsPath button = new GraphicsPath())
         {
            bounds.Y--;

            int x1 = bounds.X - (int)(bounds.Height * 0.75);
            int y1 = bounds.Top;

            int x2 = bounds.X + (int)(bounds.Height * 0.25) - 2;
            int y2 = bounds.Bottom - 2;

            int x3 = bounds.X + (int)(bounds.Height * 0.25) + 1;
            int y3 = bounds.Bottom;

            int x4 = bounds.Right - 2;
            int y4 = bounds.Bottom;

            int x5 = bounds.Right;
            int y5 = bounds.Bottom - 2;

            int x6 = bounds.Right;
            int y6 = bounds.Top;

            button.AddLine(x1, y1 - 1, x2, y2);
            button.AddLine(x2, y2, x3, y3);
            button.AddLine(x3, y3, x4, y4);
            button.AddLine(x4, y4, x5, y5);
            button.AddLine(x5, y5, x6, y6 - 1);
            button.CloseFigure();

            bounds.Y -= 2;
            bounds.Height += 2;
            using (LinearGradientBrush backBrush = new LinearGradientBrush(bounds, GetBackGradient2Color(selected), GetBackGradient1Color(selected), BackGradientMode))
            {
               graphics.FillPath(backBrush, button);

               using (Pen pen = new Pen(GetBorder2Color(selected)))
               {
                  graphics.DrawLine(pen, x1, y1, x2, y2);
                  graphics.DrawLine(pen, x2, y2, x3, y3);
                  graphics.DrawLine(pen, x3, y3, x4, y4);
                  graphics.DrawLine(pen, x4, y4, x5, y5);
                  graphics.DrawLine(pen, x5, y5, x6, y6);
               }
            }

            if (selected == false)
            {
               using (Pen pen = new Pen(GetBorder2Color(true)))
               {
                  graphics.DrawLine(pen, x1, y1 + 1, x6, y6 + 1);
               }
            }
         }

         Rectangle textBounds = bounds;
         textBounds.X += 10;
         textBounds.Y += 4;
         using (Brush textBrush = new SolidBrush(TextColor))
         {
            graphics.DrawString(text, font, textBrush, textBounds);
         }
      }

      /// <summary>
      /// Draw buttons line
      /// </summary>
      /// <param name="graphics">graphics object</param>
      /// <param name="panelBounds">panel bounds</param>
      /// <param name="buttonsPanelBounds">buttons panel bounds</param>
      public override void DrawButtonsLine(Graphics graphics, Rectangle panelBounds, Rectangle buttonsPanelBounds)
      {
         using (Pen pen = new Pen(GetBorder2Color(true)))
         {
            graphics.DrawLine(pen, panelBounds.X, buttonsPanelBounds.Y + 1, panelBounds.Width, buttonsPanelBounds.Y + 1);
         }
      }

      /// <summary>
      /// Draw the scroll back button
      /// </summary>
      /// <param name="bounds">button bounds</param>
      /// <param name="state">flag indicating the state of the button</param>
      /// <param name="graphics">graphics</param>
      public override void DrawScrollBackButton(Rectangle bounds, zButtonState state, Graphics graphics)
      {
         int x1 = bounds.Left + 5;
         int y1 = bounds.Top + bounds.Height / 2 + 1;

         int x2 = x1 + 4;
         int y2 = y1 - 4;

         int x3 = x2;
         int y3 = y1 + 4;

         using (GraphicsPath arrowHeadPath = new GraphicsPath())
         {
            arrowHeadPath.AddLine(x1, y1, x2, y2);
            arrowHeadPath.AddLine(x2, y2, x3, y3);
            arrowHeadPath.CloseFigure();

            switch (state)
            {
               case zButtonState.Normal:
                  graphics.FillPath(Brushes.LightSteelBlue, arrowHeadPath);

                  graphics.DrawLine(Pens.DarkBlue, x1, y1 - 1, x2, y2 - 1);
                  graphics.DrawLine(Pens.DarkBlue, x2, y2 - 1, x3, y3 + 1);
                  graphics.DrawLine(Pens.White, x3, y3 + 1, x1, y1 + 1);

                  break;

               case zButtonState.Focus:
                  graphics.FillPath(Brushes.LightGreen, arrowHeadPath);

                  graphics.DrawLine(Pens.Blue, x1, y1 - 1, x2, y2 - 1);
                  graphics.DrawLine(Pens.Blue, x2, y2 - 1, x3, y3 + 1);
                  graphics.DrawLine(Pens.White, x3, y3 + 1, x1, y1 + 1);

                  break;

               case zButtonState.Pressed:
                  graphics.FillPath(Brushes.LightSteelBlue, arrowHeadPath);

                  graphics.DrawLine(Pens.DarkBlue, x3, y3 + 1, x1, y1 + 1);
                  graphics.DrawLine(Pens.DarkBlue, x2, y2 - 1, x3, y3 + 1);
                  graphics.DrawLine(Pens.WhiteSmoke, x1, y1 - 1, x2, y2 - 1);

                  break;

               case zButtonState.UnderMouseCursor:
                  graphics.FillPath(Brushes.LightSteelBlue, arrowHeadPath);

                  graphics.DrawLine(Pens.Blue, x1, y1 - 1, x2, y2 - 1);
                  graphics.DrawLine(Pens.Blue, x2, y2 - 1, x3, y3 + 1);
                  graphics.DrawLine(Pens.White, x3, y3 + 1, x1, y1 + 1);

                  break;

               case zButtonState.Disabled:
                  graphics.FillPath(Brushes.Gray, arrowHeadPath);

                  graphics.DrawLine(Pens.DarkGray, x1, y1 - 1, x2, y2 - 1);
                  graphics.DrawLine(Pens.DarkGray, x2, y2 - 1, x3, y3 + 1);
                  graphics.DrawLine(Pens.White, x3, y3 + 1, x1, y1 + 1);

                  break;
            }
         }
      }

      /// <summary>
      /// Draw the scroll next button
      /// </summary>
      /// <param name="bounds">button bounds</param>
      /// <param name="state">flag indicating the state of the button</param>
      /// <param name="graphics">graphics</param>
      public override void DrawScrollNextButton(Rectangle bounds, zButtonState state, Graphics graphics)
      {
         int x1 = bounds.Left + 5;
         int y1 = bounds.Top + bounds.Height / 2 + 2;

         int x2 = x1 - 5;
         int y2 = y1 - 5;

         int x3 = x2;
         int y3 = y1 + 4;

         using (GraphicsPath arrowHeadPath = new GraphicsPath())
         {
            arrowHeadPath.AddLine(x1, y1 - 1, x2, y2 - 1);
            arrowHeadPath.AddLine(x2, y2 - 1, x3, y3 + 1);
            arrowHeadPath.CloseFigure();

            switch (state)
            {
               case zButtonState.Normal:
                  graphics.FillPath(Brushes.LightSteelBlue, arrowHeadPath);

                  graphics.DrawLine(Pens.DarkBlue, x1, y1 - 1, x2, y2 - 1);
                  graphics.DrawLine(Pens.DarkBlue, x2, y2 - 1, x3, y3 + 1);
                  graphics.DrawLine(Pens.White, x3, y3 + 1, x1, y1 + 1);

                  break;

               case zButtonState.Focus:
                  graphics.FillPath(Brushes.LightGreen, arrowHeadPath);

                  graphics.DrawLine(Pens.Blue, x1, y1 - 1, x2, y2 - 1);
                  graphics.DrawLine(Pens.Blue, x2, y2 - 1, x3, y3 + 1);
                  graphics.DrawLine(Pens.White, x3, y3 + 1, x1, y1 + 1);

                  break;

               case zButtonState.Pressed:
                  graphics.FillPath(Brushes.LightSteelBlue, arrowHeadPath);

                  graphics.DrawLine(Pens.DarkBlue, x3, y3 + 1, x1, y1 + 1);
                  graphics.DrawLine(Pens.DarkBlue, x2, y2 - 1, x3, y3 + 1);
                  graphics.DrawLine(Pens.WhiteSmoke, x1, y1 - 1, x2, y2 - 1);

                  break;

               case zButtonState.UnderMouseCursor:
                  graphics.FillPath(Brushes.LightSteelBlue, arrowHeadPath);

                  graphics.DrawLine(Pens.Blue, x1, y1 - 1, x2, y2 - 1);
                  graphics.DrawLine(Pens.Blue, x2, y2 - 1, x3, y3 + 1);
                  graphics.DrawLine(Pens.White, x3, y3 + 1, x1, y1 + 1);

                  break;

               case zButtonState.Disabled:
                  graphics.FillPath(Brushes.Gray, arrowHeadPath);

                  graphics.DrawLine(Pens.DarkGray, x1, y1 - 1, x2, y2 - 1);
                  graphics.DrawLine(Pens.DarkGray, x2, y2 - 1, x3, y3 + 1);
                  graphics.DrawLine(Pens.White, x3, y3 + 1, x1, y1 + 1);

                  break;
            }
         }
      }

      /// <summary>
      /// Checks if the panel has scrolls
      /// </summary>
      /// <param name="panelBounds">panel bounds</param>
      /// <param name="lastButtonBounds">last button bounds</param>
      /// <returns>true if the panel has scrolls</returns>
      public override bool HasScroll(Rectangle panelBounds, Rectangle lastButtonBounds)
      {
         return lastButtonBounds.Right >= panelBounds.Right;
      }

      /// <summary>
      /// Get the bounds of the scroll back button
      /// </summary>
      /// <param name="panelBounds">bounds of the panel</param>
      /// <returns>bounds of the scroll back button</returns>
      public override Rectangle GetScrollBackButtonBounds(Rectangle panelBounds)
      {
         return new Rectangle(panelBounds.Left - ButtonHeight, panelBounds.Top + 1, ButtonHeight - ButtonBottomMargin, ButtonHeight - ButtonBottomMargin);
      }

      /// <summary>
      /// Get the bounds of the scroll next button
      /// </summary>
      /// <param name="panelBounds">bounds of the panel</param>
      /// <returns>bounds of the scroll next button</returns>
      public override Rectangle GetScrollNextButtonBounds(Rectangle panelBounds)
      {
         return new Rectangle(panelBounds.Right + 2 * 4, panelBounds.Top + 1, ButtonHeight - ButtonBottomMargin, ButtonHeight - ButtonBottomMargin);
      }

      /// <summary>
      /// Get first button bounds
      /// </summary>
      /// <param name="panelBounds">bounds of the panel</param>
      /// <param name="hasScroll">flag indicating that panel has scrolls</param>
      /// <param name="scrolPos">scroll position</param>
      /// <param name="text">text of the button</param>
      /// <param name="font">font used to draw the button</param>
      /// <param name="graphics">graphics object</param>
      /// <returns>bounds of the first button</returns>
      public override Rectangle GetFirstButtonBounds(Rectangle panelBounds, bool hasScroll, int scrolPos, string text, Font font, Graphics graphics)
      {
         int dX = 5 + PanelMargin + (int)(ButtonHeight * 0.75);

         if (hasScroll)
         {
            dX += ButtonHeight - ButtonBottomMargin;
         }

         return GetButtonBounds(-scrolPos + dX, panelBounds.Bottom - ButtonHeight - ButtonBottomMargin - 1, text, font, graphics);
      }

      /// <summary>
      /// Get next button bounds
      /// </summary>
      /// <param name="previousBounds">bounds of the previous button</param>
      /// <param name="text">text of the button</param>
      /// <param name="font">font used to draw the button</param>
      /// <param name="graphics">graphics object</param>
      /// <returns>bounds of the next button</returns>
      public override Rectangle GetNextButtonBounds(Rectangle previousBounds, string text, Font font, Graphics graphics)
      {
         return GetButtonBounds(previousBounds.Right + 2, previousBounds.Top, text, font, graphics);
      }

      /// <summary>
      /// Get buttons clip rectangle
      /// </summary>
      /// <param name="panelBounds">bounds of the panel</param>
      /// <param name="hasScroll">true if the panel has scroll</param>
      /// <param name="captionButtonsCount">number of caption buttons that may be drawn on buttons panel</param>
      /// <returns>clip rectangle for the buttons</returns>
      public override Rectangle GetButtonsClipRectangle(Rectangle panelBounds, bool hasScroll, int captionButtonsCount)
      {
         int dX = 5 + PanelMargin;

         if (hasScroll)
         {
            dX += ButtonHeight - ButtonBottomMargin;
         }

         int dw = ButtonHeight * captionButtonsCount;

         return new Rectangle(dX, panelBounds.Bottom - ButtonHeight - ButtonBottomMargin - 1, panelBounds.Right - 2 * dX - PanelMargin - dw, ButtonHeight + 2);
      }

      /// <summary>
      /// Get the rectangle which will contain caption buttons drawn on panel buttons
      /// </summary>
      /// <param name="panelBounds">panel bounds</param>
      /// <param name="captionButtonsCount">number of caption buttons</param>
      /// <returns>rectangle containing caption buttons</returns>
      public override Rectangle GetCaptionButtonsRectangle(Rectangle panelBounds, int captionButtonsCount)
      {
         int width   = ButtonHeight * captionButtonsCount;
         int height  = ButtonHeight - ButtonBottomMargin;

         return new Rectangle(panelBounds.Right - width - PanelMargin, panelBounds.Bottom - ButtonHeight - 1, width, height);
      }

      /// <summary>
      /// Get client rectangle for the panel bounds
      /// </summary>
      /// <param name="panelBounds">bounds of the panel</param>
      /// <returns>client rectangle for the panel</returns>
      public override Rectangle GetClientRectangle(Rectangle panelBounds)
      {
         Rectangle clientRectangle = new Rectangle();

         clientRectangle.X       = panelBounds.X;
         clientRectangle.Y       = 0;
         clientRectangle.Width   = panelBounds.Width;
         clientRectangle.Height  = panelBounds.Height - clientRectangle.Y - ButtonHeight - ButtonBottomMargin - 1;

         //clientRectangle.X       = panelBounds.X + PanelMargin;
         //clientRectangle.Y       = PanelMargin;
         //clientRectangle.Width   = panelBounds.Width - 2 * PanelMargin - 1;
         //clientRectangle.Height  = panelBounds.Height - clientRectangle.Y - ButtonHeight - ButtonBottomMargin;

         return clientRectangle;
      }

      /// <summary>
      /// Get the caption button index
      /// </summary>
      /// <param name="captionButtonsBounds">bounds of the caption buttons block</param>
      /// <param name="point">point where to search the button</param>
      /// <returns>zero based caption button index</returns>
      public override int GetCaptionButtonIndex(Rectangle captionButtonsBounds, Point point)
      {
         if (captionButtonsBounds.Contains(point) == false)
         {
            return -1;
         }

         return (point.X - captionButtonsBounds.Left) / ButtonHeight;
      }

      /// <summary>
      /// Can undo the displacement of the next button (the next button was displaced before)
      /// </summary>
      /// <param name="displacedButton">displaced button</param>
      /// <param name="selectedButton">selected button</param>
      /// <param name="mouseLocation">current mouse location</param>
      /// <returns>true if can undo</returns>
      internal override bool CanUndoDisplaceNext(TabButton displacedButton, TabButton selectedButton, Point mouseLocation)
      {
         return true;
      }

      /// <summary>
      /// Can undo the displacement of the previous button (the previous button was displaced before)
      /// </summary>
      /// <param name="displacedButton">displaced button</param>
      /// <param name="selectedButton">selected button</param>
      /// <param name="mouseLocation">current mouse location</param>
      /// <returns>true if can undo</returns>
      internal override bool CanUndoDisplaceBack(TabButton displacedButton, TabButton selectedButton, Point mouseLocation)
      {
         return mouseLocation.X < displacedButton.Left + selectedButton.Width;
      }

      /// <summary>
      /// Checks if can scroll next
      /// </summary>
      /// <param name="lastButton">last button</param>
      /// <param name="scrollNextBounds">scroll-next bounds</param>
      /// <returns>true if can scroll next</returns>
      internal override bool CanScrollNext(TabButton lastButton, Rectangle scrollNextBounds)
      {
         return lastButton.Left + lastButton.Width > scrollNextBounds.Left;
      }

      /// <summary>
      /// Get scroll position
      /// </summary>
      /// <param name="buttons">buttons collection</param>
      /// <param name="firstShownButtonIndex">zero based first shown button index</param>
      /// <returns>scroll position</returns>
      internal override int GetScrollPos(IList<TabButton> buttons, int firstShownButtonIndex)
      {
         int scrollPos = 0;
         for (int buttonIndex = 0; buttonIndex < firstShownButtonIndex; buttonIndex++)
         {
            scrollPos += buttons[buttonIndex].Width;
         }

         return scrollPos;
      }

      #endregion Public section

      #region Private section

      /// <summary>
      /// Get button bounds
      /// </summary>
      /// <param name="xPos">x position of the button</param>
      /// <param name="yPos">y position of the button</param>
      /// <param name="text">text of the button</param>
      /// <param name="graphics">graphics object</param>
      /// <returns>bounds of the button</returns>
      private Rectangle GetButtonBounds(int xPos, int yPos, string text, Font font, Graphics graphics)
      {
         int width = ButtonHorizontalMargins + (int)graphics.MeasureString(text, font).Width;

         Rectangle bounds = new Rectangle();

         bounds.X       = xPos;
         bounds.Y       = yPos;
         bounds.Width   = width;
         bounds.Height  = ButtonHeight;

         return bounds;
      }

      #endregion Private section
   }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Romania Romania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions