From 23baeff18d7534ac3443abd5771fae6e33c4264c Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Mon, 11 May 2020 13:17:14 +0200 Subject: [PATCH] widget/button,widget/material: introduce Clickable for generic click areas material.Clickable is useful for adding a click response to any widget or area. Rename widget.Button to widget.Clickable to reflect the wider use spectrum. Signed-off-by: Elias Naur --- widget/button.go | 12 ++++++------ widget/material/button.go | 28 +++++++++++++++++++++++++--- widget/material/doc.go | 10 +++++----- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/widget/button.go b/widget/button.go index a2b14b89..a5eb1508 100644 --- a/widget/button.go +++ b/widget/button.go @@ -13,8 +13,8 @@ import ( "gioui.org/op" ) -// Button represents a clickable area. -type Button struct { +// Clickable represents a clickable area. +type Clickable struct { click gesture.Click // clicks tracks the number of unreported clicks. clicks int @@ -30,7 +30,7 @@ type Click struct { // Clicked calls Update and reports whether the button was // clicked since the last call. Multiple clicks result in Clicked // returning true once per click. -func (b *Button) Clicked(gtx *layout.Context) bool { +func (b *Clickable) Clicked(gtx *layout.Context) bool { b.Update(gtx) if b.clicks > 0 { b.clicks-- @@ -45,11 +45,11 @@ func (b *Button) Clicked(gtx *layout.Context) bool { // History is the past clicks useful for drawing click markers. // Clicks are retained for a short duration (about a second). -func (b *Button) History() []Click { +func (b *Clickable) History() []Click { return b.history } -func (b *Button) Layout(gtx *layout.Context) { +func (b *Clickable) Layout(gtx *layout.Context) { // Flush clicks from before the previous frame. b.Update(gtx) var st op.StackOp @@ -69,7 +69,7 @@ func (b *Button) Layout(gtx *layout.Context) { // Update the button state by processing events. The underlying // gesture events are returned for use beyond what Clicked offers. -func (b *Button) Update(gtx *layout.Context) []gesture.ClickEvent { +func (b *Clickable) Update(gtx *layout.Context) []gesture.ClickEvent { evts := b.click.Events(gtx) for _, e := range evts { switch e.Type { diff --git a/widget/material/button.go b/widget/material/button.go index 020c2810..334e4e61 100644 --- a/widget/material/button.go +++ b/widget/material/button.go @@ -77,7 +77,29 @@ func IconButton(th *Theme, icon *widget.Icon) IconButtonStyle { } } -func (b ButtonStyle) Layout(gtx *layout.Context, button *widget.Button) { +// Clickable lays out a rectangular clickable widget without further +// decoration. +func Clickable(gtx *layout.Context, button *widget.Clickable, w layout.Widget) { + layout.Stack{}.Layout(gtx, + layout.Expanded(func() { + button.Layout(gtx) + }), + layout.Expanded(func() { + clip.Rect{ + Rect: f32.Rectangle{Max: f32.Point{ + X: float32(gtx.Constraints.Width.Min), + Y: float32(gtx.Constraints.Height.Min), + }}, + }.Op(gtx.Ops).Add(gtx.Ops) + for _, c := range button.History() { + drawInk(gtx, c) + } + }), + layout.Stacked(w), + ) +} + +func (b ButtonStyle) Layout(gtx *layout.Context, button *widget.Clickable) { ButtonLayoutStyle{ Background: b.Background, CornerRadius: b.CornerRadius, @@ -88,7 +110,7 @@ func (b ButtonStyle) Layout(gtx *layout.Context, button *widget.Button) { }) } -func (b ButtonLayoutStyle) Layout(gtx *layout.Context, button *widget.Button, w layout.Widget) { +func (b ButtonLayoutStyle) Layout(gtx *layout.Context, button *widget.Clickable, w layout.Widget) { hmin := gtx.Constraints.Width.Min vmin := gtx.Constraints.Height.Min layout.Stack{Alignment: layout.Center}.Layout(gtx, @@ -121,7 +143,7 @@ func (b ButtonLayoutStyle) Layout(gtx *layout.Context, button *widget.Button, w ) } -func (b IconButtonStyle) Layout(gtx *layout.Context, button *widget.Button) { +func (b IconButtonStyle) Layout(gtx *layout.Context, button *widget.Clickable) { layout.Stack{Alignment: layout.Center}.Layout(gtx, layout.Expanded(func() { size := gtx.Constraints.Width.Min diff --git a/widget/material/doc.go b/widget/material/doc.go index 25f1dcf9..0431886d 100644 --- a/widget/material/doc.go +++ b/widget/material/doc.go @@ -5,14 +5,14 @@ // To maximize reusability and visual flexibility, user interface controls are // split into two parts: the stateful widget and the stateless drawing of it. // -// For example, widget.Button encapsulates the state and event -// handling of all buttons, while the Theme can draw a single Button -// in various styles. +// For example, widget.Clickable encapsulates the state and event +// handling of all clickable areas, while the Theme is responsible to +// draw a specific area, for example a button. // // This snippet defines a button that prints a message when clicked: // // var gtx *layout.Context -// button := new(widget.Button) +// button := new(widget.Clickable) // // for button.Clicked(gtx) { // fmt.Println("Clicked!") @@ -46,7 +46,7 @@ // btn.Layout(gtx) // // Widget variants: A widget can have several distinct representations even -// though the underlying state is the same. A widget.Button can be drawn as a +// though the underlying state is the same. A widget.Clickable can be drawn as a // round icon button: // // icon := material.NewIcon(...)