Eto forms, Cell color from Layer color?

I do have this basic script and I do want if possible to get the cells from the Material column to have the same color as the color of the layer on which each object is on. It is possible to achieve this? This script needs to work on both Rhino v7 for MacOS and Windows.

#!/usr/bin/env ironpython2.7
# -*- coding: utf8 -*-
# SimpleCutlist.py

import Rhino
import Rhino.Geometry as g
import rhinoscriptsyntax as rs
import Eto.Drawing as drawing
import Eto.Forms as forms
import scriptcontext

# List of layers to exclude
EXCLUDED_LAYERS = ["Booleans", "Dim", "Default", "Walls"]

# Attributes for the cutlist
class attr:
    def __init__(self, name, isEditable, valType):
        self.name = name
        self.isEditable = isEditable
        self.valType = valType

ATTRS = (
    attr("_N", True, str),        # N (number)
    attr("_Name", True, str),     # Name
    attr("Length", True, float),  # Length
    attr("Width", True, float),   # Width
    attr("Thickness", True, float), # Thickness
    attr("Material", True, str),  # Material
)

def computeDims(obj):
    objRef = Rhino.DocObjects.ObjRef(obj)
    brep = objRef.Geometry()
    edges = list(brep.Edges)
    edges.sort(key=lambda edge: edge.GetLength(), reverse=True)
    edge = edges[0]
    origin = edge.PointAtStart
    xPoint = edge.PointAtEnd
    xVec = Rhino.Geometry.Vector3d(xPoint - origin)
    xVec.Unitize()
    face = brep.Faces[0]
    yVec = Rhino.Geometry.Vector3d.CrossProduct(face.NormalAt(0, 0), xVec)
    yVec.Unitize()
    plane = Rhino.Geometry.Plane(origin, xVec, yVec)
    verts = list(brep.Vertices)
    tMatrix = g.Transform.ChangeBasis(g.Plane.WorldXY, plane)
    map(lambda vert: vert.Transform(tMatrix), verts)
    verts = list(map(lambda vert: vert.Location, verts))
    verts.sort(key=lambda vert: vert.X)
    length = verts[-1].X - verts[0].X
    verts.sort(key=lambda vert: vert.Y)
    width = verts[-1].Y - verts[0].Y
    verts.sort(key=lambda vert: vert.Z)
    thickness = verts[-1].Z - verts[0].Z
    return [length, width, thickness]

class Detail:
    def __init__(self, obj):
        self.obj = obj
        self.id = obj
        for attr_obj in ATTRS:
            key = attr_obj.name
            val = rs.GetUserText(str(obj), key)
            if val is None:
                default = "0" if attr_obj.valType in [float, str] and key != "Material" else ""
                setattr(self, key, default)
                rs.SetUserText(str(obj), key, default)
            else:
                setattr(self, key, val)
        self.setDims()
        self.update_material_from_layer()

    def setDims(self):
        dims = computeDims(self.obj)
        self.Length = str(round(dims[0], 2))
        self.Width = str(round(dims[1], 2))
        self.Thickness = str(round(dims[2], 2))
        rs.SetUserText(str(self.id), "Length", self.Length)
        rs.SetUserText(str(self.id), "Width", self.Width)
        rs.SetUserText(str(self.id), "Thickness", self.Thickness)

    def update_material_from_layer(self):
        objRef = Rhino.DocObjects.ObjRef(self.id)
        index = objRef.Object().Attributes.LayerIndex
        layer = scriptcontext.doc.Layers[index]
        self.Material = layer.Name
        self.layer_color = drawing.Color.FromArgb(layer.Color.ToArgb())
        rs.SetUserText(str(self.id), "Material", self.Material)

    def getParams(self):
        return [getattr(self, attr.name) for attr in ATTRS]

    def refresh(self):
        for attr in ATTRS:
            rs.SetUserText(str(self.id), attr.name, getattr(self, attr.name))

class Specification:
    def __init__(self, details):
        self.details = []
        idSet = set(range(len(details)))
        self.table = []
        while idSet:
            curId = idSet.pop()
            curDet = details[curId]
            curDetails = [curDet]
            for id in list(idSet):
                if curDet.getParams() == details[id].getParams():
                    curDetails.append(details[id])
                    idSet.remove(id)
            self.details.append(curDetails)
            self.table.append(curDet.getParams())

class SimpleCutlistDialog(forms.Dialog[bool]):
    def __init__(self):
        self.Title = "Simple Cutlist"
        self.Padding = drawing.Padding(2)
        self.Resizable = True
        self.m_gridview = forms.GridView()
        self.m_gridview.ShowHeader = True

        for i, attr in enumerate(ATTRS):
            column = forms.GridColumn()
            column.HeaderText = attr.name if attr.name[0] != "_" else attr.name[1:]
            column.Editable = attr.isEditable
            column.DataCell = forms.TextBoxCell(i)
            self.m_gridview.Columns.Add(column)

        self.button = forms.Button(Text="Export CSV")
        self.button.Width = 80  # Set a smaller, specific width
        self.button.Click += self.buttonClick

        layout = forms.DynamicLayout()
        layout.AddRow(self.m_gridview)
        layout.AddRow(self.button)
        self.Content = layout
        self.ClientSize = drawing.Size(600, 130)

    def buttonClick(self, sender, e):
        data = [[col.HeaderText for col in self.m_gridview.Columns]]
        data.extend(self.spec.table)
        filename = rs.SaveFileName("Save cutlist as", "CSV File (*.csv)|*.csv||")
        if filename:
            with open(filename, 'w') as f:
                for row in data:
                    f.write("|".join(str(item) for item in row) + "\n")

    def setData(self, spec):
        self.spec = spec
        self.m_gridview.DataStore = spec.table

def main():
    objs = rs.GetObjects("Select polysurface objects", 16, preselect=True)
    if not objs:
        return

    filtered_objs = [obj for obj in objs if rs.ObjectLayer(obj) not in EXCLUDED_LAYERS]
    if not filtered_objs:
        rs.MessageBox("No valid objects found.")
        return

    details = [Detail(obj) for obj in filtered_objs]
    spec = Specification(details)
    dialog = SimpleCutlistDialog()
    dialog.setData(spec)
    Rhino.UI.EtoExtensions.ShowSemiModal(dialog, Rhino.RhinoDoc.ActiveDoc, Rhino.UI.RhinoEtoApp.MainWindow)

if __name__ == "__main__":
    main()

Simple_Cutlist.py (5.9 KB)


CL_Material_Color.3dm (447.6 KB)

1 Like