Click here to Skip to main content
15,896,063 members
Articles / Desktop Programming / Windows Forms

Controls Library: Extended ListView with Column Mapping

Rate me:
Please Sign up or sign in to vote.
4.86/5 (29 votes)
27 Mar 2014CPOL5 min read 83.2K   7.6K   110  
Docking windows container, extended listview, extended property editor.
using System;
using System.Collections.Generic;
using System.Text;
using dwf.tool;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;

namespace dwf.gui
{
    public class DockPageBox : UserControl
    {
        private PCellStyle st = new PCellStyle();
        private int padding = 3;
        private Orientation itemOrientation = Orientation.Horizontal;
        private Orientation orientation = Orientation.Horizontal;
        private DockPageList items;
        private DockPage hover = null;
        private DockPage closeHover = null;
        private ToolTip toolTip = new ToolTip();
        //private int min = 100;
        private EventHandler<DockPageEventArgs> handlePageClick;
        private EventHandler<DockPageEventArgs> handlePageClose;
        private EventHandler<DockPageEventArgs> handlePageHover;
        private EventHandler<DockPageEventArgs> handlePageLeave;
        private EventHandler<DockPageEventArgs> handlePageDrag;
        private EventHandler<DockPageEventArgs> handlePageMove;
        private Point p0;
        private bool mdown = false;
        private bool visibleClose = true;
        private bool visibleImage = true;

        public DockPageBox()
            : base()
        {
            items = new DockPageList(this);
            items.ListChanged += ListChanged;

            //toolTip.AutoPopDelay = 5000;
            //toolTip.InitialDelay = 1000;
            //toolTip.ReshowDelay = 1000;
            //toolTip.AutomaticDelay = 1000;
            DoubleBuffered = true;

            st.Font = new Font("SanSeriff", 9);
            st.BackBrush.Type = CellStyleBrushType.Gradient;
            st.BackBrush.SColor = Color.FromArgb(220, 225, 220);
            st.BackBrush.HColor = Color.FromArgb(230, 225, 200);
            st.BorderBrush.SColor = Color.FromArgb(150, 150, 150);
            st.BorderBrush.HColor = Color.FromArgb(150, 150, 150);
            st.Round = 3;
            st.Format.Trimming = StringTrimming.EllipsisCharacter;
            st.FontBrush.SColor = Color.Black;
            st.FontBrush.Color = Color.WhiteSmoke;

        }
        
        protected override void Dispose(bool disposing)
        {
            items.ListChanged -= ListChanged;
            items.Dispose();
            base.Dispose(disposing);
        }

        private void ListChanged(object sender, ListChangedEventArgs arg)
        {
            AllocItems(Bounds);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            AllocItems(Bounds);
        }

        public void AllocItems(Rectangle allocation)
        {
            int max = 350;
            int itemsCount = 0;
            foreach (var item in this.Items)
                if (item.Visible)
                    itemsCount++;
            int childLen = GetChildsWidth(max);
            if (orientation != ItemOrientation)
                max = 100;
            else if (orientation == Orientation.Horizontal && childLen > allocation.Width)
            {
                max = (allocation.Width - itemsCount * padding) / itemsCount;
                foreach (var item in this.Items)
                {
                    int w = GetToolWidth(item, max);
                    if (item.Visible && w < max)
                    {
                        max += (max - w) / itemsCount;
                    }
                }
            }
            else if (orientation == Orientation.Vertical && childLen > allocation.Height)
            {
                max = (allocation.Height - itemsCount * padding) / itemsCount;
            }

            int x = 0;//allocation.X;
            int y = 0;//allocation.Y;
            foreach (DockPage w in items)
            {
                if (w.Visible)
                {
                    //w.SizeRequest();
                    int ww = GetToolWidth(w, max);
                    int hh = 25;
                    if (orientation != ItemOrientation)
                        ww = max;
                    if (this.ItemOrientation == Orientation.Vertical)
                    {
                        hh = ww;
                        ww = 25;
                    }
                    w.Allocation = new Rectangle(x, y, ww < 1 ? 1 : ww, hh < 1 ? 1 : hh);
                    if (this.Orientation == Orientation.Horizontal)
                        x = w.Allocation.Right + padding;
                    else
                        y = w.Allocation.Bottom + padding;
                }
            }
            Invalidate();
        }

        public event EventHandler<DockPageEventArgs> PageDrag
        {
            add { this.handlePageDrag += value; }
            remove { this.handlePageDrag -= value; }
        }

        protected void OnPageDrag(DockPageEventArgs arg)
        {
            if (this.handlePageDrag != null)
                this.handlePageDrag(this, arg);
        }

        public event EventHandler<DockPageEventArgs> PageMove
        {
            add { this.handlePageMove += value; }
            remove { this.handlePageMove -= value; }
        }

