Category Other  Published on 20/07/2023

Edit Icon Comment

Description

This indicator is to solve the problem cTrader ver 4.4.12 removed to access and edit the icon's comments
For problem details, please see: https://ctrader.com/forum/ctrader-support/39021
Usage:
1. Select Icon, Alt + D to popup a ChartText with the icon's comment;
2. Edit ChartText as needed;
3. Alt + D to save revised comments, hit again to hide popup ChartText;

Interested in the currency strength meter in the chart?
Get the free download link at Telegram Group: cTrader FOREX Club


using System;
using System.IO;
using System.Linq;
using cAlgo.API;

//This indicator is to solve the problem cTrader ver 4.4.12 removed to access and edit the icon's comments
//Problem details see: https://ctrader.com/forum/ctrader-support/39021
//Usage:
//1. Select Icon, Alt + D to popup a ChartText with the icon's comment;
//2. Edit ChartText as needed;
//3. Alt + D to save revised comments, hit again to hide popup ChartText;
//4. Alt + C to make a copy of comments box;
//5. Alt + E to remove copied comments box;
//
//Ver 1.01 Optimise     : Short cut key change to only Alt + D, save and hide ChartText;
//    1.02 Optimise     : Short cut key change to only Alt + D, unhide, save and hide ChartText;
//                      : Temporarily fill with 'empty...' if Icon has no comment;
//    1.03 Add Function : Can edit Trendline and Rectangle's comments;
//    1.04 Optimise     : MakeSure Textbox is interactive; TextBox can be seen(in the last trading day) if Trendline too old;
//         Optimise     : Framework .NET 6.0 ready;
//    1.05 Optimise     : Use IsInteractive to hide CommentTextBox; Code Structure; CommentTextBox color is not transparent;
//    1.06 Add Function : Alt + X: quick (Un)Lock select trendlines, rectangles, icons, text box;
//    1.07 Optimise     : Fixed bug of Alt + D to display textbox immediately;
//         Optimise     : Put Comments-Box in the mid of chart for TrendLine, Rectangle, HorizentalLine;
//         Add Function : Alt + X: can (Un)Lock ChartArrowLines;
//         Add Function : Can edit HorizentalLine's Comments;


namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class EditIconCmmt : Indicator
    {
        string s_objnme, s_objsve, s_objcmt;//Object Name, Save, Comment
        double db_obj_Y;                    //Object Y-Value
        int    i_ObjIdx;                    //Object Bar-Index
        Color  cl_objCl;                    //Object Color
        private ChartText tx_Cmmt, tx_Copy; //ChartTextBox to display,edit ObjectComment; Copy of ObjectComment;
        private ChartStaticText sx_RorS;    //Display control process
        private ChartObjectType ty_Obj;     //Record Select Object ChartObjectType 

        private readonly static string pfx_CmX = "Cmmt_Tx", pfx_Cms="RorS"; //Prifix : at Name of ObjectCommentTextBox, ControlMessage Text;
        private readonly static string sfx_Cpy = "- CmtCpy";                //Sufix  : at Name of Copy of ObjectComment;
        private readonly static string cnt_Ept = "empty...", nEp="";        //Content: Temperary to fill ObjectCommentTextBox; SymbolEmpty;
        private readonly static string act_Sve = " comment saved...";       //Action : ObjectComment saved
        private readonly static string act_Hdn = " comment hidden...";      //Action : ObjectComment hidden
        private readonly static string act_Cpy = " comment coppied...";     //Action : ObjectComment copy
        private readonly static string act_Rmv = " comment removed...";     //Action : ObjectComment remove
        private readonly static string act_unL = "Selected objects free now...";    //Action : Objects unlocked
        private readonly static string act_Lck = "Selected objects locked...";      //Action : Objects locked

        protected override void Initialize()
        {   //System.Diagnostics.Debugger.Launch();
            Chart.KeyDown += Chart_KeyDown;                                     //HotKeys to SaveChange;
            Chart.ObjectsSelectionChanged += Chart_ObjectsSelectionChanged;     //Select Icons to popup comments in ChartText;
            
            //Prepare ObjectCommentText and PopupMessageText
            sx_RorS = Chart.DrawStaticText(pfx_Cms, string.Format(nEp), VerticalAlignment.Bottom, HorizontalAlignment.Right, Color.Red); sx_RorS.IsHidden=false;

        }

        public override void Calculate(int index) {}
        
        //Select effective object to prepare CommentTextBox, hidden yet
        private void Chart_ObjectsSelectionChanged(ChartObjectsSelectionChangedEventArgs obj)
        {
            //Exempt object numbers selected (only work for 1 object) - Update Name of SelectObject
            if      ( Chart.SelectedObjects.Count()==0 )            //Clear Message when select no object
            { PPmsg(nEp,false); }
            else if ( Chart.SelectedObjects.Count()==1 )            //Record SelectObject's Name,Type,Comments
            {

                if ( Chart.SelectedObjects[0].Name!=pfx_CmX )           //Don't do, if tx_Cmmt is selected
                {
                    s_objnme = Chart.SelectedObjects[0].Name;           //SelectObjectName
                    ty_Obj   = Chart.SelectedObjects[0].ObjectType;     //ChartObjectType
                    s_objsve = s_objnme;                                //NameToSave
                    s_objcmt = Chart.SelectedObjects[0].Comment;        //Comment Content

                    int iStr = Chart.FirstVisibleBarIndex;  //Get the first bar-index in Chart
                    int iEnd = Chart.LastVisibleBarIndex;   //Get the  last bar-index in Chart
                    int iMid = (iStr + iEnd) / 2;           //Get the   mid bar-index in Chart

                    switch (ty_Obj)                                     //Record ObjectTime, Y-Value
                    {
                        case ChartObjectType.Icon           : var Ics=Chart.FindAllObjects(ChartObjectType.Icon          ).Where(x => x.Name==s_objnme); foreach (ChartIcon           ic in Ics) { int iT=Bars.OpenTimes.GetIndexByTime(ic.Time ); i_ObjIdx = iT;                  db_obj_Y = ic.Y;  cl_objCl = ic.Color; } break;
                        case ChartObjectType.TrendLine      : var Trs=Chart.FindAllObjects(ChartObjectType.TrendLine     ).Where(x => x.Name==s_objnme); foreach (ChartTrendLine      tr in Trs) { int iT=Bars.OpenTimes.GetIndexByTime(tr.Time1); i_ObjIdx = iT<iStr ? iMid : iT; db_obj_Y = tr.Y1; cl_objCl = tr.Color; } break;
                        case ChartObjectType.Rectangle      : var Rts=Chart.FindAllObjects(ChartObjectType.Rectangle     ).Where(x => x.Name==s_objnme); foreach (ChartRectangle      rt in Rts) { int iT=Bars.OpenTimes.GetIndexByTime(rt.Time1); i_ObjIdx = iT<iStr ? iMid : iT; db_obj_Y = rt.Y1; cl_objCl = rt.Color; } break;
                        case ChartObjectType.HorizontalLine : var Hls=Chart.FindAllObjects(ChartObjectType.HorizontalLine).Where(x => x.Name==s_objnme); foreach (ChartHorizontalLine hl in Hls) {                                                 i_ObjIdx = iMid               ; db_obj_Y = hl.Y ; cl_objCl = hl.Color; } break;
                        default: return;
                    }

                    RemvCmTx();                                         //Remove comments box first to avoid mis-saving
                }

            }
            else if ( Chart.SelectedObjects.Count()>=2 )            //Select multiple object to remove comment box
            { RemvCmTx(); }

        }

        //Alt+D,C,E: to Popup,Copy,Erase CommentTextBox
        private void Chart_KeyDown(ChartKeyboardEventArgs obj)
        {   
            if (obj.AltKey)
            {
                if      (obj.Key.Equals(Key.D))                                     //Alt + D: to Edit,Save,Hide ObjectComment
                {   
                    var Txs= Chart.FindAllObjects(ChartObjectType.Text).Where(x => x.Name==pfx_CmX);
                    if ( Txs.Count() == 0 )                                         //First hit to write & display comment;
                    {
                        int iStr = Chart.FirstVisibleBarIndex;  //Get the first bar-index in Chart
                        int iEnd = Chart.LastVisibleBarIndex;   //Get the  last bar-index in Chart
                        int iMid = (iStr + iEnd) / 2;           //Get the   mid bar-index in Chart

                        switch (ty_Obj)                                             //Prepare ObjectCommentText according to ObjectType
                        {   //                                                                                                                                                                                                                                              ↓↓ Visiable in chart                            ↓↓ Not transparent
                            case ChartObjectType.Icon           : var Ics=Chart.FindAllObjects(ChartObjectType.Icon          ).Where(x => x.Name==s_objnme); foreach (ChartIcon           ic in Ics) { int iT=Bars.OpenTimes.GetIndexByTime(ic.Time ); ReadCmTx(ic.Comment, iT,                   ic.Y,  Color.FromArgb(255,ic.Color)); } break;
                            case ChartObjectType.TrendLine      : var Trs=Chart.FindAllObjects(ChartObjectType.TrendLine     ).Where(x => x.Name==s_objnme); foreach (ChartTrendLine      tr in Trs) { int iT=Bars.OpenTimes.GetIndexByTime(tr.Time1); ReadCmTx(tr.Comment, iT<iStr ? iMid : iT,  tr.Y1, Color.FromArgb(255,tr.Color)); } break;
                            case ChartObjectType.Rectangle      : var Rts=Chart.FindAllObjects(ChartObjectType.Rectangle     ).Where(x => x.Name==s_objnme); foreach (ChartRectangle      rt in Rts) { int iT=Bars.OpenTimes.GetIndexByTime(rt.Time1); ReadCmTx(rt.Comment, iT<iStr ? iMid : iT,  rt.Y1, Color.FromArgb(255,rt.Color)); } break;
                            case ChartObjectType.HorizontalLine : var Hls=Chart.FindAllObjects(ChartObjectType.HorizontalLine).Where(x => x.Name==s_objnme); foreach (ChartHorizontalLine hl in Hls) {                                                 ReadCmTx(hl.Comment, iMid               ,  hl.Y , Color.FromArgb(255,hl.Color)); } break;
                            default: return;
                        }
                    }
                    else                                                            //Hit again to save if comment changed;
                    {
                        if ( tx_Cmmt.Text != s_objcmt && tx_Cmmt.Text != cnt_Ept)
                        {
                            switch (ty_Obj) //Works only at the ObjectSelected
                            {   //                                                                                                                                                            Save comments to Object,  Update Comments to compare
                                case ChartObjectType.Icon           : var Ics=Chart.FindAllObjects(ChartObjectType.Icon          ).Where(x => x.Name==s_objnme); foreach (ChartIcon           ic in Ics) { ic.Comment=tx_Cmmt.Text; s_objcmt=tx_Cmmt.Text; } break;
                                case ChartObjectType.TrendLine      : var Trs=Chart.FindAllObjects(ChartObjectType.TrendLine     ).Where(x => x.Name==s_objnme); foreach (ChartTrendLine      tr in Trs) { tr.Comment=tx_Cmmt.Text; s_objcmt=tx_Cmmt.Text; } break;
                                case ChartObjectType.Rectangle      : var Rts=Chart.FindAllObjects(ChartObjectType.Rectangle     ).Where(x => x.Name==s_objnme); foreach (ChartRectangle      rt in Rts) { rt.Comment=tx_Cmmt.Text; s_objcmt=tx_Cmmt.Text; } break;
                                case ChartObjectType.HorizontalLine : var Hls=Chart.FindAllObjects(ChartObjectType.HorizontalLine).Where(x => x.Name==s_objnme); foreach (ChartHorizontalLine hl in Hls) { hl.Comment=tx_Cmmt.Text; s_objcmt=tx_Cmmt.Text; } break;
                                default: return;
                            }
                            PPmsg(s_objsve+act_Sve, false);
                        }
                        else { RemvCmTx(); PPmsg(s_objnme+act_Hdn, true); }         //Hit again to Remove comment TextBox;
                    }
                }                                  //Alt + D: to Edit,Save,Hide ObjectComment
                else if (obj.Key.Equals(Key.C))                                     //Alt + C: Leave a Copy Unhiden for ObjectComment
                {
                    tx_Copy = Chart.DrawText(s_objnme+sfx_Cpy, s_objcmt == nEp ? cnt_Ept : s_objcmt, i_ObjIdx, db_obj_Y, Color.FromArgb(255,cl_objCl));
                    //Put CopyCommentBox at proper position by ObjectType
                    switch (ty_Obj)
                    {
                        case ChartObjectType.Icon     : tx_Copy.HorizontalAlignment=HorizontalAlignment.Left;  break;   //Left beside Icon
                        case ChartObjectType.TrendLine: tx_Copy.HorizontalAlignment=HorizontalAlignment.Right; break;   //LeftBottom Trendline
                        case ChartObjectType.Rectangle: tx_Copy.HorizontalAlignment=HorizontalAlignment.Right; break;   //LeftBotton Rectangle
                        default: return;
                    }
                    tx_Copy.IsHidden=false; tx_Copy.IsInteractive=true; tx_Copy.IsLocked=true; //Display CommentBoxCopy
                    RemvCmTx(); //Hide CommentsTextBox
                    PPmsg(s_objsve+act_Cpy, false);
                }                                  //Alt + C: Leave a Copy Unhiden for ObjectComment
                else if (obj.Key.Equals(Key.E))                                     //Alt + E: Remove Copied ObjectCommentTextBox, Hide CommentTextBox;
                {
                    var Txs=Chart.FindAllObjects(ChartObjectType.Text).Where(x => x.Name.Contains(s_objnme)); foreach (ChartText Tx in Txs) { Chart.RemoveObject(Tx.Name); }
                    RemvCmTx(); //Hide CommentsTextBox
                    PPmsg(s_objsve+act_Rmv, true);
                }                                  //Alt + E: Remove Copied ObjectCommentTextBox, Hide CommentTextBox;
                else if (obj.Key.Equals(Key.X))                                     //Alt + X: (Un)Lock select trendlines, rectangles, icons;
                {
                    string s_nm = string.Empty;
                    //Check all SelectedObjects
                    for (int i = 0; i < Chart.SelectedObjects.Count; i++ )
                    {
                        s_nm = Chart.SelectedObjects[i].Name;
                        if      (Chart.SelectedObjects[i].ObjectType == ChartObjectType.ArrowLine)
                        { var ALs = Chart.FindAllObjects(ChartObjectType.ArrowLine).Where( x => x.Name==s_nm ); foreach (ChartArrow     al in ALs) { al.IsLocked = !al.IsLocked; PPmsg(al.IsLocked ? act_Lck : act_unL, false);} }
                        if      (Chart.SelectedObjects[i].ObjectType == ChartObjectType.TrendLine)
                        { var Trs = Chart.FindAllObjects(ChartObjectType.TrendLine).Where( x => x.Name==s_nm ); foreach (ChartTrendLine tr in Trs) { tr.IsLocked = !tr.IsLocked; PPmsg(tr.IsLocked ? act_Lck : act_unL, false);} }
                        else if (Chart.SelectedObjects[i].ObjectType == ChartObjectType.Rectangle)
                        { var Rts = Chart.FindAllObjects(ChartObjectType.Rectangle).Where( x => x.Name==s_nm ); foreach (ChartRectangle rt in Rts) { rt.IsLocked = !rt.IsLocked; PPmsg(rt.IsLocked ? act_Lck : act_unL, false);} }
                        else if (Chart.SelectedObjects[i].ObjectType == ChartObjectType.Icon)
                        { var Ics = Chart.FindAllObjects(ChartObjectType.Icon)     .Where( x => x.Name==s_nm ); foreach (ChartIcon      ic in Ics) { ic.IsLocked = !ic.IsLocked; PPmsg(ic.IsLocked ? act_Lck : act_unL, false);} }
                        else if (Chart.SelectedObjects[i].ObjectType == ChartObjectType.Text)
                        { var Txs = Chart.FindAllObjects(ChartObjectType.Text)     .Where( x => x.Name==s_nm ); foreach (ChartText      tx in Txs) { tx.IsLocked = !tx.IsLocked; PPmsg(tx.IsLocked ? act_Lck : act_unL, false);} }
                    }
                }                                  //Alt + X: (Un)Lock select trendlines, rectangles, icons;
            }

        }
        
        //Read the SelectObject comment to display;
        private void ReadCmTx(string s_CmTx, int i_CmTx, double Y_CmTx, Color cl_CmTx)
        {
            //Read(Display) Comments content
            tx_Cmmt = Chart.DrawText(pfx_CmX, (s_CmTx == nEp) ? cnt_Ept : s_CmTx, i_CmTx, 0, cl_CmTx);
            tx_Cmmt.Time = Bars[i_CmTx].OpenTime; tx_Cmmt.Y = Y_CmTx; tx_Cmmt.FontSize = 14;
            tx_Cmmt.IsInteractive = true;   tx_Cmmt.IsLocked = false;
            tx_Cmmt.HorizontalAlignment=HorizontalAlignment.Right;
        }

        //Set CommentTextBox (Un)Hidden
        private void RemvCmTx()
        { if ( Chart.FindAllObjects(ChartObjectType.Text).Where(x => x.Name==pfx_CmX).Count() > 0 ) { Chart.RemoveObject(tx_Cmmt.Name); } }

        //Popup Control Message
        private void PPmsg(string msg, bool ishidden)
        {
            if (ishidden) { sx_RorS.Text = nEp; sx_RorS.IsHidden = true ; }
            else          { sx_RorS.Text = msg; sx_RorS.IsHidden = false; }
        }

    }

}

Capt.Z-Fort.Builder's avatar
Capt.Z-Fort.Builder

Joined on 03.06.2020

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: Edit Icon Comment.algo
  • Rating: 5
  • Installs: 709
Comments
Log in to add a comment.
No comments found.