/// <summary>
        /// Paints the background of the item.
        /// </summary>
        /// <param name="e">Event arguments.</param>
        protected virtual void OnDrawBackground(DrawNodeEventArgs e)
        {
            DrawBackground?.Invoke(this, e);
            if (e.Handled)
            {
                return;
            }

            using (Brush back = new SolidBrush(!e.Enabled ? DisabledBackColor :
                                               !e.ControlHasFocus && e.Selected ? UnfocusedItemBackColor :
                                               e.Selected?SelectedItemBackColor:
                                               e.Hovered ? HoveredItemBackColor : BackColor))
            {
                e.Graphics.FillRectangle(back, e.Bounds);
            }
        }
        /// <summary>
        /// Renders a list item.
        /// </summary>
        /// <param name="graphics">The graphics object to draw on.</param>
        /// <param name="bounds">Bounds of the item.</param>
        /// <param name="node">The node to draw.</param>
        /// <param name="enabled">Whether the item is enabled.</param>
        /// <param name="selected">Whether the item is selected.</param>
        /// <param name="hovered">Whether the mouse cursor is over the item.</param>
        /// <param name="controlHasFocus">Whether the control has input focus.</param>
        public void DrawItem(Graphics graphics, Rectangle bounds, FileSystemNode node, bool enabled, bool selected, bool hovered, bool controlHasFocus)
        {
            DrawNodeEventArgs e = new DrawNodeEventArgs(graphics, bounds, node, enabled, selected, hovered, controlHasFocus);

            OnDrawBackground(e);
            OnDrawBorder(e);

            if (e.Node.IsPathValid)
            {
                OnDrawContents(e);
            }
            else
            {
                OnDrawErrorMessage(e);
            }
        }
        /// <summary>
        /// Paints the contents of the control.
        /// </summary>
        /// <param name="e">Event arguments.</param>
        protected virtual void OnDrawContents(DrawNodeEventArgs e)
        {
            DrawContents?.Invoke(this, e);
            if (e.Handled)
            {
                return;
            }

            var eLines = new GetLineCountEventArgs(e.Node);

            OnGetLineCount(eLines);

            int        lines      = eLines.LineCount;
            float      textHeight = GetTextHeight(e.Node);
            RectangleF iconRect   = new RectangleF(e.Bounds.Left + ContentPadding.Width, e.Bounds.Top + (e.Bounds.Height - ThumbnailSize.Height) / 2f,
                                                   ThumbnailSize.Width, ThumbnailSize.Height);
            RectangleF textRect = new RectangleF(e.Bounds.Left + ContentPadding.Width + ThumbnailSize.Width + ThumbnailTextSpacing, e.Bounds.Top + (e.Bounds.Height - textHeight) / 2f,
                                                 e.Bounds.Width - iconRect.Width - 2 * ContentPadding.Width - ThumbnailTextSpacing, textHeight);

            // Draw the image
            if (e.Node.Thumbnail != null)
            {
                Rectangle pos = Utility.GetSizedIconBounds(e.Node.Thumbnail, Utility.ToRectangle(iconRect), 0.0f, 0.5f);
                e.Graphics.DrawImage(e.Node.Thumbnail, pos);
            }

            // Draw item text
            RectangleF lineBounds = textRect;

            for (int i = 0; i < eLines.LineCount; i++)
            {
                var eHeight = new GetLineHeightEventArgs(e.Node, i);
                OnGetLineHeight(eHeight);
                float lineHeight = eHeight.LineHeight > 0 ? eHeight.LineHeight : Font.Height;
                lineBounds.Height = lineHeight;

                // Draw line of text
                DrawNodeLineEventArgs eLine = new DrawNodeLineEventArgs(e.Graphics,
                                                                        Utility.ToRectangle(lineBounds), e.Node, e.Enabled, e.Selected, e.Hovered, e.ControlHasFocus, i);
                OnDrawLine(eLine);

                // Offset the bounds to the next line below
                lineBounds.Offset(0, lineHeight + Font.Height * 0.2f);
            }
        }
        /// <summary>
        /// Paints the border of the item.
        /// </summary>
        /// <param name="e">Event arguments.</param>
        protected virtual void OnDrawBorder(DrawNodeEventArgs e)
        {
            DrawBorder?.Invoke(this, e);
            if (e.Handled)
            {
                return;
            }

            if (!e.Enabled && e.Selected)
            {
                using (Pen bFocus = new Pen(DisabledItemBorderColor))
                {
                    e.Graphics.DrawRectangle(bFocus, e.Bounds.Left, e.Bounds.Top, e.Bounds.Width - 1, e.Bounds.Height - 1);
                }
            }
            else if (!e.ControlHasFocus && e.Selected)
            {
                using (Pen bFocus = new Pen(UnfocusedItemBorderColor))
                {
                    e.Graphics.DrawRectangle(bFocus, e.Bounds.Left, e.Bounds.Top, e.Bounds.Width - 1, e.Bounds.Height - 1);
                }
            }
            else if (e.Selected)
            {
                using (Pen bFocus = new Pen(SelectedItemBorderColor))
                {
                    e.Graphics.DrawRectangle(bFocus, e.Bounds.Left, e.Bounds.Top, e.Bounds.Width - 1, e.Bounds.Height - 1);
                }
            }
            else if (BorderStyle == BorderStyle.FixedSingle)
            {
                ControlPaint.DrawBorder3D(e.Graphics, e.Bounds, Border3DStyle.Flat);
            }
            else if (BorderStyle == BorderStyle.Fixed3D)
            {
                ControlPaint.DrawBorder3D(e.Graphics, e.Bounds, Border3DStyle.RaisedOuter);
            }
        }
        /// <summary>
        /// Draws an error message if the path is invalid.
        /// </summary>
        /// <param name="e">Event arguments.</param>
        protected virtual void OnDrawErrorMessage(DrawNodeEventArgs e)
        {
            DrawErrorMessage?.Invoke(this, e);
            if (e.Handled)
            {
                return;
            }

            Rectangle bounds = e.Bounds;

            bounds.Inflate(-ContentPadding.Width, -ContentPadding.Height);

            // Draw item text
            using (Brush bError = new SolidBrush(ErrorTextColor))
                using (StringFormat stringFormat = new StringFormat())
                {
                    stringFormat.Alignment     = StringAlignment.Near;
                    stringFormat.LineAlignment = StringAlignment.Near;
                    stringFormat.Trimming      = StringTrimming.EllipsisCharacter;

                    e.Graphics.DrawString(e.Node.ErrorMessage, Font, bError, bounds, stringFormat);
                }
        }