diff --git a/icons/copy.png b/internal/ui/icons/copy.png similarity index 100% rename from icons/copy.png rename to internal/ui/icons/copy.png diff --git a/icons/copy.svg b/internal/ui/icons/copy.svg similarity index 100% rename from icons/copy.svg rename to internal/ui/icons/copy.svg diff --git a/icons/cut.png b/internal/ui/icons/cut.png similarity index 100% rename from icons/cut.png rename to internal/ui/icons/cut.png diff --git a/icons/cut.svg b/internal/ui/icons/cut.svg similarity index 100% rename from icons/cut.svg rename to internal/ui/icons/cut.svg diff --git a/icons/gen_icons.go b/internal/ui/icons/gen_icons.go similarity index 100% rename from icons/gen_icons.go rename to internal/ui/icons/gen_icons.go diff --git a/icons/icons.go b/internal/ui/icons/icons.go similarity index 100% rename from icons/icons.go rename to internal/ui/icons/icons.go diff --git a/icons/paste.png b/internal/ui/icons/paste.png similarity index 100% rename from icons/paste.png rename to internal/ui/icons/paste.png diff --git a/icons/paste.svg b/internal/ui/icons/paste.svg similarity index 100% rename from icons/paste.svg rename to internal/ui/icons/paste.svg diff --git a/internal/ui/render.go b/internal/ui/render.go index 9961678..c0847e2 100644 --- a/internal/ui/render.go +++ b/internal/ui/render.go @@ -1,8 +1,12 @@ package ui import ( + "bytes" + "embed" "image" "image/color" + _ "image/png" + "strings" "gioui.org/f32" "gioui.org/layout" @@ -15,6 +19,9 @@ import ( "golang.org/x/image/math/fixed" ) +//go:embed icons/*.png +var iconFS embed.FS + // StateReader provides access to scale and window dimensions from State. // Implemented by editor.State to avoid import cycles. type StateReader interface { @@ -28,11 +35,31 @@ type Renderer struct { theme Theme shp *text.Shaper state StateReader // read-only access to State for scale/window size + icons map[string]image.Image // loaded PNG icons } // New creates a new Renderer. func New(th Theme, shp *text.Shaper) *Renderer { - return &Renderer{theme: th, shp: shp} + r := &Renderer{theme: th, shp: shp, icons: make(map[string]image.Image)} + r.loadIcons() + return r +} + +// loadIcons loads all PNG icons from the embedded filesystem. +func (r *Renderer) loadIcons() { + files := []string{"cut.png", "copy.png", "paste.png", "search.png", "conflict.png", "wrapOn.png", "wrapOff.png"} + for _, filename := range files { + data, err := iconFS.ReadFile(filename) + if err != nil { + continue // skip missing icons + } + img, _, err := image.Decode(bytes.NewReader(data)) + if err != nil { + continue + } + name := strings.TrimSuffix(filename, ".png") + r.icons[name] = img + } } // SetState sets the State reference for the Renderer. @@ -167,22 +194,23 @@ func (r *Renderer) drawStatusBar(gtx layout.Context, sb StatusBar, _ WindowConst // Left side: Cut, Copy, Paste icons (always visible) leftX := reg.X + Dp(8) iconY := iconsLineY + iconSize := Dp(16) // 16dp icons - r.drawText(gtx, th.Shaper, "✂", r.theme.FontSize, leftX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) - leftX += Dp(36) - r.drawText(gtx, th.Shaper, "⎘", r.theme.FontSize, leftX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) - leftX += Dp(36) - r.drawText(gtx, th.Shaper, "⎘", r.theme.FontSize, leftX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) + r.drawPng(gtx, r.icons["cut"], leftX, iconY, iconSize, iconSize, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) + leftX += Dp(28) + r.drawPng(gtx, r.icons["copy"], leftX, iconY, iconSize, iconSize, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) + leftX += Dp(28) + r.drawPng(gtx, r.icons["paste"], leftX, iconY, iconSize, iconSize, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) leftX += Dp(12) // Right side: Conflict (conditional), Search (always visible) rightX := reg.X + reg.W - Dp(8) if sb.ConflictIcon { - rightX -= Dp(36) - r.drawText(gtx, th.Shaper, "⚠", r.theme.FontSize, rightX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) + rightX -= Dp(28) + r.drawPng(gtx, r.icons["conflict"], rightX, iconY, iconSize, iconSize, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) } - rightX -= Dp(36) - r.drawText(gtx, th.Shaper, "🔍", r.theme.FontSize, rightX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) + rightX -= Dp(28) + r.drawPng(gtx, r.icons["search"], rightX, iconY, iconSize, iconSize, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) c.Pop() }