moel@345: using System; moel@345: using System.Collections.Generic; moel@345: using System.Text; moel@345: using System.ComponentModel; moel@345: using System.Windows.Forms; moel@345: using System.Drawing; moel@345: using System.Windows.Forms.VisualStyles; moel@345: using System.Drawing.Imaging; moel@345: moel@345: namespace Aga.Controls.Tree moel@345: { moel@345: [TypeConverter(typeof(TreeColumn.TreeColumnConverter)), DesignTimeVisible(false), ToolboxItem(false)] moel@345: public class TreeColumn : Component moel@345: { moel@345: private class TreeColumnConverter : ComponentConverter moel@345: { moel@345: public TreeColumnConverter() moel@345: : base(typeof(TreeColumn)) moel@345: { moel@345: } moel@345: moel@345: public override bool GetPropertiesSupported(ITypeDescriptorContext context) moel@345: { moel@345: return false; moel@345: } moel@345: } moel@345: moel@345: private const int HeaderLeftMargin = 5; moel@345: private const int HeaderRightMargin = 5; moel@345: private const int SortOrderMarkMargin = 8; moel@345: moel@345: private TextFormatFlags _headerFlags; moel@345: private TextFormatFlags _baseHeaderFlags = TextFormatFlags.NoPadding | moel@345: TextFormatFlags.EndEllipsis | moel@345: TextFormatFlags.VerticalCenter | moel@345: TextFormatFlags.PreserveGraphicsTranslateTransform; moel@345: moel@345: #region Properties moel@345: moel@345: private TreeColumnCollection _owner; moel@345: internal TreeColumnCollection Owner moel@345: { moel@345: get { return _owner; } moel@345: set { _owner = value; } moel@345: } moel@345: moel@345: [Browsable(false)] moel@345: public int Index moel@345: { moel@345: get moel@345: { moel@345: if (Owner != null) moel@345: return Owner.IndexOf(this); moel@345: else moel@345: return -1; moel@345: } moel@345: } moel@345: moel@345: private string _header; moel@345: [Localizable(true)] moel@345: public string Header moel@345: { moel@345: get { return _header; } moel@345: set moel@345: { moel@345: _header = value; moel@345: OnHeaderChanged(); moel@345: } moel@345: } moel@345: moel@345: private string _tooltipText; moel@345: [Localizable(true)] moel@345: public string TooltipText moel@345: { moel@345: get { return _tooltipText; } moel@345: set { _tooltipText = value; } moel@345: } moel@345: moel@345: private int _width; moel@345: [DefaultValue(50), Localizable(true)] moel@345: public int Width moel@345: { moel@345: get moel@345: { moel@345: return _width; moel@345: } moel@345: set moel@345: { moel@345: if (_width != value) moel@345: { moel@345: _width = Math.Max(MinColumnWidth, value); moel@345: if (_maxColumnWidth > 0) moel@345: { moel@345: _width = Math.Min(_width, MaxColumnWidth); moel@345: } moel@345: OnWidthChanged(); moel@345: } moel@345: } moel@345: } moel@345: moel@345: private int _minColumnWidth; moel@345: [DefaultValue(0)] moel@345: public int MinColumnWidth moel@345: { moel@345: get { return _minColumnWidth; } moel@345: set moel@345: { moel@345: if (value < 0) moel@345: throw new ArgumentOutOfRangeException("value"); moel@345: moel@345: _minColumnWidth = value; moel@345: Width = Math.Max(value, Width); moel@345: } moel@345: } moel@345: moel@345: private int _maxColumnWidth; moel@345: [DefaultValue(0)] moel@345: public int MaxColumnWidth moel@345: { moel@345: get { return _maxColumnWidth; } moel@345: set moel@345: { moel@345: if (value < 0) moel@345: throw new ArgumentOutOfRangeException("value"); moel@345: moel@345: _maxColumnWidth = value; moel@345: if (value > 0) moel@345: Width = Math.Min(value, _width); moel@345: } moel@345: } moel@345: moel@345: private bool _visible = true; moel@345: [DefaultValue(true)] moel@345: public bool IsVisible moel@345: { moel@345: get { return _visible; } moel@345: set moel@345: { moel@345: _visible = value; moel@345: OnIsVisibleChanged(); moel@345: } moel@345: } moel@345: moel@345: private HorizontalAlignment _textAlign = HorizontalAlignment.Left; moel@345: [DefaultValue(HorizontalAlignment.Left)] moel@345: public HorizontalAlignment TextAlign moel@345: { moel@345: get { return _textAlign; } moel@345: set moel@345: { moel@345: if (value != _textAlign) moel@345: { moel@345: _textAlign = value; moel@345: _headerFlags = _baseHeaderFlags | TextHelper.TranslateAligmentToFlag(value); moel@345: OnHeaderChanged(); moel@345: } moel@345: } moel@345: } moel@345: moel@345: private bool _sortable = false; moel@345: [DefaultValue(false)] moel@345: public bool Sortable moel@345: { moel@345: get { return _sortable; } moel@345: set { _sortable = value; } moel@345: } moel@345: moel@345: private SortOrder _sort_order = SortOrder.None; moel@345: public SortOrder SortOrder moel@345: { moel@345: get { return _sort_order; } moel@345: set moel@345: { moel@345: if (value == _sort_order) moel@345: return; moel@345: _sort_order = value; moel@345: OnSortOrderChanged(); moel@345: } moel@345: } moel@345: moel@345: public Size SortMarkSize moel@345: { moel@345: get moel@345: { moel@345: if (Application.RenderWithVisualStyles) moel@345: return new Size(9, 5); moel@345: else moel@345: return new Size(7, 4); moel@345: } moel@345: } moel@345: #endregion moel@345: moel@345: public TreeColumn(): moel@345: this(string.Empty, 50) moel@345: { moel@345: } moel@345: moel@345: public TreeColumn(string header, int width) moel@345: { moel@345: _header = header; moel@345: _width = width; moel@345: _headerFlags = _baseHeaderFlags | TextFormatFlags.Left; moel@345: } moel@345: moel@345: public override string ToString() moel@345: { moel@345: if (string.IsNullOrEmpty(Header)) moel@345: return GetType().Name; moel@345: else moel@345: return Header; moel@345: } moel@345: moel@345: protected override void Dispose(bool disposing) moel@345: { moel@345: base.Dispose(disposing); moel@345: } moel@345: moel@345: #region Draw moel@345: moel@345: private static VisualStyleRenderer _normalRenderer; moel@345: private static VisualStyleRenderer _pressedRenderer; moel@345: private static VisualStyleRenderer _hotRenderer; moel@345: moel@345: private static void CreateRenderers() moel@345: { moel@345: if (Application.RenderWithVisualStyles && _normalRenderer == null) moel@345: { moel@345: _normalRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Normal); moel@345: _pressedRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Pressed); moel@345: _hotRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Hot); moel@345: } moel@345: } moel@345: moel@345: internal Bitmap CreateGhostImage(Rectangle bounds, Font font) moel@345: { moel@345: Bitmap b = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb); moel@345: Graphics gr = Graphics.FromImage(b); moel@345: gr.FillRectangle(SystemBrushes.ControlDark, bounds); moel@345: DrawContent(gr, bounds, font); moel@345: BitmapHelper.SetAlphaChanelValue(b, 150); moel@345: return b; moel@345: } moel@345: moel@345: internal void Draw(Graphics gr, Rectangle bounds, Font font, bool pressed, bool hot) moel@345: { moel@345: DrawBackground(gr, bounds, pressed, hot); moel@345: DrawContent(gr, bounds, font); moel@345: } moel@345: moel@345: private void DrawContent(Graphics gr, Rectangle bounds, Font font) moel@345: { moel@345: Rectangle innerBounds = new Rectangle(bounds.X + HeaderLeftMargin, bounds.Y, moel@345: bounds.Width - HeaderLeftMargin - HeaderRightMargin, moel@345: bounds.Height); moel@345: moel@345: if (SortOrder != SortOrder.None) moel@345: innerBounds.Width -= (SortMarkSize.Width + SortOrderMarkMargin); moel@345: moel@345: Size maxTextSize = TextRenderer.MeasureText(gr, Header, font, innerBounds.Size, TextFormatFlags.NoPadding); moel@345: Size textSize = TextRenderer.MeasureText(gr, Header, font, innerBounds.Size, _baseHeaderFlags); moel@345: moel@345: if (SortOrder != SortOrder.None) moel@345: { moel@345: int tw = Math.Min(textSize.Width, innerBounds.Size.Width); moel@345: moel@345: int x = 0; moel@345: if (TextAlign == HorizontalAlignment.Left) moel@345: x = innerBounds.X + tw + SortOrderMarkMargin; moel@345: else if (TextAlign == HorizontalAlignment.Right) moel@345: x = innerBounds.Right + SortOrderMarkMargin; moel@345: else moel@345: x = innerBounds.X + tw + (innerBounds.Width - tw) / 2 + SortOrderMarkMargin; moel@345: DrawSortMark(gr, bounds, x); moel@345: } moel@345: moel@345: if (textSize.Width < maxTextSize.Width) moel@345: TextRenderer.DrawText(gr, Header, font, innerBounds, SystemColors.ControlText, _baseHeaderFlags | TextFormatFlags.Left); moel@345: else moel@345: TextRenderer.DrawText(gr, Header, font, innerBounds, SystemColors.ControlText, _headerFlags); moel@345: } moel@345: moel@345: private void DrawSortMark(Graphics gr, Rectangle bounds, int x) moel@345: { moel@345: int y = bounds.Y + bounds.Height / 2 - 2; moel@345: x = Math.Max(x, bounds.X + SortOrderMarkMargin); moel@345: moel@345: int w2 = SortMarkSize.Width / 2; moel@345: if (SortOrder == SortOrder.Ascending) moel@345: { moel@345: Point[] points = new Point[] { new Point(x, y), new Point(x + SortMarkSize.Width, y), new Point(x + w2, y + SortMarkSize.Height) }; moel@345: gr.FillPolygon(SystemBrushes.ControlDark, points); moel@345: } moel@345: else if (SortOrder == SortOrder.Descending) moel@345: { moel@345: Point[] points = new Point[] { new Point(x - 1, y + SortMarkSize.Height), new Point(x + SortMarkSize.Width, y + SortMarkSize.Height), new Point(x + w2, y - 1) }; moel@345: gr.FillPolygon(SystemBrushes.ControlDark, points); moel@345: } moel@345: } moel@345: moel@345: internal static void DrawDropMark(Graphics gr, Rectangle rect) moel@345: { moel@345: gr.FillRectangle(SystemBrushes.HotTrack, rect.X-1, rect.Y, 2, rect.Height); moel@345: } moel@345: moel@345: internal static void DrawBackground(Graphics gr, Rectangle bounds, bool pressed, bool hot) moel@345: { moel@345: if (Application.RenderWithVisualStyles) moel@345: { moel@345: CreateRenderers(); moel@345: if (pressed) moel@345: _pressedRenderer.DrawBackground(gr, bounds); moel@345: else if (hot) moel@345: _hotRenderer.DrawBackground(gr, bounds); moel@345: else moel@345: _normalRenderer.DrawBackground(gr, bounds); moel@345: } moel@345: else moel@345: { moel@345: gr.FillRectangle(SystemBrushes.Control, bounds); moel@345: Pen p1 = SystemPens.ControlLightLight; moel@345: Pen p2 = SystemPens.ControlDark; moel@345: Pen p3 = SystemPens.ControlDarkDark; moel@345: if (pressed) moel@345: gr.DrawRectangle(p2, bounds.X, bounds.Y, bounds.Width, bounds.Height); moel@345: else moel@345: { moel@345: gr.DrawLine(p1, bounds.X, bounds.Y, bounds.Right, bounds.Y); moel@345: gr.DrawLine(p3, bounds.X, bounds.Bottom, bounds.Right, bounds.Bottom); moel@345: gr.DrawLine(p3, bounds.Right - 1, bounds.Y, bounds.Right - 1, bounds.Bottom - 1); moel@345: gr.DrawLine(p1, bounds.Left, bounds.Y + 1, bounds.Left, bounds.Bottom - 2); moel@345: gr.DrawLine(p2, bounds.Right - 2, bounds.Y + 1, bounds.Right - 2, bounds.Bottom - 2); moel@345: gr.DrawLine(p2, bounds.X, bounds.Bottom - 1, bounds.Right - 2, bounds.Bottom - 1); moel@345: } moel@345: } moel@345: } moel@345: moel@345: #endregion moel@345: moel@345: #region Events moel@345: moel@345: public event EventHandler HeaderChanged; moel@345: private void OnHeaderChanged() moel@345: { moel@345: if (HeaderChanged != null) moel@345: HeaderChanged(this, EventArgs.Empty); moel@345: } moel@345: moel@345: public event EventHandler SortOrderChanged; moel@345: private void OnSortOrderChanged() moel@345: { moel@345: if (SortOrderChanged != null) moel@345: SortOrderChanged(this, EventArgs.Empty); moel@345: } moel@345: moel@345: public event EventHandler IsVisibleChanged; moel@345: private void OnIsVisibleChanged() moel@345: { moel@345: if (IsVisibleChanged != null) moel@345: IsVisibleChanged(this, EventArgs.Empty); moel@345: } moel@345: moel@345: public event EventHandler WidthChanged; moel@345: private void OnWidthChanged() moel@345: { moel@345: if (WidthChanged != null) moel@345: WidthChanged(this, EventArgs.Empty); moel@345: } moel@345: moel@345: #endregion moel@345: } moel@345: }