It displays things on a screen

This commit is contained in:
Sasha Koshka 2023-07-05 00:44:56 -04:00
parent 208c50a66b
commit 4c79d6772c
5 changed files with 92 additions and 49 deletions

2
box.go
View File

@ -237,9 +237,11 @@ func (this *box) recursiveRedo () {
} }
func (this *box) invalidateDraw () { func (this *box) invalidateDraw () {
if this.parent == nil { return }
this.parent.window().invalidateDraw(this) this.parent.window().invalidateDraw(this)
} }
func (this *box) invalidateLayout () { func (this *box) invalidateLayout () {
if this.parent == nil { return }
this.parent.window().invalidateLayout(this) this.parent.window().invalidateLayout(this)
} }

View File

@ -14,18 +14,19 @@ type Canvas struct {
} }
// New creates a new canvas from a bounding rectangle. // New creates a new canvas from a bounding rectangle.
func New (x *xgbutil.XUtil, bounds image.Rectangle) Canvas { func New (x *xgbutil.XUtil, bounds image.Rectangle) *Canvas {
return Canvas { xgraphics.New(x, bounds) } return NewFrom(xgraphics.New(x, bounds))
} }
// NewFrom creates a new canvas from an existing xgraphics.Image. // NewFrom creates a new canvas from an existing xgraphics.Image.
func NewFrom (image *xgraphics.Image) Canvas { func NewFrom (image *xgraphics.Image) *Canvas {
return Canvas { image } if image == nil { return nil }
return &Canvas { image }
} }
// Pen returns a new drawing context. // Pen returns a new drawing context.
func (this Canvas) Pen () canvas.Pen { func (this *Canvas) Pen () canvas.Pen {
return pen { return &pen {
image: this.Image, image: this.Image,
gfx: ggfx.Image[uint8] { gfx: ggfx.Image[uint8] {
Pix: this.Image.Pix, Pix: this.Image.Pix,
@ -37,16 +38,25 @@ func (this Canvas) Pen () canvas.Pen {
} }
// Clip returns a sub-canvas of this canvas. // Clip returns a sub-canvas of this canvas.
func (this Canvas) Clip (bounds image.Rectangle) canvas.Canvas { func (this *Canvas) Clip (bounds image.Rectangle) canvas.Canvas {
return Canvas { this.Image.SubImage(bounds).(*xgraphics.Image) } this.assert()
subImage := this.Image.SubImage(bounds)
if subImage == nil { return nil }
xImage := subImage.(*xgraphics.Image)
return &Canvas { xImage }
} }
// Push pushes this canvas to the screen. // Push pushes this canvas to the screen.
func (this Canvas) Push (window xproto.Window) { func (this *Canvas) Push (window xproto.Window) {
this.assert()
this.XDraw() this.XDraw()
this.XExpPaint(window, this.Bounds().Min.X, this.Bounds().Min.Y) this.XExpPaint(window, this.Bounds().Min.X, this.Bounds().Min.Y)
} }
func (this *Canvas) assert () {
if this == nil { panic("nil canvas") }
}
// TODO: we need to implement: // TODO: we need to implement:
// - cap // - cap
// - joint // - joint
@ -65,7 +75,7 @@ type pen struct {
fill [4]uint8 fill [4]uint8
} }
func (this pen) Rectangle (bounds image.Rectangle) { func (this *pen) Rectangle (bounds image.Rectangle) {
if this.weight == 0 { if this.weight == 0 {
this.gfx.FillRectangle(this.fill[:], bounds) this.gfx.FillRectangle(this.fill[:], bounds)
} else { } else {
@ -73,7 +83,7 @@ func (this pen) Rectangle (bounds image.Rectangle) {
} }
} }
func (this pen) Path (points ...image.Point) { func (this *pen) Path (points ...image.Point) {
if this.weight == 0 { if this.weight == 0 {
this.gfx.FillPolygon(this.fill[:], points...) this.gfx.FillPolygon(this.fill[:], points...)
} else if this.closed { } else if this.closed {
@ -83,21 +93,21 @@ func (this pen) Path (points ...image.Point) {
} }
} }
func (this pen) Closed (closed bool) { this.closed = closed } func (this *pen) Closed (closed bool) { this.closed = closed }
func (this pen) Cap (endCap canvas.Cap) { this.endCap = endCap } func (this *pen) Cap (endCap canvas.Cap) { this.endCap = endCap }
func (this pen) Joint (joint canvas.Joint) { this.joint = joint } func (this *pen) Joint (joint canvas.Joint) { this.joint = joint }
func (this pen) StrokeWeight (weight int) { this.weight = weight } func (this *pen) StrokeWeight (weight int) { this.weight = weight }
func (this pen) StrokeAlign (align canvas.StrokeAlign) { this.align = align } func (this *pen) StrokeAlign (align canvas.StrokeAlign) { this.align = align }
func (this pen) Stroke (stroke color.Color) { this.stroke = convertColor(stroke) } func (this *pen) Stroke (stroke color.Color) { this.stroke = convertColor(stroke) }
func (this pen) Fill (fill color.Color) { this.fill = convertColor(fill) } func (this *pen) Fill (fill color.Color) { this.fill = convertColor(fill) }
func convertColor (c color.Color) [4]uint8 { func convertColor (c color.Color) [4]uint8 {
r, g, b, a := c.RGBA() r, g, b, a := c.RGBA()
return [4]uint8 { return [4]uint8 {
uint8(b >> 8), uint8(b >> 8),
uint8(g >> 8), uint8(g >> 8),
uint8(a >> 8),
uint8(r >> 8), uint8(r >> 8),
uint8(a >> 8),
} }
} }

View File

@ -10,8 +10,11 @@ func (window *window) handleExpose (
connection *xgbutil.XUtil, connection *xgbutil.XUtil,
event xevent.ExposeEvent, event xevent.ExposeEvent,
) { ) {
if window.xCanvas == nil {
window.reallocateCanvas()
}
window.compressExpose(*event.ExposeEvent) window.compressExpose(*event.ExposeEvent)
window.xCanvas.Push(window.xWindow.Id) window.pushAll()
} }
func (window *window) updateBounds () { func (window *window) updateBounds () {
@ -33,7 +36,7 @@ func (window *window) handleConfigureNotify (
event xevent.ConfigureNotifyEvent, event xevent.ConfigureNotifyEvent,
) { ) {
if window.root == nil { return } if window.root == nil { return }
configureEvent := *event.ConfigureNotifyEvent configureEvent := *event.ConfigureNotifyEvent
newWidth := int(configureEvent.Width) newWidth := int(configureEvent.Width)
@ -46,7 +49,7 @@ func (window *window) handleConfigureNotify (
if sizeChanged { if sizeChanged {
configureEvent = window.compressConfigureNotify(configureEvent) configureEvent = window.compressConfigureNotify(configureEvent)
window.reallocateCanvas() window.reallocateCanvas()
window.root.SetBounds(window.metrics.bounds)
// TODO figure out what to do with this // TODO figure out what to do with this
// if !window.exposeEventFollows(configureEvent) { // if !window.exposeEventFollows(configureEvent) {
// } // }

View File

@ -2,7 +2,6 @@ package x
import "image" import "image"
import "git.tebibyte.media/tomo/tomo" import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/x/canvas"
import "git.tebibyte.media/tomo/tomo/canvas" import "git.tebibyte.media/tomo/tomo/canvas"
type boxSet map[anyBox] struct { } type boxSet map[anyBox] struct { }
@ -46,11 +45,17 @@ type anyBox interface {
} }
func (window *window) SetRoot (root tomo.Object) { func (window *window) SetRoot (root tomo.Object) {
box := root.Box().(anyBox) if window.root != nil {
window.root.setParent(nil) window.root.setParent(nil)
box.setParent(window) }
window.invalidateLayout(box) if root == nil {
window.root = box window.root = nil
} else {
box := root.Box().(anyBox)
box.setParent(window)
window.invalidateLayout(box)
window.root = box
}
} }
func (window *window) window () *window { func (window *window) window () *window {
@ -78,11 +83,20 @@ func (window *window) focus (box anyBox) {
} }
func (window *window) afterEvent () { func (window *window) afterEvent () {
if window.xCanvas == nil { return }
if window.needRedo { if window.needRedo {
// set child bounds
childBounds := window.metrics.bounds
childBounds = childBounds.Sub(childBounds.Min)
window.root.SetBounds(childBounds)
// full relayout/redraw
if window.root != nil { if window.root != nil {
window.root.recursiveRedo() window.root.recursiveRedo()
} }
window.xCanvas.Push(window.xWindow.Id) window.pushAll()
window.needRedo = false
return return
} }
@ -95,5 +109,7 @@ func (window *window) afterEvent () {
box.doDraw() box.doDraw()
toPush = toPush.Union(box.Bounds()) toPush = toPush.Union(box.Bounds())
} }
window.xCanvas.Clip(toPush).(xcanvas.Canvas).Push(window.xWindow.Id) if !toPush.Empty() {
window.pushRegion(toPush)
}
} }

View File

@ -24,7 +24,7 @@ type window struct {
backend *Backend backend *Backend
xWindow *xwindow.Window xWindow *xwindow.Window
xImage *xgraphics.Image xImage *xgraphics.Image
xCanvas xcanvas.Canvas xCanvas *xcanvas.Canvas
title string title string
@ -55,7 +55,7 @@ func (backend *Backend) NewWindow (
output tomo.MainWindow, output tomo.MainWindow,
err error, err error,
) { ) {
if backend == nil { panic("nil backend") } backend.assert()
window, err := backend.newWindow(bounds, false) window, err := backend.newWindow(bounds, false)
output = mainWindow { window: window } output = mainWindow { window: window }
@ -104,10 +104,10 @@ func (backend *Backend) newWindow (
window.Close() window.Close()
}) })
// xevent.ExposeFun(window.handleExpose). xevent.ExposeFun(window.handleExpose).
// Connect(backend.x, window.xWindow.Id) Connect(backend.x, window.xWindow.Id)
// xevent.ConfigureNotifyFun(window.handleConfigureNotify). xevent.ConfigureNotifyFun(window.handleConfigureNotify).
// Connect(backend.x, window.xWindow.Id) Connect(backend.x, window.xWindow.Id)
// xevent.KeyPressFun(window.handleKeyPress). // xevent.KeyPressFun(window.handleKeyPress).
// Connect(backend.x, window.xWindow.Id) // Connect(backend.x, window.xWindow.Id)
// xevent.KeyReleaseFun(window.handleKeyRelease). // xevent.KeyReleaseFun(window.handleKeyRelease).
@ -130,8 +130,6 @@ func (backend *Backend) newWindow (
window.metrics.bounds = bounds window.metrics.bounds = bounds
window.setMinimumSize(8, 8) window.setMinimumSize(8, 8)
window.reallocateCanvas()
backend.windows[window.xWindow.Id] = window backend.windows[window.xWindow.Id] = window
output = window output = window
@ -243,14 +241,6 @@ func (window *window) Paste (callback func (data.Data, error), accept ...data.Mi
} }
func (window *window) Show () { func (window *window) Show () {
// fill the screen with black if there is no active child
if window.root == nil {
window.xCanvas.For (func (x, y int) xgraphics.BGRA {
return xgraphics.BGRA { }
})
window.xCanvas.Push(window.xWindow.Id)
}
window.xWindow.Map() window.xWindow.Map()
if window.shy { window.grabInput() } if window.shy { window.grabInput() }
} }
@ -314,8 +304,11 @@ func (window *window) setClientLeader (leader *window) error {
} }
func (window *window) reallocateCanvas () { func (window *window) reallocateCanvas () {
previousWidth := window.xCanvas.Bounds().Dx() var previousWidth, previousHeight int
previousHeight := window.xCanvas.Bounds().Dy() if window.xCanvas != nil {
previousWidth = window.xCanvas.Bounds().Dx()
previousHeight = window.xCanvas.Bounds().Dy()
}
newWidth := window.metrics.bounds.Dx() newWidth := window.metrics.bounds.Dx()
newHeight := window.metrics.bounds.Dy() newHeight := window.metrics.bounds.Dy()
@ -325,7 +318,7 @@ func (window *window) reallocateCanvas () {
allocStep := 128 allocStep := 128
if larger || smaller { if larger || smaller {
if window.xCanvas.Image != nil { if window.xCanvas != nil {
window.xCanvas.Destroy() window.xCanvas.Destroy()
} }
window.xCanvas = xcanvas.NewFrom(xgraphics.New ( window.xCanvas = xcanvas.NewFrom(xgraphics.New (
@ -336,9 +329,28 @@ func (window *window) reallocateCanvas () {
(newHeight / allocStep + 1) * allocStep))) (newHeight / allocStep + 1) * allocStep)))
window.xCanvas.CreatePixmap() window.xCanvas.CreatePixmap()
} }
window.needRedo = true window.needRedo = true
} }
func (window *window) pushAll () {
if window.xCanvas != nil {
window.xCanvas.Push(window.xWindow.Id)
}
}
func (window *window) pushRegion (region image.Rectangle) {
if window.xCanvas == nil {
return
}
subCanvas := window.xCanvas.Clip(region)
if subCanvas == nil {
return
}
subCanvas.(*xcanvas.Canvas).Push(window.xWindow.Id)
}
func (window *window) setMinimumSize (width, height int) { func (window *window) setMinimumSize (width, height int) {
if width < 8 { width = 8 } if width < 8 { width = 8 }
if height < 8 { height = 8 } if height < 8 { height = 8 }