Click here to Skip to main content
15,881,173 members
Articles / Programming Languages / C#

C# Scripts using DynamicMethod

Rate me:
Please Sign up or sign in to vote.
5.00/5 (22 votes)
10 May 2011CPOL3 min read 70.2K   3K   64  
C# scripts using DynamicMethod
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;


namespace CSSDemo
{
  public class EditCtrl : UserControl
  {
    public EditCtrl()
    {
      BackColor = SystemColors.Window;
      AutoScroll = true;
      DoubleBuffered = true;
      Font = new Font("Courier New", 13, FontStyle.Regular, GraphicsUnit.Pixel);
      linemarker = -1;
      timer = new Timer();
      timer.Interval = 500;
      timer.Tick += new EventHandler(OnTimer);
      text = "";
    }

    public void Select(int a)
    {
      Select(a, a);
    }
    public void Select(int a, int b)
    {
      if ((selstart == a) && (selend == b)) return;
      selstart = a; selend = b;
      if (!this.IsHandleCreated) return;

      bool war = timer.Enabled;
      timer.Enabled = false;
      careton = true;
      timer.Enabled = war;

      Invalidate();
      OnSelChanged();

      lastx = 0;
    }
    public void ScrollVisible()
    {
      int y = 4 + LineFromPos(selend) * chardy;
      if (y + AutoScrollPosition.Y < 0)
      {
        AutoScrollPosition = new Point(0, y);
        Update();
      }
      else
        if (y + chardy + AutoScrollPosition.Y > Height)
        {
          AutoScrollPosition = new Point(0, y + chardy - Height);
          Update();
        }
    }
    void Replace(String s)
    {
      int a = Math.Min(selstart, selend);
      int b = Math.Max(selstart, selend);

      UndoUnit undo = new UndoUnit();
      undo.s = !String.IsNullOrEmpty(s) ? s : null;
      undo.i = a;
      undo.n = b - a;
      undo.Execute(this);

      if (undos.Count > iundo)
        undos.RemoveRange(iundo, undos.Count - iundo);
      undos.Add(undo); iundo++;
    }
    public void ClearUndo()
    {
      undos.Clear(); iundo = 0;
    }

    public bool ReadOnly
    {
      get { return _readonly; }
      set
      {
        if (_readonly == value) return;
        _readonly = value;
        BackColor = _readonly ? SystemColors.Control : SystemColors.Window;
      }
    }

    public String EditText
    {
      get { return text; }
      set
      {
        ClearUndo(); selstart = selend = 0;
        text = value;
        Format(); OnTextChanged();
      }
    }

    public bool IsModified { get { return iundo > 0; } }
    public String GetSelectedText()
    {
      int a = Math.Min(selstart, selend);
      int b = Math.Max(selstart, selend);
      return text.Substring(a, b - a);
    }
    public int SelStart { get { return selstart; } }
    public int SelEnd { get { return selend; } }
    public int SelMin { get { return Math.Min(selstart, selend); } }
    public int SelMax { get { return Math.Max(selstart, selend); } }
    public int LineMarker { get { return linemarker; } set { if (linemarker != value) { linemarker = value; Invalidate(); } } }
    public List<int> BreakPoints
    {
      get { return breakpoints; }
      set
      {
        breakpoints = (value != null) && (value.Count > 0) ? value : null;
        Invalidate();
      }
    }

    public int Cut(object test)
    {
      if (_readonly) return 0;
      if (selstart == selend) return 0;
      if (test != null) return 1;
      Copy(test);
      Replace("");
      return 1;
    }
    public int Copy(object test)
    {
      if (selstart == selend) return 0x10;
      if (test != null) return 1;
      int a = Math.Min(selstart, selend), b = Math.Max(selstart, selend);
      Clipboard.Clear();
      Clipboard.SetText(text.Substring(a, b - a));
      return 1;
    }
    public int Paste(object test)
    {
      if (_readonly) return 0;
      if (!Clipboard.ContainsText()) return 0;
      if (test != null) return 1;
      Replace(Clipboard.GetText());
      return 1;
    }
    public int Undo(object test)
    {
      if (_readonly) return 0;
      if (iundo == 0) return 0;
      if (test != null) return 1;
      undos[--iundo].Execute(this);
      return 1;
    }
    public int Redo(object test)
    {
      if (_readonly) return 0;
      if (iundo >= undos.Count) return 0x10;
      if (test != null) return 1;
      undos[iundo++].Execute(this);
      return 1;
    }
    public int Delete(object test)
    {
      if (_readonly) return 0;
      return 0;
    }

