~eliasnaur/gio-patches

gio: widget: add methods Press, Release and Click to Clickable to simulate button presses or button clicks. This can be used to implement keyboard shortcuts for buttons. v1 PROPOSED

Raffaele Sena
Raffaele Sena: 1
 widget: add methods Press, Release and Click to Clickable to simulate button presses or button clicks. This can be used to implement keyboard shortcuts for buttons.

 2 files changed, 50 insertions(+), 1 deletions(-)
#374192 apple.yml success
#374193 freebsd.yml success
#374194 linux.yml success
#374195 openbsd.yml success
Raffaele Sena
Elias, I struggled with re-using the code in addClickEvent also in
Clickable.update, but I didn't want to change the logic in
Clickable.update, but if you want this is a possible reimplementation:

func (b *Clickable) processEvent(e gesture.ClickEvent, now time.Time,
flush bool) {
        // Flush clicks from before the last update.
        if flush {
                n := copy(b.clicks, b.clicks[b.prevClicks:])
                b.clicks = b.clicks[:n]
                b.prevClicks = n
        }

        switch e.Type {
        case gesture.TypeClick:
                b.clicks = append(b.clicks, Click{
                        Modifiers: e.Modifiers,
                        NumClicks: e.NumClicks,
                })
                if l := len(b.history); l > 0 {
                        b.history[l-1].End = now
                }
        case gesture.TypeCancel:
                for i := range b.history {
                        b.history[i].Cancelled = true
                        if b.history[i].End.IsZero() {
                                b.history[i].End = now
                        }
                }
        case gesture.TypePress:
                b.history = append(b.history, Press{
                        Position: e.Position,
                        Start:    now,
                })
        }
}

// update the button state by processing events.
func (b *Clickable) update(gtx layout.Context) {
        flush := true

        for _, e := range b.click.Events(gtx) {
                b.processEvent(e, gtx.Now, flush)
                flush = false
        }
}

But at this point given the content of Clickable.update, it may be
worth moving the code directly in Clickable.Layout.
On Mon, Dec 21, 2020 at 11:10 PM Elias Naur <mail@eliasnaur.com> wrote:
Add a newline between a short patch subject and the patch message.

On Wed Dec 23, 2020 at 2:35 AM CET, Raffaele Sena wrote:
Next
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~eliasnaur/gio-patches/patches/16075/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH gio] widget: add methods Press, Release and Click to Clickable to simulate button presses or button clicks. This can be used to implement keyboard shortcuts for buttons. Export this patch

Raffaele Sena
Note that when called outside the processing of a system.FrameEvent, you will need
to explicitly call window.Invalidate in order to generate a new FrameEvent with the
button UI changes.

Also added method Pressed to Clickable (similar to Clicked) to check if the button is
currently being pressed.

Also fixed method String in key.Event (missing "{").

Signed-off-by: Raffaele Sena <raff367@gmail.com>
---
 io/key/key.go    |  2 +-
 widget/button.go | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/io/key/key.go b/io/key/key.go
index f3cda60..3f49bf4 100644
--- a/io/key/key.go
+++ b/io/key/key.go
@@ -144,7 +144,7 @@ func (Event) ImplementsEvent()      {}
func (FocusEvent) ImplementsEvent() {}

func (e Event) String() string {
	return fmt.Sprintf("%v %v %v}", e.Name, e.Modifiers, e.State)
	return fmt.Sprintf("{%v %v %v}", e.Name, e.Modifiers, e.State)
}

func (m Modifiers) String() string {
diff --git a/widget/button.go b/widget/button.go
index f534920..ea42416 100644
--- a/widget/button.go
+++ b/widget/button.go
@@ -66,6 +66,13 @@ func (b *Clickable) Clicks() []Click {
	return clicks
}

// Pressed reports if the button is currently pressed
// (the has been a Press event without a release).
func (b *Clickable) Pressed() bool {
	l := len(b.history)
	return l > 0 && b.history[l-1].End.IsZero()
}

// History is the past pointer presses useful for drawing markers.
// History is retained for a short duration (about a second).
func (b *Clickable) History() []Press {
@@ -86,9 +93,51 @@ func (b *Clickable) Layout(gtx layout.Context) layout.Dimensions {
		n := copy(b.history, b.history[1:])
		b.history = b.history[:n]
	}

	return layout.Dimensions{Size: gtx.Constraints.Min}
}

func (b *Clickable) addClickEvent(press bool, m key.Modifiers) {
	// Flush clicks from before the last update.
	n := copy(b.clicks, b.clicks[b.prevClicks:])
	b.clicks = b.clicks[:n]
	b.prevClicks = n

	if press {
		b.history = append(b.history, Press{
			Position: f32.Point{X: 1, Y: 1},
			Start:    time.Now(),
		})
	} else {
		b.clicks = append(b.clicks, Click{
			Modifiers: m,
			NumClicks: 1,
		})
		if l := len(b.history); l > 0 {
			b.history[l-1].End = time.Now()
		}
	}
}

// Press adds a button press event to the Clickable.
func (b *Clickable) Press() {
	b.addClickEvent(true, 0)
}

// Release adds a button release event to the Clickable.
func (b *Clickable) Release(m key.Modifiers) {
	b.addClickEvent(false, m)
}

// Click add a button press and later button release to the Clickable.
func (b *Clickable) Click(m key.Modifiers) {
	b.addClickEvent(true, 0)

	time.AfterFunc(200*time.Millisecond, func() {
		b.addClickEvent(false, m)
	})
}

// update the button state by processing events.
func (b *Clickable) update(gtx layout.Context) {
	// Flush clicks from before the last update.
-- 
2.29.2