Table of Contents

Keyboard and mouse

An indicator reacts to the mouse and the keyboard by overriding these methods:

The mouse methods receive a RenderControlMouseEventArgs (namespace OFT.Rendering.Control) with the button and the position. The keyboard methods take System.Windows.Input.KeyEventArgs in the classic ATAS; ATAS X declares them with its own cross-platform key event type and converts a classic build at load time (see Project setup).

Every method returns true when the indicator has handled the event: the event is then not passed to the following indicators of the chart, so that only one of several indicators reacts to it. A hidden indicator (Visible is false) or a locked one (Locked is true) receives no events.

GetCursor(e) changes the mouse cursor depending on the position: return a StdCursor value (namespace OFT.Rendering), or StdCursor.NULL to keep the default cursor.

Example

A rectangle that is selected and deselected with a click, dragged while selected, and shows the hand cursor when the mouse is over it; the keyboard and wheel events are written to the log.

using System;
using System.Drawing;
using System.Windows.Input;

using ATAS.Indicators;
using OFT.Rendering;
using OFT.Rendering.Context;
using OFT.Rendering.Control;
using OFT.Rendering.Tools;
using Utils.Common.Logging;

namespace ATAS.Docs.Samples.ChartIndicators;

public class KeyboardMouseIndicator : Indicator
{
    private readonly RenderPen _selectionPen = new(Color.Blue, 3);
    private readonly RenderFont _font = new("Arial", 20);
    private readonly RenderStringFormat _stringFormat = new() { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Center };

    private bool _selected;
    private Rectangle _rectangle = new(30, 30, 150, 50);
    private Point _pressedPoint;
    private Point _lastPoint;
    private bool _pressed;

    public KeyboardMouseIndicator()
        : base(true)
    {
        EnableCustomDrawing = true;
        DenyToChangePanel = true;
        DataSeries[0].IsHidden = true;
        SubscribeToDrawingEvents(DrawingLayouts.Final);
    }

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

    protected override void OnRender(RenderContext context, DrawingLayouts layout)
    {
        context.FillRectangle(Color.Coral, _rectangle);

        if (_selected)
            context.DrawRectangle(_selectionPen, _rectangle);

        context.DrawString(DateTime.Now.ToString("T"), _font, Color.AliceBlue, _rectangle, _stringFormat);
    }

    public override bool ProcessMouseClick(RenderControlMouseEventArgs e)
    {
        this.LogInfo("Mouse click");

        return false;
    }

    public override bool ProcessMouseDown(RenderControlMouseEventArgs e)
    {
        this.LogInfo("Mouse down");

        if (e.Button == RenderControlMouseButtons.Left && IsPointInsideRectangle(_rectangle, e.Location))
        {
            _pressedPoint = _lastPoint = e.Location;
            _pressed = true;

            return true;
        }

        return false;
    }

    public override bool ProcessMouseUp(RenderControlMouseEventArgs e)
    {
        this.LogInfo("Mouse up");

        if (Math.Abs(e.Location.X - _pressedPoint.X) < 4 && Math.Abs(e.Location.Y - _pressedPoint.Y) < 4 && e.Button == RenderControlMouseButtons.Left && IsPointInsideRectangle(_rectangle, e.Location))
        {
            _selected = !_selected;
            _pressed = false;

            return true;
        }

        if (_pressed)
        {
            _pressed = false;

            return true;
        }

        return false;
    }

    public override bool ProcessMouseMove(RenderControlMouseEventArgs e)
    {
        if (_pressed && _selected)
        {
            var dX = e.Location.X - _lastPoint.X;
            var dY = e.Location.Y - _lastPoint.Y;
            _lastPoint = e.Location;
            _rectangle.X += dX;
            _rectangle.Y += dY;

            return true;
        }

        return false;
    }

    public override bool ProcessMouseDoubleClick(RenderControlMouseEventArgs e)
    {
        this.LogInfo("Mouse double click");

        return false;
    }

    public override bool ProcessMouseWheel(int delta)
    {
        this.LogInfo("Mouse wheel {0}", delta);

        return false;
    }

    public override bool ProcessKeyDown(KeyEventArgs e)
    {
        this.LogInfo("Key down {0}", e.Key);

        return false;
    }

    public override bool ProcessKeyUp(KeyEventArgs e)
    {
        this.LogInfo("Key up {0}", e.Key);

        return false;
    }

    public override StdCursor GetCursor(RenderControlMouseEventArgs e)
    {
        if (_selected && IsPointInsideRectangle(_rectangle, e.Location))
            return StdCursor.Hand;

        return StdCursor.NULL;
    }

    private static bool IsPointInsideRectangle(Rectangle rectangle, Point point)
    {
        return point.X >= rectangle.X && point.X <= rectangle.X + rectangle.Width && point.Y >= rectangle.Y && point.Y <= rectangle.Y + rectangle.Height;
    }
}

The rectangle dragged with the mouse and the hand cursor