Eto Drawable
An overview of the Eto Drawable Control

Drawable provides infinite flexibility in Eto, you can draw anything in a reusable UI control.

Your first Drawable

Drawables let you draw anything in a 2d space. Use this as a scratch pad and try out the various drawing methods.

using Eto.Forms;
using Eto.Drawing;
using Rhino.UI;

var parent = RhinoEtoApp.MainWindowForDocument(__rhino_doc__);

var drawable = new Drawable() {
  Padding = 5,
  Width = 200,
  Height = 200
};

drawable.Paint += (s, e) => {

  // Circle
  var rect = new RectangleF(0, 0, 50, 50);
  e.Graphics.FillEllipse(Colors.Red, rect);

  // Line
  var linePen = new Pen(Colors.Blue, 4f);
  e.Graphics.DrawLine(linePen, 60, 60, 120, 60);

  // Rectangle
  var rectPen = new Pen(Colors.Green, 6f);
  e.Graphics.DrawRectangle(rectPen, 10, 80, 140, 40);

  // Rounded Rectangle
  var roundRect = new RectangleF(10, 140, 140, 40);
  var roundedRectPen = new Pen(Colors.BlueViolet, 6);
  var roundedRectPath = GraphicsPath.GetRoundRect(roundRect, 10);
  e.Graphics.DrawPath(roundedRectPen, roundedRectPath);
};

var dialog = new Dialog()
{
  Padding = 24,
  Content = drawable
};

dialog.ShowModal(parent);
import scriptcontext as sc

from Rhino.UI import RhinoEtoApp, EtoExtensions
import Eto.Forms as ef
import Eto.Drawing as ed

parent = RhinoEtoApp.MainWindowForDocument(sc.doc)

drawable = ef.Drawable()
drawable.Padding = ed.Padding(5)
drawable.Width = 200
drawable.Height = 200

def draw(sender, e):

    # Circle
    rect = ed.RectangleF(0, 0, 50, 50)
    e.Graphics.FillEllipse(ed.Colors.Red, rect)

    # Line
    linePen = ed.Pen(ed.Colors.Blue, 4)
    e.Graphics.DrawLine(linePen, 60, 60, 120, 60)

    # Rectangle
    rectPen = ed.Pen(ed.Colors.Green, 6)
    e.Graphics.DrawRectangle(rectPen, 10, 80, 140, 40)

    # Rounded Rectangle
    roundedRectPen = ed.Pen(ed.Colors.BlueViolet, 6)
    roundRect = ed.RectangleF(10, 140, 140, 40)
    roundedRectPath = ed.GraphicsPath.GetRoundRect(roundRect, 10)
    e.Graphics.DrawPath(roundedRectPen, roundedRectPath)

drawable.Paint += draw

dialog = ef.Dialog()
dialog.Padding = ed.Padding(24)
dialog.Content = drawable

dialog.ShowModal(parent)
Eto Button

Basic Drawable Mouse Events

using Eto.Forms;
using Eto.Drawing;
using Rhino.UI;

var parent = RhinoEtoApp.MainWindowForDocument(__rhino_doc__);

var drawable = new Drawable() {
  Width = 52,
  Height = 52
};

bool over;

drawable.Paint += (s, e) => {
  var rect = new RectangleF(1, 1, 50, 50);
  e.Graphics.FillEllipse(Color.FromArgb(255, 90, 89), rect);

  if (over)
  {
      var pen = new Pen(Color.FromArgb(170, 22, 1), 5f);
      e.Graphics.DrawLine(pen, 16, 16, 34, 34);
      e.Graphics.DrawLine(pen, 34, 16, 16, 34);
  }
};

drawable.MouseEnter += (s, e) => {
  over = true;
  drawable.Invalidate(true);
};

drawable.MouseLeave += (s, e) => {
  over = false;
  drawable.Invalidate(true);
};

var dialog = new Dialog()
{
  Padding = 24,
  Content = drawable
};

dialog.ShowModal(parent);
import scriptcontext as sc

import Rhino
from Rhino.UI import RhinoEtoApp, EtoExtensions
import Eto.Forms as ef
import Eto.Drawing as ed

