From 776ec1f672e144a52483c4f96b7ae8b28b266646 Mon Sep 17 00:00:00 2001 From: Stu Leak Date: Wed, 31 Dec 2025 12:42:18 -0500 Subject: [PATCH] feat(ui): Add diagonal stripe pattern to disabled modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced lock icon-only approach with diagonal stripe overlay for better visual distinction: - Added static (non-animated) diagonal stripe pattern to disabled tiles - Stripes use semi-transparent dark overlay (similar to queue progress bars) - Thicker diagonal lines (8px spacing instead of 4px) - Pattern clearly distinguishes disabled from enabled modules - Kept lock icon as secondary indicator This addresses the issue where adaptive text colors made it difficult to distinguish available vs. disabled modules. The stripe pattern provides immediate visual feedback without relying solely on color dimming. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- internal/ui/components.go | 55 ++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/internal/ui/components.go b/internal/ui/components.go index a1f09fd..7272389 100644 --- a/internal/ui/components.go +++ b/internal/ui/components.go @@ -2,6 +2,7 @@ package ui import ( "fmt" + "image" "image/color" "strings" "time" @@ -176,11 +177,35 @@ func (m *ModuleTile) CreateRenderer() fyne.WidgetRenderer { lockIcon.Hide() } + // Diagonal stripe overlay for disabled modules + disabledStripe := canvas.NewRaster(func(w, h int) image.Image { + if m.enabled { + return nil + } + img := image.NewRGBA(image.Rect(0, 0, w, h)) + // Semi-transparent dark stripes + darkStripe := color.NRGBA{R: 0, G: 0, B: 0, A: 100} + lightStripe := color.NRGBA{R: 0, G: 0, B: 0, A: 30} + + for y := 0; y < h; y++ { + for x := 0; x < w; x++ { + // Thicker diagonal stripes (dividing by 8 instead of 4) + if ((x + y) / 8 % 2) == 0 { + img.Set(x, y, darkStripe) + } else { + img.Set(x, y, lightStripe) + } + } + } + return img + }) + return &moduleTileRenderer{ - tile: m, - bg: bg, - label: txt, - lockIcon: lockIcon, + tile: m, + bg: bg, + label: txt, + lockIcon: lockIcon, + disabledStripe: disabledStripe, } } @@ -191,14 +216,23 @@ func (m *ModuleTile) Tapped(*fyne.PointEvent) { } type moduleTileRenderer struct { - tile *ModuleTile - bg *canvas.Rectangle - label *canvas.Text - lockIcon *canvas.Text + tile *ModuleTile + bg *canvas.Rectangle + label *canvas.Text + lockIcon *canvas.Text + disabledStripe *canvas.Raster } func (r *moduleTileRenderer) Layout(size fyne.Size) { r.bg.Resize(size) + r.bg.Move(fyne.NewPos(0, 0)) + + // Stripe overlay covers entire tile + if r.disabledStripe != nil { + r.disabledStripe.Resize(size) + r.disabledStripe.Move(fyne.NewPos(0, 0)) + } + // Center the label by positioning it in the middle labelSize := r.label.MinSize() r.label.Resize(labelSize) @@ -260,12 +294,15 @@ func (r *moduleTileRenderer) Refresh() { if r.lockIcon != nil { r.lockIcon.Refresh() } + if r.disabledStripe != nil { + r.disabledStripe.Refresh() + } } func (r *moduleTileRenderer) Destroy() {} func (r *moduleTileRenderer) Objects() []fyne.CanvasObject { - return []fyne.CanvasObject{r.bg, r.label, r.lockIcon} + return []fyne.CanvasObject{r.bg, r.disabledStripe, r.label, r.lockIcon} } // TintedBar creates a colored bar container