Browse Source

Add Button.SetCursorRune and CheckBox.SetCursorRune

Cursors are now shown within Buttons and CheckBoxes by default.

Resolves #62.
textarea
Trevor Slocum 6 months ago
parent
commit
454d759a42
  1. 4
      CHANGELOG
  2. 4
      README.md
  3. 21
      button.go
  4. 26
      checkbox.go
  5. 1
      demos/button/main.go
  6. 4
      demos/presentation/introduction.go
  7. 4
      dropdown.go
  8. 8
      form.go
  9. 7
      styles.go
  10. 9
      textview.go

4
CHANGELOG

@ -1,8 +1,10 @@
v1.5.6 (WIP)
- Add TrueColorTags option and do not use TrueColor tag values by default
- Add TextView.SetHighlightForegroundColor and TextView.SetHighlightBackgroundColor
- Add Button.SetCursorRune (cursors are now shown within Buttons when focused by default)
- Add CheckBox.SetCursorRune (cursors are now shown within CheckBoxes when focused by default)
- Add DropDown.SetAlwaysDrawDropDownSymbol (DropDown symbols are now shown only when focused by default)
- Add DropDown.SetDropDownOpenSymbolRune
- Add DropDown.SetAlwaysDrawDropDownSymbol (DropDown symbols are now only drawn when focused by default)
- Draw additional accents when rendering a list divider
- Update List, Table and TreeView to not handle Tab or Backtab
- Allow specifying TabbedPanels switcher height

4
README.md

