From 8401b5d0f9312f1eb82c4b98bcf5561b92b97e2d Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Tue, 22 Aug 2023 13:17:48 -0400 Subject: [PATCH] Add support for transparency Need to break away from ggfx to do this, probably put everything in xcanvas. --- box.go | 152 ++++++++++++++++++++++++++++-------------------- containerbox.go | 29 ++++++++- go.mod | 2 +- go.sum | 4 +- system.go | 1 + texture.go | 8 +++ window.go | 6 ++ 7 files changed, 134 insertions(+), 68 deletions(-) diff --git a/box.go b/box.go index 015dc86..9c94dfe 100644 --- a/box.go +++ b/box.go @@ -23,6 +23,9 @@ type box struct { padding tomo.Inset border []tomo.Border color color.Color + texture *texture + + fillTransparent bool dndData data.Data dndAccept []data.Mime @@ -111,13 +114,22 @@ func (this *box) SetBounds (bounds image.Rectangle) { } func (this *box) SetColor (c color.Color) { + if c == nil { c = color.Transparent } if this.color == c { return } this.color = c + this.determineFillTransparency() + this.invalidateDraw() +} + +func (this *box) SetTexture (texture tomo.Texture) { + this.texture = assertTexture(texture) + this.determineFillTransparency() this.invalidateDraw() } func (this *box) SetBorder (border ...tomo.Border) { this.border = border + this.determineFillTransparency() this.invalidateLayout() this.invalidateMinimum() } @@ -221,44 +233,103 @@ func (this *box) OnKeyDown (callback func(key input.Key, numberPad bool)) event. func (this *box) OnKeyUp (callback func(key input.Key, numberPad bool)) event.Cookie { return this.on.keyUp.Connect(callback) } +func (this *box) handleFocusEnter () { + this.on.focusEnter.Broadcast() +} +func (this *box) handleFocusLeave () { + this.on.focusLeave.Broadcast() +} +func (this *box) handleMouseEnter () { + this.on.mouseEnter.Broadcast() +} +func (this *box) handleMouseLeave () { + this.on.mouseLeave.Broadcast() +} +func (this *box) handleMouseMove () { + this.on.mouseMove.Broadcast() +} +func (this *box) handleMouseDown (button input.Button) { + if this.focusable { + this.SetFocused(true) + } else { + if this.parent == nil { return } + window := this.parent.window() + if window == nil { return } + window.focus(nil) + } + for _, listener := range this.on.mouseDown.Listeners() { + listener(button) + } +} +func (this *box) handleMouseUp (button input.Button) { + for _, listener := range this.on.mouseUp.Listeners() { + listener(button) + } +} +func (this *box) handleKeyDown (key input.Key, numberPad bool) { + for _, listener := range this.on.keyDown.Listeners() { + listener(key, numberPad) + } +} +func (this *box) handleKeyUp (key input.Key, numberPad bool) { + for _, listener := range this.on.keyUp.Listeners() { + listener(key, numberPad) + } +} // -------------------------------------------------------------------------- // func (this *box) Draw (can canvas.Canvas) { if can == nil { return } pen := can.Pen() pen.Fill(this.color) - pen.Rectangle(this.bounds) + if this.texture == nil || this.texture.transparent { + pen.Rectangle(this.bounds) + } + if this.texture != nil { + // TODO drawR texture + } } func (this *box) drawBorders (can canvas.Canvas) { if can == nil { return } pen := can.Pen() bounds := this.bounds + + rectangle := func (x0, y0, x1, y1 int, c color.Color) { + area := image.Rect(x0, y0, x1, y1) + _, _, _, a := c.RGBA() + if a != 0xFFFF && this.parent != nil { + this.parent.drawBackgroundPart(can.Clip(area)) + } + pen.Fill(c) + pen.Rectangle(area) + } + for _, border := range this.border { - pen.Fill(border.Color[tomo.SideTop]) - pen.Rectangle(image.Rect ( + rectangle ( bounds.Min.X, bounds.Min.Y, bounds.Max.X, - bounds.Min.Y + border.Width[tomo.SideTop])) - pen.Fill(border.Color[tomo.SideBottom]) - pen.Rectangle(image.Rect ( + bounds.Min.Y + border.Width[tomo.SideTop], + border.Color[tomo.SideTop]) + rectangle ( bounds.Min.X, bounds.Max.Y - border.Width[tomo.SideBottom], bounds.Max.X, - bounds.Max.Y)) - pen.Fill(border.Color[tomo.SideLeft]) - pen.Rectangle(image.Rect ( + bounds.Max.Y, + border.Color[tomo.SideBottom]) + rectangle ( bounds.Min.X, bounds.Min.Y + border.Width[tomo.SideTop], bounds.Min.X + border.Width[tomo.SideLeft], - bounds.Max.Y - border.Width[tomo.SideBottom])) - pen.Fill(border.Color[tomo.SideRight]) - pen.Rectangle(image.Rect ( + bounds.Max.Y - border.Width[tomo.SideBottom], + border.Color[tomo.SideLeft]) + rectangle ( bounds.Max.X - border.Width[tomo.SideRight], bounds.Min.Y + border.Width[tomo.SideTop], bounds.Max.X, - bounds.Max.Y - border.Width[tomo.SideBottom])) + bounds.Max.Y - border.Width[tomo.SideBottom], + border.Color[tomo.SideRight]) bounds = border.Width.Apply(bounds) } @@ -356,56 +427,11 @@ func (this *box) boxUnder (point image.Point) anyBox { } } -func (this *box) handleFocusEnter () { - this.on.focusEnter.Broadcast() -} - -func (this *box) handleFocusLeave () { - this.on.focusLeave.Broadcast() -} - -func (this *box) handleMouseEnter () { - this.on.mouseEnter.Broadcast() -} - -func (this *box) handleMouseLeave () { - this.on.mouseLeave.Broadcast() -} - -func (this *box) handleMouseMove () { - this.on.mouseMove.Broadcast() -} - -func (this *box) handleMouseDown (button input.Button) { - if this.focusable { - this.SetFocused(true) - } else { - if this.parent == nil { return } - window := this.parent.window() - if window == nil { return } - window.focus(nil) - } - for _, listener := range this.on.mouseDown.Listeners() { - listener(button) - } -} - -func (this *box) handleMouseUp (button input.Button) { - for _, listener := range this.on.mouseUp.Listeners() { - listener(button) - } -} - -func (this *box) handleKeyDown (key input.Key, numberPad bool) { - for _, listener := range this.on.keyDown.Listeners() { - listener(key, numberPad) - } -} - -func (this *box) handleKeyUp (key input.Key, numberPad bool) { - for _, listener := range this.on.keyUp.Listeners() { - listener(key, numberPad) - } +func (this *box) determineFillTransparency () { + _, _, _, a := this.color.RGBA() + this.fillTransparent = + a != 0xFFFF && + !(this.texture != nil && !this.texture.transparent) } func (this *box) propagate (callback func (anyBox) bool) bool { diff --git a/containerbox.go b/containerbox.go index 6e61e9b..a31a0e8 100644 --- a/containerbox.go +++ b/containerbox.go @@ -132,7 +132,6 @@ func (this *containerBox) SetLayout (layout tomo.Layout) { func (this *containerBox) Draw (can canvas.Canvas) { if can == nil { return } - this.drawBorders(can) pen := can.Pen() pen.Fill(this.color) @@ -141,7 +140,33 @@ func (this *containerBox) Draw (can canvas.Canvas) { rocks[index] = box.Bounds() } for _, tile := range canvas.Shatter(this.bounds, rocks...) { - pen.Rectangle(tile) + if this.fillTransparent && this.parent != nil { + this.parent.drawBackgroundPart(can.Clip(tile)) + } + if this.texture == nil || this.texture.transparent { + pen.Rectangle(tile) + } + if this.texture != nil { + // TODO draw texture + } + } +} + +func (this *containerBox) drawBackgroundPart (can canvas.Canvas) { + if can == nil { return } + + if this.fillTransparent && this.parent != nil { + this.parent.drawBackgroundPart(can) + } + + pen := can.Pen() + pen.Fill(this.color) + + if this.texture == nil || this.texture.transparent { + pen.Rectangle(can.Bounds()) + } + if this.texture != nil { + // TODO draw texture } } diff --git a/go.mod b/go.mod index 7fe5462..33feaa8 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( git.tebibyte.media/tomo/ggfx v0.4.0 - git.tebibyte.media/tomo/tomo v0.24.0 + git.tebibyte.media/tomo/tomo v0.25.0 git.tebibyte.media/tomo/typeset v0.5.2 git.tebibyte.media/tomo/xgbkb v1.0.1 github.com/jezek/xgb v1.1.0 diff --git a/go.sum b/go.sum index d08288d..bcca140 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ git.tebibyte.media/sashakoshka/xgbkb v1.0.0/go.mod h1:pNcE6TRO93vHd6q42SdwLSTTj25L0Yzggz7yLe0JV6Q= git.tebibyte.media/tomo/ggfx v0.4.0 h1:3aUHeGS/yYWRV/zCDubBsXnik5ygkMnj/VgrM5Z75A4= git.tebibyte.media/tomo/ggfx v0.4.0/go.mod h1:zPoz8BdVQyG2KhEmeGFQBK66V71i6Kj8oVFbrZaCwRA= -git.tebibyte.media/tomo/tomo v0.24.0 h1:Zv5S/SmGjoEzssIOx/ADZBmnIfdeeVEwHdHVQHcls9M= -git.tebibyte.media/tomo/tomo v0.24.0/go.mod h1:C9EzepS9wjkTJjnZaPBh22YvVPyA4hbBAJVU20Rdmps= +git.tebibyte.media/tomo/tomo v0.25.0 h1:nFZATsIqLQyGNB1QreVTFhFQjbyBax1hjMff2u1qpxc= +git.tebibyte.media/tomo/tomo v0.25.0/go.mod h1:C9EzepS9wjkTJjnZaPBh22YvVPyA4hbBAJVU20Rdmps= git.tebibyte.media/tomo/typeset v0.5.2 h1:qHxN62/VDnrAouOuzxLmLleQNwAebshrfVYvtoOnAG4= git.tebibyte.media/tomo/typeset v0.5.2/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g= git.tebibyte.media/tomo/xgbkb v1.0.1 h1:b3HDUopjdQp1MZrb5Vpil4bOtk3NnNXtfQW27Blw2kE= diff --git a/system.go b/system.go index 2422360..9b6a6e2 100644 --- a/system.go +++ b/system.go @@ -36,6 +36,7 @@ type parent interface { window () *window canvas () canvas.Canvas notifyMinimumSizeChange (anyBox) + drawBackgroundPart (canvas.Canvas) } type anyBox interface { diff --git a/texture.go b/texture.go index f105b32..03264bf 100644 --- a/texture.go +++ b/texture.go @@ -46,3 +46,11 @@ func (this *texture) Clip (bounds image.Rectangle) tomo.Texture { func (this *texture) Close () error { return nil } + +func assertTexture (unknown tomo.Texture) *texture { + if tx, ok := unknown.(*texture); ok { + return tx + } else { + panic("foregin texture implementation, i did not make this!") + } +} diff --git a/window.go b/window.go index ba7aae0..72f6854 100644 --- a/window.go +++ b/window.go @@ -8,6 +8,7 @@ import "git.tebibyte.media/tomo/x/canvas" import "git.tebibyte.media/tomo/tomo/data" import "git.tebibyte.media/tomo/tomo/input" import "git.tebibyte.media/tomo/tomo/event" +import "git.tebibyte.media/tomo/tomo/canvas" import "github.com/jezek/xgb/xproto" import "github.com/jezek/xgbutil/ewmh" @@ -361,6 +362,11 @@ func (window *window) pushRegion (region image.Rectangle) { subCanvas.(*xcanvas.Canvas).Push(window.xWindow.Id) } +func (window *window) drawBackgroundPart (canvas.Canvas) { + // no-op for now? maybe eventually windows will be able to have a + // background +} + func (window *window) doMinimumSize () { window.minimumClean = true