#if (FRAMEWORK20) using System; using System.Text; using System.Drawing; using System.Windows.Forms; using System.Drawing.Drawing2D; using System.ComponentModel; namespace DevComponents.DotNetBar { /// /// Represents an item that displays log information in list container. /// public class LogItem : BaseItem { #region Private Variables private const int DefaultWidth = 96; private const int VerticalPadding = 3; private const int HorizontalPadding = 7; private const int TextLineSpacing = 4; private const int MinimumHeight = 32; private Size _CalloutSize = new Size(10, 10); private int _CornerSize = 5; #endregion #region Events /// /// Occurs when text markup link is clicked. Markup links can be created using "a" tag, for example: /// Markup link /// public event MarkupLinkClickEventHandler MarkupLinkClick; #endregion #region Internal Implementation /// /// Initializes a new instance of the LogItem class. /// /// public LogItem():this("","") { } /// /// Creates new instance of LogItem and assigns the name to it. /// /// Item name. public LogItem(string sItemName):this(sItemName,"") {} /// /// Creates new instance of LogItem and assigns the name and text to it. /// /// Item name. /// item text. public LogItem(string sItemName, string ItemText) : base(sItemName, ItemText) { SetIsContainer(true); } protected override void Dispose(bool disposing) { if (BarUtilities.DisposeItemImages && !this.DesignMode) { BarUtilities.DisposeImage(ref _Image); } base.Dispose(disposing); } /// /// Returns copy of the item. /// public override BaseItem Copy() { LogItem copy = new LogItem(m_Name); this.CopyToItem(copy); return copy; } /// /// Copies the ButtonItem specific properties to new instance of the item. /// /// New ButtonItem instance. protected override void CopyToItem(BaseItem instanceCopy) { LogItem copy = instanceCopy as LogItem; base.CopyToItem(instanceCopy); copy.BackColor = this.BackColor; copy.Created = this.Created; copy.HeaderTextColor = this.HeaderTextColor; if (this.Image != null) copy.Image = (Image) this.Image.Clone(); copy.ImagePosition = this.ImagePosition; copy.SourceName = this.SourceName; copy.TextColor = this.TextColor; } public override BaseItem ItemAtLocation(int x, int y) { if (this.SubItems.Count > 0) { BaseItem item = base.ItemAtLocation(x, y); if (item != null) return item; } return this.Bounds.Contains(x, y) ? this : null; } protected virtual int GetTextWidth(Rectangle bounds) { int textWidth = Math.Max(0, bounds.Width - (HorizontalPadding * 2 + _CalloutSize.Width + (_Image != null ? _ImageSize.Width : 0))); return textWidth; } public override void RecalcSize() { // We accept the width assigned and calculate the height based on that... Rectangle bounds = this.DisplayRectangle; Size imageSize = _ImageSize; if (bounds.Width <= 0) { if (_Image != null) bounds.Width = imageSize.Width; bounds.Width += DefaultWidth; } if (_Image != null && bounds.Width - (imageSize.Width + 25) <= 1) { bounds.Height = imageSize.Height; } else { int totalHeight = VerticalPadding * 2; Control parent = this.ContainerControl as Control; if (parent != null) { Font font = parent.Font; using (Graphics g = parent.CreateGraphics()) { int textWidth = GetTextWidth(bounds); Size textSize = TextDrawing.MeasureString(g, (string.IsNullOrEmpty(this.SourceName) ? "A" : this.SourceName), font); totalHeight += textSize.Height + TextLineSpacing; textSize = ButtonItemLayout.MeasureItemText(this, g, textWidth, font, eTextFormat.WordBreak, parent.RightToLeft == RightToLeft.Yes); //textSize = TextDrawing.MeasureString(g, this.Text, font, textWidth, eTextFormat.WordBreak); totalHeight += textSize.Height + TextLineSpacing; } } bounds.Height = Math.Max(totalHeight, (imageSize != null ? imageSize.Height : MinimumHeight)); } base.RecalcSize(); m_Rect = bounds; } public override void Paint(ItemPaintArgs p) { Graphics g = p.Graphics; Rectangle bounds = this.DisplayRectangle; if (_Image != null) { Rectangle imageRect = GetImageRect(bounds); g.DrawImage(_Image, imageRect); } Rectangle contentBounds = GetContentBounds(bounds); // Draw shadow Rectangle shadowBounds = contentBounds; shadowBounds.Inflate(1, 0); shadowBounds.Offset(0, 1); using (GraphicsPath path = CreateCalloutPath(shadowBounds)) { using (Pen pen = new Pen(Color.FromArgb(32, Color.Black))) g.DrawPath(pen, path); } using (GraphicsPath path = CreateCalloutPath(contentBounds)) { Brush fill = GetCalloutBrush(); if (fill != null) { g.FillPath(fill, path); fill.Dispose(); } Pen pen = GetCalloutPen(); if (pen != null) { g.DrawPath(pen, path); pen.Dispose(); } } Color headerColor = GetHeaderColor(); Rectangle headerTextBounds = GetTextBounds(bounds); Rectangle textBounds = headerTextBounds; string userName = this.SourceName; if (!string.IsNullOrEmpty(userName)) { using (Font font = new Font(p.Font, FontStyle.Bold)) { TextDrawing.DrawString(g, userName, font, headerColor, headerTextBounds, eTextFormat.Top | eTextFormat.Left); textBounds.Y += font.Height + TextLineSpacing; textBounds.Height -= font.Height + TextLineSpacing; } } if (_Created != DateTime.MinValue && _Created != DateTime.MaxValue) { TimeSpan span = DateTime.Now.Subtract(_Created); //Console.WriteLine("Tweet from {0} created on {1}", SourceName, _Created); string timeString = GetHumanTimeSpan(span); using (Font font = new Font(p.Font, FontStyle.Italic)) { TextDrawing.DrawString(g, timeString, font, headerColor, headerTextBounds, eTextFormat.Top | eTextFormat.Right); headerTextBounds.Y += font.Height + TextLineSpacing; headerTextBounds.Height -= font.Height + TextLineSpacing; } } string text = this.Text; Color textColor = GetTextColor(); if (!string.IsNullOrEmpty(text)) { Font font = p.Font; if (this.TextMarkupBody != null) { TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, font, textColor, p.RightToLeft); d.HotKeyPrefixVisible = true; this.TextMarkupBody.Bounds = textBounds; this.TextMarkupBody.Render(d); } else TextDrawing.DrawString(g, text, font, textColor, textBounds, eTextFormat.Top | eTextFormat.Left | eTextFormat.WordBreak | eTextFormat.WordEllipsis); } } private Color _TextColor = Color.Empty; /// /// Gets or sets the color of the control text body. /// [Category("Columns"), Description("Indicates color of control text body.")] public Color TextColor { get { return _TextColor; } set { _TextColor = value; } } /// /// Gets whether property should be serialized. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeTextColor() { return !_TextColor.IsEmpty; } /// /// Resets property to its default value. /// [EditorBrowsable(EditorBrowsableState.Never)] public void ResetTextColor() { this.TextColor = Color.Empty; } private Color GetTextColor() { if (!_TextColor.IsEmpty) return _TextColor; return Color.Black; } private Color _HeaderTextColor = Color.Empty; /// /// Gets or sets the color of the header text. /// [Category("Columns"), Description("Indicates color of header text.")] public Color HeaderTextColor { get { return _HeaderTextColor; } set { _HeaderTextColor = value; } } /// /// Gets whether property should be serialized. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeHeaderTextColor() { return !_HeaderTextColor.IsEmpty; } /// /// Resets property to its default value. /// [EditorBrowsable(EditorBrowsableState.Never)] public void ResetHeaderTextColor() { this.HeaderTextColor = Color.Empty; } private Color GetHeaderColor() { if (!_HeaderTextColor.IsEmpty) return _HeaderTextColor; return ColorScheme.GetColor(0x5D8CCB); } protected virtual Rectangle GetTextBounds(Rectangle bounds) { Rectangle textBounds = GetContentBounds(bounds); if (_ImagePosition == eLogItemImagePosition.Left) textBounds.X += _CalloutSize.Width; textBounds.Width -= _CalloutSize.Width; textBounds.Inflate(-HorizontalPadding, -VerticalPadding); return textBounds; } private Brush GetCalloutBrush() { return new SolidBrush(_BackColor); return new SolidBrush(ColorScheme.GetColor(0xE6EDF7)); return new SolidBrush(Color.FromArgb(208, Color.White)); } private Pen GetCalloutPen() { return new Pen(ColorScheme.GetColor(0x5D8CC9), 1f); } private GraphicsPath CreateCalloutPath(Rectangle contentBounds) { GraphicsPath path = new GraphicsPath(); if (_ImagePosition == eLogItemImagePosition.Left) { if (_CornerSize == 0) { Rectangle pathBounds = contentBounds; pathBounds.Width--; pathBounds.Height--; int i = _CalloutSize.Height / 2; path.AddLine(pathBounds.X + _CalloutSize.Width, pathBounds.Y + _CalloutSize.Height + i, pathBounds.X, pathBounds.Y + i * 2); path.AddLine(pathBounds.X, pathBounds.Y + i * 2, pathBounds.X + _CalloutSize.Width, pathBounds.Y + i); path.AddLine(pathBounds.X + _CalloutSize.Width, pathBounds.Y, pathBounds.Right, pathBounds.Y); path.AddLine(pathBounds.Right, pathBounds.Bottom, pathBounds.X + _CalloutSize.Width, pathBounds.Bottom); path.CloseAllFigures(); } else { Rectangle pathBounds = contentBounds; pathBounds.Width--; pathBounds.Height--; int topOffset = _CornerSize; int i = _CalloutSize.Height / 2; path.AddLine(pathBounds.X + _CalloutSize.Width, pathBounds.Y + topOffset + _CalloutSize.Height + i, pathBounds.X, pathBounds.Y + topOffset + i * 2); path.AddLine(pathBounds.X, pathBounds.Y + topOffset + i * 2, pathBounds.X + _CalloutSize.Width, pathBounds.Y + topOffset + i); pathBounds.X += _CalloutSize.Width; pathBounds.Width -= _CalloutSize.Width; ArcData cornerArc = ElementStyleDisplay.GetCornerArc(pathBounds, _CornerSize, eCornerArc.TopLeft); path.AddArc(cornerArc.X, cornerArc.Y, cornerArc.Width, cornerArc.Height, cornerArc.StartAngle, cornerArc.SweepAngle); cornerArc = ElementStyleDisplay.GetCornerArc(pathBounds, _CornerSize, eCornerArc.TopRight); path.AddArc(cornerArc.X, cornerArc.Y, cornerArc.Width, cornerArc.Height, cornerArc.StartAngle, cornerArc.SweepAngle); cornerArc = ElementStyleDisplay.GetCornerArc(pathBounds, _CornerSize, eCornerArc.BottomRight); path.AddArc(cornerArc.X, cornerArc.Y, cornerArc.Width, cornerArc.Height, cornerArc.StartAngle, cornerArc.SweepAngle); cornerArc = ElementStyleDisplay.GetCornerArc(pathBounds, _CornerSize, eCornerArc.BottomLeft); path.AddArc(cornerArc.X, cornerArc.Y, cornerArc.Width, cornerArc.Height, cornerArc.StartAngle, cornerArc.SweepAngle); path.CloseAllFigures(); } } else { if (_CornerSize == 0) { Rectangle pathBounds = contentBounds; pathBounds.Width--; pathBounds.Height--; int i = _CalloutSize.Height / 2; path.AddLine(pathBounds.Right - _CalloutSize.Width, pathBounds.Y + _CalloutSize.Height + i, pathBounds.Right, pathBounds.Y + i * 2); path.AddLine(pathBounds.Right, pathBounds.Y + i * 2, pathBounds.Right - _CalloutSize.Width, pathBounds.Y + i); path.AddLine(pathBounds.Right - _CalloutSize.Width, pathBounds.Y, pathBounds.X, pathBounds.Y); path.AddLine(pathBounds.X, pathBounds.Bottom, pathBounds.Right - _CalloutSize.Width, pathBounds.Bottom); path.CloseAllFigures(); } else { Rectangle pathBounds = contentBounds; pathBounds.Width--; pathBounds.Height--; int topOffset = _CornerSize; int i = _CalloutSize.Height / 2; pathBounds.Width -= _CalloutSize.Width; ArcData cornerArc = ElementStyleDisplay.GetCornerArc(pathBounds, _CornerSize, eCornerArc.TopLeft); path.AddArc(cornerArc.X, cornerArc.Y, cornerArc.Width, cornerArc.Height, cornerArc.StartAngle, cornerArc.SweepAngle); cornerArc = ElementStyleDisplay.GetCornerArc(pathBounds, _CornerSize, eCornerArc.TopRight); path.AddArc(cornerArc.X, cornerArc.Y, cornerArc.Width, cornerArc.Height, cornerArc.StartAngle, cornerArc.SweepAngle); pathBounds.Width += _CalloutSize.Width; path.AddLine(pathBounds.Right - _CalloutSize.Width, pathBounds.Y + i, pathBounds.Right, pathBounds.Y + i * 2); path.AddLine(pathBounds.Right, pathBounds.Y + i * 2, pathBounds.Right - _CalloutSize.Width, pathBounds.Y + _CalloutSize.Height + i); pathBounds.Width -= _CalloutSize.Width; cornerArc = ElementStyleDisplay.GetCornerArc(pathBounds, _CornerSize, eCornerArc.BottomRight); path.AddArc(cornerArc.X, cornerArc.Y, cornerArc.Width, cornerArc.Height, cornerArc.StartAngle, cornerArc.SweepAngle); cornerArc = ElementStyleDisplay.GetCornerArc(pathBounds, _CornerSize, eCornerArc.BottomLeft); path.AddArc(cornerArc.X, cornerArc.Y, cornerArc.Width, cornerArc.Height, cornerArc.StartAngle, cornerArc.SweepAngle); path.CloseAllFigures(); } } return path; } private Rectangle GetContentBounds(Rectangle bounds) { if (_Image != null) { if (_ImagePosition == eLogItemImagePosition.Left) bounds.X += _ImageSize.Width; bounds.Width -= _ImageSize.Width; } // Adjust for shadow bounds.Height--; bounds.Width--; return bounds; } private Rectangle GetImageRect(Rectangle bounds) { if (_ImagePosition == eLogItemImagePosition.Left) return new Rectangle(bounds.X, bounds.Y, _ImageSize.Width, _ImageSize.Height); return new Rectangle(bounds.Right - _ImageSize.Width, bounds.Y, _ImageSize.Width, _ImageSize.Height); } private Image _Image = null; private Size _ImageSize = new Size(48, 48); /// /// Gets or sets the image displayed on the log item. /// [DefaultValue(null), Category("Appearance"), Description("Specifies image displayed on the log item.")] public Image Image { get { return _Image; } set { if (_Image == value) return; _Image = value; _ImageSize = new Size(48, 48); if (_Image != null) { try { _ImageSize = _Image.Size; } catch { } } NeedRecalcSize = true; this.Refresh(); } } private eLogItemImagePosition _ImagePosition = eLogItemImagePosition.Left; /// /// Gets or sets the image position in relation to text. /// [DefaultValue(eLogItemImagePosition.Left), Category("Appearance"), Description("Specifies the image position in relation to text.")] public eLogItemImagePosition ImagePosition { get { return _ImagePosition; } set { if (_ImagePosition == value) return; _ImagePosition = value; NeedRecalcSize = true; this.Refresh(); } } private string _SourceName = ""; [DefaultValue(""), Category("Appearance"), Description("Specifies the log item source name")] public string SourceName { get { return _SourceName; } set { _SourceName = value; } } private DateTime _Created; public DateTime Created { get { return _Created; } set { _Created = value; } } private string GetHumanTimeSpan(TimeSpan span) { if (span.TotalMinutes <= 1.5) return "now"; else if (span.TotalMinutes < 2) return "about a minute ago"; else if (span.TotalMinutes < 60) return span.TotalMinutes.ToString("N0") + " minutes ago"; else if (span.TotalHours < 2) return span.TotalHours.ToString("N0") + " hour ago"; else if (span.TotalHours < 24) return span.TotalHours.ToString("N0") + " hours ago"; else if (span.TotalDays < 2) return span.TotalDays.ToString("N0") + " day ago"; else if (span.TotalDays < 30) return span.TotalDays.ToString("N0") + " days ago"; return (span.TotalDays / 30).ToString("N0") + " months ago"; } private Color _BackColor = Color.White; /// /// Gets or sets the background color of the item. /// [Category("Appearance"), Description("Indicates background color of the item.")] public Color BackColor { get { return _BackColor; } set { if (value != _BackColor) { Color oldValue = _BackColor; _BackColor = value; OnBackColorChanged(oldValue, value); } } } private void OnBackColorChanged(Color oldValue, Color newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("BackColor")); this.Refresh(); } [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeBackColor() { return _BackColor != Color.White; } [EditorBrowsable(EditorBrowsableState.Never)] public void ResetBackColor() { this.BackColor = Color.White; } protected void SetBackColor(Color color) { _BackColor = color; } #endregion #region Markup Support /// /// Gets whether item supports text markup. Default is false. /// protected override bool IsMarkupSupported { get { return true; } } protected override void TextMarkupLinkClick(object sender, EventArgs e) { TextMarkup.HyperLink link = sender as TextMarkup.HyperLink; if (link != null) OnMarkupLinkClick(new MarkupLinkClickEventArgs(link.Name, link.HRef)); base.TextMarkupLinkClick(sender, e); } protected virtual void OnMarkupLinkClick(MarkupLinkClickEventArgs e) { if (this.MarkupLinkClick != null) MarkupLinkClick(this, e); } #endregion } public enum eLogItemImagePosition { Left, Right } } #endif