    public void SelectAll()
    {
      Select(0, text.Length);
    }

    public void Search()//Strg Shift F3
    {
      MessageBox.Show("Search");
    }
    public int SearchForward(object test) //Strg F3
    {
      if ((search == null) && (selstart == selend)) return 0x10;
      if (test != null) return 1;
      if (selstart != selend) search = GetSelectedText();
      return SearchNext(test);
    }
    public int SearchNext(object test) //F3
    {
      if (search == null) return 0x10;
      if (test != null) return 1;
      int t = Math.Max(selstart, selend);

      int i = text.IndexOf(search, t);
      if (i < 0) i = text.IndexOf(search, 0);

      if (i >= 0)
      {
        Select(i, i + search.Length);
        ScrollVisible();
        return 1;
      }
      //MessageBeep(-1);
      return 1;
    }
    public int SearchPrev(object test) //Shift F3
    {
      if (search == null) return 0x10;
      if (test != null) return 1;

      int t = Math.Min(selstart, selend);

      int last = -1;
      for (int i = t; ((i = text.IndexOf(search, i)) >= 0); ) { last = i; i += search.Length; }
      for (int i = 0; ((i = text.IndexOf(search, i)) >= 0) && (i < t); ) { last = i; i += search.Length; }

      if (last >= 0)
      {
        Select(last, last + search.Length); ScrollVisible();
        return 1;
      }
      //MessageBeep(-1);
      return 1;
    }

    protected virtual void OnSelChanged() { }

    public int LineFromPos(int pos)
    {
      String s = text; if (pos > s.Length) pos = s.Length;
      int l = 0; for (int i = 0; i < pos; i++) if (s[i] == '\n') l++;
      return l;
    }
    public int GetLineStart(int line)
    {
      if (line == 0) return 0; String s = text; int j = 0;
      for (int l = 0, n = s.Length; j < n; j++)
      {
        if (l == line) return j;
        if (s[j] == '\n') l++;
      }
      return j;
    }
    public int GetLineEnd(int line)
    {
      String s = text; int j = 0;
      for (int l = 0, n = s.Length; j < n; j++)
      {
        if (s[j] == '\n')
        {
          if (l == line)
            return (j > 0) && (s[j - 1] == '\r') ? j - 1 : j;
          l++;
        }
      }
      return j;
    }
    int PosFromPoint(Point p)
    {
      if (lines == null) _initlines();

      Rectangle r = new Rectangle(16, AutoScrollPosition.Y + 4, 0x40000000, chardy);
      p.X = Math.Max(r.Left, p.X);
      p.Y = Math.Max(r.Top, p.Y);
      for (int i = 0, t = 0; i < lines.Length; t += lines[i++].Length + 2, r.Offset(0, r.Height))
        if (r.Contains(p))
        {
          for (int l = 0; l < lines[i].Length; l++)
          {
            int x1 = r.Left + (int)_xoffs(lines[i], l + 0);
            int x2 = r.Left + (int)_xoffs(lines[i], l + 1);
            if (x2 > p.X)
              return t + (p.X <= ((x1 + x2) >> 1) ? l : l + 1);
          }

          return t + lines[i].Length;
        }

      return text.Length;
    }
    bool WordFromPoint(int i, ref Point ab)
    {
      if (i == text.Length) return false;
      int a = i; for (; a > 0; a--) if (!IsWordChar(text[a - 1])) break;
      int b = i; for (; b < text.Length; b++) if (!IsWordChar(text[b])) break;
      ab.X = a; ab.Y = b;
      return true;
    }

