From 2ecfafa46995c0b0ac29714fa9df9190b458f006 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Sat, 9 Sep 2023 15:05:08 -0400 Subject: [PATCH] Upgrade tomo version --- box.go | 11 ++++++- containerbox.go | 34 +++++++++++++++------ event.go | 79 +++++++++++++++++++++++++++++++++++++++---------- go.mod | 2 +- go.sum | 4 +-- system.go | 37 ++++++++++++++++++++--- textbox.go | 2 +- window.go | 14 +++++++++ 8 files changed, 149 insertions(+), 34 deletions(-) diff --git a/box.go b/box.go index fa5c260..7aad19c 100644 --- a/box.go +++ b/box.go @@ -259,6 +259,11 @@ func (this *box) handleMouseUp (button input.Button) { listener(button) } } +func (this *box) handleScroll (x, y float64) { + for _, listener := range this.on.scroll.Listeners() { + listener(x, y) + } +} func (this *box) handleKeyDown (key input.Key, numberPad bool) { for _, listener := range this.on.keyDown.Listeners() { listener(key, numberPad) @@ -374,6 +379,10 @@ func (this *box) setParent (parent parent) { this.parent = parent } +func (this *box) getParent () parent { + return this.parent +} + func (this *box) flushActionQueue () { if this.parent == nil || this.parent.window() == nil { return } @@ -412,7 +421,7 @@ func (this *box) canBeFocused () bool { return this.focusable } -func (this *box) boxUnder (point image.Point) anyBox { +func (this *box) boxUnder (point image.Point, category eventCategory) anyBox { if point.In(this.bounds) { return this.outer } else { diff --git a/containerbox.go b/containerbox.go index 9432766..de2df3f 100644 --- a/containerbox.go +++ b/containerbox.go @@ -13,11 +13,11 @@ type containerBox struct { hAlign, vAlign tomo.Align contentBounds image.Rectangle scroll image.Point + capture [4]bool gap image.Point children []tomo.Box layout tomo.Layout - propagateEvents bool on struct { contentBoundsChange event.FuncBroadcaster @@ -25,7 +25,7 @@ type containerBox struct { } func (backend *Backend) NewContainerBox() tomo.ContainerBox { - this := &containerBox { propagateEvents: true } + this := &containerBox { } this.box = backend.newBox(this) return this } @@ -68,8 +68,20 @@ func (this *containerBox) OnContentBoundsChange (callback func()) event.Cookie { return this.on.contentBoundsChange.Connect(callback) } -func (this *containerBox) SetPropagateEvents (propagate bool) { - this.propagateEvents = propagate +func (this *containerBox) CaptureDND (capture bool) { + this.capture[eventCategoryDND] = capture +} + +func (this *containerBox) CaptureMouse (capture bool) { + this.capture[eventCategoryMouse] = capture +} + +func (this *containerBox) CaptureScroll (capture bool) { + this.capture[eventCategoryScroll] = capture +} + +func (this *containerBox) CaptureKeyboard (capture bool) { + this.capture[eventCategoryKeyboard] = capture } func (this *containerBox) SetGap (gap image.Point) { @@ -175,7 +187,7 @@ func (this *containerBox) drawBackgroundPart (can canvas.Canvas) { func (this *containerBox) invalidateTransparentChildren () { window := this.window() - if this.window == nil { return } + if window == nil { return } for _, box := range this.children { box := assertAnyBox(box) if box.transparent() { @@ -251,15 +263,15 @@ func (this *containerBox) recursiveRedo () { } } -func (this *containerBox) boxUnder (point image.Point) anyBox { - if this.propagateEvents { +func (this *containerBox) boxUnder (point image.Point, category eventCategory) anyBox { + if !this.capture[category] { for _, box := range this.children { - candidate := box.(anyBox).boxUnder(point) + candidate := box.(anyBox).boxUnder(point, category) if candidate != nil { return candidate } } } - return this.box.boxUnder(point) + return this.box.boxUnder(point, category) } func (this *containerBox) propagate (callback func (anyBox) bool) bool { @@ -281,3 +293,7 @@ func (this *containerBox) propagateAlt (callback func (anyBox) bool) bool { return true } + +func (this *containerBox) captures (category eventCategory) bool { + return this.capture[category] +} diff --git a/event.go b/event.go index d83bdd6..ad55ecf 100644 --- a/event.go +++ b/event.go @@ -8,6 +8,31 @@ import "git.tebibyte.media/tomo/xgbkb" import "github.com/jezek/xgbutil/xevent" import "git.tebibyte.media/tomo/tomo/input" +type scrollSum struct { + x, y int +} + +// TODO: this needs to be configurable, we need a config api +const scrollDistance = 16 + +func (sum *scrollSum) add (button xproto.Button, window *window, state uint16) { + if xgbkb.StateToModifiers(state).Shift { + switch button { + case 4: sum.x -= scrollDistance + case 5: sum.x += scrollDistance + case 6: sum.y -= scrollDistance + case 7: sum.y += scrollDistance + } + } else { + switch button { + case 4: sum.y -= scrollDistance + case 5: sum.y += scrollDistance + case 6: sum.x -= scrollDistance + case 7: sum.x += scrollDistance + } + } +} + var buttonCodeTable = map[xproto.Keysym] input.Key { 0xFFFFFF: input.KeyNone, @@ -208,7 +233,7 @@ func (window *window) handleKeyPress ( } else if key == input.KeyEscape && window.shy { window.Close() } else if window.focused != nil { - window.focused.handleKeyDown(key, numberPad) + window.keyboardTarget().handleKeyDown(key, numberPad) } } @@ -241,7 +266,7 @@ func (window *window) handleKeyRelease ( window.updateModifiers(keyEvent.State) if window.focused != nil { - window.focused.handleKeyUp(key, numberPad) + window.keyboardTarget().handleKeyUp(key, numberPad) } } @@ -261,20 +286,15 @@ func (window *window) handleButtonPress ( if !insideWindow && window.shy && !scrolling { window.Close() } else if scrolling { - // TODO - // underneath := window.scrollTargetChildAt(point) - // if underneath != nil { - // if child, ok := underneath.element.(ability.ScrollTarget); ok { - // sum := scrollSum { } - // sum.add(buttonEvent.Detail, window, buttonEvent.State) - // window.compressScrollSum(buttonEvent, &sum) - // child.HandleScroll ( - // point, float64(sum.x), float64(sum.y), - // modifiers) - // } - // } + underneath := window.boxUnder(point, eventCategoryScroll) + if underneath != nil { + sum := scrollSum { } + sum.add(buttonEvent.Detail, window, buttonEvent.State) + window.compressScrollSum(buttonEvent, &sum) + underneath.handleScroll(float64(sum.x), float64(sum.y)) + } } else { - underneath := window.boxUnder(point) + underneath := window.boxUnder(point, eventCategoryMouse) window.drags[buttonEvent.Detail] = underneath if underneath != nil { underneath.handleMouseDown(input.Button(buttonEvent.Detail)) @@ -318,7 +338,7 @@ func (window *window) handleMotionNotify ( handled = true } - underneath := window.boxUnder(image.Pt(x, y)) + underneath := window.boxUnder(image.Pt(x, y), eventCategoryMouse) window.hover(underneath) if !handled { @@ -391,6 +411,33 @@ func (window *window) compressConfigureNotify ( return } +func (window *window) compressScrollSum ( + firstEvent xproto.ButtonPressEvent, + sum *scrollSum, +) { + window.backend.x.Sync() + xevent.Read(window.backend.x, false) + + for index, untypedEvent := range xevent.Peek(window.backend.x) { + if untypedEvent.Err != nil { continue } + + typedEvent, ok := untypedEvent.Event.(xproto.ButtonPressEvent) + if !ok { continue } + + if firstEvent.Event == typedEvent.Event && + typedEvent.Detail >= 4 && + typedEvent.Detail <= 7 { + + sum.add(typedEvent.Detail, window, typedEvent.State) + defer func (index int) { + xevent.DequeueAt(window.backend.x, index) + } (index) + } + } + + return +} + func (window *window) compressMotionNotify ( firstEvent xproto.MotionNotifyEvent, ) ( diff --git a/go.mod b/go.mod index d550fe3..6816911 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module git.tebibyte.media/tomo/x go 1.20 require ( - git.tebibyte.media/tomo/tomo v0.28.0 + git.tebibyte.media/tomo/tomo v0.29.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 6f9bc2d..66b6f4d 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ git.tebibyte.media/sashakoshka/xgbkb v1.0.0/go.mod h1:pNcE6TRO93vHd6q42SdwLSTTj25L0Yzggz7yLe0JV6Q= -git.tebibyte.media/tomo/tomo v0.28.0 h1:wB+RpYw48Jn2DUQhXwdUe54BnYJf/79On3jxnBYvQ1Q= -git.tebibyte.media/tomo/tomo v0.28.0/go.mod h1:C9EzepS9wjkTJjnZaPBh22YvVPyA4hbBAJVU20Rdmps= +git.tebibyte.media/tomo/tomo v0.29.0 h1:uvdPaEQYcWH965y85SjIKwhLklnTbs+x6MRwLfdRvfo= +git.tebibyte.media/tomo/tomo v0.29.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 ac06803..c1fb1db 100644 --- a/system.go +++ b/system.go @@ -37,6 +37,7 @@ type parent interface { canvas () canvas.Canvas notifyMinimumSizeChange (anyBox) drawBackgroundPart (canvas.Canvas) + captures (eventCategory) bool } type anyBox interface { @@ -48,10 +49,11 @@ type anyBox interface { doMinimumSize () contentMinimum () image.Point setParent (parent) + getParent () parent flushActionQueue () recursiveRedo () canBeFocused () bool - boxUnder (image.Point) anyBox + boxUnder (image.Point, eventCategory) anyBox transparent () bool propagate (func (anyBox) bool) bool @@ -67,7 +69,7 @@ type anyBox interface { handleMouseMove () handleMouseDown (input.Button) handleMouseUp (input.Button) - // handleScroll (float64, float64) + handleScroll (float64, float64) handleKeyDown (input.Key, bool) handleKeyUp (input.Key, bool) } @@ -153,9 +155,36 @@ func (window *window) anyFocused () bool { return window.focused != nil } -func (this *window) boxUnder (point image.Point) anyBox { +type eventCategory int; const ( + eventCategoryDND eventCategory = iota + eventCategoryMouse + eventCategoryScroll + eventCategoryKeyboard +) + +func (this *window) boxUnder (point image.Point, category eventCategory) anyBox { if this.root == nil { return nil } - return this.root.boxUnder(point) + return this.root.boxUnder(point, category) +} + +func (this *window) captures (eventCategory) bool { + return false +} + +func (this *window) keyboardTarget () anyBox { + focused := this.window().focused + if focused == nil { return nil } + parent := focused.getParent() + for { + parentBox, ok := parent.(anyBox) + if !ok { break } + if parent.captures(eventCategoryKeyboard) { + return parentBox + } + parent = parentBox.getParent() + } + + return focused } func (this *window) focusNext () { diff --git a/textbox.go b/textbox.go index 7d36dd7..d277467 100644 --- a/textbox.go +++ b/textbox.go @@ -298,7 +298,7 @@ func (this *textBox) doLayout () { this.drawer.SetMaxWidth(innerBounds.Dx()) this.drawer.SetMaxHeight(innerBounds.Dy()) - this.contentBounds = this.normalizedLayoutBoundsSpace().Sub(this.scroll) + this.contentBounds = this.normalizedLayoutBoundsSpace().Add(this.scroll) if previousContentBounds != this.contentBounds { this.on.contentBoundsChange.Broadcast() diff --git a/window.go b/window.go index 288e571..9e52c6a 100644 --- a/window.go +++ b/window.go @@ -73,6 +73,20 @@ func (backend *Backend) NewWindow ( return output, err } +func (backend *Backend) NewPlainWindow ( + bounds image.Rectangle, +) ( + output tomo.MainWindow, + err error, +) { + backend.assert() + window, err := backend.newWindow(bounds, false) + window.setType("dock") + + output = mainWindow { window: window } + return output, err +} + func (backend *Backend) newWindow ( bounds image.Rectangle, override bool,