sampler-fork/component/menu.go

233 lines
5.4 KiB
Go
Raw Normal View History

2019-02-24 04:49:09 +00:00
package component
2019-02-11 02:51:55 +00:00
import (
2019-03-14 03:01:44 +00:00
ui "github.com/gizak/termui/v3"
"github.com/sqshq/sampler/component/util"
"github.com/sqshq/sampler/config"
2019-02-11 02:51:55 +00:00
"github.com/sqshq/sampler/console"
"image"
)
type Menu struct {
*ui.Block
2019-07-29 00:27:14 +00:00
options []menuOption
2019-02-11 02:51:55 +00:00
component Component
2019-07-29 00:27:14 +00:00
mode menuMode
option menuOption
palette console.Palette
2019-02-11 02:51:55 +00:00
}
2019-07-29 00:27:14 +00:00
type menuMode rune
2019-02-11 02:51:55 +00:00
const (
2019-07-29 00:27:14 +00:00
menuModeIdle menuMode = 0
menuModeHighlight menuMode = 1
menuModeOptionSelect menuMode = 2
menuModeMoveAndResize menuMode = 3
2019-02-11 02:51:55 +00:00
)
2019-07-29 00:27:14 +00:00
type menuOption string
2019-02-11 02:51:55 +00:00
const (
2019-07-29 00:27:14 +00:00
MenuOptionMove menuOption = "MOVE"
MenuOptionResize menuOption = "RESIZE"
MenuOptionPinpoint menuOption = "PINPOINT"
MenuOptionResume menuOption = "RESUME"
2019-02-11 02:51:55 +00:00
)
2019-02-26 04:36:23 +00:00
const (
minimalMenuHeight = 8
)
func NewMenu(palette console.Palette) *Menu {
2019-02-11 02:51:55 +00:00
return &Menu{
Block: NewBlock("", true, palette),
2019-07-29 00:27:14 +00:00
options: []menuOption{MenuOptionMove, MenuOptionResize, MenuOptionPinpoint, MenuOptionResume},
mode: menuModeIdle,
2019-02-11 02:51:55 +00:00
option: MenuOptionMove,
palette: palette,
2019-02-11 02:51:55 +00:00
}
}
2019-07-29 00:27:14 +00:00
func (m *Menu) GetSelectedOption() menuOption {
2019-02-11 02:51:55 +00:00
return m.option
}
2019-03-08 04:04:46 +00:00
func (m *Menu) Highlight(component *Component) {
m.component = *component
2019-02-11 02:51:55 +00:00
m.updateDimensions()
2019-07-29 00:27:14 +00:00
m.mode = menuModeHighlight
2019-02-11 02:51:55 +00:00
m.Title = component.Title
}
2019-03-08 04:04:46 +00:00
func (m *Menu) Choose() {
2019-07-29 00:27:14 +00:00
m.mode = menuModeOptionSelect
2019-02-11 02:51:55 +00:00
}
2019-03-08 04:04:46 +00:00
func (m *Menu) Idle() {
2019-07-29 00:27:14 +00:00
m.mode = menuModeIdle
2019-02-11 02:51:55 +00:00
}
2019-03-08 04:04:46 +00:00
func (m *Menu) Up() {
2019-02-11 02:51:55 +00:00
for i := 1; i < len(m.options); i++ {
if m.options[i] == m.option {
m.option = m.options[i-1]
break
}
}
2019-02-17 23:00:00 +00:00
if m.option == MenuOptionPinpoint && m.component.Type != config.TypeRunChart {
2019-03-08 04:04:46 +00:00
m.Up()
2019-02-17 23:00:00 +00:00
}
2019-02-11 02:51:55 +00:00
}
2019-03-08 04:04:46 +00:00
func (m *Menu) Down() {
2019-02-11 02:51:55 +00:00
for i := 0; i < len(m.options)-1; i++ {
if m.options[i] == m.option {
m.option = m.options[i+1]
break
}
}
2019-02-17 23:00:00 +00:00
if m.option == MenuOptionPinpoint && m.component.Type != config.TypeRunChart {
2019-03-08 04:04:46 +00:00
m.Down()
2019-02-17 23:00:00 +00:00
}
2019-02-11 02:51:55 +00:00
}
2019-03-08 04:04:46 +00:00
func (m *Menu) MoveOrResize() {
2019-07-29 00:27:14 +00:00
m.mode = menuModeMoveAndResize
2019-02-11 02:51:55 +00:00
}
func (m *Menu) Draw(buffer *ui.Buffer) {
2019-07-29 00:27:14 +00:00
if m.mode == menuModeIdle {
2019-02-11 02:51:55 +00:00
return
}
m.updateDimensions()
buffer.Fill(ui.NewCell(' ', ui.NewStyle(m.palette.ReverseColor)), m.GetRect())
2019-02-26 04:36:23 +00:00
if m.Dy() > minimalMenuHeight {
m.drawInnerBorder(buffer)
}
m.Block.Draw(buffer)
2019-02-11 02:51:55 +00:00
switch m.mode {
2019-07-29 00:27:14 +00:00
case menuModeHighlight:
2019-02-11 02:51:55 +00:00
m.renderHighlight(buffer)
2019-07-29 00:27:14 +00:00
case menuModeMoveAndResize:
2019-02-11 02:51:55 +00:00
m.renderMoveAndResize(buffer)
2019-07-29 00:27:14 +00:00
case menuModeOptionSelect:
2019-02-11 02:51:55 +00:00
m.renderOptions(buffer)
}
}
func (m *Menu) renderHighlight(buffer *ui.Buffer) {
2019-02-26 04:36:23 +00:00
optionsText := "<ENTER> to view options"
resumeText := "<ESC> to resume"
if m.Dy() <= minimalMenuHeight {
buffer.SetString(
optionsText,
ui.NewStyle(console.ColorDarkGrey),
util.GetMiddlePoint(m.Block.Rectangle, optionsText, -1),
2019-02-26 04:36:23 +00:00
)
return
}
2019-06-09 17:00:47 +00:00
m.printAllDirectionsArrowSign(buffer, -1)
2019-02-11 02:51:55 +00:00
optionsTextPoint := util.GetMiddlePoint(m.Block.Rectangle, optionsText, 3)
2019-02-25 00:08:36 +00:00
if optionsTextPoint.Y+1 < m.Inner.Max.Y {
buffer.SetString(
optionsText,
ui.NewStyle(console.ColorDarkGrey),
util.GetMiddlePoint(m.Block.Rectangle, optionsText, 3),
)
}
2019-02-11 02:51:55 +00:00
resumeTextPoint := util.GetMiddlePoint(m.Block.Rectangle, resumeText, 4)
2019-02-25 00:08:36 +00:00
if resumeTextPoint.Y+1 < m.Inner.Max.Y {
buffer.SetString(
resumeText,
ui.NewStyle(console.ColorDarkGrey),
resumeTextPoint,
)
}
2019-02-11 02:51:55 +00:00
}
func (m *Menu) renderMoveAndResize(buffer *ui.Buffer) {
saveText := "<ENTER> to save changes"
2019-02-26 04:36:23 +00:00
if m.Dy() <= minimalMenuHeight {
buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), util.GetMiddlePoint(m.Block.Rectangle, saveText, -1))
2019-02-26 04:36:23 +00:00
return
2019-02-11 02:51:55 +00:00
}
2019-02-26 04:36:23 +00:00
m.printAllDirectionsArrowSign(buffer, -1)
buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), util.GetMiddlePoint(m.Block.Rectangle, saveText, 3))
2019-02-11 02:51:55 +00:00
}
func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) {
arrows := []string{
" ↑ ",
"← →",
2019-02-11 02:51:55 +00:00
" ↓ ",
}
for i, a := range arrows {
util.PrintString(
2019-02-11 02:51:55 +00:00
a,
ui.NewStyle(console.ColorOlive),
util.GetMiddlePoint(m.Block.Rectangle, a, i+y),
2019-03-14 04:28:26 +00:00
buffer,
2019-02-11 02:51:55 +00:00
)
}
}
func (m *Menu) renderOptions(buffer *ui.Buffer) {
2019-03-26 03:29:23 +00:00
highlightedStyle := ui.NewStyle(m.palette.ReverseColor, console.ColorOlive)
regularStyle := ui.NewStyle(m.palette.BaseColor, m.palette.ReverseColor)
2019-02-11 02:51:55 +00:00
offset := 1
for _, option := range m.options {
style := regularStyle
if m.option == option {
style = highlightedStyle
}
if option != MenuOptionPinpoint || m.component.Type == config.TypeRunChart {
2019-02-11 02:51:55 +00:00
offset += 2
point := util.GetMiddlePoint(m.Block.Rectangle, string(option), offset-6)
2019-02-26 04:36:23 +00:00
buffer.SetString(string(option), style, point)
2019-02-11 02:51:55 +00:00
}
}
}
func (m *Menu) updateDimensions() {
2019-03-16 23:59:28 +00:00
r := m.component.GetRect()
2019-02-11 02:51:55 +00:00
m.SetRect(r.Min.X, r.Min.Y, r.Max.X, r.Max.Y)
}
func (m *Menu) drawInnerBorder(buffer *ui.Buffer) {
verticalCell := ui.Cell{ui.VERTICAL_LINE, m.BorderStyle}
horizontalCell := ui.Cell{ui.HORIZONTAL_LINE, m.BorderStyle}
// draw lines
buffer.Fill(horizontalCell, image.Rect(m.Min.X+2, m.Min.Y+2, m.Max.X-2, m.Min.Y))
buffer.Fill(horizontalCell, image.Rect(m.Min.X+2, m.Max.Y-2, m.Max.X-2, m.Max.Y))
buffer.Fill(verticalCell, image.Rect(m.Min.X+2, m.Min.Y+1, m.Min.X+3, m.Max.Y-1))
buffer.Fill(verticalCell, image.Rect(m.Max.X-2, m.Min.Y, m.Max.X-3, m.Max.Y))
// draw corners
buffer.SetCell(ui.Cell{ui.TOP_LEFT, m.BorderStyle}, image.Pt(m.Min.X+2, m.Min.Y+1))
buffer.SetCell(ui.Cell{ui.TOP_RIGHT, m.BorderStyle}, image.Pt(m.Max.X-3, m.Min.Y+1))
buffer.SetCell(ui.Cell{ui.BOTTOM_LEFT, m.BorderStyle}, image.Pt(m.Min.X+2, m.Max.Y-2))
buffer.SetCell(ui.Cell{ui.BOTTOM_RIGHT, m.BorderStyle}, image.Pt(m.Max.X-3, m.Max.Y-2))
}