    void _initlines()
    {
      if (chardx == 0)
      {
        stringformat = new StringFormat(StringFormat.GenericTypographic);
        Graphics graphics = this.CreateGraphics();
        SizeF charsize = graphics.MeasureString("X", this.Font, 0, stringformat);
        graphics.Dispose();
        chardx = charsize.Width;
        chardy = (int)charsize.Height + 1;//Math.Ceiling(charsize.Height);
        tabdx = 2 * chardx;
        //stringformat.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
        stringformat.SetTabStops(0, new Single[] { tabdx });
      }
      lines = text.Split(new String[] { "\r\n" }, System.StringSplitOptions.None);
    }
    float _xoffs(String s, int n)
    {
      float dx = 0;
      for (int i = 0; i < n; i++)
      {
        if ((i < s.Length) && (s[i] == '\t'))
        {
          dx = ((int)(dx / tabdx) + 1) * tabdx;
          continue;
        }
        dx += chardx;
      }
      return dx;
    }
    void _synaxcolor()
    {
      String s = text; int n = s.Length;
      Array.Resize(ref charcolor, n + 1);

      if (syntcolors == null)
        return;

      int colorcomment = 0;
      int colorstring = 0;

      for (int t = 0; t < syntcolors.Length; t++)
      {
        SyntaxColor c = syntcolors[t];
        if (String.IsNullOrEmpty(c.s)) continue;
        if (c.s[0] != '[') continue;
        if (c.s == "[String]") colorstring = c.c.ToArgb();
        if (c.s == "[Comment]") colorcomment = c.c.ToArgb();
      }

      for (int j = 0; j < n - 1; j++)
      {
        charcolor[j] = 0;

        if ((s[j] == '/') && (s[j + 1] == '*'))
        {
          for (int t = 0; j < n; j++, t++)
          {
            charcolor[j] = colorcomment;//(0,128,0);
            if ((t > 2) && (s[j - 1] == '*') && (s[j] == '/')) break;
          }
          continue;
        }

        if ((s[j] == '/') && (s[j + 1] == '/'))
        {
          for (; j < n; j++)
          {
            if ((s[j] == 13) || (s[j] == 10)) break;
            charcolor[j] = colorcomment;
          }
          continue;
        }

        if ((s[j] == '"') || (s[j] == '\''))
          for (int t = j + 1; t < n; t++)
          {
            if (s[t] == '\\') continue;
            if ((s[t] == 13) || (s[t] == 10)) break;
            if (s[t] == s[j])
            {
              for (; j <= t; j++) charcolor[j] = colorstring; j--;
              break;
            }
          }

        if (char.IsLetter(s[j]))
          if ((j == 0) || !char.IsLetter(s[j - 1]))
          {
            int t = j + 1; for (; t < n; t++) if (!IsWordChar(s[t])) break;

            int color = 0;

            for (int x = 0; x < syntcolors.Length; x++)
              if (!String.IsNullOrEmpty(syntcolors[x].s) && (syntcolors[x].s[0] != '['))
                if (syntcolors[x].s.Length == t - j)
                  if (String.Compare(syntcolors[x].s, 0, s, j, t - j) == 0)
                  {
                    color = syntcolors[x].c.ToArgb();
                    break;
                  }

            if (color != 0)
            {
              for (; j < t; j++) charcolor[j] = color; j--;
              continue;
            }
          }

      }

      if (n != 0) charcolor[n - 1] = n > 1 ? charcolor[n - 2] : 0;
    }
    void _setcolor(int c)
    {
      if ((textbrush != null) && (lastcolor == c)) return;
      if (textbrush != null) textbrush.Dispose();
      lastcolor = c;
      textbrush = new SolidBrush(Color.FromArgb(c | unchecked((int)0xff000000)));
    }
    static bool IsWordChar(char c)
    {
      return char.IsLetterOrDigit(c) || (c == '_');
    }

