Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom decredmaterial button and clickable #630

Merged
merged 27 commits into from
Oct 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b665bb3
Add custom button layout
beansgum Sep 14, 2021
211dfed
button: disable user interactions if disabled
beansgum Sep 14, 2021
7fc0819
Add support for custom button highlight color
beansgum Sep 14, 2021
a6b18d5
Replace instances with explicit outline buttons style with predefined…
beansgum Sep 14, 2021
da091e3
Fix incorrect button background in dropdown & switch button
beansgum Sep 14, 2021
3923ab0
Add clickable layout that supports custom background & radius
beansgum Sep 14, 2021
bcc3a98
Add Hover to decredmaterial Clickable
beansgum Sep 15, 2021
27d9154
Replace usages of Clickable with decredmaterial.Clickable
beansgum Sep 15, 2021
ec4e4b2
Correctly handle button disabled states in all pages
beansgum Sep 15, 2021
198dfdb
Wrap create wallet button in a white background
beansgum Sep 15, 2021
28f97f4
Fix nav layout
beansgum Sep 16, 2021
beb570f
Add clickable hover to account selector modal
beansgum Sep 16, 2021
e154623
Add clickable hover to dropdown widget
beansgum Sep 16, 2021
c75b71c
Remove unused comments
beansgum Sep 16, 2021
2a691b3
Add clickable to linear layout
beansgum Sep 23, 2021
28c9895
Remove clickable parameter from outline button
beansgum Sep 23, 2021
b9ad1d0
Remove clickable parameter from all buttons
beansgum Sep 23, 2021
c0780c5
Fix dropdown layout clickable
beansgum Sep 23, 2021
2d8cfd6
Cleanup dropdown widget code
beansgum Sep 23, 2021
8782851
Add padding to account selector rows
beansgum Sep 23, 2021
4928cc8
Fix highlight colors
beansgum Sep 24, 2021
9fa3eee
Cleanup more page row layout
beansgum Sep 24, 2021
95829a1
Truncate wallet name
beansgum Sep 24, 2021
982bf91
Fix reconnect button bug
beansgum Sep 27, 2021
51a8075
Fix click highlight color
beansgum Sep 27, 2021
19b4b39
Fix wallet button highlight
beansgum Sep 27, 2021
b1625fd
Merge branch 'master' into action_buttons
beansgum Oct 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 122 additions & 21 deletions ui/decredmaterial/button.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,28 @@ import (
"image"
"image/color"

"gioui.org/f32"
"gioui.org/layout"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/text"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"

"gioui.org/widget"
"github.com/planetdecred/godcr/ui/values"
)

type Button struct {
material.ButtonStyle
label Label
clickable *widget.Clickable
isEnabled bool
disabledBackground color.NRGBA
surfaceColor color.NRGBA
disabledTextColor color.NRGBA
HighlightColor color.NRGBA

Margin layout.Inset
}

