feat(ui): add Paintable interface and SetFromPaintable to layout widgets
Add Paintable interface abstraction over gdk.Paintable/gdk.Texture in layout package. Implement SetFromPaintable method on ImageWidget for displaying gdk.Texture objects. Add UpdateFaviconTexture method to StackedView for tab favicon display with texture fallback support.
- commit
- 65aa3b0dc4d4884ef69d329c49d76b1ee1d89da8
- author
- brice · · 2025-12-15 17:12 UTC
- committer
- brice · · 2025-12-15 20:11 UTC
- parent
- 88a2e86
- signature
- unsigned
3 files · +43 -3
M internal/ui/layout/gtk_widgets.go +14 -2
| @@ -1,6 +1,7 @@ | |||
| 1 | 1 | package layout | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | + | "github.com/jwijenbergh/puregotk/v4/gdk" | |
| 4 | 5 | "github.com/jwijenbergh/puregotk/v4/graphene" | |
| 5 | 6 | "github.com/jwijenbergh/puregotk/v4/gtk" | |
| 6 | 7 | "github.com/jwijenbergh/puregotk/v4/pango" | |
| @@ -579,8 +580,19 @@ func (img *gtkImage) GetParent() Widget { | |||
| 579 | 580 | ||
| 580 | 581 | func (img *gtkImage) SetFromIconName(name string) { img.inner.SetFromIconName(&name) } | |
| 581 | 582 | func (img *gtkImage) SetFromFile(filename string) { img.inner.SetFromFile(&filename) } | |
| 582 | - | func (img *gtkImage) SetPixelSize(size int) { img.inner.SetPixelSize(size) } | |
| 583 | - | func (img *gtkImage) Clear() { img.inner.Clear() } | |
| 583 | + | func (img *gtkImage) SetFromPaintable(p Paintable) { | |
| 584 | + | if p == nil { | |
| 585 | + | img.inner.Clear() | |
| 586 | + | return | |
| 587 | + | } | |
| 588 | + | // Create a gdk.Paintable from the pointer | |
| 589 | + | // gdk.Texture implements gdk.Paintable | |
| 590 | + | texture := &gdk.Texture{} | |
| 591 | + | texture.Ptr = p.GoPointer() | |
| 592 | + | img.inner.SetFromPaintable(texture) | |
| 593 | + | } | |
| 594 | + | func (img *gtkImage) SetPixelSize(size int) { img.inner.SetPixelSize(size) } | |
| 595 | + | func (img *gtkImage) Clear() { img.inner.Clear() } | |
| 584 | 596 | ||
| 585 | 597 | func (img *gtkImage) GetAllocatedWidth() int { return img.inner.GetAllocatedWidth() } | |
| 586 | 598 | func (img *gtkImage) GetAllocatedHeight() int { return img.inner.GetAllocatedHeight() } | |
| @@ -1,6 +1,7 @@ | |||||
| 1 | package layout | 1 | package layout | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | + | "github.com/jwijenbergh/puregotk/v4/gdk" | |||
| 4 | "github.com/jwijenbergh/puregotk/v4/graphene" | 5 | "github.com/jwijenbergh/puregotk/v4/graphene" | ||
| 5 | "github.com/jwijenbergh/puregotk/v4/gtk" | 6 | "github.com/jwijenbergh/puregotk/v4/gtk" | ||
| 6 | "github.com/jwijenbergh/puregotk/v4/pango" | 7 | "github.com/jwijenbergh/puregotk/v4/pango" | ||
| @@ -579,8 +580,19 @@ func (img *gtkImage) GetParent() Widget { | |||||
| 579 | 580 | ||||
| 580 | func (img *gtkImage) SetFromIconName(name string) { img.inner.SetFromIconName(&name) } | 581 | func (img *gtkImage) SetFromIconName(name string) { img.inner.SetFromIconName(&name) } | ||
| 581 | func (img *gtkImage) SetFromFile(filename string) { img.inner.SetFromFile(&filename) } | 582 | func (img *gtkImage) SetFromFile(filename string) { img.inner.SetFromFile(&filename) } | ||
| 582 | - | func (img *gtkImage) SetPixelSize(size int) { img.inner.SetPixelSize(size) } | 583 | + | func (img *gtkImage) SetFromPaintable(p Paintable) { |
| 583 | - | func (img *gtkImage) Clear() { img.inner.Clear() } | 584 | + | if p == nil { |
| 585 | + | img.inner.Clear() | |||
| 586 | + | return | |||
| 587 | + | } | |||
| 588 | + | // Create a gdk.Paintable from the pointer | |||
| 589 | + | // gdk.Texture implements gdk.Paintable | |||
| 590 | + | texture := &gdk.Texture{} | |||
| 591 | + | texture.Ptr = p.GoPointer() | |||
| 592 | + | img.inner.SetFromPaintable(texture) | |||
| 593 | + | } | |||
| 594 | + | func (img *gtkImage) SetPixelSize(size int) { img.inner.SetPixelSize(size) } | |||
| 595 | + | func (img *gtkImage) Clear() { img.inner.Clear() } | |||
| 584 | 596 | ||||
| 585 | func (img *gtkImage) GetAllocatedWidth() int { return img.inner.GetAllocatedWidth() } | 597 | func (img *gtkImage) GetAllocatedWidth() int { return img.inner.GetAllocatedWidth() } | ||
| 586 | func (img *gtkImage) GetAllocatedHeight() int { return img.inner.GetAllocatedHeight() } | 598 | func (img *gtkImage) GetAllocatedHeight() int { return img.inner.GetAllocatedHeight() } | ||
M internal/ui/layout/stacked.go +22 -1
| @@ -315,7 +315,7 @@ func (sv *StackedView) UpdateTitle(index int, title string) error { | |||
| 315 | 315 | return nil | |
| 316 | 316 | } | |
| 317 | 317 | ||
| 318 | - | // UpdateFavicon updates the favicon of a pane at the given index. | |
| 318 | + | // UpdateFavicon updates the favicon of a pane at the given index using an icon name. | |
| 319 | 319 | func (sv *StackedView) UpdateFavicon(index int, iconName string) error { | |
| 320 | 320 | sv.mu.Lock() | |
| 321 | 321 | defer sv.mu.Unlock() | |
| @@ -335,6 +335,27 @@ func (sv *StackedView) UpdateFavicon(index int, iconName string) error { | |||
| 335 | 335 | return nil | |
| 336 | 336 | } | |
| 337 | 337 | ||
| 338 | + | // UpdateFaviconTexture updates the favicon of a pane at the given index using a texture. | |
| 339 | + | // If texture is nil, falls back to the default web-browser-symbolic icon. | |
| 340 | + | func (sv *StackedView) UpdateFaviconTexture(index int, texture Paintable) error { | |
| 341 | + | sv.mu.Lock() | |
| 342 | + | defer sv.mu.Unlock() | |
| 343 | + | ||
| 344 | + | if index < 0 || index >= len(sv.panes) { | |
| 345 | + | return ErrIndexOutOfBounds | |
| 346 | + | } | |
| 347 | + | ||
| 348 | + | if sv.panes[index].favicon != nil { | |
| 349 | + | if texture != nil { | |
| 350 | + | sv.panes[index].favicon.SetFromPaintable(texture) | |
| 351 | + | } else { | |
| 352 | + | sv.panes[index].favicon.SetFromIconName("web-browser-symbolic") | |
| 353 | + | } | |
| 354 | + | } | |
| 355 | + | ||
| 356 | + | return nil | |
| 357 | + | } | |
| 358 | + | ||
| 338 | 359 | // GetContainer returns the container widget for the pane at the given index. | |
| 339 | 360 | func (sv *StackedView) GetContainer(index int) (Widget, error) { | |
| 340 | 361 | sv.mu.RLock() | |
| @@ -315,7 +315,7 @@ func (sv *StackedView) UpdateTitle(index int, title string) error { | |||||
| 315 | return nil | 315 | return nil | ||
| 316 | } | 316 | } | ||
| 317 | 317 | ||||
| 318 | - | // UpdateFavicon updates the favicon of a pane at the given index. | 318 | + | // UpdateFavicon updates the favicon of a pane at the given index using an icon name. |
| 319 | func (sv *StackedView) UpdateFavicon(index int, iconName string) error { | 319 | func (sv *StackedView) UpdateFavicon(index int, iconName string) error { | ||
| 320 | sv.mu.Lock() | 320 | sv.mu.Lock() | ||
| 321 | defer sv.mu.Unlock() | 321 | defer sv.mu.Unlock() | ||
| @@ -335,6 +335,27 @@ func (sv *StackedView) UpdateFavicon(index int, iconName string) error { | |||||
| 335 | return nil | 335 | return nil | ||
| 336 | } | 336 | } | ||
| 337 | 337 | ||||
| 338 | + | // UpdateFaviconTexture updates the favicon of a pane at the given index using a texture. | |||
| 339 | + | // If texture is nil, falls back to the default web-browser-symbolic icon. | |||
| 340 | + | func (sv *StackedView) UpdateFaviconTexture(index int, texture Paintable) error { | |||
| 341 | + | sv.mu.Lock() | |||
| 342 | + | defer sv.mu.Unlock() | |||
| 343 | + | ||||
| 344 | + | if index < 0 || index >= len(sv.panes) { | |||
| 345 | + | return ErrIndexOutOfBounds | |||
| 346 | + | } | |||
| 347 | + | ||||
| 348 | + | if sv.panes[index].favicon != nil { | |||
| 349 | + | if texture != nil { | |||
| 350 | + | sv.panes[index].favicon.SetFromPaintable(texture) | |||
| 351 | + | } else { | |||
| 352 | + | sv.panes[index].favicon.SetFromIconName("web-browser-symbolic") | |||
| 353 | + | } | |||
| 354 | + | } | |||
| 355 | + | ||||
| 356 | + | return nil | |||
| 357 | + | } | |||
| 358 | + | ||||
| 338 | // GetContainer returns the container widget for the pane at the given index. | 359 | // GetContainer returns the container widget for the pane at the given index. | ||
| 339 | func (sv *StackedView) GetContainer(index int) (Widget, error) { | 360 | func (sv *StackedView) GetContainer(index int) (Widget, error) { | ||
| 340 | sv.mu.RLock() | 361 | sv.mu.RLock() | ||
M internal/ui/layout/widgets.go +7 -0
| @@ -179,12 +179,19 @@ type ButtonWidget interface { | |||
| 179 | 179 | ConnectClicked(callback func()) uint32 | |
| 180 | 180 | } | |
| 181 | 181 | ||
| 182 | + | // Paintable represents a graphics texture that can be displayed in an image. | |
| 183 | + | // This interface abstracts over gdk.Paintable/gdk.Texture. | |
| 184 | + | type Paintable interface { | |
| 185 | + | GoPointer() uintptr | |
| 186 | + | } | |
| 187 | + | ||
| 182 | 188 | // ImageWidget wraps gtk.Image for displaying images. | |
| 183 | 189 | type ImageWidget interface { | |
| 184 | 190 | Widget | |
| 185 | 191 | ||
| 186 | 192 | SetFromIconName(iconName string) | |
| 187 | 193 | SetFromFile(filename string) | |
| 194 | + | SetFromPaintable(paintable Paintable) | |
| 188 | 195 | SetPixelSize(pixelSize int) | |
| 189 | 196 | Clear() | |
| 190 | 197 | } | |
| @@ -179,12 +179,19 @@ type ButtonWidget interface { | |||||
| 179 | ConnectClicked(callback func()) uint32 | 179 | ConnectClicked(callback func()) uint32 | ||
| 180 | } | 180 | } | ||
| 181 | 181 | ||||
| 182 | + | // Paintable represents a graphics texture that can be displayed in an image. | |||
| 183 | + | // This interface abstracts over gdk.Paintable/gdk.Texture. | |||
| 184 | + | type Paintable interface { | |||
| 185 | + | GoPointer() uintptr | |||
| 186 | + | } | |||
| 187 | + | ||||
| 182 | // ImageWidget wraps gtk.Image for displaying images. | 188 | // ImageWidget wraps gtk.Image for displaying images. | ||
| 183 | type ImageWidget interface { | 189 | type ImageWidget interface { | ||
| 184 | Widget | 190 | Widget | ||
| 185 | 191 | ||||
| 186 | SetFromIconName(iconName string) | 192 | SetFromIconName(iconName string) | ||
| 187 | SetFromFile(filename string) | 193 | SetFromFile(filename string) | ||
| 194 | + | SetFromPaintable(paintable Paintable) | |||
| 188 | SetPixelSize(pixelSize int) | 195 | SetPixelSize(pixelSize int) | ||
| 189 | Clear() | 196 | Clear() | ||
| 190 | } | 197 | } | ||