Apply TEAM_STANDARDS Norma #25: project names use lowercase everywhere - repo, directory, module, documentation, imports. No CamelCase in project names. Consistency = less cognitive friction. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
431 lines
12 KiB
Markdown
431 lines
12 KiB
Markdown
# Análisis Técnico: Gio UI (Go)
|
|
|
|
> Investigación realizada: 2025-12-09
|
|
> Propósito: Entender arquitectura de Gio como referencia para zcatgui
|
|
|
|
---
|
|
|
|
## Resumen Ejecutivo
|
|
|
|
**Gio UI** (gioui.org) es una librería de GUI immediate mode para Go que permite crear interfaces gráficas cross-platform nativas. Es comparable a Flutter en diseño pero implementado completamente en Go, sin dependencias externas más allá de las librerías de sistema para ventanas y GPU.
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| **Repositorio** | https://git.sr.ht/~eliasnaur/gio |
|
|
| **Versión** | v0.9.0 (pre-1.0, API inestable) |
|
|
| **Licencia** | MIT / Unlicense |
|
|
| **Plataformas** | Android, iOS, macOS, Linux, Windows, FreeBSD, OpenBSD, WebAssembly |
|
|
|
|
---
|
|
|
|
## 1. Arquitectura General
|
|
|
|
### 1.1 Estructura de Capas
|
|
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ Material Design (widget/material) │ <- Widgets estilizados
|
|
├─────────────────────────────────────────┤
|
|
│ Widget State (widget) │ <- Estado de controles
|
|
├─────────────────────────────────────────┤
|
|
│ Layout System (layout) │ <- Sistema de layouts
|
|
├─────────────────────────────────────────┤
|
|
│ Operations (op, op/clip, op/paint) │ <- Comandos de dibujo
|
|
├─────────────────────────────────────────┤
|
|
│ Window Management (app) │ <- Manejo de ventanas
|
|
├─────────────────────────────────────────┤
|
|
│ GPU Rendering (gpu) │ <- Backends gráficos
|
|
├─────────────────────────────────────────┤
|
|
│ Platform Backend │ <- Win/macOS/Linux/etc.
|
|
└─────────────────────────────────────────┘
|
|
```
|
|
|
|
### 1.2 Módulos Principales
|
|
|
|
| Paquete | Propósito |
|
|
|---------|-----------|
|
|
| `gioui.org/app` | Window management, eventos del OS |
|
|
| `gioui.org/op` | Sistema de operaciones (comandos de dibujo) |
|
|
| `gioui.org/layout` | Layouts (Flex, Stack, List, Inset) |
|
|
| `gioui.org/widget` | Widgets con estado (Clickable, Editor, List, etc.) |
|
|
| `gioui.org/widget/material` | Material Design theme |
|
|
| `gioui.org/gpu` | Rendering GPU (OpenGL, Direct3D, Vulkan) |
|
|
| `gioui.org/io` | Input/output (pointer, keyboard, clipboard) |
|
|
| `gioui.org/text` | Text shaping, layout, glyphs |
|
|
| `gioui.org/font` | Font handling, OpenType |
|
|
| `gioui.org/gesture` | Gestures de alto nivel (Click, Drag, Scroll, Hover) |
|
|
| `gioui.org/x/component` | Componentes extendidos Material |
|
|
|
|
---
|
|
|
|
## 2. Sistema de Rendering
|
|
|
|
### 2.1 GPU Backends
|
|
|
|
Gio soporta múltiples backends GPU según la plataforma:
|
|
|
|
- **OpenGL ES** - Multiplataforma (Linux, Android, iOS, WebAssembly)
|
|
- **Direct3D 11** - Windows
|
|
- **Vulkan** - Linux, Android (opcional)
|
|
|
|
### 2.2 Vector Rendering Pipeline
|
|
|
|
Gio usa un **vector renderer basado en Pathfinder** (proyecto de Mozilla):
|
|
|
|
1. **Renderizado de outlines**: Las formas y texto se renderizan desde sus contornos vectoriales
|
|
2. **Sin pre-procesamiento CPU**: Los paths SVG se renderizan en GPU con mínimo trabajo en CPU
|
|
3. **Migración a piet-gpu**: Renderer basado en compute shaders para mayor eficiencia
|
|
|
|
### 2.3 CPU Fallback
|
|
|
|
**Importante para zcatgui**: Gio incluye un fallback CPU (`gioui.org/cpu`) con binarios pre-compilados de piet-gpu para arm, arm64, amd64, permitiendo renderizado software cuando no hay GPU disponible.
|
|
|
|
---
|
|
|
|
## 3. Sistema de Layout
|
|
|
|
### 3.1 Conceptos Fundamentales
|
|
|
|
```go
|
|
// Constraints = lo que el padre dice al hijo (límites de tamaño)
|
|
type Constraints struct {
|
|
Min, Max image.Point
|
|
}
|
|
|
|
// Dimensions = lo que el hijo devuelve al padre (tamaño usado)
|
|
type Dimensions struct {
|
|
Size image.Point
|
|
Baseline int
|
|
}
|
|
|
|
// Context = bundle de estado pasado a todos los widgets
|
|
type Context struct {
|
|
Constraints Constraints
|
|
Metric unit.Metric
|
|
Now time.Time
|
|
// ...
|
|
}
|
|
|
|
// Widget = función que calcula dimensions desde constraints
|
|
type Widget func(gtx layout.Context) layout.Dimensions
|
|
```
|
|
|
|
### 3.2 Layouts Principales
|
|
|
|
#### Flex - Distribución lineal con pesos
|
|
|
|
```go
|
|
layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
|
layout.Rigid(func(gtx C) D { return header.Layout(gtx) }),
|
|
layout.Flexed(1, func(gtx C) D { return content.Layout(gtx) }),
|
|
layout.Rigid(func(gtx C) D { return footer.Layout(gtx) }),
|
|
)
|
|
```
|
|
|
|
**Spacing modes:**
|
|
- `SpaceEnd` - Espacio al final
|
|
- `SpaceStart` - Espacio al inicio
|
|
- `SpaceSides` - Espacio en ambos lados
|
|
- `SpaceAround` - Espacio alrededor de children
|
|
- `SpaceBetween` - Espacio entre children
|
|
- `SpaceEvenly` - Distribución uniforme
|
|
|
|
#### Stack - Elementos apilados
|
|
|
|
```go
|
|
layout.Stack{}.Layout(gtx,
|
|
layout.Expanded(func(gtx C) D { return image.Layout(gtx) }),
|
|
layout.Stacked(func(gtx C) D { return button.Layout(gtx) }),
|
|
)
|
|
```
|
|
|
|
#### List - Lista scrollable virtualizada
|
|
|
|
```go
|
|
// Solo renderiza los elementos visibles
|
|
list.Layout(gtx, 1_000_000, func(gtx C, i int) D {
|
|
return material.Label(theme, unit.Sp(16), fmt.Sprintf("Item %d", i)).Layout(gtx)
|
|
})
|
|
```
|
|
|
|
#### Inset - Padding
|
|
|
|
```go
|
|
layout.UniformInset(10).Layout(gtx, func(gtx C) D {
|
|
return widget.Layout(gtx)
|
|
})
|
|
```
|
|
|
|
### 3.3 Sistema de Unidades
|
|
|
|
```go
|
|
type Px // Physical pixels (dependiente de dispositivo)
|
|
type Dp // Device-independent pixels (escala por densidad)
|
|
type Sp // Scaled points (incluye scaling de fuente del sistema)
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Sistema de Eventos
|
|
|
|
### 4.1 Tipos de Eventos
|
|
|
|
```go
|
|
type pointer.Event // Mouse/touch (Press, Release, Move, Drag, Scroll)
|
|
type key.Event // Keyboard
|
|
type key.EditEvent // Edición de texto
|
|
type key.FocusEvent // Cambio de foco
|
|
```
|
|
|
|
### 4.2 Distribución de Eventos (Tag-based)
|
|
|
|
Gio usa un sistema **sin callbacks** basado en **tags**:
|
|
|
|
```go
|
|
// Declarar área clickable
|
|
pointer.InputOp{
|
|
Tag: &button, // Tag único
|
|
Types: pointer.Press | pointer.Release,
|
|
}.Add(ops)
|
|
|
|
// Consultar eventos
|
|
for {
|
|
ev, ok := gtx.Event(pointer.Filter{Target: &button, ...})
|
|
if !ok { break }
|
|
// Procesar evento
|
|
}
|
|
```
|
|
|
|
**Ventaja**: Elimina el overhead de callbacks y simplifica el manejo de estado.
|
|
|
|
### 4.3 Gestures de Alto Nivel
|
|
|
|
```go
|
|
type Click // Detecta clicks
|
|
type Drag // Detecta drags
|
|
type Hover // Detecta hover
|
|
type Scroll // Detecta scroll
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Widgets Incluidos
|
|
|
|
### 5.1 Widget Pattern (Separación de Concerns)
|
|
|
|
Gio separa **estado** (stateful) y **presentación** (stateless):
|
|
|
|
```
|
|
widget.Clickable (state) → material.Button (presentation)
|
|
widget.Editor (state) → material.Editor (presentation)
|
|
widget.Bool (state) → material.CheckBox (presentation)
|
|
```
|
|
|
|
### 5.2 Widget State (`gioui.org/widget`)
|
|
|
|
| Widget | Propósito |
|
|
|--------|-----------|
|
|
| `Clickable` | Área clickable (botones, cards, etc.) |
|
|
| `Editor` | Editor de texto de una línea |
|
|
| `Selectable` | Texto seleccionable (no editable) |
|
|
| `Float` | Valor float para sliders |
|
|
| `Bool` | Valor booleano (checkboxes, switches) |
|
|
| `Enum` | Valor enum (radio buttons) |
|
|
| `List` | Estado de lista scrollable |
|
|
| `Scrollbar` | Estado de scrollbar |
|
|
| `Draggable` | Soporte drag & drop |
|
|
| `Decorations` | Decoraciones de ventana |
|
|
| `Icon` | Ícono vectorial |
|
|
|
|
### 5.3 Material Widgets (`gioui.org/widget/material`)
|
|
|
|
**Texto:** Label, H1-H6, Body1, Body2, Caption, Subtitle1, Subtitle2, Overline
|
|
**Botones:** Button, IconButton, ButtonLayout
|
|
**Input:** Editor, CheckBox, RadioButton, Switch, Slider
|
|
**Contenedores:** List, Scrollbar
|
|
**Indicadores:** ProgressBar, ProgressCircle, Loader (spinner)
|
|
**Ventanas:** Decorations
|
|
|
|
### 5.4 Extended Components (`gioui.org/x/component`)
|
|
|
|
- AppBar, NavDrawer, Menu, MenuItem, ContextArea
|
|
- Grid, Table, Sheet, Surface
|
|
- TextField (con label animada), Tooltip
|
|
- Discloser (expandible), Divider
|
|
- ModalLayer, Scrim
|
|
|
|
---
|
|
|
|
## 6. Theming y Styling
|
|
|
|
### 6.1 Sistema de Theme
|
|
|
|
```go
|
|
type Theme struct {
|
|
Shaper *text.Shaper
|
|
Palette Palette
|
|
TextSize unit.Sp
|
|
Face text.Face
|
|
FingerSize unit.Dp // Tamaño mínimo área touch (48dp)
|
|
}
|
|
|
|
type Palette struct {
|
|
Bg color.NRGBA
|
|
Fg color.NRGBA
|
|
ContrastBg color.NRGBA
|
|
ContrastFg color.NRGBA
|
|
}
|
|
```
|
|
|
|
### 6.2 Niveles de Customización
|
|
|
|
**Global (Theme-wide):**
|
|
```go
|
|
theme := material.NewTheme()
|
|
theme.Palette.Fg = color.NRGBA{R: 255, G: 255, B: 255, A: 255}
|
|
```
|
|
|
|
**Widget-local:**
|
|
```go
|
|
btn := material.Button(theme, button, "Click me!")
|
|
btn.Background = color.NRGBA{R: 0, G: 150, B: 0, A: 255}
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Window Management
|
|
|
|
### 7.1 Creación de Ventana
|
|
|
|
```go
|
|
func main() {
|
|
go func() {
|
|
window := new(app.Window)
|
|
window.Option(app.Title("My App"))
|
|
window.Option(app.Size(unit.Dp(800), unit.Dp(600)))
|
|
if err := run(window); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
os.Exit(0)
|
|
}()
|
|
app.Main() // BLOQUEANTE en algunas plataformas
|
|
}
|
|
```
|
|
|
|
### 7.2 Event Loop
|
|
|
|
```go
|
|
func run(window *app.Window) error {
|
|
var ops op.Ops
|
|
for {
|
|
switch e := window.Event().(type) {
|
|
case app.DestroyEvent:
|
|
return e.Err
|
|
case app.FrameEvent:
|
|
ops.Reset()
|
|
gtx := app.NewContext(&ops, e)
|
|
drawUI(gtx)
|
|
e.Frame(gtx.Ops)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Paradigma Immediate Mode
|
|
|
|
### 8.1 Filosofía
|
|
|
|
```
|
|
while running:
|
|
eventos ← poll_events()
|
|
actualizar_estado(eventos)
|
|
|
|
ops.Reset()
|
|
dibujar_ui_completa(ops, estado) ← UI es función pura del estado
|
|
enviar_a_gpu(ops)
|
|
```
|
|
|
|
### 8.2 Ventajas Específicas de Gio
|
|
|
|
**Sin callbacks:**
|
|
```go
|
|
// NO HAY ESTO:
|
|
button.onClick(func() { ... })
|
|
|
|
// EN SU LUGAR:
|
|
for button.Clicked(gtx) {
|
|
count++
|
|
}
|
|
```
|
|
|
|
**Estado mínimo:**
|
|
```go
|
|
// El estado es tuyo, no del framework
|
|
type State struct {
|
|
count int
|
|
name string
|
|
}
|
|
|
|
// Widgets solo contienen estado UI mínimo
|
|
var button widget.Clickable
|
|
```
|
|
|
|
**UI como función pura:**
|
|
```go
|
|
func drawUI(gtx layout.Context, state *State) {
|
|
label := material.H1(theme, fmt.Sprintf("Count: %d", state.count))
|
|
label.Layout(gtx)
|
|
}
|
|
```
|
|
|
|
### 8.3 Zero-Allocation Design
|
|
|
|
```go
|
|
// Método tipado, sin interfaz → sin allocación
|
|
operation.Add(ops)
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Lecciones para zcatgui
|
|
|
|
### 9.1 Qué Adoptar
|
|
|
|
1. **Separación estado/presentación**: Widget state vs widget render
|
|
2. **Sistema de constraints**: Constraints/Dimensions muy robusto
|
|
3. **Event tags**: Sin callbacks, consulta de eventos
|
|
4. **Zero-allocation**: Operaciones tipadas
|
|
5. **Spacing modes**: Flex con SpaceBetween, SpaceAround, etc.
|
|
|
|
### 9.2 Qué Adaptar
|
|
|
|
1. **Rendering**: Gio usa GPU, nosotros software renderer
|
|
2. **Operaciones**: Gio usa op.Ops (GPU), nosotros DrawCommand (CPU)
|
|
3. **Complejidad**: Gio es ~40K LOC, nosotros apuntamos a ~5-10K
|
|
|
|
### 9.3 Diferencias Clave
|
|
|
|
| Aspecto | Gio | zcatgui |
|
|
|---------|-----|---------|
|
|
| Lenguaje | Go | Zig |
|
|
| Rendering | GPU (Pathfinder) | Software (framebuffer) |
|
|
| Complejidad | Alta (~40K LOC) | Baja (target ~5K) |
|
|
| Macros | No tiene | Piedra angular |
|
|
| Fonts | HarfBuzz | Bitmap + stb_truetype |
|
|
|
|
---
|
|
|
|
## 10. Referencias
|
|
|
|
- [Gio UI Website](https://gioui.org/)
|
|
- [Architecture](https://gioui.org/doc/architecture)
|
|
- [Layout](https://gioui.org/doc/architecture/layout)
|
|
- [Widget](https://gioui.org/doc/architecture/widget)
|
|
- [Input](https://gioui.org/doc/architecture/input)
|
|
- [API Reference](https://pkg.go.dev/gioui.org)
|
|
- [Examples](https://github.com/gioui/gio-example)
|
|
- [Extended Components](https://github.com/gioui/gio-x)
|
|
- [GUI with Gio Tutorial](https://jonegil.github.io/gui-with-gio/)
|
|
- [Immediate Mode GUI Programming](https://eliasnaur.com/blog/immediate-mode-gui-programming)
|