This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch main
in repository ego.
View the commit online.
commit 88bab8695de35cebafb82b147e895ad2b7c4e909
Author: [email protected] <[email protected]>
AuthorDate: Tue Mar 31 15:40:35 2026 -0600
feat(ego-gen): map EFL (r,g,b,a) color tuples to color.RGBA
Detect 4-param r,g,b,a int patterns in multi-value properties
and collapse to image/color.RGBA. Getters return color.RGBA,
setters accept color.RGBA. Applied to regular and indexed
property templates with conditional import.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
cmd/ego-gen/generator.go | 5 +++
cmd/ego-gen/generator_test.go | 75 +++++++++++++++++++++++++++++++++++++
cmd/ego-gen/main.go | 28 ++++++++++++++
cmd/ego-gen/templates/class.go.tmpl | 51 +++++++++++++++++++++++--
4 files changed, 155 insertions(+), 4 deletions(-)
diff --git a/cmd/ego-gen/generator.go b/cmd/ego-gen/generator.go
index e1eb223..3ac986f 100644
--- a/cmd/ego-gen/generator.go
+++ b/cmd/ego-gen/generator.go
@@ -35,6 +35,7 @@ type ClassData struct {
IndexedProperties []IndexedPropertyData // indexed properties with key params
IteratorMethods []IteratorMethodData // methods returning Eina_Iterator
HasIterators bool // true if IteratorMethods is non-empty (controls import)
+ HasColor bool // true if any property uses color.RGBA (controls import)
IteratorStructTypes []IteratorMethodData // one entry per distinct struct elem type (for C helpers)
GlobalFunctions []GlobalFunctionData // package-level functions with no Eo receiver
CallbackTypes []CallbackTypeData // distinct callback typedefs used by this class
@@ -114,6 +115,9 @@ type PropertyData struct {
// IsMultiValue is true when the property has more than one value parameter.
// The getter returns multiple Go values and the setter takes multiple params.
IsMultiValue bool
+ // IsColor is true when the multi-value property is an (r, g, b, a int) color
+ // tuple that should be collapsed into a color.RGBA value.
+ IsColor bool
// MultiGetValues holds the getter out-params (may differ from MultiSetValues
// for get-only properties like cell_size).
MultiGetValues []MultiValueData
@@ -148,6 +152,7 @@ type IndexedPropertyData struct {
// Multi-value fields:
IsMultiValue bool
+ IsColor bool // true when multi-value is an (r,g,b,a) color tuple → color.RGBA
MultiGetValues []MultiValueData
MultiSetValues []MultiValueData
}
diff --git a/cmd/ego-gen/generator_test.go b/cmd/ego-gen/generator_test.go
index b35c97c..36e8b0a 100644
--- a/cmd/ego-gen/generator_test.go
+++ b/cmd/ego-gen/generator_test.go
@@ -1330,3 +1330,78 @@ func TestGenerateClass_EinaValueParam(t *testing.T) {
}
}
}
+
+func TestGenerateClass_ColorProperty(t *testing.T) {
+ g, outDir := newTestGenerator(t)
+
+ data := ClassData{
+ PackageName: "gfx",
+ GoName: "ColorMixin",
+ EolianName: "Efl.Gfx.Color",
+ CClassName: "EFL_GFX_COLOR_CLASS",
+ CClassGetFunc: "efl_gfx_color_class_get",
+ CPrefix: "efl_gfx_color",
+ EOHeaderFile: "efl_gfx_color.eo.h",
+ IsAbstract: true,
+ HasColor: true,
+ Properties: []PropertyData{
+ {
+ GoGetter: "Color",
+ GoSetter: "SetColor",
+ CGetName: "efl_gfx_color_get",
+ CSetName: "efl_gfx_color_set",
+ HasGet: true,
+ HasSet: true,
+ IsMultiValue: true,
+ IsColor: true,
+ MultiGetValues: []MultiValueData{
+ {GoName: "R", LowerGoName: "r", GoType: "int", CType: "int"},
+ {GoName: "G", LowerGoName: "g", GoType: "int", CType: "int"},
+ {GoName: "B", LowerGoName: "b", GoType: "int", CType: "int"},
+ {GoName: "A", LowerGoName: "a", GoType: "int", CType: "int"},
+ },
+ MultiSetValues: []MultiValueData{
+ {GoName: "R", LowerGoName: "r", GoType: "int", CType: "int"},
+ {GoName: "G", LowerGoName: "g", GoType: "int", CType: "int"},
+ {GoName: "B", LowerGoName: "b", GoType: "int", CType: "int"},
+ {GoName: "A", LowerGoName: "a", GoType: "int", CType: "int"},
+ },
+ },
+ },
+ }
+
+ if err := g.GenerateClass(data); err != nil {
+ t.Fatalf("GenerateClass: %v", err)
+ }
+
+ outFile := filepath.Join(outDir, "gfx", "color_mixin.go")
+ content, err := os.ReadFile(outFile)
+ if err != nil {
+ t.Fatalf("output file not found at %s: %v", outFile, err)
+ }
+
+ src := string(content)
+
+ mustContain := []string{
+ `"image/color"`,
+ "func (o *ColorMixin) Color() color.RGBA",
+ "uint8(cR)",
+ "func (o *ColorMixin) SetColor(c color.RGBA)",
+ "C.int(c.R)",
+ }
+
+ mustNotContain := []string{
+ "(r int, g int, b int, a int)",
+ }
+
+ for _, want := range mustContain {
+ if !strings.Contains(src, want) {
+ t.Errorf("output missing expected pattern %q\nfile content:\n%s", want, src)
+ }
+ }
+ for _, banned := range mustNotContain {
+ if strings.Contains(src, banned) {
+ t.Errorf("output contains banned pattern %q", banned)
+ }
+ }
+}
diff --git a/cmd/ego-gen/main.go b/cmd/ego-gen/main.go
index 69f6b3f..aeb7fa6 100644
--- a/cmd/ego-gen/main.go
+++ b/cmd/ego-gen/main.go
@@ -910,9 +910,21 @@ func buildClassData(c *Class, pkgOptionNames map[string]map[string]bool) (ClassD
GlobalFunctions: globalFunctions,
CallbackTypes: callbackTypes,
HasCallbacks: len(callbackTypes) > 0,
+ HasColor: hasColorProperty(properties),
}, nil
}
+// hasColorProperty reports whether any property in the slice has IsColor set,
+// used to decide whether to import "image/color" in the generated file.
+func hasColorProperty(props []PropertyData) bool {
+ for _, p := range props {
+ if p.IsColor {
+ return true
+ }
+ }
+ return false
+}
+
// deduplicateIteratorStructTypes returns one representative IteratorMethodData
// per distinct StructCType among methods with ElemIsStruct == true. This is
// used to generate one set of C field-accessor helpers per struct type, rather
@@ -933,6 +945,21 @@ func deduplicateIteratorStructTypes(methods []IteratorMethodData) []IteratorMeth
return result
}
+// isColorPattern reports whether a slice of MultiValueData represents an
+// EFL (r, g, b, a int) color tuple that should map to color.RGBA.
+func isColorPattern(vals []MultiValueData) bool {
+ if len(vals) != 4 {
+ return false
+ }
+ names := [4]string{"r", "g", "b", "a"}
+ for i, v := range vals {
+ if v.LowerGoName != names[i] || v.GoType != "int" {
+ return false
+ }
+ }
+ return true
+}
+
// isSimpleCgoType reports whether a C type can be used directly in a cgo call
// as a plain integer/float value. These are the types that can safely appear as
// multiple return values or multiple parameters without needing any C wrapper.
@@ -1042,6 +1069,7 @@ func buildPropertyData(f *Function, cPrefix string) (PropertyData, error) {
HasGet: hasGet && len(getMulti) > 0,
HasSet: hasSet && len(setMulti) > 0,
IsMultiValue: true,
+ IsColor: isColorPattern(getMulti) || isColorPattern(setMulti),
MultiGetValues: getMulti,
MultiSetValues: setMulti,
}, nil
diff --git a/cmd/ego-gen/templates/class.go.tmpl b/cmd/ego-gen/templates/class.go.tmpl
index 78ab935..0ca1d69 100644
--- a/cmd/ego-gen/templates/class.go.tmpl
+++ b/cmd/ego-gen/templates/class.go.tmpl
@@ -269,6 +269,9 @@ import (
{{- if .HasIterators}}
"iter"
{{- end}}
+{{- if .HasColor}}
+ "image/color"
+{{- end}}
"git.enlightenment.org/cedric/ego/efl"
{{- if and .ParentPkg (ne .ParentPkg .PackageName) (ne .ParentPkg "efl")}}
@@ -369,7 +372,16 @@ func {{$opt.GoOptionName}}(val {{$opt.StructGoType}}) efl.Option {
{{- range $prop := .Properties}}
{{- if $prop.HasGet}}
-{{- if $prop.IsMultiValue}}
+{{- if and $prop.IsMultiValue $prop.IsColor}}
+// {{$prop.GoGetter}} returns the {{$prop.GoGetter}} color of the {{$.GoName}}.
+func (o *{{$.GoName}}) {{$prop.GoGetter}}() color.RGBA {
+{{- range $v := $prop.MultiGetValues}}
+ var c{{$v.GoName}} C.int
+{{- end}}
+ C.{{$prop.CGetName}}((*C.Eo)(o.Eo()){{range $prop.MultiGetValues}}, &c{{.GoName}}{{end}})
+ return color.RGBA{R: uint8(cR), G: uint8(cG), B: uint8(cB), A: uint8(cA)}
+}
+{{- else if $prop.IsMultiValue}}
// {{$prop.GoGetter}} returns the {{$prop.GoGetter}} property of the {{$.GoName}}.
func (o *{{$.GoName}}) {{$prop.GoGetter}}() ({{range $i, $v := $prop.MultiGetValues}}{{if $i}}, {{end}}{{$v.LowerGoName}} {{if needsStringConversion $v.CType}}string{{else if $v.IsEo}}unsafe.Pointer{{else}}{{$v.GoType}}{{end}}{{end}}) {
{{- range $v := $prop.MultiGetValues}}
@@ -412,7 +424,12 @@ func (o *{{$.GoName}}) {{$prop.GoGetter}}() {{$prop.GoType}} {
{{- end}}
{{- if $prop.HasSet}}
-{{- if $prop.IsMultiValue}}
+{{- if and $prop.IsMultiValue $prop.IsColor}}
+// {{$prop.GoSetter}} sets the {{$prop.GoGetter}} color of the {{$.GoName}}.
+func (o *{{$.GoName}}) {{$prop.GoSetter}}(c color.RGBA) {
+ C.{{$prop.CSetName}}((*C.Eo)(o.Eo()), C.int(c.R), C.int(c.G), C.int(c.B), C.int(c.A))
+}
+{{- else if $prop.IsMultiValue}}
// {{$prop.GoSetter}} sets the {{$prop.GoGetter}} property of the {{$.GoName}}.
func (o *{{$.GoName}}) {{$prop.GoSetter}}({{range $i, $v := $prop.MultiSetValues}}{{if $i}}, {{end}}{{$v.LowerGoName}} {{if needsStringConversion $v.CType}}string{{else if $v.IsEo}}efl.Objecter{{else}}{{$v.GoType}}{{end}}{{end}}) {
{{- range $v := $prop.MultiSetValues}}
@@ -603,7 +620,22 @@ func (o *{{$.GoName}}) {{$ip.GoAccessorMethod}}({{range $i, $k := $ip.Keys}}{{if
}
{{- if $ip.HasGet}}
-{{- if $ip.IsMultiValue}}
+{{- if and $ip.IsMultiValue $ip.IsColor}}
+// Get returns the color for the captured key(s).
+func (p {{$ip.AccessorTypeName}}) Get() color.RGBA {
+{{- range $ip.Keys}}
+{{- if needsStringConversion .CType}}
+ c{{.GoName}} := C.CString(p.{{.GoName}})
+ defer C.free(unsafe.Pointer(c{{.GoName}}))
+{{- end}}
+{{- end}}
+{{- range $v := $ip.MultiGetValues}}
+ var c{{$v.GoName}} C.int
+{{- end}}
+ C.{{$ip.CGetName}}(p.obj{{range $ip.Keys}}, {{template "indexedKeyArg" .}}{{end}}{{range $ip.MultiGetValues}}, &c{{.GoName}}{{end}})
+ return color.RGBA{R: uint8(cR), G: uint8(cG), B: uint8(cB), A: uint8(cA)}
+}
+{{- else if $ip.IsMultiValue}}
// Get returns the values for the captured key(s).
func (p {{$ip.AccessorTypeName}}) Get() ({{range $i, $v := $ip.MultiGetValues}}{{if $i}}, {{end}}{{$v.LowerGoName}} {{if needsStringConversion $v.CType}}string{{else if $v.IsEo}}unsafe.Pointer{{else}}{{$v.GoType}}{{end}}{{end}}) {
{{- range $ip.Keys}}
@@ -660,7 +692,18 @@ func (p {{$ip.AccessorTypeName}}) Get() {{if $ip.IsStruct}}{{$ip.StructGoType}}{
{{- end}}
{{- if $ip.HasSet}}
-{{- if $ip.IsMultiValue}}
+{{- if and $ip.IsMultiValue $ip.IsColor}}
+// Set sets the color for the captured key(s).
+func (p {{$ip.AccessorTypeName}}) Set(c color.RGBA) {
+{{- range $ip.Keys}}
+{{- if needsStringConversion .CType}}
+ c{{.GoName}} := C.CString(p.{{.GoName}})
+ defer C.free(unsafe.Pointer(c{{.GoName}}))
+{{- end}}
+{{- end}}
+ C.{{$ip.CSetName}}(p.obj{{range $ip.Keys}}, {{template "indexedKeyArg" .}}{{end}}, C.int(c.R), C.int(c.G), C.int(c.B), C.int(c.A))
+}
+{{- else if $ip.IsMultiValue}}
// Set sets the values for the captured key(s).
func (p {{$ip.AccessorTypeName}}) Set({{range $i, $v := $ip.MultiSetValues}}{{if $i}}, {{end}}{{$v.LowerGoName}} {{if needsStringConversion $v.CType}}string{{else if $v.IsEo}}efl.Objecter{{else}}{{$v.GoType}}{{end}}{{end}}) {
{{- range $ip.Keys}}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.