diff --git a/termbox_menu.go b/termbox_menu.go index 70b888f..44e7485 100644 --- a/termbox_menu.go +++ b/termbox_menu.go @@ -15,6 +15,7 @@ type Menu struct { disabledBg, disabledFg termbox.Attribute isDone bool bordered bool + vimMode bool } // CreateMenu Creates a menu with the specified attributes @@ -178,6 +179,20 @@ func (i *Menu) SelectNextOption() *Menu { return i } +// SetOptionDisabled Disables the specified option +func (i *Menu) SetOptionDisabled(idx int) { + if len(i.options) > idx { + i.GetOptionFromIndex(idx).Disable() + } +} + +// SetOptionEnabled Enables the specified option +func (i *Menu) SetOptionEnabled(idx int) { + if len(i.options) > idx { + i.GetOptionFromIndex(idx).Enable() + } +} + // HelpIsShown returns true or false if the help is displayed func (i *Menu) HelpIsShown() bool { return i.showHelp } @@ -223,6 +238,18 @@ func (i *Menu) SetBordered(b bool) *Menu { return i } +// EnableVimMode Enables h,j,k,l navigation +func (i *Menu) EnableVimMode() *Menu { + i.vimMode = true + return i +} + +// DisableVimMode Disables h,j,k,l navigation +func (i *Menu) DisableVimMode() *Menu { + i.vimMode = false + return i +} + // HandleKeyPress handles the termbox event and returns whether it was consumed func (i *Menu) HandleKeyPress(event termbox.Event) bool { if event.Key == termbox.KeyEnter { @@ -236,6 +263,14 @@ func (i *Menu) HandleKeyPress(event termbox.Event) bool { case termbox.KeyArrowDown: i.SelectNextOption() } + if i.vimMode { + switch event.Ch { + case 'j': + i.SelectNextOption() + case 'k': + i.SelectPrevOption() + } + } if i.GetSelectedIndex() != currentIdx { return true } diff --git a/termbox_progressbar.go b/termbox_progressbar.go new file mode 100644 index 0000000..afb0ed8 --- /dev/null +++ b/termbox_progressbar.go @@ -0,0 +1,224 @@ +package termboxUtil + +import "github.com/nsf/termbox-go" + +// ProgressBar Just contains the data needed to display a progress bar +type ProgressBar struct { + total int + progress int + allowOverflow bool + allowUnderflow bool + fullChar rune + emptyChar rune + bordered bool + alignment TextAlignment + + x, y int + width, height int + bg, fg termbox.Attribute +} + +// CreateProgressBar Create a progress bar object +func CreateProgressBar(tot, x, y int, fg, bg termbox.Attribute) *ProgressBar { + i := ProgressBar{total: tot, + fullChar: '#', emptyChar: ' ', + x: x, y: y, height: 1, width: 10, + bordered: true, fg: fg, bg: bg, + alignment: AlignLeft, + } + return &i +} + +// GetProgress returns the curret progress value +func (i *ProgressBar) GetProgress() int { + return i.progress +} + +// SetProgress sets the current progress of the bar +func (i *ProgressBar) SetProgress(p int) *ProgressBar { + if (p <= i.total || i.allowOverflow) || (p >= 0 || i.allowUnderflow) { + i.progress = p + } + return i +} + +// IncrProgress increments the current progress of the bar +func (i *ProgressBar) IncrProgress() *ProgressBar { + if i.progress < i.total || i.allowOverflow { + i.progress++ + } + return i +} + +// DecrProgress decrements the current progress of the bar +func (i *ProgressBar) DecrProgress() *ProgressBar { + if i.progress > 0 || i.allowUnderflow { + i.progress-- + } + return i +} + +// GetPercent returns the percent full of the bar +func (i *ProgressBar) GetPercent() int { + return int(float64(i.progress) / float64(i.total) * 100) +} + +// EnableOverflow Tells the progress bar that it can go over the total +func (i *ProgressBar) EnableOverflow() *ProgressBar { + i.allowOverflow = true + return i +} + +// DisableOverflow Tells the progress bar that it can NOT go over the total +func (i *ProgressBar) DisableOverflow() *ProgressBar { + i.allowOverflow = false + return i +} + +// EnableUnderflow Tells the progress bar that it can go below zero +func (i *ProgressBar) EnableUnderflow() *ProgressBar { + i.allowUnderflow = true + return i +} + +// DisableUnderflow Tells the progress bar that it can NOT go below zero +func (i *ProgressBar) DisableUnderflow() *ProgressBar { + i.allowUnderflow = false + return i +} + +// GetFullChar returns the rune used for 'full' +func (i *ProgressBar) GetFullChar() rune { + return i.fullChar +} + +// SetFullChar sets the rune used for 'full' +func (i *ProgressBar) SetFullChar(f rune) *ProgressBar { + i.fullChar = f + return i +} + +// GetEmptyChar gets the rune used for 'empty' +func (i *ProgressBar) GetEmptyChar() rune { + return i.emptyChar +} + +// SetEmptyChar sets the rune used for 'empty' +func (i *ProgressBar) SetEmptyChar(f rune) *ProgressBar { + i.emptyChar = f + return i +} + +// GetX Return the x position of the Progress Bar +func (i *ProgressBar) GetX() int { return i.x } + +// SetX set the x position of the ProgressBar to x +func (i *ProgressBar) SetX(x int) *ProgressBar { + i.x = x + return i +} + +// GetY Return the y position of the ProgressBar +func (i *ProgressBar) GetY() int { return i.y } + +// SetY Set the y position of the ProgressBar to y +func (i *ProgressBar) SetY(y int) *ProgressBar { + i.y = y + return i +} + +// GetHeight returns the height of the progress bar +// Defaults to 1 (3 if bordered) +func (i *ProgressBar) GetHeight() int { + return i.height +} + +// SetHeight Sets the height of the progress bar +func (i *ProgressBar) SetHeight(h int) *ProgressBar { + i.height = h + return i +} + +// GetWidth returns the width of the progress bar +func (i *ProgressBar) GetWidth() int { + return i.width +} + +// SetWidth Sets the width of the progress bar +func (i *ProgressBar) SetWidth(w int) *ProgressBar { + i.width = w + return i +} + +// GetBackground Return the current background color of the modal +func (i *ProgressBar) GetBackground() termbox.Attribute { return i.bg } + +// SetBackground Set the current background color to bg +func (i *ProgressBar) SetBackground(bg termbox.Attribute) *ProgressBar { + i.bg = bg + return i +} + +// GetForeground Return the current foreground color +func (i *ProgressBar) GetForeground() termbox.Attribute { return i.fg } + +// SetForeground Set the foreground color to fg +func (i *ProgressBar) SetForeground(fg termbox.Attribute) *ProgressBar { + i.fg = fg + return i +} + +// Align Tells which direction the progress bar empties +func (i *ProgressBar) Align(a TextAlignment) *ProgressBar { + i.alignment = a + return i +} + +// HandleKeyPress accepts the termbox event and returns whether it was consumed +func (i *ProgressBar) HandleKeyPress(event termbox.Event) bool { + return false +} + +// Draw outputs the input field on the screen +func (i *ProgressBar) Draw() { + // For now, just draw a [#### ] bar + // TODO: make this more advanced + drawX, drawY := i.x, i.y + fillWidth, fillHeight := i.width-2, i.height + DrawStringAtPoint("[", drawX, drawY, i.fg, i.bg) + numFull := int(float64(fillWidth) * float64(i.progress) / float64(i.total)) + FillWithChar(i.fullChar, drawX+1, drawY, drawX+1+numFull, drawY+(fillHeight-1), i.fg, i.bg) + DrawStringAtPoint("]", drawX+i.width-1, drawY, i.fg, i.bg) + + /* + drawX, drawY := i.x, i.y + drawWidth, drawHeight := i.width, i.height + if i.bordered { + if i.height == 1 && i.width > 2 { + // Just using [ & ] for the border + DrawStringAtPoint("[", drawX, drawY, i.fg, i.bg) + DrawStringAtPoint("]", drawX+i.width-1, drawY, i.fg, i.bg) + drawX++ + drawWidth -= 2 + } else if i.height >= 3 { + DrawBorder(drawX, drawY, drawX+i.width, drawY+i.height, i.fg, i.bg) + drawX++ + drawY++ + drawWidth -= 2 + drawHeight -= 2 + } + } + + // Figure out how many chars are full + numFull := drawWidth * (i.progress / i.total) + switch i.alignment { + case AlignRight: // TODO: Fill from right to left + case AlignCenter: // TODO: Fill from middle out + default: // Fill from left to right + FillWithChar(i.fullChar, drawX, drawY, drawX+numFull, drawY+(drawHeight-1), i.fg, i.bg) + if numFull < drawWidth { + FillWithChar(i.emptyChar, drawX+numFull, drawY, drawX+drawWidth-1, drawY+(drawHeight-1), i.fg, i.bg) + } + } + */ +}