        protected void OnPageMove(DockPageEventArgs arg)
        {
            if (this.handlePageMove != null)
                this.handlePageMove(this, arg);
            if (mdown && p0.X != 0 && p0.Y != 0)
                if (Math.Abs(p0.X - arg.Point.X) > 12 ||
                    Math.Abs(p0.Y - arg.Point.Y) > 12)
                    OnPageDrag(arg);
        }

        public event EventHandler<DockPageEventArgs> PageClick
        {
            add { this.handlePageClick += value; }
            remove { this.handlePageClick -= value; }
        }

        protected void OnPageClick(DockPageEventArgs arg)
        {
            if (!arg.Page.Active)
                arg.Page.Active = !arg.Page.Active;
            Invalidate();
            if (this.handlePageClick != null)
                this.handlePageClick(this, arg);
        }

        public event EventHandler<DockPageEventArgs> PageClose
        {
            add { this.handlePageClose += value; }
            remove { this.handlePageClose -= value; }
        }

        public void ClosePage(DockPage page)
        {
            DockPageEventArgs arg = new DockPageEventArgs(page);
            OnPageClose(arg);
        }

        protected void OnPageClose(DockPageEventArgs arg)
        {
            if (this.handlePageClose != null)
                this.handlePageClose(this, arg);

            if (!arg.Page.HideOnClose)
            {
                arg.Page.Widget.Dispose();
            }
            Items.Remove(arg.Page);
        }

        public event EventHandler<DockPageEventArgs> PageHover
        {
            add { this.handlePageHover += value; }
            remove { this.handlePageHover -= value; }
        }

        protected void OnPageHover(DockPageEventArgs arg)
        {
            if (this.handlePageHover != null)
                this.handlePageHover(this, arg);
            hover = arg.Page;
            toolTip.SetToolTip(this, arg.Page.Label);
        }

        public event EventHandler<DockPageEventArgs> PageLeave
        {
            add { this.handlePageLeave += value; }
            remove { this.handlePageLeave -= value; }
        }

        protected void OnPageLeave(DockPageEventArgs arg)
        {
            if (this.handlePageLeave != null)
                this.handlePageLeave(this, arg);
            hover = null;
            closeHover = null;
            p0.X = 0;

        }

        public DockPageList Items
        {
            get { return this.items; }
        }

        public Orientation ItemOrientation
        {
            get { return this.itemOrientation; }
            set
            {
                if (itemOrientation == value)
                    return;
                itemOrientation = value;
                AllocItems(Bounds);
            }
        }

        public Orientation Orientation
        {
            get { return this.orientation; }
            set
            {
                if (orientation == value)
                    return;
                orientation = value;
                AllocItems(Bounds);
            }
        }

        public int Pad
        {
            get { return this.padding; }
            set { padding = value; }
        }

        public PCellStyle PageStyle
        {
            get { return this.st; }
            set
            {
                st = value;
                AllocItems(Bounds);
            }
        }

        public DockPanel Panel
        {
            get { return Parent as DockPanel; }
        }

