From 02537f2b96dab8cae8e4044cf2b8fdd81d8ba59e Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Mon, 26 Oct 2015 17:38:49 -0500 Subject: [PATCH] Updated a few things Add a few handy things to asciiart and menu --- termbox_asciiart.go | 24 +++++ termbox_menu.go | 248 ++++++++++++++++++++++++++++++++++---------- termbox_util.go | 5 +- 3 files changed, 221 insertions(+), 56 deletions(-) diff --git a/termbox_asciiart.go b/termbox_asciiart.go index 9b60d11..d86855b 100644 --- a/termbox_asciiart.go +++ b/termbox_asciiart.go @@ -35,6 +35,30 @@ func (i *ASCIIArt) SetY(y int) *ASCIIArt { return i } +// GetHeight Returns the number of strings in the contents slice +func (i *ASCIIArt) GetHeight() int { + return len(i.contents) +} + +// SetContents Sets the contents of i to c +func (i *ASCIIArt) SetContents(c []string) *ASCIIArt { + i.contents = c + return i +} + +// GetContents returns the ascii art +func (i *ASCIIArt) GetContents() []string { + return i.contents +} + +// SetContentLine Sets a specific line of the contents to s +func (i *ASCIIArt) SetContentLine(s string, idx int) *ASCIIArt { + if idx >= 0 && idx < len(i.contents) { + i.contents[idx] = s + } + return i +} + // GetBackground Return the current background color of the modal func (i *ASCIIArt) GetBackground() termbox.Attribute { return i.bg } diff --git a/termbox_menu.go b/termbox_menu.go index 0c54a1c..70b888f 100644 --- a/termbox_menu.go +++ b/termbox_menu.go @@ -1,38 +1,36 @@ package termboxUtil -import ( - "github.com/nsf/termbox-go" -) +import "github.com/nsf/termbox-go" // Menu is a menu with a list of options type Menu struct { title string - options []string + options []MenuOption // If height is -1, then it is adaptive to the menu x, y, width, height int - optionsDisabled []bool - optionsHelp []string showHelp bool cursor int bg, fg termbox.Attribute selectedBg, selectedFg termbox.Attribute disabledBg, disabledFg termbox.Attribute isDone bool - selectedOption int bordered bool - hasFocus bool } // CreateMenu Creates a menu with the specified attributes func CreateMenu(title string, options []string, x, y, width, height int, fg, bg termbox.Attribute) *Menu { - i := Menu{title: title, options: options, x: x, y: y, width: width, height: height, fg: fg, bg: bg} - for len(i.optionsDisabled) < len(i.options) { - i.optionsDisabled = append(i.optionsDisabled, false) + i := Menu{ + title: title, + x: x, y: y, width: width, height: height, + fg: fg, bg: bg, selectedFg: bg, selectedBg: fg, + disabledFg: bg, disabledBg: bg, + } + for _, line := range options { + i.options = append(i.options, MenuOption{text: line}) + } + if len(i.options) > 0 { + i.SetSelectedOption(&i.options[0]) } - i.selectedFg = i.bg - i.selectedBg = i.fg - i.disabledFg = i.bg - i.disabledBg = i.bg return &i } @@ -46,30 +44,23 @@ func (i *Menu) SetTitle(s string) *Menu { } // GetOptions returns the current options of the menu -func (i *Menu) GetOptions() []string { +func (i *Menu) GetOptions() []MenuOption { return i.options } // SetOptions set the menu's options to opts -func (i *Menu) SetOptions(opts []string) *Menu { +func (i *Menu) SetOptions(opts []MenuOption) *Menu { i.options = opts return i } -// SetOptionDisabled sets an option in the menu to disabled -func (i *Menu) SetOptionDisabled(idx int) *Menu { - if idx > 0 && idx < len(i.options) { - i.optionsDisabled[idx] = true +// SetOptionsFromStrings sets the options of this menu from a slice of strings +func (i *Menu) SetOptionsFromStrings(opts []string) *Menu { + var newOpts []MenuOption + for _, v := range opts { + newOpts = append(newOpts, *CreateOptionFromText(v)) } - return i -} - -// SetOptionEnabled sets an option to enabled -func (i *Menu) SetOptionEnabled(idx int) *Menu { - if idx >= 0 && idx < len(i.options) { - i.optionsDisabled[idx] = false - } - return i + return i.SetOptions(newOpts) } // GetX returns the current x coordinate of the menu @@ -108,6 +99,85 @@ func (i *Menu) SetHeight(height int) *Menu { return i } +// GetSelectedOption returns the current selected option +func (i *Menu) GetSelectedOption() *MenuOption { + idx := i.GetSelectedIndex() + if idx != -1 { + return &i.options[idx] + } + return nil +} + +// GetOptionFromIndex Returns the +func (i *Menu) GetOptionFromIndex(idx int) *MenuOption { + if idx >= 0 && idx < len(i.options) { + return &i.options[idx] + } + return nil +} + +// GetOptionFromText Returns the first option with the text v +func (i *Menu) GetOptionFromText(v string) *MenuOption { + for idx := range i.options { + testOption := &i.options[idx] + if testOption.GetText() == v { + return testOption + } + } + return nil +} + +// GetSelectedIndex returns the index of the selected option +// Returns -1 if nothing is selected +func (i *Menu) GetSelectedIndex() int { + for idx := range i.options { + if i.options[idx].IsSelected() { + return idx + } + } + return -1 +} + +// SetSelectedOption sets the current selected option to v (if it's valid) +func (i *Menu) SetSelectedOption(v *MenuOption) *Menu { + for idx := range i.options { + if &i.options[idx] == v { + i.options[idx].Select() + } else { + i.options[idx].Unselect() + } + } + return i +} + +// SelectPrevOption Decrements the selected option (if it can) +func (i *Menu) SelectPrevOption() *Menu { + idx := i.GetSelectedIndex() + for idx >= 0 { + idx-- + testOption := i.GetOptionFromIndex(idx) + if testOption != nil && !testOption.IsDisabled() { + i.SetSelectedOption(testOption) + return i + } + } + return i +} + +// SelectNextOption Increments the selected option (if it can) +func (i *Menu) SelectNextOption() *Menu { + idx := i.GetSelectedIndex() + for idx < len(i.options) { + idx++ + testOption := i.GetOptionFromIndex(idx) + if testOption != nil && !testOption.IsDisabled() { + i.SetSelectedOption(testOption) + return i + } + } + return i +} + // HelpIsShown returns true or false if the help is displayed func (i *Menu) HelpIsShown() bool { return i.showHelp } @@ -155,23 +225,19 @@ func (i *Menu) SetBordered(b bool) *Menu { // HandleKeyPress handles the termbox event and returns whether it was consumed func (i *Menu) HandleKeyPress(event termbox.Event) bool { - if i.hasFocus { - if event.Key == termbox.KeyEnter { - i.isDone = true - return true - } - switch event.Key { - case termbox.KeyArrowUp: - if i.selectedOption > 0 { - i.selectedOption-- - return true - } - case termbox.KeyArrowDown: - if i.selectedOption < len(i.options) { - i.selectedOption++ - return true - } - } + if event.Key == termbox.KeyEnter { + i.isDone = true + return true + } + currentIdx := i.GetSelectedIndex() + switch event.Key { + case termbox.KeyArrowUp: + i.SelectPrevOption() + case termbox.KeyArrowDown: + i.SelectNextOption() + } + if i.GetSelectedIndex() != currentIdx { + return true } return false } @@ -196,7 +262,7 @@ func (i *Menu) Draw() { } optionStartX = i.x + 1 optionStartY = i.y + 1 - optionWidth = i.width - 2 + optionWidth = i.width - 1 } // The title @@ -210,13 +276,85 @@ func (i *Menu) Draw() { } // Print the options - for idx, opt := range i.options { - if i.optionsDisabled[idx] { - DrawStringAtPoint(opt, optionStartX, optionStartY, i.disabledFg, i.disabledBg) - } else if i.selectedOption == idx { - DrawStringAtPoint(opt, optionStartX, optionStartY, i.selectedFg, i.selectedBg) - } else { - DrawStringAtPoint(opt, optionStartX, optionStartY, i.fg, i.bg) + if len(i.options) > 0 { + for idx := range i.options { + currOpt := &i.options[idx] + if currOpt.IsDisabled() { + DrawStringAtPoint(currOpt.GetText(), optionStartX, optionStartY, i.disabledFg, i.disabledBg) + } else if i.GetSelectedOption() == currOpt { + DrawStringAtPoint(AlignText(currOpt.GetText(), optionWidth, AlignLeft), optionStartX, optionStartY, i.selectedFg, i.selectedBg) + } else { + DrawStringAtPoint(currOpt.GetText(), optionStartX, optionStartY, i.fg, i.bg) + } + optionStartY++ } } } + +/* MenuOption Struct & methods */ + +// MenuOption An option in the menu +type MenuOption struct { + text string + selected bool + disabled bool + helpText string +} + +// CreateOptionFromText just returns a MenuOption object +// That only has it's text value set. +func CreateOptionFromText(s string) *MenuOption { + return &MenuOption{text: s} +} + +// SetText Sets the text for this option +func (i *MenuOption) SetText(s string) *MenuOption { + i.text = s + return i +} + +// GetText Returns the text for this option +func (i *MenuOption) GetText() string { return i.text } + +// Disable Sets this option to disabled +func (i *MenuOption) Disable() *MenuOption { + i.disabled = true + return i +} + +// Enable Sets this option to enabled +func (i *MenuOption) Enable() *MenuOption { + i.disabled = false + return i +} + +// IsDisabled returns whether this option is enabled +func (i *MenuOption) IsDisabled() bool { + return i.disabled +} + +// IsSelected Returns whether this option is selected +func (i *MenuOption) IsSelected() bool { + return i.selected +} + +// Select Sets this option to selected +func (i *MenuOption) Select() *MenuOption { + i.selected = true + return i +} + +// Unselect Sets this option to not selected +func (i *MenuOption) Unselect() *MenuOption { + i.selected = false + return i +} + +// SetHelpText Sets this option's help text to s +func (i *MenuOption) SetHelpText(s string) *MenuOption { + i.helpText = s + return i +} + +// GetHelpText Returns the help text for this option +func (i *MenuOption) GetHelpText() string { return i.helpText } diff --git a/termbox_util.go b/termbox_util.go index 67ecb3f..db05a84 100644 --- a/termbox_util.go +++ b/termbox_util.go @@ -69,7 +69,10 @@ func AlignText(txt string, width int, align TextAlignment) string { case AlignRight: return fmt.Sprintf("%s%s", strings.Repeat(" ", numSpaces), txt) default: - return fmt.Sprintf("%s%s", txt, strings.Repeat(" ", numSpaces)) + if numSpaces >= 0 { + return fmt.Sprintf("%s%s", txt, strings.Repeat(" ", numSpaces)) + } + return txt } }