From 4ee042973b8a587d013da9679e80f5acf73b9633 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Tue, 20 Aug 2024 23:24:51 -0700 Subject: [PATCH 1/8] web expanded size converts NewWindow Dialog -> nomodal --- core/mainstage.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/mainstage.go b/core/mainstage.go index 7031fa5e67..df636330f9 100644 --- a/core/mainstage.go +++ b/core/mainstage.go @@ -165,9 +165,18 @@ func (st *Stage) firstWindowStages() *stages { // configMainStage does main-stage configuration steps func (st *Stage) configMainStage() { + sc := st.Scene if st.NewWindow { st.FullWindow = true } + if st.NewWindow && st.Type == DialogStage && TheApp.Platform() == system.Web && st.Context != nil { + if st.Context.AsWidget().SizeClass() == SizeExpanded { + st.NewWindow = false + st.FullWindow = false + st.Modal = false + st.Scrim = false + } + } // if we are on mobile, we can never have new windows if TheApp.Platform().IsMobile() { st.NewWindow = false @@ -175,7 +184,6 @@ func (st *Stage) configMainStage() { if st.FullWindow || st.NewWindow { st.Scrim = false } - sc := st.Scene sc.makeSceneBars() sc.updateScene() } From 6fb47e93d1ceebcf989bd14cc6ccf8954670b5ea Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Wed, 21 Aug 2024 00:30:33 -0700 Subject: [PATCH 2/8] events: when spawning secondary event (e.g., SlideMove), mark primary (MouseDrag) as handled, because otherwise the handler that deals with the SlideMove will not suppress the continued sending of the MouseDrag to other levels, defeating the purpose of marking event as handled! This fixes dragging of non-modal dialogs. also automatically absorb any non-handled events that occur within bounds of non-modal dialog. --- core/events.go | 9 +++++++-- core/handle.go | 1 + core/mainstage.go | 10 ++++++++++ xyz/xyzcore/manip.go | 1 + 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/core/events.go b/core/events.go index dd108e0346..648ce523ec 100644 --- a/core/events.go +++ b/core/events.go @@ -249,11 +249,13 @@ func (em *Events) handlePosEvent(e events.Event) { em.resetOnMouseDown() case events.MouseDrag: if em.spriteSlide != nil { + e.SetHandled() em.spriteSlide.handleEvent(e) em.spriteSlide.send(events.SlideMove, e) return } if em.slide != nil { + e.SetHandled() em.slide.AsWidget().HandleEvent(e) em.slide.AsWidget().Send(events.SlideMove, e) return @@ -397,17 +399,19 @@ func (em *Events) handlePosEvent(e events.Event) { } } em.dragHovers = em.updateHovers(hovs, em.dragHovers, e, events.DragEnter, events.DragLeave) - em.dragMove(e) // updates sprite position - em.drag.AsWidget().HandleEvent(e) // raw drag + em.dragMove(e) // updates sprite position + e.SetHandled() em.drag.AsWidget().Send(events.DragMove, e) // usually ignored } else { if em.dragPress != nil && em.dragStartCheck(e, DeviceSettings.DragStartTime, DeviceSettings.DragStartDistance) { em.cancelRepeatClick() em.cancelLongPress() + e.SetHandled() em.dragPress.AsWidget().Send(events.DragStart, e) } else if em.slidePress != nil && em.dragStartCheck(e, DeviceSettings.SlideStartTime, DeviceSettings.DragStartDistance) { em.cancelRepeatClick() em.cancelLongPress() + e.SetHandled() em.slide = em.slidePress em.slide.AsWidget().Send(events.SlideStart, e) } @@ -419,6 +423,7 @@ func (em *Events) handlePosEvent(e events.Event) { case events.MouseUp: em.cancelRepeatClick() if em.slide != nil { + e.SetHandled() em.slide.AsWidget().Send(events.SlideStop, e) em.slide = nil em.press = nil diff --git a/core/handle.go b/core/handle.go index 358bcad1ca..3cf2ac538a 100644 --- a/core/handle.go +++ b/core/handle.go @@ -62,6 +62,7 @@ func (hl *Handle) Init() { }) hl.On(events.SlideMove, func(e events.Event) { + e.SetHandled() pos := hl.parentWidget().PointToRelPos(e.Pos()) hl.Pos = math32.FromPoint(pos).Dim(hl.Styles.Direction.Dim()) hl.SendChange(e) diff --git a/core/mainstage.go b/core/mainstage.go index df636330f9..33ae86b75e 100644 --- a/core/mainstage.go +++ b/core/mainstage.go @@ -406,5 +406,15 @@ func (sm *stages) mainHandleEvent(e events.Event) { if e.IsHandled() || st.Modal || st.Type == WindowStage || st.FullWindow { break } + if st.Type == DialogStage { // modal dialog, by definition + if e.HasPos() { + b := st.Scene.SceneGeom.Bounds() + b.Min.Y -= 10 // include a buffer around for dialog decoration + b.Max.Y += 10 + if e.WindowPos().In(b) { // don't propagate + break + } + } + } } } diff --git a/xyz/xyzcore/manip.go b/xyz/xyzcore/manip.go index 2f2feac085..aab3b8693d 100644 --- a/xyz/xyzcore/manip.go +++ b/xyz/xyzcore/manip.go @@ -218,6 +218,7 @@ func (sw *Scene) handleSelectEventsImpl(e events.Event) { func (sw *Scene) handleSlideEvents() { sw.On(events.SlideMove, func(e events.Event) { + e.SetHandled() pos := sw.Geom.ContentBBox.Min e.SetLocalOff(e.LocalOff().Add(pos)) xy := sw.XYZ From 79493427f1783737034623f9de7b8b00bd0e87ab Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Wed, 21 Aug 2024 00:33:31 -0700 Subject: [PATCH 3/8] remove unnec. bounds expansion now that handling logic is fixed. --- core/mainstage.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/mainstage.go b/core/mainstage.go index 33ae86b75e..3fdab7cd14 100644 --- a/core/mainstage.go +++ b/core/mainstage.go @@ -409,8 +409,6 @@ func (sm *stages) mainHandleEvent(e events.Event) { if st.Type == DialogStage { // modal dialog, by definition if e.HasPos() { b := st.Scene.SceneGeom.Bounds() - b.Min.Y -= 10 // include a buffer around for dialog decoration - b.Max.Y += 10 if e.WindowPos().In(b) { // don't propagate break } From ac2aca211d26291dcd95f5e866ab4e243a95fbf2 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Wed, 21 Aug 2024 10:05:11 -0700 Subject: [PATCH 4/8] fixes for kai's comments --- core/events.go | 14 +++++++------- core/mainstage.go | 12 +++++------- core/value.go | 4 +++- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/core/events.go b/core/events.go index 648ce523ec..45c2cfcff7 100644 --- a/core/events.go +++ b/core/events.go @@ -249,15 +249,15 @@ func (em *Events) handlePosEvent(e events.Event) { em.resetOnMouseDown() case events.MouseDrag: if em.spriteSlide != nil { - e.SetHandled() em.spriteSlide.handleEvent(e) em.spriteSlide.send(events.SlideMove, e) + e.SetHandled() return } if em.slide != nil { - e.SetHandled() em.slide.AsWidget().HandleEvent(e) em.slide.AsWidget().Send(events.SlideMove, e) + e.SetHandled() return } case events.Scroll: @@ -399,21 +399,21 @@ func (em *Events) handlePosEvent(e events.Event) { } } em.dragHovers = em.updateHovers(hovs, em.dragHovers, e, events.DragEnter, events.DragLeave) - em.dragMove(e) // updates sprite position - e.SetHandled() + em.dragMove(e) // updates sprite position em.drag.AsWidget().Send(events.DragMove, e) // usually ignored + e.SetHandled() } else { if em.dragPress != nil && em.dragStartCheck(e, DeviceSettings.DragStartTime, DeviceSettings.DragStartDistance) { em.cancelRepeatClick() em.cancelLongPress() - e.SetHandled() em.dragPress.AsWidget().Send(events.DragStart, e) + e.SetHandled() } else if em.slidePress != nil && em.dragStartCheck(e, DeviceSettings.SlideStartTime, DeviceSettings.DragStartDistance) { em.cancelRepeatClick() em.cancelLongPress() - e.SetHandled() em.slide = em.slidePress em.slide.AsWidget().Send(events.SlideStart, e) + e.SetHandled() } } // if we already have a long press widget, we update it based on our dragging movement @@ -423,8 +423,8 @@ func (em *Events) handlePosEvent(e events.Event) { case events.MouseUp: em.cancelRepeatClick() if em.slide != nil { - e.SetHandled() em.slide.AsWidget().Send(events.SlideStop, e) + e.SetHandled() em.slide = nil em.press = nil } diff --git a/core/mainstage.go b/core/mainstage.go index 3fdab7cd14..35202a2a75 100644 --- a/core/mainstage.go +++ b/core/mainstage.go @@ -169,13 +169,11 @@ func (st *Stage) configMainStage() { if st.NewWindow { st.FullWindow = true } - if st.NewWindow && st.Type == DialogStage && TheApp.Platform() == system.Web && st.Context != nil { - if st.Context.AsWidget().SizeClass() == SizeExpanded { - st.NewWindow = false - st.FullWindow = false - st.Modal = false - st.Scrim = false - } + if st.NewWindow && st.Type == DialogStage && TheApp.Platform().IsMobile() && st.Context != nil && st.Context.AsWidget().SizeClass() != SizeCompact { + st.NewWindow = false + st.FullWindow = false + st.Modal = false + st.Scrim = false } // if we are on mobile, we can never have new windows if TheApp.Platform().IsMobile() { diff --git a/core/value.go b/core/value.go index 18a445ab41..20e080771d 100644 --- a/core/value.go +++ b/core/value.go @@ -116,7 +116,9 @@ func InitValueButton(v Value, allowReadOnly bool, make func(d *Body), after ...f } wb.OnClick(func(e events.Event) { if allowReadOnly || !wb.IsReadOnly() { - wb.setFlag(e.HasAnyModifier(key.Shift), widgetValueNewWindow) + if e.HasAnyModifier(key.Shift) { + wb.setFlag(!wb.hasFlag(widgetValueNewWindow), widgetValueNewWindow) + } openValueDialog(v, make, after...) } }) From 5d93aabc953fef060ccbce6a0e4791201d98ba98 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Wed, 21 Aug 2024 10:19:06 -0700 Subject: [PATCH 5/8] process new-window:"+" tag to set default to open a new window dialog for pointer item --- core/style.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/style.go b/core/style.go index 3f20961014..1d6f6410f5 100644 --- a/core/style.go +++ b/core/style.go @@ -225,4 +225,7 @@ func styleFromTags(w Widget, tags reflect.StructTag) { setFromTag(tags, "grow", func(v float32) { s.Grow.X = v }) setFromTag(tags, "grow-y", func(v float32) { s.Grow.Y = v }) }) + if v, ok := tags.Lookup("new-window"); ok && v == "+" { + w.AsWidget().setFlag(true, widgetValueNewWindow) + } } From 0617cc1f11a3151ba0f1c42e4002e5f8b3efdf47 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Wed, 21 Aug 2024 10:26:42 -0700 Subject: [PATCH 6/8] nil guard for closing windows --- core/mainstage.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mainstage.go b/core/mainstage.go index 35202a2a75..2b6e4ac388 100644 --- a/core/mainstage.go +++ b/core/mainstage.go @@ -405,7 +405,7 @@ func (sm *stages) mainHandleEvent(e events.Event) { break } if st.Type == DialogStage { // modal dialog, by definition - if e.HasPos() { + if e.HasPos() && st.Scene != nil { b := st.Scene.SceneGeom.Bounds() if e.WindowPos().In(b) { // don't propagate break From 430d609963be50fd18aac6d301b8fbf3c8183fe9 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Wed, 21 Aug 2024 10:43:39 -0700 Subject: [PATCH 7/8] kai fixes --- core/events.go | 1 + core/mainstage.go | 2 +- core/style.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/events.go b/core/events.go index 45c2cfcff7..64f4b986ef 100644 --- a/core/events.go +++ b/core/events.go @@ -400,6 +400,7 @@ func (em *Events) handlePosEvent(e events.Event) { } em.dragHovers = em.updateHovers(hovs, em.dragHovers, e, events.DragEnter, events.DragLeave) em.dragMove(e) // updates sprite position + em.drag.AsWidget().HandleEvent(e) // raw drag em.drag.AsWidget().Send(events.DragMove, e) // usually ignored e.SetHandled() } else { diff --git a/core/mainstage.go b/core/mainstage.go index 2b6e4ac388..2713e12a94 100644 --- a/core/mainstage.go +++ b/core/mainstage.go @@ -404,7 +404,7 @@ func (sm *stages) mainHandleEvent(e events.Event) { if e.IsHandled() || st.Modal || st.Type == WindowStage || st.FullWindow { break } - if st.Type == DialogStage { // modal dialog, by definition + if st.Type == DialogStage { // modeless dialog, by definition if e.HasPos() && st.Scene != nil { b := st.Scene.SceneGeom.Bounds() if e.WindowPos().In(b) { // don't propagate diff --git a/core/style.go b/core/style.go index 1d6f6410f5..0c39194500 100644 --- a/core/style.go +++ b/core/style.go @@ -225,7 +225,7 @@ func styleFromTags(w Widget, tags reflect.StructTag) { setFromTag(tags, "grow", func(v float32) { s.Grow.X = v }) setFromTag(tags, "grow-y", func(v float32) { s.Grow.Y = v }) }) - if v, ok := tags.Lookup("new-window"); ok && v == "+" { + if tags.Get("new-window") == "+" { w.AsWidget().setFlag(true, widgetValueNewWindow) } } From 33718ef17969944d55fc6be5d70c8b083d9067ad Mon Sep 17 00:00:00 2001 From: Kai O'Reilly Date: Wed, 21 Aug 2024 10:48:21 -0700 Subject: [PATCH 8/8] clean up new window logic --- core/mainstage.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/core/mainstage.go b/core/mainstage.go index 2713e12a94..20c55ce0d2 100644 --- a/core/mainstage.go +++ b/core/mainstage.go @@ -169,14 +169,15 @@ func (st *Stage) configMainStage() { if st.NewWindow { st.FullWindow = true } - if st.NewWindow && st.Type == DialogStage && TheApp.Platform().IsMobile() && st.Context != nil && st.Context.AsWidget().SizeClass() != SizeCompact { - st.NewWindow = false - st.FullWindow = false - st.Modal = false - st.Scrim = false - } - // if we are on mobile, we can never have new windows if TheApp.Platform().IsMobile() { + // If we are a new window dialog on a large single-window platform, + // we use a modeless dialog as a substitute. + if st.NewWindow && st.Type == DialogStage && st.Context != nil && st.Context.AsWidget().SizeClass() != SizeCompact { + st.FullWindow = false + st.Modal = false + st.Scrim = false + } + // If we are on mobile, we can never have new windows. st.NewWindow = false } if st.FullWindow || st.NewWindow {