@ -67,10 +67,10 @@ func main() {
```
Examples are available via [godoc](https://docs.rocketnine.space/code.rocketnine.space/tslocum/cview#pkg-examples)
and in the [demos](https://code.rocketnine.space/tslocum/cview/src/branch/master/demos) subdirectory.
and in the [demos](https://code.rocketnine.space/tslocum/cview/src/branch/master/demos) directory.
For a presentation highlighting the features of this package, compile and run
the program in the [demos/presentation](https://code.rocketnine.space/tslocum/cview/src/branch/master/demos/presentation) subdirectory.
the program in the [demos/presentation](https://code.rocketnine.space/tslocum/cview/src/branch/master/demos/presentation) directory.
## Documentation

21
button.go

@ -4,6 +4,7 @@ import (
"sync"
"github.com/gdamore/tcell/v2"
"github.com/mattn/go-runewidth"
)
// Button is labeled box that triggers an action when selected.
@ -29,6 +30,9 @@ type Button struct {
// key is provided indicating which key was pressed to leave (tab or backtab).
blur func(tcell.Key)
// An optional rune which is drawn after the label when the button is focused.
cursorRune rune
sync.RWMutex
}
@ -36,13 +40,14 @@ type Button struct {
func NewButton(label string) *Button {
box := NewBox()
box.SetRect(0, 0, TaggedStringWidth(label)+4, 1)
box.SetBackgroundColor(Styles.ContrastBackgroundColor)
box.SetBackgroundColor(Styles.MoreContrastBackgroundColor)
return &Button{
Box: box,
label: []byte(label),
labelColor: Styles.PrimaryTextColor,
labelColorFocused: Styles.PrimaryTextColor,
backgroundColorFocused: Styles.MoreContrastBackgroundColor,
cursorRune: Styles.ButtonCursorRune,
backgroundColorFocused: Styles.ContrastBackgroundColor,
}
}
@ -79,6 +84,14 @@ func (b *Button) SetLabelColorFocused(color tcell.Color) {
b.labelColorFocused = color
}
// SetCursorRune sets the rune to show within the button when it is focused.
func (b *Button) SetCursorRune(rune rune) {
b.Lock()
defer b.Unlock()
b.cursorRune = rune
}
// SetBackgroundColorFocused sets the background color of the button text when
// the button is in focus.
func (b *Button) SetBackgroundColorFocused(color tcell.Color) {
@ -141,6 +154,10 @@ func (b *Button) Draw(screen tcell.Screen) {
labelColor := b.labelColor
if b.focus.HasFocus() {
labelColor = b.labelColorFocused
// Draw cursor.
if b.cursorRune != 0 {
Print(screen, []byte(string(b.cursorRune)), x+width-(width-runewidth.StringWidth(string(b.label)))/2+1, y, width, AlignLeft, labelColor)
}
}
Print(screen, b.label, x, y, width, AlignCenter, labelColor)
}

26
checkbox.go

@ -58,6 +58,9 @@ type CheckBox struct {
// The rune to show when the checkbox is checked
checkedRune rune
// An optional rune to show within the checkbox when it is focused
cursorRune rune
sync.RWMutex
}
@ -66,11 +69,12 @@ func NewCheckBox() *CheckBox {
return &CheckBox{
Box: NewBox(),
labelColor: Styles.SecondaryTextColor,
fieldBackgroundColor: Styles.ContrastBackgroundColor,
fieldBackgroundColor: Styles.MoreContrastBackgroundColor,
fieldBackgroundColorFocused: Styles.ContrastBackgroundColor,
fieldTextColor: Styles.PrimaryTextColor,
checkedRune: Styles.CheckBoxCheckedRune,
cursorRune: Styles.CheckBoxCursorRune,
labelColorFocused: ColorUnset,
fieldBackgroundColorFocused: ColorUnset,
fieldTextColorFocused: ColorUnset,
}
}
@ -91,6 +95,14 @@ func (c *CheckBox) SetCheckedRune(rune rune) {
c.checkedRune = rune
}
// SetCursorRune sets the rune to show within the checkbox when it is focused.
func (c *CheckBox) SetCursorRune(rune rune) {
c.Lock()
defer c.Unlock()
c.cursorRune = rune
}
// IsChecked returns whether or not the box is checked.
func (c *CheckBox) IsChecked() bool {
c.RLock()
@ -248,11 +260,13 @@ func (c *CheckBox) Draw(screen tcell.Screen) {
c.Lock()
defer c.Unlock()
hasFocus := c.GetFocusable().HasFocus()
// Select colors
labelColor := c.labelColor
fieldBackgroundColor := c.fieldBackgroundColor
fieldTextColor := c.fieldTextColor
if c.GetFocusable().HasFocus() {
if hasFocus {
if c.labelColorFocused != ColorUnset {
labelColor = c.labelColorFocused
}
@ -291,9 +305,13 @@ func (c *CheckBox) Draw(screen tcell.Screen) {
if !c.checked {
checkedRune = ' '
}
rightRune := ' '
if c.cursorRune != 0 && hasFocus {
rightRune = c.cursorRune
}
screen.SetContent(x, y, ' ', nil, fieldStyle)
screen.SetContent(x+1, y, checkedRune, nil, fieldStyle)
screen.SetContent(x+2, y, ' ', nil, fieldStyle)
screen.SetContent(x+2, y, rightRune, nil, fieldStyle)
if len(c.message) > 0 {
Print(screen, c.message, x+4, y, len(c.message), AlignLeft, labelColor)

1
demos/button/main.go

@ -8,7 +8,6 @@ func main() {
app.EnableMouse(true)
button := cview.NewButton("Hit Enter to close")
button.SetBorder(true)
button.SetRect(0, 0, 22, 3)
button.SetSelectedFunc(func() {
app.Stop()

4
demos/presentation/introduction.go

@ -8,8 +8,8 @@ func Introduction(nextSlide func()) (title string, info string, content cview.Pr
listText := [][]string{
{"A Go package for terminal based UIs", "with a special focus on rich interactive widgets"},
{"Based on github.com/gdamore/tcell", "Like termbox but better (see tcell docs)"},
{"Designed to be simple", `"Hello world" is 5 lines of code`},
{"Based on github.com/gdamore/tcell", "Supports Linux, FreeBSD, MacOS and Windows"},
{"Designed to be simple", `"Hello world" is less than 20 lines of code`},
{"Good for data entry", `For charts, use "termui" - for low-level views, use "gocui" - ...`},
{"Supports context menus", "Right click on one of these items or press Alt+Enter"},
{"Extensive documentation", "Demo code is available for each widget"},

4
dropdown.go

@ -154,14 +154,14 @@ func NewDropDown() *DropDown {
list.SetSelectedTextColor(Styles.PrimitiveBackgroundColor)
list.SetSelectedBackgroundColor(Styles.PrimaryTextColor)
list.SetHighlightFullLine(true)
list.SetBackgroundColor(Styles.MoreContrastBackgroundColor)
list.SetBackgroundColor(Styles.ContrastBackgroundColor)
d := &DropDown{
Box: NewBox(),
currentOption: -1,
list: list,
labelColor: Styles.SecondaryTextColor,
fieldBackgroundColor: Styles.ContrastBackgroundColor,
fieldBackgroundColor: Styles.MoreContrastBackgroundColor,
fieldTextColor: Styles.PrimaryTextColor,
prefixTextColor: Styles.ContrastSecondaryTextColor,
dropDownSymbol: Styles.DropDownSymbol,

8
form.go

@ -151,12 +151,12 @@ func NewForm() *Form {
Box: box,
itemPadding: 1,
labelColor: Styles.SecondaryTextColor,
fieldBackgroundColor: Styles.ContrastBackgroundColor,
fieldBackgroundColorFocused: Styles.MoreContrastBackgroundColor,
fieldBackgroundColor: Styles.MoreContrastBackgroundColor,
fieldBackgroundColorFocused: Styles.ContrastBackgroundColor,
fieldTextColor: Styles.PrimaryTextColor,
fieldTextColorFocused: Styles.PrimaryTextColor,
buttonBackgroundColor: Styles.ContrastBackgroundColor,
buttonBackgroundColorFocused: Styles.MoreContrastBackgroundColor,
buttonBackgroundColor: Styles.MoreContrastBackgroundColor,
buttonBackgroundColorFocused: Styles.ContrastBackgroundColor,
buttonTextColor: Styles.PrimaryTextColor,
buttonTextColorFocused: Styles.PrimaryTextColor,
labelColorFocused: ColorUnset,

7
styles.go

@ -22,8 +22,12 @@ type Theme struct {
ContrastBackgroundColor tcell.Color // Background color for contrasting elements.
MoreContrastBackgroundColor tcell.Color // Background color for even more contrasting elements.
// Button
ButtonCursorRune rune // The symbol to draw at the end of button labels when focused.
// Check box
CheckBoxCheckedRune rune
CheckBoxCursorRune rune // The symbol to draw within the checkbox when focused.
// Context menu
ContextMenuPaddingTop int
@ -63,7 +67,10 @@ var Styles = Theme{
ContrastBackgroundColor: tcell.ColorGreen.TrueColor(),
MoreContrastBackgroundColor: tcell.ColorDarkGreen.TrueColor(),
ButtonCursorRune: '◀',
CheckBoxCheckedRune: 'X',
CheckBoxCursorRune: '◀',
ContextMenuPaddingTop: 0,
ContextMenuPaddingBottom: 0,

9
textview.go

@ -14,14 +14,15 @@ import (
)
var (
openColorRegex = regexp.MustCompile(`\[([a-zA-Z]*|#[0-9a-zA-Z]*)$`)
openRegionRegex = regexp.MustCompile(`\["[a-zA-Z0-9_,;: \-\.]*"?$`)
newLineRegex = regexp.MustCompile(`\r?\n`)
// TabSize is the number of spaces with which a tab character will be replaced.
TabSize = 4
)
var (
openColorRegex = regexp.MustCompile(`\[([a-zA-Z]*|#[0-9a-zA-Z]*)$`)
openRegionRegex = regexp.MustCompile(`\["[a-zA-Z0-9_,;: \-\.]*"?$`)
)
// textViewIndex contains information about each line displayed in the text
// view.
type textViewIndex struct {

Loading…
Cancel
Save