Watermark

Example of the indicator which displays the watermark in the chart

namespace ATAS.Indicators.Technical
{
    using System;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Drawing;

    using ATAS.Indicators.Editors;
    using ATAS.Indicators.Properties;

    using OFT.Rendering.Context;
    using OFT.Rendering.Tools;

    using Color = System.Windows.Media.Color;

    public class Watermark : Indicator
    {
        #region Nested types

        public enum Location
        {
            [Display(Name = "Center")]
            Center,

            [Display(Name = "TopLeft")]
            TopLeft,

            [Display(Name = "TopRight")]
            TopRight,

            [Display(Name = "BottomLeft")]
            BottomLeft,

            [Display(Name = "BottomRight")]
            BottomRight
        }

        #endregion

        #region Properties

        [Display(Name = "Color", GroupName = "Common", Order = 10)]
        public Color TextColor { get; set; } = Color.FromArgb(255, 225, 225, 225);

        [Display(Name = "TextLocation", GroupName = "Common", Order = 20)]
        public Location TextLocation { get; set; }

        [Display(Name = "HorizontalOffset", GroupName = "Common", Order = 30)]
        public int HorizontalOffset { get; set; }

        [Display(Name = "VerticalOffset", GroupName = "Common", Order = 40)]
        public int VerticalOffset { get; set; }

        [Display(Name = "ShowInstrument", GroupName = "FirstLine", Order = 50)]
        public bool ShowInstrument { get; set; } = true;

        [Display(Name = "ShowPeriod", GroupName = "FirstLine", Order = 60)]
        public bool ShowPeriod { get; set; } = true;

        [Display(Name = "Font", GroupName = "FirstLine", Order = 70)]
        [Editor(typeof(FontEditor), typeof(FontEditor))]
        public FontSetting Font { get; set; } = new FontSetting { Size = 60, Bold = true };

        [Display(Name = "Text", GroupName = "SecondLine", Order = 80)]
        public string AdditionalText { get; set; } = "";

        [Display(Name = "Font", GroupName = "SecondLine", Order = 90)]
        [Editor(typeof(FontEditor), typeof(FontEditor))]
        public FontSetting AdditionalFont { get; set; } = new FontSetting { Size = 55 };

        [Display(Name = "VerticalOffset", GroupName = "SecondLine", Order = 90)]
        public int AdditionalTextYOffset { get; set; } = -40;

        #endregion

        #region ctor

        public Watermark()
            : base(true)
        {
            Font.PropertyChanged += (a, b) => RedrawChart();
            AdditionalFont.PropertyChanged += (a, b) => RedrawChart();

            DataSeries[0].IsHidden = true;
            DenyToChangePanel = true;
            EnableCustomDrawing = true;
            SubscribeToDrawingEvents(DrawingLayouts.Historical);
            DrawAbovePrice = false;
        }

        #endregion

        #region Overrides of BaseIndicator

        protected override void OnCalculate(int bar, decimal value)
        {

        }

