mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-19 05:24:48 -04:00
fix(tracker/gioui): make own TipArea ensuring tips don't stay around
Closes #141.
This commit is contained in:
parent
31007515b5
commit
6f1db6b392
@ -52,6 +52,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
be computed every draw. ([#176][i176])
|
be computed every draw. ([#176][i176])
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- Tooltips will be hidden after certain amount of time has passed, to ensure
|
||||||
|
that the tooltips don't stay around ([#141][i141])
|
||||||
- BREAKING CHANGE: always first modulate delay time, then apply notetracking. In
|
- BREAKING CHANGE: always first modulate delay time, then apply notetracking. In
|
||||||
a delay unit, modulation adds to the delay time, while note tracking
|
a delay unit, modulation adds to the delay time, while note tracking
|
||||||
multiplies it with a multiplier dependent on the note. The order of these
|
multiplies it with a multiplier dependent on the note. The order of these
|
||||||
@ -311,6 +313,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
[i130]: https://github.com/vsariola/sointu/issues/130
|
[i130]: https://github.com/vsariola/sointu/issues/130
|
||||||
[i136]: https://github.com/vsariola/sointu/issues/136
|
[i136]: https://github.com/vsariola/sointu/issues/136
|
||||||
[i139]: https://github.com/vsariola/sointu/issues/139
|
[i139]: https://github.com/vsariola/sointu/issues/139
|
||||||
|
[i141]: https://github.com/vsariola/sointu/issues/141
|
||||||
[i142]: https://github.com/vsariola/sointu/issues/142
|
[i142]: https://github.com/vsariola/sointu/issues/142
|
||||||
[i144]: https://github.com/vsariola/sointu/issues/144
|
[i144]: https://github.com/vsariola/sointu/issues/144
|
||||||
[i145]: https://github.com/vsariola/sointu/issues/145
|
[i145]: https://github.com/vsariola/sointu/issues/145
|
||||||
|
@ -17,7 +17,6 @@ import (
|
|||||||
"gioui.org/text"
|
"gioui.org/text"
|
||||||
"gioui.org/unit"
|
"gioui.org/unit"
|
||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
"gioui.org/x/component"
|
|
||||||
"github.com/vsariola/sointu/tracker"
|
"github.com/vsariola/sointu/tracker"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,7 +26,7 @@ type (
|
|||||||
history []widget.Press
|
history []widget.Press
|
||||||
|
|
||||||
requestClicks int
|
requestClicks int
|
||||||
TipArea component.TipArea // since almost all buttons have tooltips, we include the state for a tooltip here for convenience
|
TipArea TipArea // since almost all buttons have tooltips, we include the state for a tooltip here for convenience
|
||||||
}
|
}
|
||||||
|
|
||||||
ButtonStyle struct {
|
ButtonStyle struct {
|
||||||
@ -289,13 +288,6 @@ func (b *ToggleIconButton) Layout(gtx C) D {
|
|||||||
return b.IconButton.Layout(gtx)
|
return b.IconButton.Layout(gtx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Tooltip(th *Theme, tip string) component.Tooltip {
|
|
||||||
tooltip := component.PlatformTooltip(&th.Material, tip)
|
|
||||||
tooltip.Bg = th.Tooltip.Bg
|
|
||||||
tooltip.Text.Color = th.Tooltip.Color
|
|
||||||
return tooltip
|
|
||||||
}
|
|
||||||
|
|
||||||
// Click executes a simple programmatic click.
|
// Click executes a simple programmatic click.
|
||||||
func (b *Clickable) Click() {
|
func (b *Clickable) Click() {
|
||||||
b.requestClicks++
|
b.requestClicks++
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"gioui.org/op/paint"
|
"gioui.org/op/paint"
|
||||||
"gioui.org/unit"
|
"gioui.org/unit"
|
||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
"gioui.org/x/component"
|
|
||||||
|
|
||||||
"gioui.org/gesture"
|
"gioui.org/gesture"
|
||||||
"gioui.org/io/event"
|
"gioui.org/io/event"
|
||||||
@ -31,7 +30,7 @@ type (
|
|||||||
dragStartXY float32
|
dragStartXY float32
|
||||||
clickDecrease gesture.Click
|
clickDecrease gesture.Click
|
||||||
clickIncrease gesture.Click
|
clickIncrease gesture.Click
|
||||||
tipArea component.TipArea
|
tipArea TipArea
|
||||||
}
|
}
|
||||||
|
|
||||||
NumericUpDownStyle struct {
|
NumericUpDownStyle struct {
|
||||||
|
150
tracker/gioui/tooltip.go
Normal file
150
tracker/gioui/tooltip.go
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
package gioui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gioui.org/io/event"
|
||||||
|
"gioui.org/io/pointer"
|
||||||
|
"gioui.org/layout"
|
||||||
|
"gioui.org/op"
|
||||||
|
"gioui.org/op/clip"
|
||||||
|
"gioui.org/x/component"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TipArea holds the state information for displaying a tooltip. The zero
|
||||||
|
// value will choose sensible defaults for all fields.
|
||||||
|
type TipArea struct {
|
||||||
|
component.VisibilityAnimation
|
||||||
|
Hover component.InvalidateDeadline
|
||||||
|
Press component.InvalidateDeadline
|
||||||
|
LongPress component.InvalidateDeadline
|
||||||
|
Exit component.InvalidateDeadline
|
||||||
|
init bool
|
||||||
|
// HoverDelay is the delay between the cursor entering the tip area
|
||||||
|
// and the tooltip appearing.
|
||||||
|
HoverDelay time.Duration
|
||||||
|
// LongPressDelay is the required duration of a press in the area for
|
||||||
|
// it to count as a long press.
|
||||||
|
LongPressDelay time.Duration
|
||||||
|
// LongPressDuration is the amount of time the tooltip should be displayed
|
||||||
|
// after being triggered by a long press.
|
||||||
|
LongPressDuration time.Duration
|
||||||
|
// FadeDuration is the amount of time it takes the tooltip to fade in
|
||||||
|
// and out.
|
||||||
|
FadeDuration time.Duration
|
||||||
|
// ExitDuration is the amount of time the tooltip will remain visible at
|
||||||
|
// maximum, to avoid tooltips staying visible indefinitely if the user
|
||||||
|
// managed to leave the area without triggering a pointer.Leave event.
|
||||||
|
ExitDuration time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
tipAreaHoverDelay = time.Millisecond * 500
|
||||||
|
tipAreaLongPressDuration = time.Millisecond * 1500
|
||||||
|
tipAreaFadeDuration = time.Millisecond * 250
|
||||||
|
longPressTheshold = time.Millisecond * 500
|
||||||
|
tipAreaExitDelay = time.Millisecond * 5000
|
||||||
|
)
|
||||||
|
|
||||||
|
// Layout renders the provided widget with the provided tooltip. The tooltip
|
||||||
|
// will be summoned if the widget is hovered or long-pressed.
|
||||||
|
func (t *TipArea) Layout(gtx C, tip component.Tooltip, w layout.Widget) D {
|
||||||
|
if !t.init {
|
||||||
|
t.init = true
|
||||||
|
t.VisibilityAnimation.State = component.Invisible
|
||||||
|
if t.HoverDelay == time.Duration(0) {
|
||||||
|
t.HoverDelay = tipAreaHoverDelay
|
||||||
|
}
|
||||||
|
if t.LongPressDelay == time.Duration(0) {
|
||||||
|
t.LongPressDelay = longPressTheshold
|
||||||
|
}
|
||||||
|
if t.LongPressDuration == time.Duration(0) {
|
||||||
|
t.LongPressDuration = tipAreaLongPressDuration
|
||||||
|
}
|
||||||
|
if t.FadeDuration == time.Duration(0) {
|
||||||
|
t.FadeDuration = tipAreaFadeDuration
|
||||||
|
}
|
||||||
|
if t.ExitDuration == time.Duration(0) {
|
||||||
|
t.ExitDuration = tipAreaExitDelay
|
||||||
|
}
|
||||||
|
t.VisibilityAnimation.Duration = t.FadeDuration
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
ev, ok := gtx.Event(pointer.Filter{
|
||||||
|
Target: t,
|
||||||
|
Kinds: pointer.Press | pointer.Release | pointer.Enter | pointer.Leave,
|
||||||
|
})
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
e, ok := ev.(pointer.Event)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch e.Kind {
|
||||||
|
case pointer.Enter:
|
||||||
|
t.Hover.SetTarget(gtx.Now.Add(t.HoverDelay))
|
||||||
|
t.Exit.SetTarget(gtx.Now.Add(t.ExitDuration))
|
||||||
|
case pointer.Leave:
|
||||||
|
t.VisibilityAnimation.Disappear(gtx.Now)
|
||||||
|
t.Hover.ClearTarget()
|
||||||
|
t.Exit.ClearTarget()
|
||||||
|
case pointer.Press:
|
||||||
|
t.Press.SetTarget(gtx.Now.Add(t.LongPressDelay))
|
||||||
|
case pointer.Release:
|
||||||
|
t.Press.ClearTarget()
|
||||||
|
case pointer.Cancel:
|
||||||
|
t.Hover.ClearTarget()
|
||||||
|
t.Press.ClearTarget()
|
||||||
|
t.Exit.ClearTarget()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if t.Hover.Process(gtx) {
|
||||||
|
t.VisibilityAnimation.Appear(gtx.Now)
|
||||||
|
}
|
||||||
|
if t.Press.Process(gtx) {
|
||||||
|
t.VisibilityAnimation.Appear(gtx.Now)
|
||||||
|
t.LongPress.SetTarget(gtx.Now.Add(t.LongPressDuration))
|
||||||
|
}
|
||||||
|
if t.LongPress.Process(gtx) {
|
||||||
|
t.VisibilityAnimation.Disappear(gtx.Now)
|
||||||
|
}
|
||||||
|
if t.Exit.Process(gtx) {
|
||||||
|
t.VisibilityAnimation.Disappear(gtx.Now)
|
||||||
|
}
|
||||||
|
return layout.Stack{}.Layout(gtx,
|
||||||
|
layout.Stacked(w),
|
||||||
|
layout.Expanded(func(gtx C) D {
|
||||||
|
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||||
|
defer clip.Rect(image.Rectangle{Max: gtx.Constraints.Min}).Push(gtx.Ops).Pop()
|
||||||
|
event.Op(gtx.Ops, t)
|
||||||
|
|
||||||
|
originalMin := gtx.Constraints.Min
|
||||||
|
gtx.Constraints.Min = image.Point{}
|
||||||
|
|
||||||
|
if t.Visible() {
|
||||||
|
macro := op.Record(gtx.Ops)
|
||||||
|
tip.Bg = component.Interpolate(color.NRGBA{}, tip.Bg, t.VisibilityAnimation.Revealed(gtx))
|
||||||
|
dims := tip.Layout(gtx)
|
||||||
|
call := macro.Stop()
|
||||||
|
xOffset := (originalMin.X / 2) - (dims.Size.X / 2)
|
||||||
|
yOffset := originalMin.Y
|
||||||
|
macro = op.Record(gtx.Ops)
|
||||||
|
op.Offset(image.Pt(xOffset, yOffset)).Add(gtx.Ops)
|
||||||
|
call.Add(gtx.Ops)
|
||||||
|
call = macro.Stop()
|
||||||
|
op.Defer(gtx.Ops, call)
|
||||||
|
}
|
||||||
|
return D{}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Tooltip(th *Theme, tip string) component.Tooltip {
|
||||||
|
tooltip := component.PlatformTooltip(&th.Material, tip)
|
||||||
|
tooltip.Bg = th.Tooltip.Bg
|
||||||
|
tooltip.Text.Color = th.Tooltip.Color
|
||||||
|
return tooltip
|
||||||
|
}
|
@ -228,7 +228,7 @@ type ParameterWidget struct {
|
|||||||
unitBtn Clickable
|
unitBtn Clickable
|
||||||
unitMenu Menu
|
unitMenu Menu
|
||||||
Parameter tracker.Parameter
|
Parameter tracker.Parameter
|
||||||
tipArea component.TipArea
|
tipArea TipArea
|
||||||
}
|
}
|
||||||
|
|
||||||
type ParameterStyle struct {
|
type ParameterStyle struct {
|
||||||
|
Reference in New Issue
Block a user