Click here to Skip to main content
15,896,359 members
Articles / Programming Languages / C#

Horizontal Tree Control

Rate me:
Please Sign up or sign in to vote.
4.57/5 (7 votes)
12 Jan 2008CPOL5 min read 78.5K   1.2K   94  
A Vista Explorer like implementation of a control that represents hierachical data.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using Sarafian.Framework.ClientSide.UI.Resources.HorizontalTree.NodeControls;
using Sarafian.Framework.ClientSide.UI.Resources.HorizontalTree.Nodes;
using Sarafian.Framework.ClientSide.UI.Resources.HorizontalTree.NodeParts;

namespace Sarafian.Framework.ClientSide.UI.Resources.HorizontalTree.Selection
{
    public partial class SelectorControl : ListBox
    {
        public SelectorControl()
        {
            base.BackColor = Color.WhiteSmoke;
            base.DrawMode = DrawMode.OwnerDrawFixed;
            base.Visible = false;
        }
        private SolidBrush sbBack = new SolidBrush(Color.FromArgb(100, Color.LightGray));

        private HorizontalTreeControl horizontalTree;
        public HorizontalTreeControl HorizontalTree
        {
            get { return this.horizontalTree; }
            set
            {
                this.horizontalTree = value;
                base.BackColor = this.horizontalTree.SelectorBackColor;
                this.horizontalTree.ParentForm.Controls.Add(this);
            }
        }

        private NodeBaseControl baseParent;
        public NodeBaseControl BaseParent
        {
            get { return this.baseParent; }
            set { this.baseParent = value; }
        }
        internal void Populate()
        {
            base.Items.Clear();
            AddNodes(this.baseParent.Nodes);
        }
        private bool itemsHaveImage = false;
        internal void AddNodes(NodeBase[] nodes)
        {
            base.Items.AddRange(nodes);
            this.itemsHaveImage = false;
            foreach (NodeBase node in nodes)
            {
                if (node is Node)
                {
                    if ((node as Node).Image != null)
                    {
                        this.itemsHaveImage = true;
                        continue;
                    }
                }
            }
            base.ClientSize = new Size(GetWidth(), base.Items.Count * base.ItemHeight);
        }
        internal void RemoveNode(object node)
        {
            base.Items.Remove(node);
            base.ClientSize = new Size(base.ClientSize.Width, base.Items.Count * base.ItemHeight);
        }
        private Node selectedNode = null;
        public Node SelectedNode
        {
            get { return this.selectedNode; }
        }

        private int GetWidth()
        {
            int width = 0;
            using (Graphics g = Graphics.FromHwnd(this.Handle))
            {
                foreach (NodeBase nodeBase in base.Items)
                {
                    if (nodeBase is NodeSeperator)
                    {
                        continue;
                    }
                    Node node = nodeBase as Node;
                    Size temp = g.MeasureString(node.DisplayText, base.Font).ToSize();
                    if (temp.Width + node.ImageSize.Width > width)
                    {
                        width = temp.Width + node.ImageSize.Width + 5;
                    }
                }
            }
            return width + Configuration.Margin;
        }
        private void DrawSeperator(Rectangle bounds, Graphics g, NodeSeperator seperator)
        {
            int offSet = (bounds.Width * (100 - seperator.Percent)) / 100;
            Point start = bounds.Location;
            start.Y += (int)((float)bounds.Height) / 2;
            start.X += offSet;
            Point end = new Point(bounds.Right - offSet, start.Y);
            g.DrawLine(HorizontalTree.LinePen, start, end);
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            if (base.Items[e.Index] is NodeSeperator)
            {
                DrawSeperator(e.Bounds, e.Graphics, (NodeSeperator)base.Items[e.Index]);
                return;
            }
            Node node = (Node)base.Items[e.Index];
            Rectangle border = e.Bounds;
            border.Width--;
            border.Height--;

            if (e.State == DrawItemState.Selected)
            {

                using (LinearGradientBrush lgb = new LinearGradientBrush(e.Bounds, this.horizontalTree.HotColorMinOpacity, this.horizontalTree.HotColorMaxOpacity, 90, false))
                {
                    e.Graphics.FillRectangle(lgb, e.Bounds);
                }
                e.Graphics.DrawPath(HorizontalTree.HotColorPen, Sarafian.Framework.General.Drawing.Rectangle.GetBorderPath(border));
            }
            else
            {
                e.Graphics.FillRectangle(HorizontalTree.SelectorBackBrush, e.Bounds);
            }
            if (this.itemsHaveImage)
            {
                Rectangle imageRect = new Rectangle(0, e.Bounds.Y, e.Bounds.Height, e.Bounds.Height);
                Rectangle textRect = e.Bounds;
                Point lineStart = new Point(imageRect.Right + 2, imageRect.Y);
                Point lineEnd = new Point(lineStart.X, imageRect.Bottom);
                textRect.X = lineEnd.X + 3;
                textRect.Width = e.Bounds.Width - textRect.X;

                if (node.Image != null)
                {
                    e.Graphics.DrawImage(node.Image, imageRect);
                }
                e.Graphics.DrawLine(HorizontalTree.LinePen, lineStart, lineEnd);

                e.Graphics.DrawString(node.DisplayText, e.Font, Brushes.Black, textRect);
            }
            else
            {
                e.Graphics.DrawString(node.DisplayText, e.Font, Brushes.Black, e.Bounds);
            }
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (!base.ClientRectangle.Contains(e.Location))
            {
                Canceled();
            }
        }
        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
            if (base.SelectedIndex == -1 || base.SelectedItem is NodeSeperator)
            {
            }
            else
            {
                this.selectedNode = (Node)base.SelectedItem;
                Selected();
            }
        }


        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (base.ClientRectangle.Contains(e.Location))
            {
                int indexToSelect = (int)((float)e.Y / base.ItemHeight);
                if (indexToSelect < base.Items.Count)
                {
                    base.SelectedIndex = indexToSelect;
                }
            }
            else
            {
                this.horizontalTree.MouseMoveFromSelector(Sarafian.Framework.General.Drawing.Point.TranslatePoint(this, this.horizontalTree, e.Location));
                base.SelectedIndex = -1;
            }

        }


        protected override void OnMouseLeave(EventArgs e)
        {
            base.SelectedIndex = -1;
        }
        internal event DelegateEnum.DelegateSelectorSelected Selected = null;
        internal event DelegateEnum.DelegateSelectorCanceled Canceled = null;

    }
}

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
Team Leader ALGOSYSTEMS
Greece Greece
I live in Athens Greece and currently I am working with Business scale application with .NET latest technologies

I've been developing applications for personal and friends usage with C++ using majorly Borland's various IDEs since 1994.
In 2002 I began working for an R&D institute where I was introduced to C# which I worships ever since.

I love core application development and I would like to publish more articles here and on my blog, but there is not enough time to do so.

I usualy "waste" my spare time watching sitcoms, preferable SCI-FI.
I would like to play chess but I can't find any real world players to hang out with.

Comments and Discussions