using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Windows.Forms; using System.Reflection; using System.ComponentModel; namespace Aga.Controls.Tree.NodeControls { public abstract class BaseTextControl : EditableControl { private TextFormatFlags _baseFormatFlags; private TextFormatFlags _formatFlags; private Pen _focusPen; private StringFormat _format; #region Properties private Font _font = null; public Font Font { get { if (_font == null) return Control.DefaultFont; else return _font; } set { if (value == Control.DefaultFont) _font = null; else _font = value; } } protected bool ShouldSerializeFont() { return (_font != null); } private HorizontalAlignment _textAlign = HorizontalAlignment.Left; [DefaultValue(HorizontalAlignment.Left)] public HorizontalAlignment TextAlign { get { return _textAlign; } set { _textAlign = value; SetFormatFlags(); } } private StringTrimming _trimming = StringTrimming.None; [DefaultValue(StringTrimming.None)] public StringTrimming Trimming { get { return _trimming; } set { _trimming = value; SetFormatFlags(); } } private bool _displayHiddenContentInToolTip = true; [DefaultValue(true)] public bool DisplayHiddenContentInToolTip { get { return _displayHiddenContentInToolTip; } set { _displayHiddenContentInToolTip = value; } } private bool _useCompatibleTextRendering = false; [DefaultValue(false)] public bool UseCompatibleTextRendering { get { return _useCompatibleTextRendering; } set { _useCompatibleTextRendering = value; } } [DefaultValue(false)] public bool TrimMultiLine { get; set; } #endregion protected BaseTextControl() { IncrementalSearchEnabled = true; _focusPen = new Pen(Color.Black); _focusPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; _format = new StringFormat(StringFormatFlags.LineLimit | StringFormatFlags.NoClip | StringFormatFlags.FitBlackBox | StringFormatFlags.MeasureTrailingSpaces); _baseFormatFlags = TextFormatFlags.PreserveGraphicsClipping | TextFormatFlags.PreserveGraphicsTranslateTransform; SetFormatFlags(); LeftMargin = 3; } private void SetFormatFlags() { _format.Alignment = TextHelper.TranslateAligment(TextAlign); _format.Trimming = Trimming; _formatFlags = _baseFormatFlags | TextHelper.TranslateAligmentToFlag(TextAlign) | TextHelper.TranslateTrimmingToFlag(Trimming); } public override Size MeasureSize(TreeNodeAdv node, DrawContext context) { return GetLabelSize(node, context); } protected Size GetLabelSize(TreeNodeAdv node, DrawContext context) { return GetLabelSize(node, context, GetLabel(node)); } protected Size GetLabelSize(TreeNodeAdv node, DrawContext context, string label) { PerformanceAnalyzer.Start("GetLabelSize"); CheckThread(); Font font = GetDrawingFont(node, context, label); Size s = Size.Empty; if (UseCompatibleTextRendering) s = TextRenderer.MeasureText(label, font); else { SizeF sf = context.Graphics.MeasureString(label, font); s = new Size((int)Math.Ceiling(sf.Width), (int)Math.Ceiling(sf.Height)); } PerformanceAnalyzer.Finish("GetLabelSize"); if (!s.IsEmpty) return s; else return new Size(10, Font.Height); } protected Font GetDrawingFont(TreeNodeAdv node, DrawContext context, string label) { Font font = context.Font; if (DrawTextMustBeFired(node)) { DrawEventArgs args = new DrawEventArgs(node, this, context, label); args.Font = context.Font; OnDrawText(args); font = args.Font; } return font; } protected void SetEditControlProperties(Control control, TreeNodeAdv node) { string label = GetLabel(node); DrawContext context = new DrawContext(); context.Font = control.Font; control.Font = GetDrawingFont(node, context, label); } public override void Draw(TreeNodeAdv node, DrawContext context) { if (context.CurrentEditorOwner == this && node == Parent.CurrentNode) return; PerformanceAnalyzer.Start("BaseTextControl.Draw"); string label = GetLabel(node); Rectangle bounds = GetBounds(node, context); Rectangle focusRect = new Rectangle(bounds.X, context.Bounds.Y, bounds.Width, context.Bounds.Height); Brush backgroundBrush; Color textColor; Font font; CreateBrushes(node, context, label, out backgroundBrush, out textColor, out font, ref label); if (backgroundBrush != null) context.Graphics.FillRectangle(backgroundBrush, focusRect); if (context.DrawFocus) { focusRect.Width--; focusRect.Height--; if (context.DrawSelection == DrawSelectionMode.None) _focusPen.Color = SystemColors.ControlText; else _focusPen.Color = SystemColors.InactiveCaption; context.Graphics.DrawRectangle(_focusPen, focusRect); } PerformanceAnalyzer.Start("BaseTextControl.DrawText"); if (UseCompatibleTextRendering) TextRenderer.DrawText(context.Graphics, label, font, bounds, textColor, _formatFlags); else context.Graphics.DrawString(label, font, GetFrush(textColor), bounds, _format); PerformanceAnalyzer.Finish("BaseTextControl.DrawText"); PerformanceAnalyzer.Finish("BaseTextControl.Draw"); } private static Dictionary _brushes = new Dictionary(); private static Brush GetFrush(Color color) { Brush br; if (_brushes.ContainsKey(color)) br = _brushes[color]; else { br = new SolidBrush(color); _brushes.Add(color, br); } return br; } private void CreateBrushes(TreeNodeAdv node, DrawContext context, string text, out Brush backgroundBrush, out Color textColor, out Font font, ref string label) { textColor = SystemColors.ControlText; backgroundBrush = null; font = context.Font; if (context.DrawSelection == DrawSelectionMode.Active) { textColor = SystemColors.HighlightText; backgroundBrush = SystemBrushes.Highlight; } else if (context.DrawSelection == DrawSelectionMode.Inactive) { textColor = SystemColors.ControlText; backgroundBrush = SystemBrushes.InactiveBorder; } else if (context.DrawSelection == DrawSelectionMode.FullRowSelect) textColor = SystemColors.HighlightText; if (!context.Enabled) textColor = SystemColors.GrayText; if (DrawTextMustBeFired(node)) { DrawEventArgs args = new DrawEventArgs(node, this, context, text); args.Text = label; args.TextColor = textColor; args.BackgroundBrush = backgroundBrush; args.Font = font; OnDrawText(args); textColor = args.TextColor; backgroundBrush = args.BackgroundBrush; font = args.Font; label = args.Text; } } public string GetLabel(TreeNodeAdv node) { if (node != null && node.Tag != null) { object obj = GetValue(node); if (obj != null) return FormatLabel(obj); } return string.Empty; } protected virtual string FormatLabel(object obj) { var res = obj.ToString(); if (TrimMultiLine && res != null) { string[] parts = res.Split('\n'); if (parts.Length > 1) return parts[0] + "..."; } return res; } public void SetLabel(TreeNodeAdv node, string value) { SetValue(node, value); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { _focusPen.Dispose(); _format.Dispose(); } } /// /// Fires when control is going to draw a text. Can be used to change text or back color /// public event EventHandler DrawText; protected virtual void OnDrawText(DrawEventArgs args) { TreeViewAdv tree = args.Node.Tree; if (tree != null) tree.FireDrawControl(args); if (DrawText != null) DrawText(this, args); } protected virtual bool DrawTextMustBeFired(TreeNodeAdv node) { return DrawText != null || (node.Tree != null && node.Tree.DrawControlMustBeFired()); } } }