Skip to content

Commit

Permalink
Merge pull request #1337 from cogentcore/focus
Browse files Browse the repository at this point in the history
Added Deferred functions, set by Defer method, which are called after…
  • Loading branch information
kkoreilly authored Nov 25, 2024
2 parents 6908afa + d73f69e commit 3857cf6
Show file tree
Hide file tree
Showing 29 changed files with 154 additions and 100 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:

# we can't test gpu, xyz, and system on the CI since there is no Vulkan support
- name: Test
run: go test -v $(go list ./... | grep -v gpu | grep -v xyz | grep -v system) -coverprofile cover.out
run: go test -v $(go list ./... | grep -v gpu | grep -v xyz | grep -v system) -coverprofile cover.out -timeout 30s

- name: Update coverage report
uses: ncruces/go-coverage-report@v0
Expand Down
10 changes: 5 additions & 5 deletions core/enumgen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 15 additions & 15 deletions core/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,12 @@ func (em *Events) handleFocusEvent(e events.Event) {
if DebugSettings.FocusTrace {
fmt.Println(em.scene, "StartFocus:", em.startFocus)
}
em.setFocusEvent(em.startFocus)
em.setFocus(em.startFocus)
case em.prevFocus != nil:
if DebugSettings.FocusTrace {
fmt.Println(em.scene, "PrevFocus:", em.prevFocus)
}
em.setFocusEvent(em.prevFocus)
em.setFocus(em.prevFocus)
em.prevFocus = nil
}
}
Expand Down Expand Up @@ -881,14 +881,14 @@ func (em *Events) focusClear() bool {
}
em.prevFocus = em.focus
}
return em.setFocusEvent(nil)
return em.setFocus(nil)
}

// setFocus sets focus to given item, and returns true if focus changed.
// setFocusQuiet sets focus to given item, and returns true if focus changed.
// If item is nil, then nothing has focus.
// This does NOT send the events.Focus event to the widget.
// See [SetFocusEvent] for version that does send event.
func (em *Events) setFocus(w Widget) bool {
// This does NOT send the [events.Focus] event to the widget.
// See [Events.setFocus] for version that does send an event.
func (em *Events) setFocusQuiet(w Widget) bool {
if DebugSettings.FocusTrace {
fmt.Println(em.scene, "SetFocus:", w)
}
Expand All @@ -905,11 +905,11 @@ func (em *Events) setFocus(w Widget) bool {
return got
}

// setFocusEvent sets focus to given item, and returns true if focus changed.
// setFocus sets focus to given item, and returns true if focus changed.
// If item is nil, then nothing has focus.
// This sends the [events.Focus] event to the widget.
// See [SetFocus] for a version that does not.
func (em *Events) setFocusEvent(w Widget) bool {
// See [Events.setFocusQuiet] for a version that does not.
func (em *Events) setFocus(w Widget) bool {
if DebugSettings.FocusTrace {
fmt.Println(em.scene, "SetFocusEvent:", w)
}
Expand Down Expand Up @@ -975,7 +975,7 @@ func (em *Events) FocusNextFrom(from Widget) bool {
wb := w.AsWidget()
return wb.IsVisible() && !wb.StateIs(states.Disabled) && wb.AbilityIs(abilities.Focusable)
})
em.setFocusEvent(next)
em.setFocus(next)
return next != nil
}

Expand All @@ -991,7 +991,7 @@ func (em *Events) focusOnOrNext(foc Widget) bool {
return false
}
if wb.AbilityIs(abilities.Focusable) {
em.setFocusEvent(foc)
em.setFocus(foc)
return true
}
return em.FocusNextFrom(foc)
Expand All @@ -1009,7 +1009,7 @@ func (em *Events) focusOnOrPrev(foc Widget) bool {
return false
}
if wb.AbilityIs(abilities.Focusable) {
em.setFocusEvent(foc)
em.setFocus(foc)
return true
}
return em.focusPrevFrom(foc)
Expand All @@ -1031,7 +1031,7 @@ func (em *Events) focusPrevFrom(from Widget) bool {
wb := w.AsWidget()
return wb.IsVisible() && !wb.StateIs(states.Disabled) && wb.AbilityIs(abilities.Focusable)
})
em.setFocusEvent(prev)
em.setFocus(prev)
return prev != nil
}

