/* 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.Forms; namespace XenAdmin.Controls.CustomGridView { public abstract class GridArrayItem : GridItemBase { protected readonly GridItemBase[] items; public GridArrayItem(GridItemBase[] items, bool clickSelectsRow) : base(false, 1, clickSelectsRow, null, null) { this.items = items; } // NB public abstract void OnPaint(ItemPaintArgs itemPaintArgs) still abstract from base class // Which subitem the mouse is in, and where it is in it. // May return null if we're in the padding between items. protected abstract GridItemBase CurrentItem(Point point, out Point subItemPoint); public override GridRow Row { set { base.Row = value; foreach (GridItemBase item in items) item.Row = value; } } public override void OnMouseButtonAction(Point point, MouseButtonAction type) { Point subItemPoint; GridItemBase subItem = CurrentItem(point, out subItemPoint); if (subItem != null) subItem.OnMouseButtonAction(subItemPoint, type); else base.OnMouseButtonAction(point, type); } protected GridItemBase mouseTrackedItem; public override void OnEnter(Point point) { if (mouseTrackedItem != null) OnLeave(); Point subItemPoint; mouseTrackedItem = CurrentItem(point, out subItemPoint); if (mouseTrackedItem != null) mouseTrackedItem.OnEnter(subItemPoint); } public override void OnMouseMove(Point point) { Point subItemPoint; GridItemBase subItem = CurrentItem(point, out subItemPoint); if (mouseTrackedItem != subItem) { if (mouseTrackedItem != null) mouseTrackedItem.OnLeave(); mouseTrackedItem = subItem; if (subItem != null) subItem.OnEnter(subItemPoint); } if (mouseTrackedItem != null) mouseTrackedItem.OnMouseMove(subItemPoint); } public override void OnLeave() { if (mouseTrackedItem == null) return; mouseTrackedItem.OnLeave(); mouseTrackedItem = null; } public override int CompareTo(GridItemBase other) { GridVerticalArrayItem otherArrayItem = other as GridVerticalArrayItem; if (otherArrayItem == null) return -1; for (int i = 0; i < items.Length; i++) { if (i >= otherArrayItem.items.Length) return 1; int comp = items[i].CompareTo(otherArrayItem.items[i]); if (comp != 0) return comp; } return items.Length == otherArrayItem.items.Length ? 0 : -1; } } public class GridVerticalArrayItem : GridArrayItem { private const int Padding = 1; private bool RegularSpacing; private int ItemHeight; public GridVerticalArrayItem(GridItemBase[] items, bool clickSelectsRow) : this(items, -1, clickSelectsRow) { } public GridVerticalArrayItem(GridItemBase[] items, int itemfixedheight, bool clickSelectsRow) : base(items, clickSelectsRow) { RegularSpacing = itemfixedheight != -1; ItemHeight = itemfixedheight; } /// /// Gets the total width of all the contents of the grid item. For this type of item /// it will be the width of the longest of the consisting items. /// /// The column this item belongs to internal override int GetGridItemWidth(string column) { int maxWidth = 0; foreach (GridItemBase item in items) { int itemWidth = item.GetGridItemWidth(column); if (itemWidth > maxWidth) maxWidth = itemWidth; } return maxWidth; } public override void OnPaint(ItemPaintArgs itemPaintArgs) { if (items.Length == 0) return; Rectangle rect = itemPaintArgs.Rectangle; // Padding at top, bottom and between each item. // If this changes, CurrentItem() needs to change. rect.Y += Padding; if (RegularSpacing) rect.Height = ItemHeight; else { rect.Height -= Padding * items.Length; rect.Height /= items.Length; } foreach (GridItemBase item in items) { item.OnPaint(new ItemPaintArgs(itemPaintArgs.Graphics, rect, itemPaintArgs.State)); rect.Y += rect.Height + Padding; } } // Needs to be coordinated with OnPaint(). protected override GridItemBase CurrentItem(Point point, out Point subItemPoint) { if (items.Length == 0) { subItemPoint = new Point(0, 0); return null; } int subItemHeight; if (RegularSpacing) subItemHeight = ItemHeight; else subItemHeight = (Row.RowHeight - (Padding * (items.Length + 1))) / items.Length; // from OnPaint() int offset = 0; foreach (GridItemBase item in items) { // The padding above an item: return null if (point.Y < offset + Padding) { subItemPoint = new Point(point.X, point.Y - offset); return null; } offset += Padding; // The item itself if (point.Y < offset + subItemHeight) { subItemPoint = new Point(point.X, point.Y - offset); return item; } offset += subItemHeight; } // The padding below the last item: return null subItemPoint = new Point(point.X, point.Y - offset); return null; } } public class GridHorizontalArrayItem : GridArrayItem { private const int IndentDistance = 25; private const int MinimumWidth = 75; private const int Padding = 3; private int indent; private int[] widths; private Rectangle lastPaintRectangle; // There should be one fewer width than items public GridHorizontalArrayItem(int indent, GridItemBase[] items, int[] widths, bool clickSelectsRow) : base(items, clickSelectsRow) { this.indent = indent; this.widths = widths; } /// /// Gets the total width of all the contents of the grid item. For this type of item /// it will be the sum of the widths of the consisting items plus the indentation and paddings. /// /// The column this item belongs to internal override int GetGridItemWidth(string column) { int itemWidth = indent * IndentDistance; for (int i = 0; i < widths.Length; i++) itemWidth += widths[i] + Padding; //items are one more than widths so the last one has index widths.Length itemWidth += items[widths.Length].GetGridItemWidth(column); if (itemWidth > MinimumWidth) return itemWidth; return MinimumWidth; } public override void OnPaint(ItemPaintArgs itemPaintArgs) { lastPaintRectangle = itemPaintArgs.Rectangle; if (items.Length == 0) return; Rectangle rect = itemPaintArgs.Rectangle; int ind = indent * IndentDistance; if (rect.Width - ind < MinimumWidth) // not enough room to indent fully: do as much as we can ind = Math.Max(rect.Width - MinimumWidth, 0); rect.X += ind; rect.Width -= ind; for (int i = 0; i < items.Length; ++i) { items[i].OnPaint(new ItemPaintArgs(itemPaintArgs.Graphics, rect, itemPaintArgs.State)); if (i < items.Length - 1) { ind = widths[i] + Padding; rect.X += ind; rect.Width -= ind; } } } // Needs to be coordinated with OnPaint(). protected override GridItemBase CurrentItem(Point point, out Point subItemPoint) { if (items.Length == 0) { subItemPoint = new Point(0, 0); return null; } // The padding before the first item: return null int offset = indent * IndentDistance; if (lastPaintRectangle.Width - offset < MinimumWidth) // not enough room to indent fully: do as much as we can offset = Math.Max(lastPaintRectangle.Width - MinimumWidth, 0); if (point.X < offset) { subItemPoint = new Point(point.X, point.Y); return null; } for (int i = 0; i < items.Length; ++i) { // The item itself if (i == items.Length - 1 || point.X < offset + widths[i]) { subItemPoint = new Point(point.X - offset, point.Y); return items[i]; } offset += widths[i]; // The padding right of an item: return null if (point.X < offset + Padding) { subItemPoint = new Point(point.X - offset, point.Y); return null; } offset += Padding; } // Can't get here, but the compiler isn't smart enough to know that subItemPoint = new Point(0, 0); return null; } } }