using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using System.Drawing.Drawing2D; namespace UsageControl { public partial class QueueUsageControl : UserControl { private List _queuedItems; private int _maxItemsVisible = 0; private int _lastVisibleItemIndex = 0; private int _itemHeight = 0; private Dictionary _imagesCache = new Dictionary(); private GraphicsPath _pathBorder; private RectangleF [] _slots; private bool _invalidate = true; public QueueUsageControl() { //Debug.WriteLine("QueueUsageControl"); EnableDoubleBuffering(); Reset(); InitializeComponent(); ControlRezised(); } public static Bitmap GenerateItemImage(string text, Color color, int width, int height, Font font) { //Debug.WriteLine("GenerateItemImage"); Rectangle rc = new Rectangle(0, 0, width, height); Bitmap itemImage = new Bitmap(rc.Width, rc.Height); /// Create button rc.Inflate(-3, -3); GraphicsPath path1 = GetPath(rc, 10); rc.Inflate(0, 6); LinearGradientBrush br1 = new LinearGradientBrush(rc, color, Color.White, LinearGradientMode.Vertical); rc.Inflate(0, -6); /// Create shadow Rectangle rc2 = rc; rc2.Offset(8, 8); GraphicsPath path2 = GetPath(rc2, 20); PathGradientBrush br2 = new PathGradientBrush(path2); br2.CenterColor = ControlPaint.DarkDark(Color.Silver); br2.SurroundColors = new Color[] { Color.White }; /// Create bubble Rectangle rc3 = rc; rc3.Inflate(-15, -rc.Height / 3); rc3.Y = rc3.Y - 2; //rc3.Height = rc3.Height; GraphicsPath path3 = GetPath(rc3, rc3.Height); LinearGradientBrush br3 = new LinearGradientBrush(rc3, Color.FromArgb(255, Color.White), Color.FromArgb(0, Color.White), LinearGradientMode.Vertical); itemImage = new Bitmap(width - 2, height); Graphics g = Graphics.FromImage(itemImage); g.SmoothingMode = SmoothingMode.AntiAlias; g.FillPath(br2, path2); g.FillPath(br1, path1); g.FillPath(br3, path3); //SizeF size = g.MeasureString(text, font); //int fontHeight = (int)size.Height + 5; //g.DrawString( // text, // font, // Brushes.Black, // new RectangleF((rc.Width - size.Width) / 2, 2, width, fontHeight)); return itemImage; } private Bitmap GetItemsImage(Color color) { //Debug.WriteLine("GetItemsImage"); Bitmap itemImage; if (!_imagesCache.ContainsKey(color)) { Rectangle rc = new Rectangle(0, 0, Width, _itemHeight); itemImage = new Bitmap(rc.Width, rc.Height); /// Create button rc.Inflate(-3, -3); GraphicsPath path1 = GetPath(rc, 10); rc.Inflate(0, 6); LinearGradientBrush br1 = new LinearGradientBrush(rc, color, Color.White, LinearGradientMode.Vertical); rc.Inflate(0, -6); /// Create shadow Rectangle rc2 = rc; rc2.Offset(8, 8); GraphicsPath path2 = GetPath(rc2, 20); PathGradientBrush br2 = new PathGradientBrush(path2); br2.CenterColor = ControlPaint.DarkDark(Color.Silver); br2.SurroundColors = new Color[] { Color.White }; /// Create bubble Rectangle rc3 = rc; rc3.Inflate(-15, -rc.Height / 3); rc3.Y = rc3.Y - 2; //rc3.Height = rc3.Height; GraphicsPath path3 = GetPath(rc3, rc3.Height); LinearGradientBrush br3 = new LinearGradientBrush(rc3, Color.FromArgb(255, Color.White), Color.FromArgb(0, Color.White), LinearGradientMode.Vertical); itemImage = new Bitmap(Width - 2, _itemHeight); Graphics g = Graphics.FromImage(itemImage); g.SmoothingMode = SmoothingMode.AntiAlias; g.FillPath(br2, path2); g.FillPath(br1, path1); g.FillPath(br3, path3); _imagesCache[color] = itemImage; } itemImage = _imagesCache[color]; return itemImage; } private void EnableDoubleBuffering() { //Debug.WriteLine("EnableDoubleBuffering"); // Set the value of the double-buffering style bits to true. SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor, true); UpdateStyles(); } public void Reset() { //Debug.WriteLine("Reset"); _queuedItems = new List(); } //public void Queue(string text, Color color, bool blink) //{ // //Debug.WriteLine("Queue"); // _queuedItems.Add(new QueueUsageEntry(text, color, blink)); // //this.Invalidate(); //} public void SetQueue(List list) { //Debug.WriteLine("SetQueue"); bool invalidate = false; if (_queuedItems.Count != list.Count) { invalidate = true; } else { int counter = Math.Min(list.Count, _maxItemsVisible); for (int i = 0; i < counter; i++) { if (_queuedItems[i] != list[i]) { invalidate = true; break; } } } if (invalidate) { //Debug.WriteLine("_invalidate = true"); _queuedItems = list; _invalidate = invalidate; } //_queuedItems = list; //_queuedItems.Clear(); //foreach (QueueUsageEntry entry in list) //{ // _queuedItems.Add(entry); //} //_invalidate = true; //this.Invalidate(); } protected override void OnPaint(PaintEventArgs e) { //Debug.WriteLine("OnPaint"); Bitmap bitmap = new Bitmap(Width, Height); Graphics g = Graphics.FromImage(bitmap); g.FillPath(Brushes.White, _pathBorder); int counter = Math.Min(_maxItemsVisible, _queuedItems.Count); int i = 0; foreach (QueueUsageEntry entry in _queuedItems) { if (i > counter) { break; } //int top = 0; //int bottom = 0; //if (topdown) //{ // bottom = 1; // top = bottom; // top += i * _itemHeight; // bottom += (i + 1) * _itemHeight; //} //else //{ // bottom = this.Height - 1; // top = bottom; // bottom -= i * _itemHeight; // top -= (i + 1) * _itemHeight; //} //g.DrawLine(Pens.Black, 0, top, this.Width, top); string text = (entry.IsExecuting ? ">" : "") + entry.Text; if (i == _lastVisibleItemIndex) { text = "(" + (_queuedItems.Count - _maxItemsVisible) + ")..."; } SizeF size = g.MeasureString(entry.Text, Font); //Debug.WriteLine(size.Width); Bitmap itemImage = GetItemsImage(entry.Color); RectangleF slot = _slots[i]; //g.DrawImage(itemImage, -1, top); g.DrawImage(itemImage, -1, slot.Top-2); //g.DrawString(text, this.Font, Brushes.Black, new RectangleF((this.Width - size.Width) / 2, top + 2, this.Width, bottom)); g.DrawString(text, Font, Brushes.Black, slot); ++i; } g.DrawPath(Pens.Black, _pathBorder); //g.DrawRectangle(Pens.Black, border); e.Graphics.DrawImage(bitmap, 0, 0); } private static GraphicsPath GetPath(Rectangle rc, int r) { //Debug.WriteLine("GetPath"); int x = rc.X, y = rc.Y, w = rc.Width, h = rc.Height; GraphicsPath path = new GraphicsPath(); path.AddArc(x, y, r, r, 180, 90); //Upper left corner path.AddArc(x + w - r, y, r, r, 270, 90); //Upper right corner path.AddArc(x + w - r, y + h - r, r, r, 0, 90); //Lower right corner path.AddArc(x, y + h - r, r, r, 90, 90); //Lower left corner path.CloseFigure(); return path; } private void ControlRezised() { //Debug.WriteLine("ControlRezised"); Graphics g = Graphics.FromHwnd(Handle); SizeF size = g.MeasureString("X", Font); g.Dispose(); _itemHeight = (int)size.Height + 5; _maxItemsVisible = Height / _itemHeight - 1; _lastVisibleItemIndex = _maxItemsVisible; _imagesCache = new Dictionary(); Rectangle border = new Rectangle(0, 0, ClientRectangle.Width - 1, ClientRectangle.Height - 1); _pathBorder = GetPath(border, 20); PrepareSlots(); } private void PrepareSlots() { bool topdown = true; _slots = new RectangleF[_maxItemsVisible+5]; for (int i = 0; i < _slots.Length; i++) { int top; int bottom; if (topdown) { bottom = 1; top = bottom; top += i * _itemHeight; bottom += (i + 1) * _itemHeight; } else { bottom = Height - 1; top = bottom; bottom -= i * _itemHeight; top -= (i + 1) * _itemHeight; } _slots[i] = new RectangleF((Width - 55) / 2, top + 2, Width, bottom); } } private void QueueUsageControl_Resize(object sender, EventArgs e) { //Debug.WriteLine("QueueUsageControl_Resize"); ControlRezised(); } private void timer1_Tick(object sender, EventArgs e) { if (_invalidate) { _invalidate = false; } Invalidate(); } } }