mirror of
https://github.com/mum4k/termdash.git
synced 2025-04-25 13:48:50 +08:00
Merge pull request #276 from mum4k/243-button-improvements
Improving the button widget.
This commit is contained in:
commit
09baa7d379
21
CHANGELOG.md
21
CHANGELOG.md
@ -30,9 +30,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
#### Infrastructure changes
|
||||
- ability to configure keyboard keys that move focus to the next or the
|
||||
previous container.
|
||||
- widgets can not request keyboard events exclusively when focused.
|
||||
- widgets can now request keyboard events exclusively when focused.
|
||||
- ability to configure keyboard keys that move focus to the next or the
|
||||
previous container.
|
||||
- `container` now allows users to configure keyboard keys that move focus to
|
||||
the next or the previous container.
|
||||
|
||||
#### Updates to the `button` widget
|
||||
- the `button` widget allows users to specify multiple trigger keys.
|
||||
- the `button` widget now supports different keys for the global and focused
|
||||
scope.
|
||||
- the `button` widget can now be drawn without the shadow or the press
|
||||
animation.
|
||||
- the `button` widget can now be drawn without horizontal padding around its
|
||||
text.
|
||||
- the `button` widget now allows specifying cell options for each cell of the
|
||||
displayed text. Separate cell options can be specified for each of button's
|
||||
main states (up, focused and up, down).
|
||||
- the `button` widget allows specifying separate fill color values for each of
|
||||
its main states (up, focused and up, down).
|
||||
|
||||
## [0.13.0] - 17-Nov-2020
|
||||
|
||||
|
@ -18,7 +18,9 @@ package button
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -26,6 +28,7 @@ import (
|
||||
"github.com/mum4k/termdash/cell"
|
||||
"github.com/mum4k/termdash/mouse"
|
||||
"github.com/mum4k/termdash/private/alignfor"
|
||||
"github.com/mum4k/termdash/private/attrrange"
|
||||
"github.com/mum4k/termdash/private/button"
|
||||
"github.com/mum4k/termdash/private/canvas"
|
||||
"github.com/mum4k/termdash/private/draw"
|
||||
@ -45,6 +48,20 @@ import (
|
||||
// termdash.ErrorHandler.
|
||||
type CallbackFn func() error
|
||||
|
||||
// TextChunk is a part of or the full text displayed in the button.
|
||||
type TextChunk struct {
|
||||
text string
|
||||
tOpts *textOptions
|
||||
}
|
||||
|
||||
// NewChunk creates a new text chunk. Each chunk of text can have its own cell options.
|
||||
func NewChunk(text string, tOpts ...TextOption) *TextChunk {
|
||||
return &TextChunk{
|
||||
text: text,
|
||||
tOpts: newTextOptions(tOpts...),
|
||||
}
|
||||
}
|
||||
|
||||
// Button can be pressed using a mouse click or a configured keyboard key.
|
||||
//
|
||||
// Upon each press, the button invokes a callback provided by the user.
|
||||
@ -52,7 +69,12 @@ type CallbackFn func() error
|
||||
// Implements widgetapi.Widget. This object is thread-safe.
|
||||
type Button struct {
|
||||
// text in the text label displayed in the button.
|
||||
text string
|
||||
text strings.Builder
|
||||
|
||||
// givenTOpts are text options given for the button's of text.
|
||||
givenTOpts []*textOptions
|
||||
// tOptsTracker tracks the positions in a text to which the givenTOpts apply.
|
||||
tOptsTracker *attrrange.Tracker
|
||||
|
||||
// mouseFSM tracks left mouse clicks.
|
||||
mouseFSM *button.FSM
|
||||
@ -78,22 +100,57 @@ type Button struct {
|
||||
// New returns a new Button that will display the provided text.
|
||||
// Each press of the button will invoke the callback function.
|
||||
func New(text string, cFn CallbackFn, opts ...Option) (*Button, error) {
|
||||
return NewFromChunks([]*TextChunk{NewChunk(text)}, cFn, opts...)
|
||||
}
|
||||
|
||||
// NewFromChunks is like New, but allows specifying write options for
|
||||
// individual chunks of text displayed in the button.
|
||||
func NewFromChunks(chunks []*TextChunk, cFn CallbackFn, opts ...Option) (*Button, error) {
|
||||
if cFn == nil {
|
||||
return nil, errors.New("the CallbackFn argument cannot be nil")
|
||||
}
|
||||
|
||||
opt := newOptions(text)
|
||||
if len(chunks) == 0 {
|
||||
return nil, errors.New("at least one text chunk must be specified")
|
||||
}
|
||||
|
||||
var (
|
||||
text strings.Builder
|
||||
givenTOpts []*textOptions
|
||||
)
|
||||
tOptsTracker := attrrange.NewTracker()
|
||||
for i, tc := range chunks {
|
||||
if tc.text == "" {
|
||||
return nil, fmt.Errorf("text chunk[%d] is empty, all chunks must contains some text", i)
|
||||
}
|
||||
|
||||
pos := text.Len()
|
||||
givenTOpts = append(givenTOpts, tc.tOpts)
|
||||
tOptsIdx := len(givenTOpts) - 1
|
||||
if err := tOptsTracker.Add(pos, pos+len(tc.text), tOptsIdx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
text.WriteString(tc.text)
|
||||
}
|
||||
|
||||
opt := newOptions(text.String())
|
||||
for _, o := range opts {
|
||||
o.set(opt)
|
||||
}
|
||||
if err := opt.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, tOpts := range givenTOpts {
|
||||
tOpts.setDefaultFgColor(opt.textColor)
|
||||
}
|
||||
return &Button{
|
||||
text: text,
|
||||
mouseFSM: button.NewFSM(mouse.ButtonLeft, image.ZR),
|
||||
callback: cFn,
|
||||
opts: opt,
|
||||
text: text,
|
||||
givenTOpts: givenTOpts,
|
||||
tOptsTracker: tOptsTracker,
|
||||
mouseFSM: button.NewFSM(mouse.ButtonLeft, image.ZR),
|
||||
callback: cFn,
|
||||
opts: opt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -126,40 +183,90 @@ func (b *Button) Draw(cvs *canvas.Canvas, meta *widgetapi.Meta) error {
|
||||
cvsAr := cvs.Area()
|
||||
b.mouseFSM.UpdateArea(cvsAr)
|
||||
|
||||
shadowAr := image.Rect(shadowWidth, shadowWidth, cvsAr.Dx(), cvsAr.Dy())
|
||||
if err := cvs.SetAreaCells(shadowAr, shadowRune, cell.BgColor(b.opts.shadowColor)); err != nil {
|
||||
return err
|
||||
sw := b.shadowWidth()
|
||||
shadowAr := image.Rect(sw, sw, cvsAr.Dx(), cvsAr.Dy())
|
||||
if !b.opts.disableShadow {
|
||||
if err := cvs.SetAreaCells(shadowAr, shadowRune, cell.BgColor(b.opts.shadowColor)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var buttonAr image.Rectangle
|
||||
if b.state == button.Up {
|
||||
buttonAr = image.Rect(0, 0, cvsAr.Dx()-shadowWidth, cvsAr.Dy()-shadowWidth)
|
||||
} else {
|
||||
buttonAr := image.Rect(0, 0, cvsAr.Dx()-sw, cvsAr.Dy()-sw)
|
||||
if b.state == button.Down && !b.opts.disableShadow {
|
||||
buttonAr = shadowAr
|
||||
}
|
||||
|
||||
if err := cvs.SetAreaCells(buttonAr, buttonRune, cell.BgColor(b.opts.fillColor)); err != nil {
|
||||
return err
|
||||
var fillColor cell.Color
|
||||
switch {
|
||||
case b.state == button.Down && b.opts.pressedFillColor != nil:
|
||||
fillColor = *b.opts.pressedFillColor
|
||||
case meta.Focused && b.opts.focusedFillColor != nil:
|
||||
fillColor = *b.opts.focusedFillColor
|
||||
default:
|
||||
fillColor = b.opts.fillColor
|
||||
}
|
||||
|
||||
textAr := image.Rect(buttonAr.Min.X+1, buttonAr.Min.Y, buttonAr.Dx()-1, buttonAr.Max.Y)
|
||||
start, err := alignfor.Text(textAr, b.text, align.HorizontalCenter, align.VerticalMiddle)
|
||||
if err := cvs.SetAreaCells(buttonAr, buttonRune, cell.BgColor(fillColor)); err != nil {
|
||||
return err
|
||||
}
|
||||
return b.drawText(cvs, meta, buttonAr)
|
||||
}
|
||||
|
||||
// drawText draws the text inside the button.
|
||||
func (b *Button) drawText(cvs *canvas.Canvas, meta *widgetapi.Meta, buttonAr image.Rectangle) error {
|
||||
pad := b.opts.textHorizontalPadding
|
||||
textAr := image.Rect(buttonAr.Min.X+pad, buttonAr.Min.Y, buttonAr.Dx()-pad, buttonAr.Max.Y)
|
||||
start, err := alignfor.Text(textAr, b.text.String(), align.HorizontalCenter, align.VerticalMiddle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return draw.Text(cvs, b.text, start,
|
||||
draw.TextOverrunMode(draw.OverrunModeThreeDot),
|
||||
draw.TextMaxX(buttonAr.Max.X),
|
||||
draw.TextCellOpts(cell.FgColor(b.opts.textColor)),
|
||||
)
|
||||
|
||||
maxCells := buttonAr.Max.X - start.X
|
||||
trimmed, err := draw.TrimText(b.text.String(), maxCells, draw.OverrunModeThreeDot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
optRange, err := b.tOptsTracker.ForPosition(0) // Text options for the current byte.
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cur := start
|
||||
for i, r := range trimmed {
|
||||
if i >= optRange.High { // Get the next write options.
|
||||
or, err := b.tOptsTracker.ForPosition(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
optRange = or
|
||||
}
|
||||
|
||||
tOpts := b.givenTOpts[optRange.AttrIdx]
|
||||
var cellOpts []cell.Option
|
||||
switch {
|
||||
case b.state == button.Down && len(tOpts.pressedCellOpts) > 0:
|
||||
cellOpts = tOpts.pressedCellOpts
|
||||
case meta.Focused && len(tOpts.focusedCellOpts) > 0:
|
||||
cellOpts = tOpts.focusedCellOpts
|
||||
default:
|
||||
cellOpts = tOpts.cellOpts
|
||||
}
|
||||
cells, err := cvs.SetCell(cur, r, cellOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cur = image.Point{cur.X + cells, cur.Y}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// activated asserts whether the keyboard event activated the button.
|
||||
func (b *Button) keyActivated(k *terminalapi.Keyboard) bool {
|
||||
func (b *Button) keyActivated(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) bool {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if k.Key == b.opts.key {
|
||||
if b.opts.globalKeys[k.Key] || (b.opts.focusedKeys[k.Key] && meta.Focused) {
|
||||
b.state = button.Down
|
||||
now := time.Now().UTC()
|
||||
b.keyTriggerTime = &now
|
||||
@ -173,7 +280,7 @@ func (b *Button) keyActivated(k *terminalapi.Keyboard) bool {
|
||||
//
|
||||
// Implements widgetapi.Widget.Keyboard.
|
||||
func (b *Button) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error {
|
||||
if b.keyActivated(k) {
|
||||
if b.keyActivated(k, meta) {
|
||||
// Mutex must be released when calling the callback.
|
||||
// Users might call container methods from the callback like the
|
||||
// Container.Update, see #205.
|
||||
@ -208,19 +315,32 @@ func (b *Button) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// shadowWidth is the width of the shadow under the button in cell.
|
||||
const shadowWidth = 1
|
||||
// shadowWidth returns the width of the shadow under the button or zero if the
|
||||
// button shouldn't have any shadow.
|
||||
func (b *Button) shadowWidth() int {
|
||||
if b.opts.disableShadow {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// Options implements widgetapi.Widget.Options.
|
||||
func (b *Button) Options() widgetapi.Options {
|
||||
// No need to lock, as the height and width get fixed when New is called.
|
||||
|
||||
width := b.opts.width + shadowWidth
|
||||
height := b.opts.height + shadowWidth
|
||||
width := b.opts.width + b.shadowWidth() + 2*b.opts.textHorizontalPadding
|
||||
height := b.opts.height + b.shadowWidth()
|
||||
|
||||
var keyScope widgetapi.KeyScope
|
||||
if len(b.opts.focusedKeys) > 0 || len(b.opts.globalKeys) > 0 {
|
||||
keyScope = widgetapi.KeyScopeGlobal
|
||||
} else {
|
||||
keyScope = widgetapi.KeyScopeNone
|
||||
}
|
||||
return widgetapi.Options{
|
||||
MinimumSize: image.Point{width, height},
|
||||
MaximumSize: image.Point{width, height},
|
||||
WantKeyboard: b.opts.keyScope,
|
||||
WantKeyboard: keyScope,
|
||||
WantMouse: widgetapi.MouseScopeGlobal,
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -42,18 +42,25 @@ func (o option) set(opts *options) {
|
||||
|
||||
// options holds the provided options.
|
||||
type options struct {
|
||||
fillColor cell.Color
|
||||
textColor cell.Color
|
||||
shadowColor cell.Color
|
||||
height int
|
||||
width int
|
||||
key keyboard.Key
|
||||
keyScope widgetapi.KeyScope
|
||||
keyUpDelay time.Duration
|
||||
fillColor cell.Color
|
||||
focusedFillColor *cell.Color
|
||||
pressedFillColor *cell.Color
|
||||
textColor cell.Color
|
||||
textHorizontalPadding int
|
||||
shadowColor cell.Color
|
||||
disableShadow bool
|
||||
height int
|
||||
width int
|
||||
focusedKeys map[keyboard.Key]bool
|
||||
globalKeys map[keyboard.Key]bool
|
||||
keyUpDelay time.Duration
|
||||
}
|
||||
|
||||
// validate validates the provided options.
|
||||
func (o *options) validate() error {
|
||||
if min := 0; o.textHorizontalPadding < min {
|
||||
return fmt.Errorf("invalid textHorizontalPadding %d, must be %d <= textHorizontalPadding", o.textHorizontalPadding, min)
|
||||
}
|
||||
if min := 1; o.height < min {
|
||||
return fmt.Errorf("invalid height %d, must be %d <= height", o.height, min)
|
||||
}
|
||||
@ -63,18 +70,33 @@ func (o *options) validate() error {
|
||||
if min := time.Duration(0); o.keyUpDelay < min {
|
||||
return fmt.Errorf("invalid keyUpDelay %v, must be %v <= keyUpDelay", o.keyUpDelay, min)
|
||||
}
|
||||
|
||||
for k := range o.globalKeys {
|
||||
if o.focusedKeys[k] {
|
||||
return fmt.Errorf("key %q cannot be configured as both a focused key (options Key or Keys) and a global key (options GlobalKey or GlobalKeys)", k)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// keyScope stores a key and its scope.
|
||||
type keyScope struct {
|
||||
key keyboard.Key
|
||||
scope widgetapi.KeyScope
|
||||
}
|
||||
|
||||
// newOptions returns options with the default values set.
|
||||
func newOptions(text string) *options {
|
||||
return &options{
|
||||
fillColor: cell.ColorNumber(117),
|
||||
textColor: cell.ColorBlack,
|
||||
shadowColor: cell.ColorNumber(240),
|
||||
height: DefaultHeight,
|
||||
width: widthFor(text),
|
||||
keyUpDelay: DefaultKeyUpDelay,
|
||||
fillColor: cell.ColorNumber(117),
|
||||
textColor: cell.ColorBlack,
|
||||
textHorizontalPadding: DefaultTextHorizontalPadding,
|
||||
shadowColor: cell.ColorNumber(240),
|
||||
height: DefaultHeight,
|
||||
width: widthFor(text),
|
||||
keyUpDelay: DefaultKeyUpDelay,
|
||||
focusedKeys: map[keyboard.Key]bool{},
|
||||
globalKeys: map[keyboard.Key]bool{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,6 +107,23 @@ func FillColor(c cell.Color) Option {
|
||||
})
|
||||
}
|
||||
|
||||
// FocusedFillColor sets the fill color of the button when the widget's
|
||||
// container is focused.
|
||||
// Defaults to FillColor.
|
||||
func FocusedFillColor(c cell.Color) Option {
|
||||
return option(func(opts *options) {
|
||||
opts.focusedFillColor = &c
|
||||
})
|
||||
}
|
||||
|
||||
// PressedFillColor sets the fill color of the button when it is pressed.
|
||||
// Defaults to FillColor.
|
||||
func PressedFillColor(c cell.Color) Option {
|
||||
return option(func(opts *options) {
|
||||
opts.pressedFillColor = &c
|
||||
})
|
||||
}
|
||||
|
||||
// TextColor sets the color of the text label in the button.
|
||||
func TextColor(c cell.Color) Option {
|
||||
return option(func(opts *options) {
|
||||
@ -114,6 +153,8 @@ func Height(cells int) Option {
|
||||
// Width sets the width of the button in cells.
|
||||
// Must be a positive non-zero integer.
|
||||
// Defaults to the auto-width based on the length of the text label.
|
||||
// Not all the width may be available to the text if TextHorizontalPadding is
|
||||
// set to a non-zero integer.
|
||||
func Width(cells int) Option {
|
||||
return option(func(opts *options) {
|
||||
opts.width = cells
|
||||
@ -131,21 +172,47 @@ func WidthFor(text string) Option {
|
||||
|
||||
// Key configures the keyboard key that presses the button.
|
||||
// The widget responds to this key only if its container is focused.
|
||||
// When not provided, the widget ignores all keyboard events.
|
||||
//
|
||||
// Clears all keys set by Key() or Keys() previously.
|
||||
func Key(k keyboard.Key) Option {
|
||||
return option(func(opts *options) {
|
||||
opts.key = k
|
||||
opts.keyScope = widgetapi.KeyScopeFocused
|
||||
opts.focusedKeys = map[keyboard.Key]bool{}
|
||||
opts.focusedKeys[k] = true
|
||||
})
|
||||
}
|
||||
|
||||
// GlobalKey is like Key, but makes the widget respond to the key even if its
|
||||
// container isn't focused.
|
||||
// When not provided, the widget ignores all keyboard events.
|
||||
//
|
||||
// Clears all keys set by GlobalKey() or GlobalKeys() previously.
|
||||
func GlobalKey(k keyboard.Key) Option {
|
||||
return option(func(opts *options) {
|
||||
opts.key = k
|
||||
opts.keyScope = widgetapi.KeyScopeGlobal
|
||||
opts.globalKeys = map[keyboard.Key]bool{}
|
||||
opts.globalKeys[k] = true
|
||||
})
|
||||
}
|
||||
|
||||
// Keys is like Key, but allows to configure multiple keys.
|
||||
//
|
||||
// Clears all keys set by Key() or Keys() previously.
|
||||
func Keys(keys ...keyboard.Key) Option {
|
||||
return option(func(opts *options) {
|
||||
opts.focusedKeys = map[keyboard.Key]bool{}
|
||||
for _, k := range keys {
|
||||
opts.focusedKeys[k] = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// GlobalKeys is like GlobalKey, but allows to configure multiple keys.
|
||||
//
|
||||
// Clears all keys set by GlobalKey() or GlobalKeys() previously.
|
||||
func GlobalKeys(keys ...keyboard.Key) Option {
|
||||
return option(func(opts *options) {
|
||||
opts.globalKeys = map[keyboard.Key]bool{}
|
||||
for _, k := range keys {
|
||||
opts.globalKeys[k] = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -165,7 +232,26 @@ func KeyUpDelay(d time.Duration) Option {
|
||||
})
|
||||
}
|
||||
|
||||
// DisableShadow when provided the button will not have a shadow area and will
|
||||
// have no animation when pressed.
|
||||
func DisableShadow() Option {
|
||||
return option(func(opts *options) {
|
||||
opts.disableShadow = true
|
||||
})
|
||||
}
|
||||
|
||||
// DefaultTextHorizontalPadding is the default value for the HorizontalPadding option.
|
||||
const DefaultTextHorizontalPadding = 1
|
||||
|
||||
// TextHorizontalPadding sets padding on the left and right side of the
|
||||
// button's text as the amount of cells.
|
||||
func TextHorizontalPadding(p int) Option {
|
||||
return option(func(opts *options) {
|
||||
opts.textHorizontalPadding = p
|
||||
})
|
||||
}
|
||||
|
||||
// widthFor returns the required width for the specified text.
|
||||
func widthFor(text string) int {
|
||||
return runewidth.StringWidth(text) + 2 // One empty cell at each side.
|
||||
return runewidth.StringWidth(text)
|
||||
}
|
||||
|
85
widgets/button/text_options.go
Normal file
85
widgets/button/text_options.go
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright 2020 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package button
|
||||
|
||||
// text_options.go contains options used for the text displayed by the button.
|
||||
|
||||
import "github.com/mum4k/termdash/cell"
|
||||
|
||||
// TextOption is used to provide options to NewChunk().
|
||||
type TextOption interface {
|
||||
// set sets the provided option.
|
||||
set(*textOptions)
|
||||
}
|
||||
|
||||
// textOptions stores the provided options.
|
||||
type textOptions struct {
|
||||
cellOpts []cell.Option
|
||||
focusedCellOpts []cell.Option
|
||||
pressedCellOpts []cell.Option
|
||||
}
|
||||
|
||||
// setDefaultFgColor configures a default color for text if one isn't specified
|
||||
// in the text options.
|
||||
func (to *textOptions) setDefaultFgColor(c cell.Color) {
|
||||
to.cellOpts = append(
|
||||
[]cell.Option{cell.FgColor(c)},
|
||||
to.cellOpts...,
|
||||
)
|
||||
}
|
||||
|
||||
// newTextOptions returns new textOptions instance.
|
||||
func newTextOptions(tOpts ...TextOption) *textOptions {
|
||||
to := &textOptions{}
|
||||
for _, o := range tOpts {
|
||||
o.set(to)
|
||||
}
|
||||
return to
|
||||
}
|
||||
|
||||
// textOption implements TextOption.
|
||||
type textOption func(*textOptions)
|
||||
|
||||
// set implements TextOption.set.
|
||||
func (to textOption) set(tOpts *textOptions) {
|
||||
to(tOpts)
|
||||
}
|
||||
|
||||
// TextCellOpts sets options on the cells that contain the button text.
|
||||
// If not specified, all cells will just have their foreground color set to the
|
||||
// value of TextColor().
|
||||
func TextCellOpts(opts ...cell.Option) TextOption {
|
||||
return textOption(func(tOpts *textOptions) {
|
||||
tOpts.cellOpts = opts
|
||||
})
|
||||
}
|
||||
|
||||
// FocusedTextCellOpts sets options on the cells that contain the button text
|
||||
// when the widget's container is focused.
|
||||
// If not specified, TextCellOpts will be used instead.
|
||||
func FocusedTextCellOpts(opts ...cell.Option) TextOption {
|
||||
return textOption(func(tOpts *textOptions) {
|
||||
tOpts.focusedCellOpts = opts
|
||||
})
|
||||
}
|
||||
|
||||
// PressedTextCellOpts sets options on the cells that contain the button text
|
||||
// when it is pressed.
|
||||
// If not specified, TextCellOpts will be used instead.
|
||||
func PressedTextCellOpts(opts ...cell.Option) TextOption {
|
||||
return textOption(func(tOpts *textOptions) {
|
||||
tOpts.pressedCellOpts = opts
|
||||
})
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user