    public struct SyntaxColor
    {
      public override string ToString()
      {
        return Token + " " + Color.ToString(); // GetType().Name;
      }
      public SyntaxColor(String s, Color c)
      {
        this.s = s;
        this.c = c;
      }
      public String s;
      public Color c;
      public String Token
      {
        get { return s; }
        set { s = value; }
      }
      public Color Color
      {
        get { return c; }
        set { c = value; }
      }
    };
    public virtual SyntaxColor[] SyntaxColors
    {
      get { return syntcolors; }
      set
      {
        syntcolors = value;
        if (charcolor == null) return;
        _synaxcolor();
        Invalidate();
      }
    }

    void replace(int i, int n, string s)
    {
      if (breakpoints != null)
        for (int k = 0; k < breakpoints.Count; k++)
          breakpoints[k] = GetLineStart(breakpoints[k]);

      text = text.Substring(0, i) + s + text.Substring(i + n, text.Length - (i + n));

      if (breakpoints != null)
        for (int k = 0; k < breakpoints.Count; k++)
        {
          int t = breakpoints[k];
          if (t >= i)
          {
            if (t < i + n)
            {
              breakpoints.RemoveAt(k--);
              continue;
            }
            t -= n;
            t += s.Length;
          }
          breakpoints[k] = LineFromPos(t);
        }
      Format();
      OnTextChanged();
    }

    class UndoUnit
    {
      public void Execute(EditCtrl ctrl)
      {
        String os = n != 0 ? ctrl.text.Substring(i, n) : null;
        ctrl.replace(i, n, s != null ? s : "");
        n = s != null ? s.Length : 0;
        s = os;
        ctrl.Select(i + n); ctrl.ScrollVisible();

      }
      public int i, n; public String s;
    };
    void Format()
    {
      _initlines();
      selstart = Math.Min(selstart, text.Length);
      selend = Math.Min(selend, text.Length);
      AutoScrollMinSize = new Size(0, lines.Length * chardy + chardy);
      _synaxcolor();
      Invalidate();
    }
    protected virtual void OnTextChanged()
    {
      if (EditTextChanged != null) EditTextChanged(this, EventArgs.Empty);
    }
    public event EventHandler EditTextChanged;

