diff --git a/box.go b/box.go index 776a159..fa5c260 100644 --- a/box.go +++ b/box.go @@ -17,6 +17,7 @@ type box struct { bounds image.Rectangle minSize image.Point userMinSize image.Point + innerClippingBounds image.Rectangle minSizeQueued bool focusQueued *bool @@ -84,7 +85,7 @@ func (this *box) Bounds () image.Rectangle { } func (this *box) InnerBounds () image.Rectangle { - return this.padding.Apply(this.innerClippingBounds()) + return this.padding.Apply(this.innerClippingBounds) } func (this *box) MinimumSize () image.Point { @@ -102,10 +103,6 @@ func (this *box) borderSum () tomo.Inset { return sum } -func (this *box) innerClippingBounds () image.Rectangle { - return this.borderSum().Apply(this.bounds) -} - func (this *box) SetBounds (bounds image.Rectangle) { if this.bounds == bounds { return } this.bounds = bounds @@ -358,11 +355,12 @@ func (this *box) doDraw () { if this.canvas == nil { return } if this.drawer != nil { this.drawBorders(this.canvas) - this.drawer.Draw(this.canvas.Clip(this.innerClippingBounds())) + this.drawer.Draw(this.canvas.Clip(this.innerClippingBounds)) } } func (this *box) doLayout () { + this.innerClippingBounds = this.borderSum().Apply(this.bounds) if this.parent == nil { this.canvas = nil; return } parentCanvas := this.parent.canvas() if parentCanvas == nil { this.canvas = nil; return } diff --git a/canvas/canvas.go b/canvas/canvas.go index ed276d9..9ab229c 100644 --- a/canvas/canvas.go +++ b/canvas/canvas.go @@ -79,9 +79,12 @@ type pen struct { func (this *pen) Rectangle (bounds image.Rectangle) { bounds = bounds.Canon() if this.weight == 0 { - if this.fill.A > 0 { + if this.fill.A > 0 && !this.textureObscures() { this.fillRectangle(this.fill, bounds) } + if this.texture != nil { + this.textureRectangle(bounds) + } } else { if this.stroke.A > 0 { this.strokeRectangle(this.stroke, bounds) @@ -115,6 +118,10 @@ func (this *pen) Stroke (stroke color.Color) { this.stroke = convertColor( func (this *pen) Fill (fill color.Color) { this.fill = convertColor(fill) } func (this *pen) Texture (texture canvas.Texture) { this.texture = AssertTexture(texture) } +func (this *pen) textureObscures () bool { + return this.texture != nil && this.texture.Opaque() +} + func convertColor (c color.Color) xgraphics.BGRA { r, g, b, a := c.RGBA() return xgraphics.BGRA { diff --git a/canvas/draw.go b/canvas/draw.go index 653dab6..827d8e4 100644 --- a/canvas/draw.go +++ b/canvas/draw.go @@ -4,6 +4,46 @@ import "sort" import "image" import "github.com/jezek/xgbutil/xgraphics" +func (this *pen) textureRectangle (bounds image.Rectangle) { + if this.texture.Opaque() { + this.textureRectangleOpaque(bounds) + } else { + this.textureRectangleTransparent(bounds) + } +} + +func (this *pen) textureRectangleOpaque (bounds image.Rectangle) { + + dstBounds := bounds.Intersect(this.image.Bounds()) + srcBounds := this.texture.rect + + offset := dstBounds.Min.Sub(bounds.Min) + + + dstStep := this.image.Stride - bounds.Dx() * 4 + srcStep := this.texture.stride - srcBounds.Dx() * 4 +} + +func (this *pen) textureRectangleTransparent (bounds image.Rectangle) { + bounds = bounds.Intersect(this.image.Bounds()) + var pos image.Point + + for pos.Y = bounds.Min.Y; pos.Y < bounds.Max.Y; pos.Y ++ { + for pos.X = bounds.Min.X; pos.X < bounds.Max.X; pos.X ++ { + index := this.image.PixOffset(pos.X, pos.Y) + pixel := xgraphics.BlendBGRA(xgraphics.BGRA { + B: this.image.Pix[index + 0], + G: this.image.Pix[index + 1], + R: this.image.Pix[index + 2], + A: this.image.Pix[index + 3], + }, c) + this.image.Pix[index + 0] = pixel.B + this.image.Pix[index + 1] = pixel.G + this.image.Pix[index + 2] = pixel.R + this.image.Pix[index + 3] = pixel.A + }} +} + func (this *pen) fillRectangle (c xgraphics.BGRA, bounds image.Rectangle) { if c.A == 255 { this.fillRectangleOpaque(c, bounds) @@ -227,3 +267,11 @@ func (this *pen) polyLine (c xgraphics.BGRA, points ...image.Point) { prevPoint = point } } + +func wrap (n, min, max int) int { + max -= min + n -= min + n %= max + if n < 0 { n += max } + return n + min +} diff --git a/canvas/texture.go b/canvas/texture.go index d5777d4..5a6d023 100644 --- a/canvas/texture.go +++ b/canvas/texture.go @@ -17,7 +17,7 @@ func NewTextureFrom (source image.Image) *Texture { bounds := source.Bounds() texture := &Texture { pix: make([]uint8, bounds.Dx() * bounds.Dy() * 4), - stride: bounds.Dx(), + stride: bounds.Dx() * 4, rect: bounds.Sub(bounds.Min), } @@ -59,6 +59,8 @@ func (this *Texture) Clip (bounds image.Rectangle) canvas.Texture { return &clipped } +func (this *Texture) pixOffset + // AssertTexture checks if a given canvas.Texture is a texture from this package. func AssertTexture (unknown canvas.Texture) *Texture { if tx, ok := unknown.(*Texture); ok { diff --git a/containerbox.go b/containerbox.go index 70670c3..0a597fa 100644 --- a/containerbox.go +++ b/containerbox.go @@ -132,19 +132,21 @@ func (this *containerBox) SetLayout (layout tomo.Layout) { func (this *containerBox) Draw (can canvas.Canvas) { if can == nil { return } - pen := can.Pen() - pen.Fill(this.color) - pen.Texture(this.texture) rocks := make([]image.Rectangle, len(this.children)) for index, box := range this.children { rocks[index] = box.Bounds() } for _, tile := range canvas.Shatter(this.bounds, rocks...) { + clipped := can.Clip(tile) if this.transparent() && this.parent != nil { - this.parent.drawBackgroundPart(can.Clip(tile)) + this.parent.drawBackgroundPart(clipped) } - pen.Rectangle(tile) + if clipped == nil { continue } + pen := clipped.Pen() + pen.Fill(this.color) + pen.Texture(this.texture) + pen.Rectangle(this.innerClippingBounds) } } @@ -157,7 +159,7 @@ func (this *containerBox) drawBackgroundPart (can canvas.Canvas) { if this.transparent() && this.parent != nil { this.parent.drawBackgroundPart(can) } - pen.Rectangle(can.Bounds()) + pen.Rectangle(this.innerClippingBounds) } func (this *containerBox) flushActionQueue () {