Add support for transparency

Need to break away from ggfx to do this, probably put everything
in xcanvas.
This commit is contained in:
Sasha Koshka 2023-08-22 13:17:48 -04:00
parent 45fa282b61
commit 8401b5d0f9
7 changed files with 134 additions and 68 deletions

152
box.go
View File

@ -23,6 +23,9 @@ type box struct {
padding tomo.Inset padding tomo.Inset
border []tomo.Border border []tomo.Border
color color.Color color color.Color
texture *texture
fillTransparent bool
dndData data.Data dndData data.Data
dndAccept []data.Mime dndAccept []data.Mime
@ -111,13 +114,22 @@ func (this *box) SetBounds (bounds image.Rectangle) {
} }
func (this *box) SetColor (c color.Color) { func (this *box) SetColor (c color.Color) {
if c == nil { c = color.Transparent }
if this.color == c { return } if this.color == c { return }
this.color = c this.color = c
this.determineFillTransparency()
this.invalidateDraw()
}
func (this *box) SetTexture (texture tomo.Texture) {
this.texture = assertTexture(texture)
this.determineFillTransparency()
this.invalidateDraw() this.invalidateDraw()
} }
func (this *box) SetBorder (border ...tomo.Border) { func (this *box) SetBorder (border ...tomo.Border) {
this.border = border this.border = border
this.determineFillTransparency()
this.invalidateLayout() this.invalidateLayout()
this.invalidateMinimum() 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 { func (this *box) OnKeyUp (callback func(key input.Key, numberPad bool)) event.Cookie {
return this.on.keyUp.Connect(callback) 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) { func (this *box) Draw (can canvas.Canvas) {
if can == nil { return } if can == nil { return }
pen := can.Pen() pen := can.Pen()
pen.Fill(this.color) 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) { func (this *box) drawBorders (can canvas.Canvas) {
if can == nil { return } if can == nil { return }
pen := can.Pen() pen := can.Pen()
bounds := this.bounds 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 { for _, border := range this.border {
pen.Fill(border.Color[tomo.SideTop]) rectangle (
pen.Rectangle(image.Rect (
bounds.Min.X, bounds.Min.X,
bounds.Min.Y, bounds.Min.Y,
bounds.Max.X, bounds.Max.X,
bounds.Min.Y + border.Width[tomo.SideTop])) bounds.Min.Y + border.Width[tomo.SideTop],
pen.Fill(border.Color[tomo.SideBottom]) border.Color[tomo.SideTop])
pen.Rectangle(image.Rect ( rectangle (
bounds.Min.X, bounds.Min.X,
bounds.Max.Y - border.Width[tomo.SideBottom], bounds.Max.Y - border.Width[tomo.SideBottom],
bounds.Max.X, bounds.Max.X,
bounds.Max.Y)) bounds.Max.Y,
pen.Fill(border.Color[tomo.SideLeft]) border.Color[tomo.SideBottom])
pen.Rectangle(image.Rect ( rectangle (
bounds.Min.X, bounds.Min.X,
bounds.Min.Y + border.Width[tomo.SideTop], bounds.Min.Y + border.Width[tomo.SideTop],
bounds.Min.X + border.Width[tomo.SideLeft], bounds.Min.X + border.Width[tomo.SideLeft],
bounds.Max.Y - border.Width[tomo.SideBottom])) bounds.Max.Y - border.Width[tomo.SideBottom],
pen.Fill(border.Color[tomo.SideRight]) border.Color[tomo.SideLeft])
pen.Rectangle(image.Rect ( rectangle (
bounds.Max.X - border.Width[tomo.SideRight], bounds.Max.X - border.Width[tomo.SideRight],
bounds.Min.Y + border.Width[tomo.SideTop], bounds.Min.Y + border.Width[tomo.SideTop],
bounds.Max.X, 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) bounds = border.Width.Apply(bounds)
} }
@ -356,56 +427,11 @@ func (this *box) boxUnder (point image.Point) anyBox {
} }
} }
func (this *box) handleFocusEnter () { func (this *box) determineFillTransparency () {
this.on.focusEnter.Broadcast() _, _, _, a := this.color.RGBA()
} this.fillTransparent =
a != 0xFFFF &&
func (this *box) handleFocusLeave () { !(this.texture != nil && !this.texture.transparent)
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) propagate (callback func (anyBox) bool) bool { func (this *box) propagate (callback func (anyBox) bool) bool {

View File

@ -132,7 +132,6 @@ func (this *containerBox) SetLayout (layout tomo.Layout) {
func (this *containerBox) Draw (can canvas.Canvas) { func (this *containerBox) Draw (can canvas.Canvas) {
if can == nil { return } if can == nil { return }
this.drawBorders(can)
pen := can.Pen() pen := can.Pen()
pen.Fill(this.color) pen.Fill(this.color)
@ -141,7 +140,33 @@ func (this *containerBox) Draw (can canvas.Canvas) {
rocks[index] = box.Bounds() rocks[index] = box.Bounds()
} }
for _, tile := range canvas.Shatter(this.bounds, rocks...) { 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
} }
} }

2
go.mod
View File

@ -4,7 +4,7 @@ go 1.20
require ( require (
git.tebibyte.media/tomo/ggfx v0.4.0 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/typeset v0.5.2
git.tebibyte.media/tomo/xgbkb v1.0.1 git.tebibyte.media/tomo/xgbkb v1.0.1
github.com/jezek/xgb v1.1.0 github.com/jezek/xgb v1.1.0

4
go.sum
View File

@ -1,8 +1,8 @@
git.tebibyte.media/sashakoshka/xgbkb v1.0.0/go.mod h1:pNcE6TRO93vHd6q42SdwLSTTj25L0Yzggz7yLe0JV6Q= 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 h1:3aUHeGS/yYWRV/zCDubBsXnik5ygkMnj/VgrM5Z75A4=
git.tebibyte.media/tomo/ggfx v0.4.0/go.mod h1:zPoz8BdVQyG2KhEmeGFQBK66V71i6Kj8oVFbrZaCwRA= 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.25.0 h1:nFZATsIqLQyGNB1QreVTFhFQjbyBax1hjMff2u1qpxc=
git.tebibyte.media/tomo/tomo v0.24.0/go.mod h1:C9EzepS9wjkTJjnZaPBh22YvVPyA4hbBAJVU20Rdmps= 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 h1:qHxN62/VDnrAouOuzxLmLleQNwAebshrfVYvtoOnAG4=
git.tebibyte.media/tomo/typeset v0.5.2/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g= git.tebibyte.media/tomo/typeset v0.5.2/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
git.tebibyte.media/tomo/xgbkb v1.0.1 h1:b3HDUopjdQp1MZrb5Vpil4bOtk3NnNXtfQW27Blw2kE= git.tebibyte.media/tomo/xgbkb v1.0.1 h1:b3HDUopjdQp1MZrb5Vpil4bOtk3NnNXtfQW27Blw2kE=

View File

@ -36,6 +36,7 @@ type parent interface {
window () *window window () *window
canvas () canvas.Canvas canvas () canvas.Canvas
notifyMinimumSizeChange (anyBox) notifyMinimumSizeChange (anyBox)
drawBackgroundPart (canvas.Canvas)
} }
type anyBox interface { type anyBox interface {

View File

@ -46,3 +46,11 @@ func (this *texture) Clip (bounds image.Rectangle) tomo.Texture {
func (this *texture) Close () error { func (this *texture) Close () error {
return nil 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!")
}
}

View File

@ -8,6 +8,7 @@ import "git.tebibyte.media/tomo/x/canvas"
import "git.tebibyte.media/tomo/tomo/data" import "git.tebibyte.media/tomo/tomo/data"
import "git.tebibyte.media/tomo/tomo/input" import "git.tebibyte.media/tomo/tomo/input"
import "git.tebibyte.media/tomo/tomo/event" import "git.tebibyte.media/tomo/tomo/event"
import "git.tebibyte.media/tomo/tomo/canvas"
import "github.com/jezek/xgb/xproto" import "github.com/jezek/xgb/xproto"
import "github.com/jezek/xgbutil/ewmh" import "github.com/jezek/xgbutil/ewmh"
@ -361,6 +362,11 @@ func (window *window) pushRegion (region image.Rectangle) {
subCanvas.(*xcanvas.Canvas).Push(window.xWindow.Id) 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 () { func (window *window) doMinimumSize () {
window.minimumClean = true window.minimumClean = true