        protected override void OnRender(RenderContext context, DrawingLayouts layout)
        {
            var showSecondLine = !string.IsNullOrWhiteSpace(AdditionalText);

            if (!showSecondLine && !ShowInstrument && !ShowPeriod)
                return;

            var textColor = TextColor.Convert();
            var mainTextRectangle = new Rectangle();
            var additionalTextRectangle = new Rectangle();
            var firstLine = string.Empty;

            if (showSecondLine && !string.IsNullOrEmpty(AdditionalText))
            {
                var size = context.MeasureString(AdditionalText, AdditionalFont.Font);
                additionalTextRectangle = new Rectangle(0, 0, (int)size.Width, (int)size.Height);
            }

            if (ShowInstrument || ShowPeriod)
            {
                if (ShowInstrument)
                    firstLine = InstrumentInfo.Instrument;

                if (ShowPeriod)
                {
                    var period = ChartInfo.ChartType == "TimeFrame" ? ChartInfo.TimeFrame : $"{ChartInfo.ChartType} {ChartInfo.TimeFrame}";

                    if (ShowInstrument)
                        firstLine += $", {period}";
                    else
                        firstLine += $"{period}";
                }

                var size = context.MeasureString(firstLine, Font.Font);
                mainTextRectangle = new Rectangle(0, 0, (int)size.Width, (int)size.Height);
            }

            if (mainTextRectangle.Height > 0 && additionalTextRectangle.Height > 0)
            {
                int firstLineX;
                int secondLineX;
                var y = 0;

                var totalHeight = mainTextRectangle.Height + additionalTextRectangle.Height + AdditionalTextYOffset;

                switch (TextLocation)
                {
                    case Location.Center:
                    {
                        firstLineX = ChartInfo.PriceChartContainer.Region.Width / 2 - mainTextRectangle.Width / 2 + HorizontalOffset;
                        secondLineX = ChartInfo.PriceChartContainer.Region.Width / 2 - additionalTextRectangle.Width / 2 + HorizontalOffset;
                        y = ChartInfo.PriceChartContainer.Region.Height / 2 - totalHeight / 2 + VerticalOffset;

                        break;
                    }
                    case Location.TopLeft:
                    {
                        firstLineX = secondLineX = HorizontalOffset;
                        break;
                    }
                    case Location.TopRight:
                    {
                        firstLineX = ChartInfo.PriceChartContainer.Region.Width - mainTextRectangle.Width + HorizontalOffset;
                        secondLineX = ChartInfo.PriceChartContainer.Region.Width - additionalTextRectangle.Width + HorizontalOffset;

                        break;
                    }
                    case Location.BottomLeft:
                    {
                        firstLineX = secondLineX = HorizontalOffset;
                        y = ChartInfo.PriceChartContainer.Region.Height - totalHeight + VerticalOffset;

                        break;
                    }
                    case Location.BottomRight:
                    {
                        firstLineX = ChartInfo.PriceChartContainer.Region.Width - mainTextRectangle.Width + HorizontalOffset;
                        secondLineX = ChartInfo.PriceChartContainer.Region.Width - additionalTextRectangle.Width + HorizontalOffset;
                        y = ChartInfo.PriceChartContainer.Region.Height - totalHeight + VerticalOffset;

                        break;
                    }
                    default:
                        throw new ArgumentOutOfRangeException();
                }

                context.DrawString(firstLine, Font.Font, textColor, firstLineX, y);
                context.DrawString(AdditionalText, AdditionalFont.Font, textColor, secondLineX, y + mainTextRectangle.Height + AdditionalTextYOffset);
            }
            else if (mainTextRectangle.Height > 0)
            {
                DrawString(context, firstLine, Font.Font, textColor, mainTextRectangle);
            }
            else if (additionalTextRectangle.Height > 0)
            {
                DrawString(context, AdditionalText, AdditionalFont.Font, textColor, additionalTextRectangle);
            }
        }

        private void DrawString(RenderContext context, string text, RenderFont font, System.Drawing.Color color, Rectangle rectangle)
        {
            switch (TextLocation)
            {
                case Location.Center:
                {
                    context.DrawString(text, font, color, ChartInfo.PriceChartContainer.Region.Width / 2 - rectangle.Width / 2 + HorizontalOffset,
                                       ChartInfo.PriceChartContainer.Region.Height / 2 - rectangle.Height / 2 + VerticalOffset);
                    break;
                }
                case Location.TopLeft:
                {
                    context.DrawString(text, font, color, HorizontalOffset, VerticalOffset);
                    break;
                }
                case Location.TopRight:
                {
                    context.DrawString(text, font, color, ChartInfo.PriceChartContainer.Region.Width - rectangle.Width + HorizontalOffset, VerticalOffset);
                    break;
                }
                case Location.BottomLeft:
                {
                    context.DrawString(text, font, color, HorizontalOffset, ChartInfo.PriceChartContainer.Region.Height - rectangle.Height + VerticalOffset);
                    break;
                }
                case Location.BottomRight:
                {
                    context.DrawString(text, font, color, ChartInfo.PriceChartContainer.Region.Width - rectangle.Width + HorizontalOffset,
                                       ChartInfo.PriceChartContainer.Region.Height - rectangle.Height + VerticalOffset);
                    break;
                }
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        #endregion
    }
}