@@ -26,32 +26,56 @@ const (
2626 FormatPill
2727)
2828
29+ // ButtonTexts is a list of texts for the button.
30+ // The first is preferred, the second is fallback,
31+ // when the first doesn't fit the button width.
32+ type ButtonTexts [2 ]string
33+
2934// ButtonStyle is the style for Google buttons.
3035//
3136// Notice that you may violate some branding guidelines, it's
3237// safer to use DefaultGoogleButtonStyle or DefaultAppleButtonStyle.
3338type ButtonStyle struct {
34- Text string
35- TextSize unit.Dp
36- TextFont font.Font
37- TextShaper * text.Shaper
38- TextColor color.NRGBA
39- TextAlignment layout.Alignment
40- IconAlignment layout.Alignment
41- IconColor color.NRGBA
42- BackgroundColor color.NRGBA
39+ // TextSize is the size of the text.
40+ TextSize unit.Dp
41+ // TextFont is the font to use for the text.
42+ TextFont font.Font
43+ // TextShaper is the shaper to use for the text.
44+ TextShaper * text.Shaper
45+ // TextColor is the color of the text.
46+ TextColor color.NRGBA
47+ // TextAlignment is the alignment of the text.
48+ TextAlignment layout.Alignment
49+ // IconAlignment is the alignment of the icon.
50+ IconAlignment layout.Alignment
51+ // IconColor is the color of the icon.
52+ IconColor color.NRGBA
53+ // IconSize is the size of the icon.
54+ IconSize unit.Dp
55+ // IconPadding is the padding of the icon.
56+ IconPadding unit.Dp
57+ // IconVector is the vector of the icon.
58+ IconVector giosvg.Vector
59+ // BackgroundColor is the color of the background.
60+ BackgroundColor color.NRGBA
61+ // BackgroundIconColor is the color of the background of the icon.
4362 BackgroundIconColor color.NRGBA
44- BorderColor color.NRGBA
45- BorderThickness unit.Dp
46- Format Format
63+ // BorderColor is the color of the border.
64+ BorderColor color.NRGBA
65+ // BorderThickness is the thickness of the border.
66+ BorderThickness unit.Dp
67+ // Format is the format of the button.
68+ Format Format
69+
70+ icon * giosvg.Icon
4771}
4872
49- func (b ButtonStyle ) label (gtx layout.Context , text string ) (op.CallOp , layout.Dimensions ) {
73+ func (b * ButtonStyle ) label (gtx layout.Context , text string ) (call op.CallOp , dims layout.Dimensions ) {
5074 gtx .Constraints .Min .X = 0
5175 gtx .Constraints .Min .Y = 0
5276
5377 r := op .Record (gtx .Ops )
54- dims : = widget.Label {}.Layout (gtx , b .TextShaper , b .TextFont , gtx .Metric .DpToSp (b .TextSize ), text , toLabelColor (gtx , b .TextColor ))
78+ dims = widget.Label {}.Layout (gtx , b .TextShaper , b .TextFont , gtx .Metric .DpToSp (b .TextSize ), text , toLabelColor (gtx , b .TextColor ))
5579 return r .Stop (), dims
5680}
5781
@@ -61,8 +85,16 @@ func toLabelColor(gtx layout.Context, c color.NRGBA) op.CallOp {
6185 return r .Stop ()
6286}
6387
64- func (b ButtonStyle ) layoutText (gtx layout.Context , icon * giosvg.Icon , pointer * Pointer , text string , logoSize int , logoPadding int ) layout.Dimensions {
65- label , labelDims := b .label (gtx , text )
88+ func (b * ButtonStyle ) LayoutText (gtx layout.Context , pointer * Pointer , texts ButtonTexts ) layout.Dimensions {
89+ return b .layoutText (gtx , pointer , texts , 0 )
90+ }
91+
92+ func (b * ButtonStyle ) layoutText (gtx layout.Context , pointer * Pointer , texts ButtonTexts , textIndex int ) layout.Dimensions {
93+ if b .icon == nil {
94+ b .icon = giosvg .NewIcon (b .IconVector )
95+ }
96+
97+ label , labelDims := b .label (gtx , texts [textIndex ])
6698
6799 minHeight := int (math .Round (float64 (labelDims .Size .Y ) * 233 / 100 ))
68100
@@ -73,68 +105,82 @@ func (b ButtonStyle) layoutText(gtx layout.Context, icon *giosvg.Icon, pointer *
73105 Right : unit .Dp (16 ),
74106 }
75107
76- if logoSize == 0 {
77- logoSize = labelDims .Size .Y
108+ iconSize := gtx .Dp (b .IconSize )
109+ iconPadding := gtx .Dp (b .IconPadding )
110+
111+ if b .IconSize == 0 {
112+ iconSize = labelDims .Size .Y
78113 }
79114
80- avalSize := gtx .Constraints .Max .X - (labelDims .Size .X + gtx .Dp (inset .Left ) + gtx .Dp (inset .Right ) + logoSize )
81- if avalSize < 0 {
82- // The label is too long, we need to render the icon-only button.
115+ avalSize := gtx .Constraints .Max .X - (labelDims .Size .X + gtx .Dp (inset .Left ) + gtx .Dp (inset .Right ) + iconSize + iconPadding )
116+ isLogoOnly := avalSize < 0
117+ if avalSize > iconPadding && b .TextAlignment != layout .Start && b .IconAlignment != layout .Middle {
118+ iconPadding = 0
83119 }
84120
85- if avalSize > (logoPadding * 2 ) && b .TextAlignment != layout .Start && b .IconAlignment != layout .Middle {
86- logoPadding = 0
121+ if isLogoOnly && textIndex != len (texts )- 1 {
122+ return b .layoutText (gtx , pointer , texts , textIndex + 1 )
123+ }
124+
125+ if isLogoOnly {
126+ labelDims .Size .X = 0
127+ iconPadding = 0
87128 }
88129
89130 main := op .Record (gtx .Ops )
90131 dims := inset .Layout (gtx , func (gtx layout.Context ) layout.Dimensions {
91132 d := layout.Dimensions {Size : image .Pt (gtx .Constraints .Max .X , labelDims .Size .Y )}
92133
93134 {
135+ align := b .IconAlignment
136+ if isLogoOnly {
137+ align = layout .Middle
138+ }
139+
94140 // Logo
95141 var off op.TransformStack
96- switch b . IconAlignment {
142+ switch align {
97143 case layout .Start , layout .Baseline :
98144 off = op .Offset (image .Pt (0 , 0 )).Push (gtx .Ops )
99145 case layout .Middle :
100- off = op .Offset (image .Pt ((gtx .Constraints .Max .X - logoSize - logoPadding - labelDims .Size .X )/ 2 , 0 )).Push (gtx .Ops )
146+ off = op .Offset (image .Pt ((gtx .Constraints .Max .X - iconSize - iconPadding - labelDims .Size .X )/ 2 , 0 )).Push (gtx .Ops )
101147 case layout .End :
102- off = op .Offset (image .Pt (gtx .Constraints .Max .X - logoSize , 0 )).Push (gtx .Ops )
148+ off = op .Offset (image .Pt (gtx .Constraints .Max .X - iconSize , 0 )).Push (gtx .Ops )
103149 }
104150
105151 // Logo Background
106152 padding := gtx .Dp (6 )
107153 offBackground := op .Offset (image .Pt (- padding / 2 , - padding / 2 )).Push (gtx .Ops )
108- background := clip .UniformRRect (image.Rectangle {Max : image .Pt (logoSize + padding , logoSize + padding )}, (logoSize + padding )/ 2 ).Push (gtx .Ops )
154+ background := clip .UniformRRect (image.Rectangle {Max : image .Pt (iconSize + padding , iconSize + padding )}, (iconSize + padding )/ 2 ).Push (gtx .Ops )
109155 paint .Fill (gtx .Ops , b .BackgroundIconColor )
110156 background .Pop ()
111157 offBackground .Pop ()
112158
113159 gtx := gtx
114160 gtx .Constraints .Min = image.Point {}
115- gtx .Constraints .Max .X , gtx .Constraints .Max .Y = logoSize , logoSize
161+ gtx .Constraints .Max .X , gtx .Constraints .Max .Y = iconSize , iconSize
116162 if b .IconColor .A != 0 {
117163 paint.ColorOp {Color : b .IconColor }.Add (gtx .Ops )
118164 }
119165
120166 iconR := op .Record (gtx .Ops )
121- dimsIcon := icon .Layout (gtx )
167+ dimsIcon := b . icon .Layout (gtx )
122168 iconOp := iconR .Stop ()
123169
124- iconOff := op .Offset (image .Pt ((logoSize - dimsIcon .Size .X )/ 2 , (logoSize - dimsIcon .Size .Y )/ 2 )).Push (gtx .Ops )
170+ iconOff := op .Offset (image .Pt ((iconSize - dimsIcon .Size .X )/ 2 , (iconSize - dimsIcon .Size .Y )/ 2 )).Push (gtx .Ops )
125171 iconOp .Add (gtx .Ops )
126172 iconOff .Pop ()
127173
128174 off .Pop ()
129175 }
130176
131- {
177+ if ! isLogoOnly {
132178 // Text
133179 gtx := gtx
134- gtx .Constraints .Max .X = gtx .Constraints .Max .X - logoSize - logoPadding
180+ gtx .Constraints .Max .X = gtx .Constraints .Max .X - iconSize - iconPadding
135181
136182 if b .TextAlignment != layout .End {
137- defer op .Offset (image .Pt (logoSize + logoPadding , 0 )).Push (gtx .Ops ).Pop ()
183+ defer op .Offset (image .Pt (iconSize + iconPadding , 0 )).Push (gtx .Ops ).Pop ()
138184 }
139185
140186 switch b .TextAlignment {
0 commit comments