Expand Down Expand Up @@ -1072,7 +1072,7 @@ func (em *Events) activateStartFocus() bool {
em.focusFirst()
} else {
// fmt.Println("start focus on:", sf)
em.setFocusEvent(sf)
em.setFocus(sf)
}
return true
}
Expand Down
2 changes: 1 addition & 1 deletion core/filepicker.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (fp *FilePicker) Init() {
case keymap.Search:
e.SetHandled()
sf := fp.selectField
sf.SetFocusEvent()
sf.SetFocus()
}
})

Expand Down
2 changes: 1 addition & 1 deletion core/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ func (fr *Frame) focusOnName(e events.Event) bool {
if focel != nil {
em := fr.Events()
if em != nil {
em.setFocusEvent(focel.(Widget)) // this will also scroll by default!
em.setFocus(focel.(Widget)) // this will also scroll by default!
}
fr.focusNameLast = focel
return true
Expand Down
4 changes: 2 additions & 2 deletions core/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ func (lb *ListBase) MakeGrid(p *tree.Plan, maker func(p *tree.Plan)) {
s.Min.Y.Em(6)
})
oc := func(e events.Event) {
lb.SetFocusEvent()
lb.SetFocus()
row, _, isValid := w.indexFromPixel(e.Pos())
if isValid {
lb.updateSelectRow(row, e.SelectMode())
Expand Down Expand Up @@ -868,7 +868,7 @@ func (lb *ListBase) RowGrabFocus(row int) *WidgetBase {
return w
}
lb.InFocusGrab = true
w.SetFocusEvent()
w.SetFocus()
lb.InFocusGrab = false
return w
}
Expand Down
2 changes: 1 addition & 1 deletion core/mainstage.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ func (st *Stage) runDialog() *Stage {

// if our main stages are nil, we wait until our context is shown and then try again
if ctx.Scene.Stage == nil || ctx.Scene.Stage.Mains == nil {
ctx.OnShow(func(e events.Event) {
ctx.Defer(func() {
st.runDialog()
})
return st
Expand Down
1 change: 1 addition & 0 deletions core/pages.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func (pg *Pages) Init() {
}
pg.page = pg.Page
fun(pg)
pg.DeferShown()
})
}

Expand Down
2 changes: 1 addition & 1 deletion core/popupstage.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (st *Stage) runPopup() *Stage {
// if our context stage is nil, we wait until
// our context is shown and then try again
if ctx.Scene.Stage == nil {
ctx.OnShow(func(e events.Event) {
ctx.Defer(func() {
st.runPopup()
})
return st
Expand Down
59 changes: 49 additions & 10 deletions core/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"cogentcore.org/core/base/profile"
"cogentcore.org/core/colors"
"cogentcore.org/core/colors/cam/hct"
"cogentcore.org/core/events"
"cogentcore.org/core/math32"
"cogentcore.org/core/styles"
"cogentcore.org/core/tree"
Expand Down Expand Up @@ -213,12 +214,8 @@ func (sc *Scene) doUpdate() bool {
}

if sc.showIter == sceneShowIters { // end of first pass
sc.showIter++
if !sc.hasFlag(sceneContentSizing) {
sc.Events.activateStartFocus()
}
sc.showIter++ // just go 1 past the iters cutoff
}

return true
}

Expand Down Expand Up @@ -399,8 +396,51 @@ func (wb *WidgetBase) renderChildren() {
})
}

////////////////////////////////////////////////////////////////////////////////
// Standard Box Model rendering
//////// Defer

// Defer adds a function to [WidgetBase.Deferred] that will be called after the next
// [Scene] update/render, including on the initial Scene render. After the function
// is called, it is removed and not called again. In the function, sending events
// etc will work as expected.
func (wb *WidgetBase) Defer(fun func()) {
wb.Deferred = append(wb.Deferred, fun)
if wb.Scene != nil {
wb.Scene.setFlag(true, sceneHasDeferred)
}
}

// runDeferred runs deferred functions on all widgets in the scene.
func (sc *Scene) runDeferred() {
sc.WidgetWalkDown(func(cw Widget, cwb *WidgetBase) bool {
for _, f := range cwb.Deferred {
f()
}
cwb.Deferred = nil
return tree.Continue
})
}

// DeferShown adds a [WidgetBase.Defer] function to call [WidgetBase.Shown]
// and activate [WidgetBase.StartFocus]. For example, this is called in [Tabs]
// and [Pages] when a tab/page is newly shown, so that elements can perform
// [WidgetBase.OnShow] updating as needed.
func (wb *WidgetBase) DeferShown() {
wb.Defer(func() {
wb.Shown()
wb.Scene.Events.activateStartFocus()
})
}

// Shown sends [events.Show] to all widgets from this one down. Also see
// [WidgetBase.DeferShown].
func (wb *WidgetBase) Shown() {
wb.WidgetWalkDown(func(cw Widget, cwb *WidgetBase) bool {
cwb.Send(events.Show)
return tree.Continue
})
}

//////// Standard Box Model rendering

// RenderBoxGeom renders a box with the given geometry.
func (wb *WidgetBase) RenderBoxGeom(pos math32.Vector2, sz math32.Vector2, bs styles.Border) {
Expand All @@ -414,8 +454,7 @@ func (wb *WidgetBase) RenderStandardBox() {
wb.Scene.PaintContext.DrawStandardBox(&wb.Styles, pos, sz, wb.parentActualBackground())
}

//////////////////////////////////////////////////////////////////
// Widget position functions
//////// Widget position functions

// PointToRelPos translates a point in Scene pixel coords
// into relative position within node, based on the Content BBox
Expand Down Expand Up @@ -446,7 +485,7 @@ func (wb *WidgetBase) winPos(x, y float32) image.Point {
return pt
}

// Profiling and Benchmarking, controlled by settings app bar:
//////// Profiling and Benchmarking, controlled by settings app bar

// ProfileToggle turns profiling on or off, which does both
// targeted profiling and global CPU and memory profiling.
Expand Down
2 changes: 1 addition & 1 deletion core/renderwindow.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ func (w *renderWindow) handleWindowEvents(e events.Event) {
rc.unlock() // one case where we need to break lock
w.renderWindow()
rc.lock()
w.mains.sendShowEvents()
w.mains.runDeferred() // note: must be outside of locks in renderWindow

case events.WindowResize:
e.SetHandled()
Expand Down
3 changes: 3 additions & 0 deletions core/scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ const (
// sceneNeedsLayout is whether the Scene needs a new layout pass.
sceneNeedsLayout

// sceneHasDeferred is whether the Scene has elements with Deferred functions.
sceneHasDeferred

// sceneImageUpdated indicates that the Scene's image has been updated
// e.g., due to a render or a resize. This is reset by the
// global [RenderWindow] rendering pass, so it knows whether it needs to
Expand Down
24 changes: 13 additions & 11 deletions core/stages.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import (
"sync"

"cogentcore.org/core/base/ordmap"
"cogentcore.org/core/events"
"cogentcore.org/core/math32"
"cogentcore.org/core/tree"
)

// stages manages a stack of [Stage]s.
Expand Down Expand Up @@ -246,25 +244,29 @@ func (sm *stages) windowStage() *Stage {
return nil
}

func (sm *stages) sendShowEvents() {
func (sm *stages) runDeferred() {
for _, kv := range sm.stack.Order {
st := kv.Value
if st.Scene == nil {
continue
}
sc := st.Scene
if sc.hasFlag(sceneContentSizing) {
continue
}
if sc.hasFlag(sceneHasDeferred) {
sc.setFlag(false, sceneHasDeferred)
sc.runDeferred()
}

if sc.showIter == sceneShowIters+1 {
sc.showIter++
if !sc.hasFlag(sceneHasShown) {
if !sc.hasFlag(sceneContentSizing) {
sc.Events.activateStartFocus()
}
sc.setFlag(true, sceneHasShown)
// profile.Profiling = true
// pr := profile.Start("send show")
sc.WidgetWalkDown(func(cw Widget, cwb *WidgetBase) bool {
cwb.Send(events.Show)
return tree.Continue
})
// pr.End()
// profile.Report(time.Millisecond)
sc.Shown()
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ func (tb *Table) RowGrabFocus(row int) *WidgetBase {
for fli := 0; fli < tb.numVisibleFields; fli++ {
w := lg.Child(ridx + idxOff + fli).(Widget).AsWidget()
if w.CanFocus() {
w.SetFocusEvent()
w.SetFocus()
return w
}
}
Expand Down
1 change: 1 addition & 0 deletions core/tabs.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ func (ts *Tabs) SelectTabIndex(idx int) *Frame {
tab.SetSelected(true)
fr.StackTop = idx
fr.Update()
frame.DeferShown()
ts.mu.Unlock()
return frame
}
Expand Down
2 changes: 1 addition & 1 deletion core/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func (tx *Text) Init() {
})
tx.OnDoubleClick(func(e events.Event) {
tx.SetSelected(true)
tx.SetFocus()
tx.SetFocusQuiet()
})
tx.OnFocusLost(func(e events.Event) {
tx.SetSelected(false)
Expand Down
Loading

0 comments on commit 3857cf6

Please sign in to comment.