type ButtonLayout struct {
Expand All @@ -28,31 +38,63 @@ type IconButton struct {
material.IconButtonStyle
}

func (t *Theme) Button(button *widget.Clickable, txt string) Button {
func (t *Theme) Button(txt string) Button {
clickable := new(widget.Clickable)
buttonStyle := material.Button(t.Base, clickable, txt)
buttonStyle.TextSize = values.TextSize16
buttonStyle.Background = t.Color.Primary
buttonStyle.CornerRadius = values.MarginPadding8
buttonStyle.Inset = layout.Inset{
Top: values.MarginPadding10,
Right: values.MarginPadding16,
Bottom: values.MarginPadding10,
Left: values.MarginPadding16,
}
return Button{
ButtonStyle: material.Button(t.Base, button, txt),
disabledBackground: t.Color.Gray,
surfaceColor: t.Color.Surface,
ButtonStyle: buttonStyle,
label: t.Label(values.TextSize16, txt),
clickable: clickable,
disabledBackground: t.Color.InactiveGray,
disabledTextColor: t.Color.Surface,
HighlightColor: t.Color.PrimaryHighlight,
isEnabled: true,
}
}

func (t *Theme) ButtonLayout(button *widget.Clickable) ButtonLayout {
return ButtonLayout{material.ButtonLayout(t.Base, button)}
func (t *Theme) OutlineButton(txt string) Button {
btn := t.Button(txt)
btn.Background = color.NRGBA{}
btn.HighlightColor = t.Color.SurfaceHighlight
btn.Color = t.Color.Primary
btn.disabledBackground = color.NRGBA{}
btn.disabledTextColor = t.Color.InactiveGray

return btn
}

// DangerButton a button with the background set to theme.Danger
func (t *Theme) DangerButton(text string) Button {
btn := t.Button(text)
btn.Background = t.Color.Danger
return btn
}

func (t *Theme) ButtonLayout() ButtonLayout {
return ButtonLayout{material.ButtonLayout(t.Base, new(widget.Clickable))}
}

func (t *Theme) IconButton(button *widget.Clickable, icon *widget.Icon) IconButton {
return IconButton{material.IconButton(t.Base, button, icon)}
func (t *Theme) IconButton(icon *widget.Icon) IconButton {
return IconButton{material.IconButton(t.Base, new(widget.Clickable), icon)}
}

func (t *Theme) PlainIconButton(button *widget.Clickable, icon *widget.Icon) IconButton {
btn := IconButton{material.IconButton(t.Base, button, icon)}
func (t *Theme) PlainIconButton(icon *widget.Icon) IconButton {
btn := IconButton{material.IconButton(t.Base, new(widget.Clickable), icon)}
btn.Background = color.NRGBA{}
return btn
}

func Clickable(gtx layout.Context, button *widget.Clickable, w layout.Widget) layout.Dimensions {
return material.Clickable(gtx, button, w)
func (b *Button) SetClickable(clickable *widget.Clickable) {
b.clickable = clickable
}

func (b *Button) SetEnabled(enabled bool) {
Expand All @@ -64,16 +106,75 @@ func (b *Button) Enabled() bool {
}

func (b Button) Clicked() bool {
return b.Button.Clicked()
return b.clickable.Clicked()
}

func (b Button) Hovered() bool {
return b.clickable.Hovered()
}

func (b Button) Click() {
b.clickable.Click()
}

func (b *Button) Layout(gtx layout.Context) layout.Dimensions {
if !b.Enabled() {
gtx.Queue = nil
b.Background, b.Color = b.disabledBackground, b.surfaceColor
wdg := func(gtx layout.Context) layout.Dimensions {
return b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
textColor := b.Color
if !b.Enabled() {
textColor = b.disabledTextColor
}

b.label.Text = b.Text
b.label.Font = b.Font
b.label.Alignment = text.Middle
b.label.TextSize = b.TextSize
b.label.Color = textColor
return b.label.Layout(gtx)
})
}

return b.ButtonStyle.Layout(gtx)
return b.Margin.Layout(gtx, func(gtx C) D {
return b.buttonStyleLayout(gtx, wdg)
})
}

func (b Button) buttonStyleLayout(gtx layout.Context, w layout.Widget) layout.Dimensions {
min := gtx.Constraints.Min
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
rr := float32(gtx.Px(b.CornerRadius))
clip.UniformRRect(f32.Rectangle{Max: f32.Point{
X: float32(gtx.Constraints.Min.X),
Y: float32(gtx.Constraints.Min.Y),
}}, rr).Add(gtx.Ops)

background := b.Background
if !b.Enabled() {
background = b.disabledBackground
} else if b.clickable.Hovered() {
background = Hovered(b.Background)
}

paint.Fill(gtx.Ops, background)
for _, c := range b.clickable.History() {
drawInk(gtx, c, b.HighlightColor)
}

return layout.Dimensions{Size: gtx.Constraints.Min}
}),
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Min = min
return layout.Center.Layout(gtx, w)
}),
layout.Expanded(func(gtx C) D {
if !b.Enabled() {
return D{}
}

return b.clickable.Layout(gtx)
}),
)
}

func (bl ButtonLayout) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions {
Expand All @@ -93,10 +194,10 @@ type TextAndIconButton struct {
BackgroundColor color.NRGBA
}

func (t *Theme) TextAndIconButton(btn *widget.Clickable, text string, icon *widget.Icon) TextAndIconButton {
func (t *Theme) TextAndIconButton(text string, icon *widget.Icon) TextAndIconButton {
return TextAndIconButton{
theme: t,
Button: btn,
Button: new(widget.Clickable),
icon: icon,
text: text,
Color: t.Color.Surface,
Expand Down
12 changes: 0 additions & 12 deletions ui/decredmaterial/buttons.go

This file was deleted.

69 changes: 69 additions & 0 deletions ui/decredmaterial/clickable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package decredmaterial

import (
"image/color"

"gioui.org/f32"
"gioui.org/layout"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/unit"
"gioui.org/widget"
)

type Clickable struct {
button *widget.Clickable
Color color.NRGBA
HoverColor color.NRGBA
Hoverable bool
Radius CornerRadius
}

func (t *Theme) NewClickable(hoverable bool) *Clickable {
// TODO: Temp fix until dark mode colors are sorted out.
color := t.Color.ActiveGray
if !t.DarkMode {
color = Hovered(color)
}

return &Clickable{
button: &widget.Clickable{},
Color: t.Color.SurfaceHighlight,
HoverColor: color,
Hoverable: hoverable,
}
}

func (cl *Clickable) Clicked() bool {
return cl.button.Clicked()
}

func (cl *Clickable) Layout(gtx C, w layout.Widget) D {
return layout.Stack{}.Layout(gtx,
layout.Expanded(cl.button.Layout),
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
tr := float32(gtx.Px(unit.Dp(cl.Radius.TopRight)))
tl := float32(gtx.Px(unit.Dp(cl.Radius.TopLeft)))
br := float32(gtx.Px(unit.Dp(cl.Radius.BottomRight)))
bl := float32(gtx.Px(unit.Dp(cl.Radius.BottomLeft)))
clip.RRect{
Rect: f32.Rectangle{Max: f32.Point{
X: float32(gtx.Constraints.Min.X),
Y: float32(gtx.Constraints.Min.Y),
}},
NW: tl, NE: tr, SE: br, SW: bl,
}.Add(gtx.Ops)
clip.Rect{Max: gtx.Constraints.Min}.Add(gtx.Ops)

if cl.Hoverable && cl.button.Hovered() {
paint.Fill(gtx.Ops, cl.HoverColor)
}

for _, c := range cl.button.History() {
drawInk(gtx, c, cl.Color)
}
return layout.Dimensions{Size: gtx.Constraints.Min}
}),
layout.Stacked(w),
)
}
80 changes: 37 additions & 43 deletions ui/decredmaterial/clickable_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@ import (

"gioui.org/layout"
"gioui.org/unit"
"gioui.org/widget"
)

type ClickableList struct {
layout.List
theme *Theme
clickables []*widget.Clickable
selectedItem int
DividerHeight unit.Value
theme *Theme
clickables []*Clickable
ClickHighlight color.NRGBA
Radius CornerRadius // this radius is used by the clickable
selectedItem int
DividerHeight unit.Value
}

func (t *Theme) NewClickableList(axis layout.Axis) *ClickableList {
return &ClickableList{
theme: t,
List: layout.List{Axis: axis},
selectedItem: -1,
theme: t,
List: layout.List{Axis: axis},
ClickHighlight: t.Color.SurfaceHighlight,
selectedItem: -1,
}
}

Expand All @@ -34,9 +36,11 @@ func (cl *ClickableList) ItemClicked() (bool, int) {
func (cl *ClickableList) handleClickables(count int) {
if len(cl.clickables) != count {

cl.clickables = make([]*widget.Clickable, count)
cl.clickables = make([]*Clickable, count)
for i := 0; i < count; i++ {
cl.clickables[i] = new(widget.Clickable)
clickable := cl.theme.NewClickable(true)
clickable.Color = cl.ClickHighlight
cl.clickables[i] = clickable
}
}

Expand All @@ -50,40 +54,30 @@ func (cl *ClickableList) handleClickables(count int) {
func (cl *ClickableList) Layout(gtx layout.Context, count int, w layout.ListElement) layout.Dimensions {
cl.handleClickables(count)
return cl.List.Layout(gtx, count, func(gtx layout.Context, i int) layout.Dimensions {
return cl.clickableLayout(gtx, count, i, w)
})
}

func (cl *ClickableList) HoverableLayout(gtx layout.Context, count int, w layout.ListElement) layout.Dimensions {
cl.handleClickables(count)

card := cl.theme.Card()
card.Color = color.NRGBA{}
card.Radius = Radius(0)
return cl.List.Layout(gtx, count, func(gtx layout.Context, i int) layout.Dimensions {
return card.HoverableLayout(gtx, cl.clickables[i], func(gtx layout.Context) layout.Dimensions {
return cl.clickableLayout(gtx, count, i, w)
if i == 0 { // first item
cl.clickables[i].Radius.TopLeft = cl.Radius.TopLeft
cl.clickables[i].Radius.TopRight = cl.Radius.TopRight
}
if i == count-1 { // last item
cl.clickables[i].Radius.BottomLeft = cl.Radius.BottomLeft
cl.clickables[i].Radius.BottomRight = cl.Radius.BottomRight
}
row := cl.clickables[i].Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return w(gtx, i)
})
})
}

func (cl *ClickableList) clickableLayout(gtx layout.Context, count, i int, w layout.ListElement) layout.Dimensions {
row := Clickable(gtx, cl.clickables[i], func(gtx layout.Context) layout.Dimensions {
return w(gtx, i)
// add divider to all rows except last
if i < (count-1) && cl.DividerHeight.V > 0 {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return row
}),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Min.Y += gtx.Px(cl.DividerHeight)
return layout.Dimensions{Size: gtx.Constraints.Min}
}),
)
}
return row
})

// add divider to all rows except last
if i < (count-1) && cl.DividerHeight.V > 0 {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return row
}),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Min.Y += gtx.Px(cl.DividerHeight)

return layout.Dimensions{Size: gtx.Constraints.Min}
}),
)
}
return row
}
Loading