        public DockPageEventArgs HitTest(int x, int y)
        {
            foreach (DockPage page in items)
            {
                if (page.Visible && page.Allocation.Contains(x, y))
                {
                    DockPageEventArgs arg = new DockPageEventArgs(page);
                    arg.Point = new Point(x, y);
                    return arg;
                }
            }
            return null;
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            DockPageEventArgs arg = HitTest((int)e.X, (int)e.Y);
            if (arg != null)
            {
                if (hover != arg.Page)
                {
                    if (hover != null)
                        OnPageLeave(arg);
                    OnPageHover(arg);
                }
                else
                {
                    OnPageMove(arg);
                }
                Rectangle r = GetCloseRect(arg.Page);
                if (r.Contains((int)e.X, (int)e.Y))
                {
                    closeHover = arg.Page;
                    Invalidate();
                }
                else if (closeHover != null)
                {
                    closeHover = null;
                    Invalidate();
                }
            }
            else if (hover != null)
            {
                OnPageLeave(new DockPageEventArgs(hover));
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            DockPageEventArgs arg = HitTest((int)e.X, (int)e.Y);
            if (arg != null)
            {
                if (e.Button == MouseButtons.Left)
                {
                    if (VisibleClose && GetCloseRect(arg.Page).Contains((int)e.X, (int)e.Y))
                    {
                        if (arg.Page.Widget is Form && !arg.Page.HideOnClose)
                        {
                            ((Form)arg.Page.Widget).Close();
                        }
                        else
                            OnPageClose(arg);
                    }
                    else
                    {
                        OnPageClick(arg);
                    }
                }
            }
            mdown = false;
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            DockPageEventArgs arg = HitTest((int)e.X, (int)e.Y);
            if (arg != null)
            {
                mdown = true;
                p0 = arg.Point;
            }
        }

        protected override void OnLeave(EventArgs e)
        {
            base.OnLeave(e);
            if (closeHover != null)
            {
                closeHover = null;
                Invalidate();
            }
            if (hover != null)
                OnPageLeave(new DockPageEventArgs(hover));
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            GraphContext c = new GraphContext(e.Graphics);
            c.G.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            c.G.SmoothingMode = SmoothingMode.AntiAlias;
            PCellStyle st = PageStyle;

            Rectangle rectb = new Rectangle();
            if (this.orientation == Orientation.Horizontal)
                rectb = new Rectangle(0, Bounds.Bottom - 4, Bounds.Width, 4);
            else
                rectb = new Rectangle(Bounds.Right - 4, 0, 4, Bounds.Height);

            if (Panel.PagesAlign == LayoutAlignType.Bottom)
                rectb.Y = 0;

            if (ItemOrientation == Orientation.Horizontal)
                st.Angle = 0;
            else
                st.Angle = 90;
            foreach (DockPage page in items)
            {
                if (page.Visible)
                {
                    Rectangle rect = page.Allocation;
                    Rectangle irect = new Rectangle(page.Allocation.X + 2, page.Allocation.Y + 2, VisibleImage && page.Image != null ? 20 : 3, VisibleImage && page.Image != null ? 20 : 3);
                    Rectangle trect = new Rectangle(
                    page.Allocation.X + (ItemOrientation == Orientation.Horizontal ? irect.Width + 4 : 2),
                    page.Allocation.Y + (ItemOrientation == Orientation.Horizontal ? 2 : irect.Height + 4),
                    ItemOrientation == Orientation.Horizontal ? page.Allocation.Width - (2 + irect.Width + (VisibleClose ? 15 : 0)) : 20,
                    ItemOrientation == Orientation.Horizontal ? 18 : page.Allocation.Height - (2 + irect.Height + (VisibleClose ? 15 : 0)));

                    GuiService.PaintCell(c, page.Label, rect, trect, st, page.Active ? ContainsFocus ? CellDisplayState.Hover : CellDisplayState.Selected : CellDisplayState.Default);
                    if (VisibleClose)
                        PaintClose(c, page);
                    //image
                    if (VisibleImage && page.Image != null)
                        c.G.DrawImage(page.Image, irect);
                }
            }
            if (items.Count > 0)
                e.Graphics.FillRectangle(st.BackBrush.GetBrush(rectb, st.BackBrush.SColor), rectb);
            //c.Dispose ();
        }

        public Rectangle GetCloseRect(DockPage page)
        {
            return new Rectangle(
                (ItemOrientation == Orientation.Horizontal ? page.Allocation.Right - 14 : page.Allocation.X + 3),
                (ItemOrientation == Orientation.Horizontal ? page.Allocation.Y + 6 : page.Allocation.Bottom - 14),
                12, 12);
        }

        protected virtual void PaintClose(GraphContext c, DockPage page)
        {
            Rectangle r = GetCloseRect(page);
            if (closeHover == page)
            {
                GraphicsPath path = GuiService.GetRoundedRect(r, 4);
                c.G.DrawPath(SystemPens.ActiveBorder, path);
                path.Dispose();
            }
            Pen p = new Pen(SystemBrushes.GrayText);
            p.SetLineCap(LineCap.Round, LineCap.Round, DashCap.Round);
            if (page.Active)
                p.Width = 2;
            else
                p.Width = 1;
            c.G.DrawLine(p, r.X + 3, r.Y + 3, r.Right - 3, r.Bottom - 3);
            c.G.DrawLine(p, r.X + 3, r.Bottom - 3, r.Right - 3, r.Y + 3);
        }

        public int GetChildsWidth(int max)
        {
            int w = 0;
            foreach (DockPage dt in items)
            {
                if (dt.Visible)
                    w += GetToolWidth(dt, max) + padding;
            }
            return w;
        }

        public int GetChildsHeight()
        {
            int w = 0;
            foreach (DockPage dt in items)
            {
                w += dt.Allocation.Height;
            }
            return w;
        }

        public int GetToolWidth(DockPage tool, int max)
        {
            int w = 18;
            if (tool.Image != null && visibleImage)
                w += 20;
            if (visibleClose)
                w += 5;
            w += (int)GuiService.MeasureString(tool.Label, st.Font, st.Format, max).Width;
            return (w > max) ? max : w;
        }

        public bool VisibleClose
        {
            get { return visibleClose; }
            set { visibleClose = value; }
        }

        public bool VisibleImage
        {
            get { return visibleImage; }
            set { visibleImage = value; }
        }
    }

    public class DockPageEventArgs : EventArgs
    {
        private DockPage page;
        private Point point;

        public DockPageEventArgs(DockPage page)
        {
            this.page = page;
        }

        public Point Point
        {
            get { return this.point; }
            set { point = value; }
        }

        public DockPage Page
        {
            get { return this.page; }
            set { page = value; }
        }
    }
}

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
Kazakstan Kazakstan
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions