I made progress thanks to the code you shared @clement. I now have a gradient brush fill working (I was trying to test other drawable options). And managed to create a Pixel Layout so that I can “layer” some of these drawables on top of themselves visually.
I have two questions:
-
Is there a way to layer drawables on top of eachother visually without a PixelLayout? It seems that I can only add rows, cells, or stacking with the other layout types? I tried wrapping in a panel and adding the drawable graphics on a panel but that wasn’t working for me.
-
While the Custom Toggle Switch graphics show up in general, the Green/Red circles do not. My guess is they are there “somewhere” but perhaps way off screen? To me, self.Bounds.TopLeft seems like it could work to position these circles properly (at least on the general UI overall) so I would love an insight if you see why this is not the case.
-
When I switched to PixelLayout, it seems to have scaled the “background graphics” to about half size of what they were intended to be. I tried to scale it by 2 to test if it was just a general size issue but then it gets cropped oddly. You can see in the snip below it should be filling the whole “translucent panel” less the padding width as it properly does on the left and top but the right side extents are off and not filling to the edge. I can’t seem to figure out why but I’ll keep looking. I also noticed in the SampleSwitch code you shared, if you set the Dialog to resizable and scale the window, the circles get stretched yet the pill stays persistently sized. Perhaps this is the same thing happening to the Form or circle drawable I’m trying to create in my modification?


