/* Copyright (c) Citrix Systems Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Windows; using System.Windows.Forms; using System.Drawing.Drawing2D; using XenAdmin.TabPages; namespace XenAdmin.Controls { public class CustomListRow { private Color ForeColor_ = SystemColors.ControlText; private Color BackColor_ = SystemColors.Control; private Color BorderColor_ = SystemColors.ActiveBorder; private Pen BorderPen = null; private Pen ForePen = null; public Color SelectedBackColor_ = Color.Black; private Brush BackBrush = null; private Brush SelectedBackBrush = null; public bool ShowBorder = true; public bool Enabled = true; public bool DrawChildren = true; private bool _selected = false; public bool Selectable = true; public bool DrawGroupBox = true; public bool ShowOnlyHorizBorder = false; public int Indent = 13; // left-indent to any child rows public float BorderWidth = 1.0f; public Padding Padding = new Padding(0, 3, 0, 3); public List MenuItems = new List(); public ToolStripMenuItem DefaultMenuItem; public CustomListRow Parent; public CustomListPanel ParentPanel; public List Children = new List(); public List Items = new List(); /// /// Construct a header. /// public CustomListRow(object tag, Color back, Color fore, Color border, Font font) { this.BackColor = back; this.ForeColor = fore; this.BorderColor = border; this.SelectedBackColor = back; this.DrawGroupBox = false; this.ShowOnlyHorizBorder = true; CustomListItem name = new CustomListItem(tag, font, fore, new Padding(10, 3, 3, 3)); AddItem(name); init(); } /// /// Construct child rows. /// public CustomListRow(Color back, params CustomListItem[] items) { Selectable = true; BackColor = back; this.SelectedBackColor = back; ShowBorder = false; foreach (CustomListItem item in items) { AddItem(item); } init(); } /// /// Construct fixed row. /// public CustomListRow(Color back, int height) { Selectable = true; BackColor = back; this.SelectedBackColor = back; ShowBorder = false; this.Padding = new Padding(0, 0, 0, height); init(); } private void init() { RecalculateBorderPen(); RecalculateForePen(); RecalculateBackBrushes(); } public Color ForeColor { get { return ForeColor_; } set { ForeColor_ = value; RecalculateForePen(); } } public Color BackColor { get { return BackColor_; } set { BackColor_ = value; RecalculateBorderPen(); } } public Color BorderColor { get { return BorderColor_; } set { BorderColor_ = value; RecalculateBorderPen(); } } private void RecalculateBorderPen() { if (BorderPen != null) BorderPen.Dispose(); BorderPen = new Pen(BorderColor, BorderWidth); } private void RecalculateForePen() { if (ForePen != null) ForePen.Dispose(); ForePen = new Pen(ForeColor); } public Color SelectedBackColor { get { return SelectedBackColor_; } set { SelectedBackColor_ = value; RecalculateBackBrushes(); } } private void RecalculateBackBrushes() { if (BackBrush != null) BackBrush.Dispose(); if (SelectedBackBrush != null) SelectedBackBrush.Dispose(); BackBrush = new SolidBrush(BackColor); SelectedBackBrush = new SolidBrush(SelectedBackColor); } public bool Selected { get { return _selected; } set { _selected = value; if (!value) foreach (CustomListRow child in Children) child.Selected = false; } } public int RowAndChildrenHeight { get { int height = Padding.Vertical + RowHeight; if (DrawChildren) { foreach (CustomListRow child in Children) { height += child.RowAndChildrenHeight; } } return height; } } public int RowHeight { get { int height = 0; int headWidth = HeaderWidth; for (int i = 0; i < Items.Count; i++) { CustomListItem item = Items[i]; Size cSize = item.WrappedSize(headWidth); if (cSize.Height > height) { height = cSize.Height; } if(ParentPanel.level1ColWidths != null && i < ParentPanel.level1ColWidths.Length) headWidth -= ParentPanel.level1ColWidths[i]; } return height; } } public int HeaderWidth { get { if (Parent != null) return Parent.HeaderWidth - (Padding.Horizontal + Indent); else return ParentPanel.Width - (ParentPanel.Padding.Horizontal + Padding.Horizontal); } } public void Dispose() { if (ForePen != null) ForePen.Dispose(); if (BorderPen != null) BorderPen.Dispose(); if (BackBrush != null) BackBrush.Dispose(); if (SelectedBackBrush != null) SelectedBackBrush.Dispose(); foreach (CustomListRow r in Children) { r.Dispose(); } } public void DrawSelf(Graphics g, Rectangle bounds) { int rowHeight = RowHeight; int headWidth = HeaderWidth; using (Brush ParentBackBrush = new SolidBrush(ParentPanel.BackColor)) { g.FillRectangle(ParentBackBrush, bounds); } int top = bounds.Top + Padding.Top; int left = bounds.Left + Padding.Left; for(int i = 0; i < Items.Count; i++) { CustomListItem item = Items[i]; Size itemSize = item.PreferredSize; int itemTop = top; if ((item.Anchor & AnchorStyles.Bottom) > 0) { itemTop += rowHeight - itemSize.Height; } else if ((item.Anchor & AnchorStyles.Top) == 0) { itemTop += Convert.ToInt32(Math.Ceiling(Convert.ToDouble(rowHeight - itemSize.Height) / 2.0d)); } Rectangle itemBounds; if (Parent != null && (i == Items.Count - 1 || Items[i+1].InCorrectColumn)) { int colWidth = 1; if (ParentPanel.level1ColWidths.Length > i) { colWidth = ParentPanel.level1ColWidths[i]; } itemBounds = new Rectangle(new Point(left, itemTop), item.WrappedSize(headWidth - (left - bounds.Left))); left += colWidth; } else { itemBounds = new Rectangle(left, itemTop, itemSize.Width, itemSize.Height); left += itemSize.Width; } if (itemBounds.Right > bounds.Right - Padding.Right) itemBounds.Width -= itemBounds.Right - (bounds.Right - Padding.Right); if (itemBounds.Bottom > bounds.Bottom - Padding.Bottom) itemBounds.Height -= itemBounds.Bottom - (bounds.Bottom - Padding.Bottom); if (i > 0 && Selected && !string.IsNullOrEmpty(item.Tag.ToString())) { if ((i < Items.Count - 1 && !Items[i + 1].InCorrectColumn)) { g.FillRectangle(SystemBrushes.Highlight, new Rectangle(itemBounds.Left - 2, itemBounds.Top - 3, itemBounds.Width + Items[i + 1].PreferredSize.Width + 4, Items[i + 1].PreferredSize.Height + 2)); } else if (item.InCorrectColumn) { g.FillRectangle(SystemBrushes.Highlight, new Rectangle(itemBounds.Left - 2, itemBounds.Top - 1, itemBounds.Width + 4, itemBounds.Height)); } } item.DrawSelf(g, itemBounds, Selected && i > 0 && !(i < Items.Count - 1 && !Items[i + 1].InCorrectColumn)); } top += rowHeight + Padding.Bottom; if (DrawChildren) { foreach (CustomListRow child in Children) { int childHeight = child.RowAndChildrenHeight; Rectangle childBounds = new Rectangle(bounds.Left + Padding.Left + Indent, top, bounds.Width - (Padding.Horizontal + Indent), childHeight); child.DrawSelf(g, childBounds); top += childHeight; } } if (ShowBorder) { if (ShowOnlyHorizBorder) { int w = 1; if(ParentPanel.level1ColWidths.Length >= 2) w = 450; using (Brush brush = new LinearGradientBrush(Point.Empty, new Point(w, 0), BorderColor, BackColor)) { g.FillRectangle(brush, bounds.Left, bounds.Top + rowHeight, w, 1); } } else { g.DrawRectangle(BorderPen, bounds.Left, bounds.Top, headWidth, rowHeight); } if (DrawGroupBox) g.DrawRectangle(BorderPen, bounds.Left, bounds.Top, headWidth, RowAndChildrenHeight); } } public void AddItem(CustomListItem item) { item.Row = this; this.Items.Add(item); } public void AddChild(CustomListRow row) { row.Parent = this; if (this.Children.Count == 0) row.Padding.Top = 10; row.ParentPanel = ParentPanel; Children.Add(row); } internal CustomListRow SelectChild(Point point, out Point rowRelativePoint) { int top = Padding.Vertical + RowHeight; foreach (CustomListRow child in Children) { int height = child.RowAndChildrenHeight; if (point.Y >= top && point.Y < top + height) { int leftPos = point.X - Padding.Left - Indent; rowRelativePoint = new Point(leftPos, point.Y - top); if (leftPos < 0) // off the left hand side of the subrow return null; return child; } top += height; } rowRelativePoint = new Point(); return null; } private CustomListItem GetItemFromPosition(Point point, out Point itemRelativePoint) { int left = Padding.Left; for (int i = 0; i < ParentPanel.level1ColWidths.Length; i++) { if (i >= Items.Count) continue; CustomListItem item = Items[i]; if (item == null) continue; int width = item.itemBorder.Horizontal + ParentPanel.level1ColWidths[i]; if (point.X >= left && point.X < left + width) { itemRelativePoint = new Point(point.X - left, point.Y - Padding.Top); return item; } left += width; } itemRelativePoint = new Point(); return null; } public void OnMouseClick(MouseEventArgs e, Point point) { if (point.Y > RowHeight + Padding.Vertical) { Point rowRelativePoint; CustomListRow row = SelectChild(point, out rowRelativePoint); if (row == null) return; row.OnMouseClick(e, rowRelativePoint); } else { Point itemRelativePoint; CustomListItem item = GetItemFromPosition(point, out itemRelativePoint); if (item == null) return; item.OnMouseClick(e, itemRelativePoint); } } public void OnMouseDoubleClick(MouseEventArgs e, Point point) { if (e.Button == MouseButtons.Left) { if (DefaultMenuItem != null) DefaultMenuItem.PerformClick(); } if (point.Y > RowHeight + Padding.Vertical) { Point rowRelativePoint; CustomListRow row = SelectChild(point, out rowRelativePoint); if (row == null) return; row.OnMouseDoubleClick(e, rowRelativePoint); } else { Point itemRelativePoint; CustomListItem item = GetItemFromPosition(point, out itemRelativePoint); if (item == null) return; item.OnMouseDoubleClick(e, itemRelativePoint); } } public void OnMouseDown(Point point) { if (point.Y > RowHeight + Padding.Vertical) { Point rowRelativePoint; CustomListRow row = SelectChild(point, out rowRelativePoint); if (row == null) { ParentPanel.ClearSelection(); return; } row.OnMouseDown(rowRelativePoint); } else { if (!Selectable) return; ParentPanel.ClearSelection(); Selected = true; ParentPanel.SelectedRow = this; ParentPanel.Invalidate(); } } /* * This code is almost identical to the code for tracking mouse movements * in the CustomGridRow. */ private CustomListItem currentItem; private CustomListRow currentRow; public virtual void OnMouseEnter(Point point) { System.Diagnostics.Trace.Assert(currentItem == null && currentRow == null); if (point.Y > RowHeight + Padding.Vertical) { Point rowRelativePoint; currentRow = SelectChild(point, out rowRelativePoint); if (currentRow == null) return; currentRow.OnMouseEnter(rowRelativePoint); } else { Point itemRelativePoint; currentItem = GetItemFromPosition(point, out itemRelativePoint); if (currentItem == null) return; currentItem.OnMouseEnter(itemRelativePoint); } } public virtual void OnMouseMove(Point point) { System.Diagnostics.Trace.Assert(currentItem == null || currentRow == null); if (point.Y > RowHeight + Padding.Vertical) { if (currentItem != null) { currentItem.OnMouseLeave(); currentItem = null; } Point rowRelativePoint; CustomListRow row = SelectChild(point, out rowRelativePoint); if (row != null && currentRow == row) { currentRow.OnMouseMove(rowRelativePoint); return; } if (currentRow != null) currentRow.OnMouseLeave(); currentRow = row; if (currentRow != null) currentRow.OnMouseEnter(rowRelativePoint); } else { if(currentRow != null) { currentRow.OnMouseLeave(); currentRow = null; } Point itemRelativePoint; CustomListItem item = GetItemFromPosition(point, out itemRelativePoint); if (item != null && currentItem == item) { currentItem.OnMouseMove(itemRelativePoint); return; } if (currentItem != null) currentItem.OnMouseLeave(); currentItem = item; if (currentItem != null) currentItem.OnMouseEnter(itemRelativePoint); } } public virtual void OnMouseLeave() { System.Diagnostics.Trace.Assert(currentItem == null || currentRow == null); if (currentItem != null) { currentItem.OnMouseLeave(); currentItem = null; } if (currentRow != null) { currentRow.OnMouseLeave(); currentRow = null; } } } }