Add base dot manipulation implementation
This commit is contained in:
parent
a0fd8a694b
commit
991f72cd8f
13
box.go
13
box.go
@ -132,6 +132,11 @@ func (this *box) SetDNDAccept (types ...data.Mime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *box) SetFocused (focused bool) {
|
func (this *box) SetFocused (focused bool) {
|
||||||
|
if this.parent == nil { return }
|
||||||
|
window := this.parent.window()
|
||||||
|
if window == nil { return }
|
||||||
|
if !this.focusable { return }
|
||||||
|
|
||||||
if this.Focused () && !focused {
|
if this.Focused () && !focused {
|
||||||
this.parent.window().focus(nil)
|
this.parent.window().focus(nil)
|
||||||
} else if !this.Focused() && focused {
|
} else if !this.Focused() && focused {
|
||||||
@ -309,6 +314,14 @@ func (this *box) handleFocusLeave () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *box) handleMouseDown (button input.Button) {
|
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() {
|
for _, listener := range this.on.mouseDown.Listeners() {
|
||||||
listener(button)
|
listener(button)
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ func (this *containerBox) OnContentBoundsChange (callback func()) event.Cookie {
|
|||||||
return this.on.contentBoundsChange.Connect(callback)
|
return this.on.contentBoundsChange.Connect(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *containerBox) PropagateEvents (propagate bool) {
|
func (this *containerBox) SetPropagateEvents (propagate bool) {
|
||||||
this.propagateEvents = propagate
|
this.propagateEvents = propagate
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +143,6 @@ func (this *containerBox) Draw (can canvas.Canvas) {
|
|||||||
pen := can.Pen()
|
pen := can.Pen()
|
||||||
pen.Fill(this.color)
|
pen.Fill(this.color)
|
||||||
|
|
||||||
// TODO: do this in doLayout and save the result
|
|
||||||
rocks := make([]image.Rectangle, len(this.children))
|
rocks := make([]image.Rectangle, len(this.children))
|
||||||
for index, box := range this.children {
|
for index, box := range this.children {
|
||||||
rocks[index] = box.Bounds()
|
rocks[index] = box.Bounds()
|
||||||
|
4
go.mod
4
go.mod
@ -4,15 +4,15 @@ 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.16.0
|
git.tebibyte.media/tomo/tomo v0.17.0
|
||||||
git.tebibyte.media/tomo/typeset v0.4.0
|
git.tebibyte.media/tomo/typeset v0.4.0
|
||||||
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
|
||||||
github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0
|
github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0
|
||||||
|
golang.org/x/image v0.9.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect
|
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect
|
||||||
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect
|
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect
|
||||||
golang.org/x/image v0.9.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
20
go.sum
20
go.sum
@ -1,24 +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.11.0 h1:Gh9c/6rDqvhxt/DaNQHYNUfdRmSQTuz9T3F+pb5W6BI=
|
git.tebibyte.media/tomo/tomo v0.17.0 h1:J+Sxh24o7YDls/18b86VHriilhrGYmObaMbzrYNyVaY=
|
||||||
git.tebibyte.media/tomo/tomo v0.11.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
git.tebibyte.media/tomo/tomo v0.17.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
||||||
git.tebibyte.media/tomo/tomo v0.12.0 h1:MwcudNzo7hSeiEWGSLt6lxJGK3itxTSgdggaZoHZLJo=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.12.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.13.0 h1:xQvEia1vDUfq3QkpU3De72z53ON+y8I6HMP8TDtcS2k=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.13.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.14.0 h1:cMCOLjBEH9OtF+CODn0XFWa9liE0keMnLWs3t66I+Zw=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.14.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.15.0 h1:xjHPB+nq1M2myjFeRU79p3DvuIIG/94hKwFr/OB8cGY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.15.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.16.0 h1:5tgN0Uj+3LSMzvXRLNE8AxgRUOTc/GEw8+TEJKmVGtQ=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.16.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/typeset v0.1.0 h1:ZLwQzy51vUskjg1nB4Emjag8VXn3ki2jEkE19kwVQ4c=
|
|
||||||
git.tebibyte.media/tomo/typeset v0.1.0/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
|
|
||||||
git.tebibyte.media/tomo/typeset v0.2.0 h1:7DcnB0sW12eL+MxkEMv99eVG2IQxsZHDDK6pz6VE1O8=
|
|
||||||
git.tebibyte.media/tomo/typeset v0.2.0/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
|
|
||||||
git.tebibyte.media/tomo/typeset v0.3.0 h1:9koJzy0bguBHjlesrHpXK8odIVEMmQRBIFIRXDhv7Bk=
|
|
||||||
git.tebibyte.media/tomo/typeset v0.3.0/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
|
|
||||||
git.tebibyte.media/tomo/typeset v0.4.0 h1:JdTmbqSJlMtdvqlwXC5AseM1GgG4tyfWcqPFGkHFRpU=
|
git.tebibyte.media/tomo/typeset v0.4.0 h1:JdTmbqSJlMtdvqlwXC5AseM1GgG4tyfWcqPFGkHFRpU=
|
||||||
git.tebibyte.media/tomo/typeset v0.4.0/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
|
git.tebibyte.media/tomo/typeset v0.4.0/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=
|
||||||
|
66
textbox.go
66
textbox.go
@ -5,6 +5,7 @@ import "image/color"
|
|||||||
import "golang.org/x/image/font"
|
import "golang.org/x/image/font"
|
||||||
import "git.tebibyte.media/tomo/tomo"
|
import "git.tebibyte.media/tomo/tomo"
|
||||||
import "git.tebibyte.media/tomo/typeset"
|
import "git.tebibyte.media/tomo/typeset"
|
||||||
|
import "git.tebibyte.media/tomo/tomo/text"
|
||||||
import "git.tebibyte.media/tomo/tomo/event"
|
import "git.tebibyte.media/tomo/tomo/event"
|
||||||
import "git.tebibyte.media/tomo/tomo/canvas"
|
import "git.tebibyte.media/tomo/tomo/canvas"
|
||||||
|
|
||||||
@ -20,11 +21,15 @@ type textBox struct {
|
|||||||
face font.Face
|
face font.Face
|
||||||
wrap bool
|
wrap bool
|
||||||
hAlign tomo.Align
|
hAlign tomo.Align
|
||||||
|
|
||||||
|
selectable bool
|
||||||
|
dot text.Dot
|
||||||
|
|
||||||
drawer typeset.Drawer
|
drawer typeset.Drawer
|
||||||
|
|
||||||
on struct {
|
on struct {
|
||||||
contentBoundsChange event.FuncBroadcaster
|
contentBoundsChange event.FuncBroadcaster
|
||||||
|
dotChange event.FuncBroadcaster
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +93,28 @@ func (this *textBox) SetWrap (wrap bool) {
|
|||||||
this.invalidateLayout()
|
this.invalidateLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *textBox) SetSelectable (selectable bool) {
|
||||||
|
if this.selectable == selectable { return }
|
||||||
|
this.selectable = selectable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) Select (dot text.Dot) {
|
||||||
|
if !this.selectable { return }
|
||||||
|
if this.dot == dot { return }
|
||||||
|
this.SetFocused(true)
|
||||||
|
this.dot = dot
|
||||||
|
this.on.dotChange.Broadcast()
|
||||||
|
this.invalidateDraw()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) Dot () text.Dot {
|
||||||
|
return this.dot
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) OnDotChange (callback func ()) event.Cookie {
|
||||||
|
return this.on.dotChange.Connect(callback)
|
||||||
|
}
|
||||||
|
|
||||||
func (this *textBox) SetAlign (x, y tomo.Align) {
|
func (this *textBox) SetAlign (x, y tomo.Align) {
|
||||||
if this.hAlign == x { return }
|
if this.hAlign == x { return }
|
||||||
this.hAlign = x
|
this.hAlign = x
|
||||||
@ -109,11 +136,46 @@ func (this *textBox) Draw (can canvas.Canvas) {
|
|||||||
pen.Fill(this.color)
|
pen.Fill(this.color)
|
||||||
pen.Rectangle(can.Bounds())
|
pen.Rectangle(can.Bounds())
|
||||||
|
|
||||||
|
if this.selectable && this.Focused() {
|
||||||
|
this.drawDot(can)
|
||||||
|
}
|
||||||
|
|
||||||
if this.face == nil { return }
|
if this.face == nil { return }
|
||||||
offset := this.InnerBounds().Min.
|
this.drawer.Draw(can, this.textColor, this.textOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) drawDot (can canvas.Canvas) {
|
||||||
|
pen := can.Pen()
|
||||||
|
pen.Fill(color.Transparent)
|
||||||
|
pen.Stroke(this.textColor)
|
||||||
|
pen.StrokeWeight(1)
|
||||||
|
|
||||||
|
// TODO draw dot
|
||||||
|
if this.dot.Empty() {
|
||||||
|
metrics := this.face.Metrics()
|
||||||
|
position := this.drawer.PositionAt(this.dot.Start)
|
||||||
|
roundPos :=
|
||||||
|
image.Pt(position.X.Round(), position.Y.Round()).
|
||||||
|
Add(this.textOffset())
|
||||||
|
pen.Path (
|
||||||
|
roundPos.Add(image.Pt(0, metrics.Descent.Round())),
|
||||||
|
roundPos.Sub(image.Pt(0, metrics.Ascent.Round())))
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) textOffset () image.Point {
|
||||||
|
return this.InnerBounds().Min.
|
||||||
Sub(this.scroll).
|
Sub(this.scroll).
|
||||||
Sub(this.drawer.LayoutBoundsSpace().Min)
|
Sub(this.drawer.LayoutBoundsSpace().Min)
|
||||||
this.drawer.Draw(can, this.textColor, offset)
|
}
|
||||||
|
|
||||||
|
func (this *textBox) handleFocusLeave () {
|
||||||
|
this.dot = text.EmptyDot(0)
|
||||||
|
this.on.dotChange.Broadcast()
|
||||||
|
this.invalidateDraw()
|
||||||
|
this.box.handleFocusLeave()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *textBox) normalizedLayoutBoundsSpace () image.Rectangle {
|
func (this *textBox) normalizedLayoutBoundsSpace () image.Rectangle {
|
||||||
|
@ -144,7 +144,7 @@ func (window *window) SetTitle (title string) {
|
|||||||
icccm.WmIconNameSet (window.backend.x, window.xWindow.Id, title)
|
icccm.WmIconNameSet (window.backend.x, window.xWindow.Id, title)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) SetIcon (sizes []image.Image) {
|
func (window *window) SetIcon (sizes ...image.Image) {
|
||||||
wmIcons := []ewmh.WmIcon { }
|
wmIcons := []ewmh.WmIcon { }
|
||||||
|
|
||||||
for _, icon := range sizes {
|
for _, icon := range sizes {
|
||||||
|
Reference in New Issue
Block a user