...

Source file src/gitlab.com/tslocum/cview/checkbox.go

Documentation: gitlab.com/tslocum/cview

     1  package cview
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/gdamore/tcell/v2"
     7  )
     8  
     9  // CheckBox implements a simple box for boolean values which can be checked and
    10  // unchecked.
    11  type CheckBox struct {
    12  	*Box
    13  
    14  	// Whether or not this box is checked.
    15  	checked bool
    16  
    17  	// The text to be displayed before the checkbox.
    18  	label []byte
    19  
    20  	// The text to be displayed after the checkbox.
    21  	message []byte
    22  
    23  	// The screen width of the label area. A value of 0 means use the width of
    24  	// the label text.
    25  	labelWidth int
    26  
    27  	// The label color.
    28  	labelColor tcell.Color
    29  
    30  	// The label color when focused.
    31  	labelColorFocused tcell.Color
    32  
    33  	// The background color of the input area.
    34  	fieldBackgroundColor tcell.Color
    35  
    36  	// The background color of the input area when focused.
    37  	fieldBackgroundColorFocused tcell.Color
    38  
    39  	// The text color of the input area.
    40  	fieldTextColor tcell.Color
    41  
    42  	// The text color of the input area when focused.
    43  	fieldTextColorFocused tcell.Color
    44  
    45  	// An optional function which is called when the user changes the checked
    46  	// state of this checkbox.
    47  	changed func(checked bool)
    48  
    49  	// An optional function which is called when the user indicated that they
    50  	// are done entering text. The key which was pressed is provided (tab,
    51  	// shift-tab, or escape).
    52  	done func(tcell.Key)
    53  
    54  	// A callback function set by the Form class and called when the user leaves
    55  	// this form item.
    56  	finished func(tcell.Key)
    57  
    58  	// The rune to show when the checkbox is checked
    59  	checkedRune rune
    60  
    61  	sync.RWMutex
    62  }
    63  
    64  // NewCheckBox returns a new input field.
    65  func NewCheckBox() *CheckBox {
    66  	return &CheckBox{
    67  		Box:                         NewBox(),
    68  		labelColor:                  Styles.SecondaryTextColor,
    69  		fieldBackgroundColor:        Styles.ContrastBackgroundColor,
    70  		fieldTextColor:              Styles.PrimaryTextColor,
    71  		checkedRune:                 Styles.CheckBoxCheckedRune,
    72  		labelColorFocused:           ColorUnset,
    73  		fieldBackgroundColorFocused: ColorUnset,
    74  		fieldTextColorFocused:       ColorUnset,
    75  	}
    76  }
    77  
    78  // SetChecked sets the state of the checkbox.
    79  func (c *CheckBox) SetChecked(checked bool) {
    80  	c.Lock()
    81  	defer c.Unlock()
    82  
    83  	c.checked = checked
    84  }
    85  
    86  // SetCheckedRune sets the rune to show when the checkbox is checked.
    87  func (c *CheckBox) SetCheckedRune(rune rune) {
    88  	c.Lock()
    89  	defer c.Unlock()
    90  
    91  	c.checkedRune = rune
    92  }
    93  
    94  // IsChecked returns whether or not the box is checked.
    95  func (c *CheckBox) IsChecked() bool {
    96  	c.RLock()
    97  	defer c.RUnlock()
    98  
    99  	return c.checked
   100  }
   101  
   102  // SetLabel sets the text to be displayed before the input area.
   103  func (c *CheckBox) SetLabel(label string) {
   104  	c.Lock()
   105  	defer c.Unlock()
   106  
   107  	c.label = []byte(label)
   108  }
   109  
   110  // GetLabel returns the text to be displayed before the input area.
   111  func (c *CheckBox) GetLabel() string {
   112  	c.RLock()
   113  	defer c.RUnlock()
   114  
   115  	return string(c.label)
   116  }
   117  
   118  // SetMessage sets the text to be displayed after the checkbox
   119  func (c *CheckBox) SetMessage(message string) {
   120  	c.Lock()
   121  	defer c.Unlock()
   122  
   123  	c.message = []byte(message)
   124  }
   125  
   126  // GetMessage returns the text to be displayed after the checkbox
   127  func (c *CheckBox) GetMessage() string {
   128  	c.RLock()
   129  	defer c.RUnlock()
   130  
   131  	return string(c.message)
   132  }
   133  
   134  // SetLabelWidth sets the screen width of the label. A value of 0 will cause the
   135  // primitive to use the width of the label string.
   136  func (c *CheckBox) SetLabelWidth(width int) {
   137  	c.Lock()
   138  	defer c.Unlock()
   139  
   140  	c.labelWidth = width
   141  }
   142  
   143  // SetLabelColor sets the color of the label.
   144  func (c *CheckBox) SetLabelColor(color tcell.Color) {
   145  	c.Lock()
   146  	defer c.Unlock()
   147  
   148  	c.labelColor = color
   149  }
   150  
   151  // SetLabelColorFocused sets the color of the label when focused.
   152  func (c *CheckBox) SetLabelColorFocused(color tcell.Color) {
   153  	c.Lock()
   154  	defer c.Unlock()
   155  
   156  	c.labelColorFocused = color
   157  }
   158  
   159  // SetFieldBackgroundColor sets the background color of the input area.
   160  func (c *CheckBox) SetFieldBackgroundColor(color tcell.Color) {
   161  	c.Lock()
   162  	defer c.Unlock()
   163  
   164  	c.fieldBackgroundColor = color
   165  }
   166  
   167  // SetFieldBackgroundColorFocused sets the background color of the input area when focused.
   168  func (c *CheckBox) SetFieldBackgroundColorFocused(color tcell.Color) {
   169  	c.Lock()
   170  	defer c.Unlock()
   171  
   172  	c.fieldBackgroundColorFocused = color
   173  }
   174  
   175  // SetFieldTextColor sets the text color of the input area.
   176  func (c *CheckBox) SetFieldTextColor(color tcell.Color) {
   177  	c.Lock()
   178  	defer c.Unlock()
   179  
   180  	c.fieldTextColor = color
   181  }
   182  
   183  // SetFieldTextColorFocused sets the text color of the input area when focused.
   184  func (c *CheckBox) SetFieldTextColorFocused(color tcell.Color) {
   185  	c.Lock()
   186  	defer c.Unlock()
   187  
   188  	c.fieldTextColorFocused = color
   189  }
   190  
   191  // GetFieldHeight returns the height of the field.
   192  func (c *CheckBox) GetFieldHeight() int {
   193  	return 1
   194  }
   195  
   196  // GetFieldWidth returns this primitive's field width.
   197  func (c *CheckBox) GetFieldWidth() int {
   198  	c.RLock()
   199  	defer c.RUnlock()
   200  
   201  	if len(c.message) == 0 {
   202  		return 1
   203  	}
   204  
   205  	return 2 + len(c.message)
   206  }
   207  
   208  // SetChangedFunc sets a handler which is called when the checked state of this
   209  // checkbox was changed by the user. The handler function receives the new
   210  // state.
   211  func (c *CheckBox) SetChangedFunc(handler func(checked bool)) {
   212  	c.Lock()
   213  	defer c.Unlock()
   214  
   215  	c.changed = handler
   216  }
   217  
   218  // SetDoneFunc sets a handler which is called when the user is done using the
   219  // checkbox. The callback function is provided with the key that was pressed,
   220  // which is one of the following:
   221  //
   222  //   - KeyEscape: Abort text input.
   223  //   - KeyTab: Move to the next field.
   224  //   - KeyBacktab: Move to the previous field.
   225  func (c *CheckBox) SetDoneFunc(handler func(key tcell.Key)) {
   226  	c.Lock()
   227  	defer c.Unlock()
   228  
   229  	c.done = handler
   230  }
   231  
   232  // SetFinishedFunc sets a callback invoked when the user leaves this form item.
   233  func (c *CheckBox) SetFinishedFunc(handler func(key tcell.Key)) {
   234  	c.Lock()
   235  	defer c.Unlock()
   236  
   237  	c.finished = handler
   238  }
   239  
   240  // Draw draws this primitive onto the screen.
   241  func (c *CheckBox) Draw(screen tcell.Screen) {
   242  	if !c.GetVisible() {
   243  		return
   244  	}
   245  
   246  	c.Box.Draw(screen)
   247  
   248  	c.Lock()
   249  	defer c.Unlock()
   250  
   251  	// Select colors
   252  	labelColor := c.labelColor
   253  	fieldBackgroundColor := c.fieldBackgroundColor
   254  	fieldTextColor := c.fieldTextColor
   255  	if c.GetFocusable().HasFocus() {
   256  		if c.labelColorFocused != ColorUnset {
   257  			labelColor = c.labelColorFocused
   258  		}
   259  		if c.fieldBackgroundColorFocused != ColorUnset {
   260  			fieldBackgroundColor = c.fieldBackgroundColorFocused
   261  		}
   262  		if c.fieldTextColorFocused != ColorUnset {
   263  			fieldTextColor = c.fieldTextColorFocused
   264  		}
   265  	}
   266  
   267  	// Prepare
   268  	x, y, width, height := c.GetInnerRect()
   269  	rightLimit := x + width
   270  	if height < 1 || rightLimit <= x {
   271  		return
   272  	}
   273  
   274  	// Draw label.
   275  	if c.labelWidth > 0 {
   276  		labelWidth := c.labelWidth
   277  		if labelWidth > rightLimit-x {
   278  			labelWidth = rightLimit - x
   279  		}
   280  		Print(screen, c.label, x, y, labelWidth, AlignLeft, labelColor)
   281  		x += labelWidth
   282  	} else {
   283  		_, drawnWidth := Print(screen, c.label, x, y, rightLimit-x, AlignLeft, labelColor)
   284  		x += drawnWidth
   285  	}
   286  
   287  	// Draw checkbox.
   288  	fieldStyle := tcell.StyleDefault.Background(fieldBackgroundColor).Foreground(fieldTextColor)
   289  
   290  	checkedRune := c.checkedRune
   291  	if !c.checked {
   292  		checkedRune = ' '
   293  	}
   294  	screen.SetContent(x, y, ' ', nil, fieldStyle)
   295  	screen.SetContent(x+1, y, checkedRune, nil, fieldStyle)
   296  	screen.SetContent(x+2, y, ' ', nil, fieldStyle)
   297  
   298  	if len(c.message) > 0 {
   299  		Print(screen, c.message, x+4, y, len(c.message), AlignLeft, labelColor)
   300  	}
   301  }
   302  
   303  // InputHandler returns the handler for this primitive.
   304  func (c *CheckBox) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
   305  	return c.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
   306  		if HitShortcut(event, Keys.Select, Keys.Select2) {
   307  			c.Lock()
   308  			c.checked = !c.checked
   309  			c.Unlock()
   310  			if c.changed != nil {
   311  				c.changed(c.checked)
   312  			}
   313  		} else if HitShortcut(event, Keys.Cancel, Keys.MovePreviousField, Keys.MoveNextField) {
   314  			if c.done != nil {
   315  				c.done(event.Key())
   316  			}
   317  			if c.finished != nil {
   318  				c.finished(event.Key())
   319  			}
   320  		}
   321  	})
   322  }
   323  
   324  // MouseHandler returns the mouse handler for this primitive.
   325  func (c *CheckBox) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
   326  	return c.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
   327  		x, y := event.Position()
   328  		_, rectY, _, _ := c.GetInnerRect()
   329  		if !c.InRect(x, y) {
   330  			return false, nil
   331  		}
   332  
   333  		// Process mouse event.
   334  		if action == MouseLeftClick && y == rectY {
   335  			setFocus(c)
   336  			c.checked = !c.checked
   337  			if c.changed != nil {
   338  				c.changed(c.checked)
   339  			}
   340  			consumed = true
   341  		}
   342  
   343  		return
   344  	})
   345  }
   346  

View as plain text