    protected override void OnPaint(PaintEventArgs e)
    {
      Graphics graphics = e.Graphics;
      String text = this.text;
      rcaret.Width = 0;
      RectangleF rcc = graphics.ClipBounds;
      Rectangle rc = new Rectangle((int)rcc.Left, (int)rcc.Top, (int)rcc.Width + 1, (int)rcc.Height + 1);

      if (lines == null) _initlines();

      int a = Math.Min(selstart, selend);
      int b = Math.Max(selstart, selend);

      //graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

      Rectangle r = new Rectangle(16, AutoScrollPosition.Y + 4, 0x40000000, chardy);
      for (int i = 0, t = 0; i < lines.Length; t += lines[i++].Length + 2, r.Offset(0, r.Height))
      {
        String line = lines[i];
        if (rc.IntersectsWith(r))
        {
          if (charcolor != null)
          {
            int n = line.Length;
            for (int aa = 0, bb = 0; ; bb++)
              if ((charcolor[t + aa] != charcolor[t + bb]) || (bb == n))
              {
                _setcolor(charcolor[t + aa]);
                if ((aa == 0) && (bb == n))
                {
                  graphics.DrawString(line, this.Font, textbrush, r, stringformat);
                }
                else
                {
                  //Rectangle rr=r; rr.X = (int)Math.Round(rr.X+_xoffs(line,a));
                  //graphics.DrawString(line.Substring(a,b-a),this.Font,textbrush,rr,stringformat);

                  Rectangle rr = Rectangle.FromLTRB(r.Left + (int)_xoffs(line, aa) + 0, r.Top, r.Left + (int)_xoffs(line, bb) + 1, r.Bottom);
                  graphics.SetClip(rr);
                  graphics.DrawString(line, this.Font, textbrush, r, stringformat);
                  graphics.ResetClip();
                }
                if (bb == n) break;
                aa = bb;
              }
          }
          else
          {
            graphics.DrawString(line, this.Font, Brushes.Black, r, stringformat);
          }

          if (breakpoints != null)
            for (int tt = 0; tt < breakpoints.Count; tt++)
              if (breakpoints[tt] == i)
              {
                graphics.FillEllipse(Brushes.DarkRed, new Rectangle(3, r.Top + 3, 10, 10));
                break;
              }

          if (linemarker == i)
          {
            Point[] pp = new Point[] { new Point(6, r.Top + 2), new Point(6 + 7, r.Top + 2 + 6), new Point(6, r.Top + 2 + 12) };
            graphics.FillPolygon(Brushes.Green, pp);
          }
        }

        if (b >= t)
          if (a <= t + line.Length)
          {
            int i1 = Math.Max(a - t, 0);
            int i2 = Math.Min(b - t, line.Length);

            Rectangle rr = Rectangle.FromLTRB(r.Left + (int)_xoffs(line, i1) + 0, r.Top, r.Left + (int)_xoffs(line, i2) + 1, r.Bottom);

            if ((a != b) && (b > t))
              if (rc.IntersectsWith(r))
              {
                if ((i2 >= line.Length) && ((t + i2) != selend)) rr.Width += 8;

                graphics.FillRectangle(Focused ? SystemBrushes.Highlight : SystemBrushes.GradientInactiveCaption, rr);

                graphics.SetClip(rr);
                graphics.DrawString(line, this.Font, Focused ? SystemBrushes.HighlightText : Brushes.Black, r, stringformat);
                graphics.ResetClip();
              }

            if (((t + i1) == selend) || ((t + i2) == selend))
            {
              rcaret = rr;
              if ((t + i2) == selend) rcaret.X = rcaret.Right;
              rcaret.Width = 1;
              rcaret.X--;
              if (Focused && careton)
                graphics.FillRectangle(Brushes.Black, rcaret);
            }
          }
      }
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
      int i = PosFromPoint(e.Location); //System.Diagnostics.Debug.WriteLine(i);
      if (Capture)
      {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
          Select(selstart, i);
          ScrollVisible();
        }
      }
      else
      {
        /*
        Point ab; 
        if(WordFromPoint(i,ab)) 
        {
          String s=Text.Substring(ab.X,ab.Y-ab.X);
          if(this.toolTip1.GetToolTip(this)!=s)
          {
            this.toolTip1.SetToolTip(this,s);
          }
        }
        */
      }
      Cursor = Cursors.IBeam;
      base.OnMouseMove(e);
    }
    protected override void OnMouseDown(MouseEventArgs e)
    {
      base.OnMouseDown(e);
      if (e.Button == System.Windows.Forms.MouseButtons.Left)
        Select(PosFromPoint(e.Location));
    }
    protected override void OnMouseUp(MouseEventArgs e)
    {
      base.OnMouseUp(e);
    }
    protected override void OnMouseLeave(EventArgs e)
    {
      Cursor = Cursors.Arrow;
    }
    protected override void OnMouseDoubleClick(MouseEventArgs e)
    {
      base.OnMouseDoubleClick(e);
      Point ab = new Point(); if (WordFromPoint(PosFromPoint(e.Location), ref ab)) Select(ab.X, ab.Y);
    }

