diff --git a/.qwen/settings.json b/.qwen/settings.json index bb4e6a3..352d47a 100644 --- a/.qwen/settings.json +++ b/.qwen/settings.json @@ -3,5 +3,6 @@ "allow": [ "Bash(pkill *)" ] - } + }, + "$version": 4 } \ No newline at end of file diff --git a/internal/editor/state.go b/internal/editor/state.go index e9783e0..2d5f3dd 100644 --- a/internal/editor/state.go +++ b/internal/editor/state.go @@ -39,7 +39,7 @@ func EditorLayout(screenWidth, screenHeight ui.Dp) []ui.Element { margin := ui.Dp(10) // Compute StatusBar region - statusBarHeight := ui.Dp(48) + statusBarHeight := ui.Dp(80) statusBarRegion := ui.Region{ X: margin, Y: margin, diff --git a/internal/ui/render.go b/internal/ui/render.go index 5be6278..07ee868 100644 --- a/internal/ui/render.go +++ b/internal/ui/render.go @@ -2,11 +2,10 @@ package ui import ( "bytes" - "embed" - "fmt" "image" "image/color" + _ "image/png" "gioui.org/f32" "gioui.org/layout" @@ -128,8 +127,6 @@ func (r *Renderer) drawListView(gtx layout.Context, lv ListView, _ WindowConstra func (r *Renderer) drawStatusBar(gtx layout.Context, sb StatusBar, _ WindowConstraints) { reg := sb.Region() - th := material.NewTheme() - th.Shaper = r.shp // Draw light gray background bgColor := color.NRGBA{R: 230, G: 230, B: 230, A: 255} @@ -147,15 +144,15 @@ func (r *Renderer) drawStatusBar(gtx layout.Context, sb StatusBar, _ WindowConst Max: image.Point{X: int(r.toPx(reg.X + reg.W)), Y: int(r.toPx(reg.Y + reg.H))}, }.Push(gtx.Ops) - // Line 1: Filename (truncated with ellipsis if needed) - filenameLineY := reg.Y + // Line 1: Filename (top at reg.Y + 2dp) + filenameLineY := reg.Y + Dp(2) // Truncate filename only if it doesn't fit displayFilename := sb.Filename availableWidth := int(r.toPx(reg.W - Dp(8) - Dp(40))) // left margin + right icons in DP // Layout ellipsis once and get its width - th.Shaper.LayoutString(text.Parameters{ + r.shp.LayoutString(text.Parameters{ PxPerEm: fixed.I(gtx.Sp(r.theme.FontSize)), MinWidth: 0, MaxWidth: 1000, @@ -163,7 +160,7 @@ func (r *Renderer) drawStatusBar(gtx layout.Context, sb StatusBar, _ WindowConst }, "...") var ellipsisWidth int for { - g, ok := th.Shaper.NextGlyph() + g, ok := r.shp.NextGlyph() if !ok { break } @@ -173,36 +170,32 @@ func (r *Renderer) drawStatusBar(gtx layout.Context, sb StatusBar, _ WindowConst spaceForText := availableWidth - ellipsisWidth // Layout filename, measure widths, and draw in a single pass - r.drawTruncatedText(gtx, th.Shaper, displayFilename, r.theme.FontSize, reg.X+Dp(8), filenameLineY, availableWidth, spaceForText, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) + r.drawTruncatedText(gtx, r.shp, displayFilename, r.theme.FontSize, reg.X+Dp(8), filenameLineY, availableWidth, spaceForText, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) - // Line 2: Icons — positioned 20DP below filename baseline. - iconsLineY := filenameLineY + Dp(32) + // Line 2: Icons (top at reg.Y + 26dp) + iconsLineY := reg.Y + Dp(26) // Left side: Cut, Copy, Paste icons (always visible) leftX := reg.X + Dp(8) iconY := iconsLineY iconSize := Dp(16) - fmt.Printf("[DEBUG drawStatusBar] reg=(%d, %d, %d, %d) filenameLineY=%d iconsLineY=%d iconY=%d iconSize=%d scale=%f\n", - reg.X, reg.Y, reg.W, reg.H, filenameLineY, iconsLineY, iconY, iconSize, r.scale) - // Icon Y is baseline position; drawPng uses top-left, so offset by icon height - - // drawPng uses top-left, drawText uses baseline — offset by icon height - r.drawPng(gtx, r.icons["cut"], leftX, iconY-iconSize, iconSize, iconSize, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) + // Draw PNG icons at their top-left position (iconY) + r.drawPng(gtx, r.icons["cut"], leftX, iconY, iconSize, iconSize, 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.drawText(gtx, r.shp, "⎘", 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.drawText(gtx, r.shp, "⎘", r.theme.FontSize, leftX, iconY, 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}) + r.drawText(gtx, r.shp, "⚠", r.theme.FontSize, rightX, iconY, 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}) + r.drawText(gtx, r.shp, "🔍", r.theme.FontSize, rightX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) c.Pop() } @@ -405,7 +398,6 @@ type WindowConstraints struct { // col is the tint color — if alpha < 255, the image is tinted using blendOp.DstIn. func (r *Renderer) drawPng(gtx layout.Context, img image.Image, x, y Dp, width, height Dp, col color.NRGBA) { if img == nil { - fmt.Printf("[DEBUG drawPng] SKIPPED: img is nil\n") return } @@ -414,8 +406,6 @@ func (r *Renderer) drawPng(gtx layout.Context, img image.Image, x, y Dp, width, yPx := int(r.toPx(y)) wPx := int(r.toPx(width)) hPx := int(r.toPx(height)) - fmt.Printf("[DEBUG drawPng] Dp=(%d, %d, %d, %d) Px=(%d, %d, %d, %d) scale=%f\n", - x, y, width, height, xPx, yPx, wPx, hPx, r.scale) // Compute destination rectangle dst := image.Rect(xPx, yPx, xPx+wPx, yPx+hPx) @@ -430,6 +420,8 @@ func (r *Renderer) drawPng(gtx layout.Context, img image.Image, x, y Dp, width, } // Draw the image + stack := op.Offset(image.Pt(xPx, yPx)).Push(gtx.Ops) paint.NewImageOp(img).Add(gtx.Ops) paint.PaintOp{}.Add(gtx.Ops) + stack.Pop() }