Here’s the code I’m working off of thus far:
#! python 2
import Eto
import Rhino
# Code For The Custom Toggle Switch
class SwitchControl(Eto.Forms.Drawable):
def __init__(self, state):
# Custom Control Style Variables
self.radius = 30
self.highlight_color = Eto.Drawing.Colors.LightGoldenrodYellow
self.border_color = Eto.Drawing.Color(180,180,180)
self.background_color = Eto.Drawing.Colors.Transparent
self.enabled_color = Eto.Drawing.Color(255,40,5)
self.disabled_color = Eto.Drawing.Color(152,237,90)
self.Size = Eto.Drawing.Size(60,self.radius)
self._hover = False
self._state = state
self._rect = Eto.Drawing.RectangleF.Inflate(self.Bounds, -5, -5)
self.g_brush = Eto.Drawing.LinearGradientBrush(self._rect, self.highlight_color, self.background_color,0)
self._path = Eto.Drawing.GraphicsPath.GetRoundRect(self._rect, 10)
self._pen1 = Eto.Drawing.Pen(self.highlight_color, 3)
self._pen2 = Eto.Drawing.Pen(self.border_color, 2)
def OnPaint(self, e):
try:
# draws the switch background pill shape
e.Graphics.FillPath(Eto.Drawing.Colors.Transparent, self._path)
e.Graphics.DrawPath(self._pen2, self._path)
if self._state == True:
# draws the green circle
r = Eto.Drawing.RectangleF(self.Bounds.TopLeft, self.Bounds.MiddleBottom)
r.Inflate(-10,-10)
e.Graphics.FillEllipse(self.enabled_color, r)
elif self._state == False:
# draws the red circle
r = Eto.Drawing.Rectangle(self.Bounds.MiddleTop, self.Bounds.BottomRight)
r.Inflate(-10,-10)
e.Graphics.FillEllipse(self.disabled_color, r)
if self._hover:
# draws the pill shape outline on hover
e.Graphics.DrawPath(self._pen1, self._path)
# draws the switch background pill shape with gradient fill
e.Graphics.FillPath(self.g_brush, self._path)
except Exception as ex:
print ex
def OnMouseEnter(self, e):
self._hover = True
self.Invalidate()
def OnMouseLeave(self, e):
self._hover = False
self.Invalidate()
def OnMouseDown(self, e):
# Rhino.RhinoApp.WriteLine("Clicked")
pass
def OnMouseUp(self, e):
if e.Buttons == Eto.Forms.MouseButtons.Primary and self._hover == True:
self._state = not self._state
self.Invalidate()
def OnPreLoad(self, e):
pass
# Code For The Main Toolbar UI
class MainToolbar(Eto.Forms.Form):
def __init__(self):
# Set Form General Settings
self.Title = "Main Toolbar"
self.Size = Eto.Drawing.Size(500, 120) # Set The Overall Form Size
self.WindowStyle = Eto.Forms.WindowStyle.None
self.Resizable = False
padding = 30 # Set Form Padding
self.Padding = Eto.Drawing.Padding(padding)
self.MovableByWindowBackground = True
# Custom Control Style Variables
self.radius_1 = 30
# Add Transparent Style To The Form Background Panel
self.Styles.Add[Eto.Forms.Panel]("transparent", self.MyFormStyler)
self.Style = "transparent"
# Custom Controls
self.switch = SwitchControl(True) # Pass True Argument For Switch To Start In Activated State
# Set UI Location
def SetLocation():
# Get Rhino Window Dimensions (Pixels)
s = Rhino.UI.RhinoEtoApp.MainWindow.Screen
w = s.WorkingArea.Width
h = s.WorkingArea.Height
# self.Location = vp_bottom_center
self.Location = Eto.Drawing.Point((w / 2 - (self.Width / 2)), (h - self.Height + padding)) # Locate Form At Bottom Center Of Screen (WIP)
SetLocation()
# Set Custom Dark Mode Colors
def SetDarkModeCustomColors():
self.dark_mode = Rhino.Runtime.HostUtils.RunningInDarkMode # Get Current Rhino Theme For Custom Dark Mode UI Functions
if self.dark_mode:
self.background_color = Eto.Drawing.Color(220,220,220)
self.midground_color = Eto.Drawing.Color(200,200,200)
self.foreground_color = Eto.Drawing.Color(180,180,180)
else:
self.background_color = Eto.Drawing.Color(40,40,40)
self.midground_color = Eto.Drawing.Color(10,10,10)
self.foreground_color = Eto.Drawing.Color(0,0,0)
SetDarkModeCustomColors()
# Setup bitmap to have background graphics drawn on
pixelformat = Eto.Drawing.PixelFormat.Format32bppRgba
bitmap = Eto.Drawing.Bitmap(self.Size, pixelformat)
self.graphics = Eto.Drawing.Graphics(bitmap)
self.DrawBackgroundGraphics() # Call The Function That Creates The Graphics
self.bg_graphics = Eto.Forms.ImageView()
self.bg_graphics.Image = bitmap
# Update / Populate Layout
def UpdateLayout():
# Add Items To Layout
self.layout = Eto.Forms.PixelLayout()
self.layout.Add(self.bg_graphics, 0,0) # Add Background Graphics
self.layout.Add(self.switch, 180,0)
self.Content = self.layout
UpdateLayout()
# Handle Overall Background Transparency
def MyFormStyler(self, control):
self.BackgroundColor = Eto.Drawing.Colors.Transparent
window = control.ControlObject
if hasattr(window, "AllowsTransparency"):
window.AllowsTransparency = True
if hasattr(window, "Background"):
brush = window.Background.Clone()
brush.Opacity = 0.1
window.Background = brush
else:
color = window.BackgroundColor
window.BackgroundColor = color.FromRgba(0,0,0,0)
# Create The Background Graphics
def DrawBackgroundGraphics(self):
# Create Background Graphics
brush_1 = Eto.Drawing.SolidBrush(self.background_color)
rect_1 = Eto.Drawing.Rectangle(0,0, self.Width, self.Height)
path_1 = Eto.Drawing.GraphicsPath.GetRoundRect(rect_1, self.radius_1,self.radius_1,5,5)
self.graphics.FillPath(brush_1, path_1)
button_padding = 10
button_height = 40
radius_inner = self.radius_1 - button_padding
brush_2 = Eto.Drawing.SolidBrush(self.midground_color)
rect_2 = Eto.Drawing.Rectangle(button_padding,button_padding, self.Width - (button_padding * 2), button_height)
path_2 = Eto.Drawing.GraphicsPath.GetRoundRect(rect_2, radius_inner,radius_inner,radius_inner,radius_inner)
self.graphics.FillPath(brush_2, path_2)
self.graphics.Dispose()
def OnDarkModeButtonClick(self, sender, e):
self.dark_mode = sender.Checked
if sender.Checked:
# Rhino.RhinoApp.WriteLine("Dark Mode On")
Rhino.ApplicationSettings.AppearanceSettings.SetToDarkMode()
else:
# Rhino.RhinoApp.WriteLine("Dark Mode Off")
Rhino.ApplicationSettings.AppearanceSettings.SetToLightMode()
def EstablishForm():
form = MainToolbar()
form.Owner = Rhino.UI.RhinoEtoApp.MainWindow
form.Show()
if __name__=="__main__":
EstablishForm()
Thank you for any tips!