parent = RhinoEtoApp.MainWindowForDocument(sc.doc)

drawable = ef.Drawable()
drawable.Width = 52
drawable.Height = 52
drawable.over = False

def mouse_enter(sender, e):
    drawable.over = True
    drawable.Invalidate(True)
    
def mouse_leave(sender, e):
    drawable.over = False
    drawable.Invalidate(True)
    
def draw(sender, e):
    rect = ed.RectangleF(1, 1, 50, 50)
    e.Graphics.FillEllipse(ed.Color.FromArgb(255, 90, 89), rect)

    if drawable.over:
        pen = ed.Pen(ed.Color.FromArgb(170, 22, 1), 5)
        e.Graphics.DrawLine(pen, 16, 16, 34, 34)
        e.Graphics.DrawLine(pen, 34, 16, 16, 34)

drawable.Paint += draw
drawable.MouseEnter += mouse_enter
drawable.MouseLeave += mouse_leave


dialog = ef.Dialog()
dialog.Content = drawable
dialog.Padding = ed.Padding(24)
dialog.ShowModal(parent)
Eto Button

Dragging in Drawables

using Eto.Forms;
using Eto.Drawing;
using Rhino.UI;

var parent = RhinoEtoApp.MainWindowForDocument(__rhino_doc__);

bool mouseDown = false;
PointF location = new (100, 100);

RectangleF GetRect()
{
  return RectangleF.FromCenter(new PointF(location.X, location.Y), new SizeF(30, 30));
}

var drawable = new Drawable() {
  Width = 200,
  Height = 200
};

bool over;

drawable.Paint += (s, e) => {
  var rect = GetRect();
  e.Graphics.FillEllipse(Colors.OrangeRed, rect);
  
  if (!mouseDown) return;
  e.Graphics.DrawEllipse(Colors.Goldenrod, rect);
};

drawable.MouseMove += (s, e) => {
  if (!mouseDown) return;
  location = e.Location;
  drawable.Invalidate(true);
};

drawable.MouseUp += (s, e) => {
  mouseDown = false;
  drawable.Invalidate(true);
};

drawable.MouseDown += (s, e) => {
  if (!GetRect().Contains(e.Location)) return;
  mouseDown = true;
  location = e.Location;
  drawable.Invalidate(true);
};

var dialog = new Dialog()
{
  Padding = 24,
  Content = drawable
};

dialog.ShowInTaskbar = true;
dialog.ShowModal();
import scriptcontext as sc

import Rhino
from Rhino.UI import RhinoEtoApp, EtoExtensions
import Eto.Forms as ef
import Eto.Drawing as ed

parent = RhinoEtoApp.MainWindowForDocument(sc.doc)

drawable = ef.Drawable()
drawable.Width = 200
drawable.Height = 200
drawable.down = False
drawable.mouse_location = ed.PointF(100, 100)

def get_rect():
    point = ed.PointF(drawable.mouse_location.X, drawable.mouse_location.Y)
    size = ed.SizeF(30, 30)
    rect = ed.RectangleF.FromCenter(point, size)
    return rect

def mouse_move(sender, e):
    if not drawable.down:
        return
        
    drawable.mouse_location = e.Location
    drawable.Invalidate(True)
    
def mouse_up(sender, e):
    drawable.down = False
    drawable.Invalidate(True)

def mouse_down(sender, e):
    if not get_rect().Contains(e.Location):
        return

    drawable.down = True
    drawable.mouse_location = e.Location
    drawable.Invalidate(True)
    
def draw(sender, e):
    rect = get_rect()
    e.Graphics.FillEllipse(ed.Colors.OrangeRed, rect)
    
    if not drawable.down:
        return

    e.Graphics.DrawEllipse(ed.Colors.Goldenrod, rect)

drawable.Paint += draw
drawable.MouseMove += mouse_move
drawable.MouseUp += mouse_up
drawable.MouseDown += mouse_down


dialog = ef.Dialog()
dialog.Padding = ed.Padding(24)
dialog.Content = drawable

dialog.ShowModal(parent)
Eto Button