    protected override void OnGotFocus(EventArgs e)
    {
      Invalidate();
      careton = true;
      timer.Enabled = true;
      base.OnGotFocus(e);
    }
    protected override void OnLostFocus(EventArgs e)
    {
      Invalidate();
      timer.Enabled = false;
      base.OnLostFocus(e);
    }
    protected override void OnKeyDown(KeyEventArgs e)
    {
      base.OnKeyDown(e);
      switch (e.KeyCode)
      {
        case Keys.Delete:
          if (selstart == selend)
          {
            int i = selend;
            if (i >= text.Length) return;
            i++; if ((i < text.Length) && (text[i] == '\n')) i++;
            Select(selstart, i); ScrollVisible();
          }
          if (_readonly) return;
          Replace("");
          break;

        case Keys.Left:
          if (selstart == selend)
          {
            int i = selstart;
            if (i == 0) break;
            i--; if (text[i] == '\n') i--;
            Select(i); ScrollVisible();
          }
          else
          {
            Select(Math.Min(selstart, selend)); ScrollVisible();
          }
          break;
        case Keys.Right:
          if (selstart == selend)
          {
            int i = selstart;
            if (i >= text.Length) break;
            i++; if ((i < text.Length) && (text[i] == '\n')) i++;
            Select(i); ScrollVisible();
          }
          else
          {
            Select(Math.Max(selstart, selend)); ScrollVisible();
          }
          break;

        case Keys.Up:
          {
            Point P = rcaret.Location; P.Y -= chardy; if (lastx != 0) P.X = lastx;
            Select(PosFromPoint(P)); ScrollVisible();
            lastx = P.X;
          }
          break;

        case Keys.Down:
          {
            Point P = rcaret.Location; P.Y += chardy; if (lastx != 0) P.X = lastx;
            Select(PosFromPoint(P)); ScrollVisible();
            lastx = P.X;
          }
          break;
      }

    }
    protected override void OnKeyPress(KeyPressEventArgs e)
    {
      base.OnKeyPress(e);
      if (_readonly) return;

      if (e.KeyChar == (char)13)
      {
        String s = text;
        int a = SelMin; for (; (a > 0) && (s[a - 1] != '\n'); a--) ;
        int b = a; for (; (b < s.Length) && ((s[b] == ' ') || (s[b] == '\t')); b++) ;
        Replace("\r\n" + s.Substring(a, b - a));
        return;
      }
      if (e.KeyChar == (char)8)
      {
        if (selstart == selend)
        {
          if (selstart == 0) return;
          selstart--;
          if (text[selstart] == '\n')
            selstart--;
        }
        Replace("");
        return;
      }
      if (e.KeyChar == '\t')
      {
        int l1 = LineFromPos(SelMin), l2 = LineFromPos(SelMax);
        if (l1 != l2)
        {
          int i1 = GetLineStart(l1);
          int i2 = GetLineEnd(l2);
          bool bout = (ModifierKeys & Keys.Shift) == Keys.Shift;

          String s = text.Substring(i1, i2 - i1), r = "";
          Select(i1, i2);
          String[] ss = s.Split(new String[] { "\r\n" }, System.StringSplitOptions.None);
          for (int i = 0; i < ss.Length; i++)
          {
            if (i != 0) r += "\r\n";
            if (bout)
              r += (ss[i].Length > 0) && ((ss[i][0] == '\t') || (ss[i][0] == ' ')) ? ss[i].Substring(1, ss[i].Length - 1) : ss[i];
            else
              r += "\t" + ss[i];
          }
          if (r == s) return;
          Replace(r);
          Select(i1, i1 + r.Length);
          return;
        }
        Replace(e.KeyChar.ToString());
        return;
      }

      if (!char.IsControl(e.KeyChar))
        Replace(e.KeyChar.ToString());

    }

    protected override bool IsInputKey(Keys keyData)
    {
      return true;
    }

    private void OnTimer(Object sender, EventArgs e)
    {
      careton ^= true;// careton ? false : true;
      Invalidate(rcaret);
    }
    
    String text;
    String[] lines;
    int selstart, selend;
    bool careton;
    Rectangle rcaret;
    int[] charcolor;
    List<int> breakpoints;
    int linemarker;
    StringFormat stringformat;
    SolidBrush textbrush;
    int lastcolor;
    float chardx;
    int chardy;
    int lastx;
    float tabdx;
    SyntaxColor[] syntcolors;
    List<UndoUnit> undos = new List<UndoUnit>();
    int iundo;
    static String search;
    bool _readonly;
    Timer timer;

  }

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions