implemented move/resize/pinpoint menu
This commit is contained in:
parent
f5ccf6c464
commit
b9cc09c1e4
|
@ -8,7 +8,7 @@ runcharts:
|
|||
script: curl -o /dev/null -s -w '%{time_total}' https://search.yahoo.com/
|
||||
- label: BING
|
||||
script: curl -o /dev/null -s -w '%{time_total}' https://www.bing.com/
|
||||
refresh-rate-ms: 500
|
||||
refresh-rate-ms: 200
|
||||
decimal-places: 3
|
||||
alert:
|
||||
value:
|
||||
|
@ -52,8 +52,8 @@ runcharts:
|
|||
x: 0
|
||||
y: 15
|
||||
size:
|
||||
x: 15
|
||||
y: 15
|
||||
x: 4
|
||||
y: 4
|
||||
- title: MONGO COLLECTIONS COUNT
|
||||
items:
|
||||
- label: POSTS
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package console
|
||||
|
||||
const (
|
||||
KeyPause = "p"
|
||||
KeyQuit = "q"
|
||||
KeyResize = "<Resize>"
|
||||
KeyExit = "<C-c>"
|
||||
KeyLeft = "<Left>"
|
||||
KeyRight = "<Right>"
|
||||
KeyUp = "<Up>"
|
||||
KeyDown = "<Down>"
|
||||
KeyEnter = "<Enter>"
|
||||
KeyEsc = "<Escape>"
|
||||
)
|
|
@ -17,6 +17,9 @@ const (
|
|||
ColorDeepSkyBlue ui.Color = 39
|
||||
ColorDeepPink ui.Color = 162
|
||||
ColorDarkGrey ui.Color = 240
|
||||
ColorWhite ui.Color = 7
|
||||
ColorBlack ui.Color = 0
|
||||
ColorClear ui.Color = -1
|
||||
)
|
||||
|
||||
type Palette struct {
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package event
|
||||
|
||||
type Event string
|
||||
|
||||
const (
|
||||
EventPause = "p"
|
||||
EventQuit = "q"
|
||||
EventResize = "<Resize>"
|
||||
EventExit = "<C-c>"
|
||||
EventMouseClick = "<MouseLeft>"
|
||||
EventKeyboardLeft = "<Left>"
|
||||
EventKeyboardRight = "<Right>"
|
||||
EventKeyboardUp = "<Up>"
|
||||
EventKeyboardDown = "<Down>"
|
||||
)
|
|
@ -1,6 +1,7 @@
|
|||
package event
|
||||
|
||||
import (
|
||||
"github.com/sqshq/sampler/console"
|
||||
"github.com/sqshq/sampler/widgets"
|
||||
ui "github.com/sqshq/termui"
|
||||
"time"
|
||||
|
@ -24,23 +25,17 @@ func (self *Handler) HandleEvents() {
|
|||
}
|
||||
case e := <-self.ConsoleEvents:
|
||||
switch e.ID {
|
||||
case EventQuit, EventExit:
|
||||
case console.KeyQuit, console.KeyExit:
|
||||
return
|
||||
case EventPause:
|
||||
case console.KeyPause:
|
||||
pause = !pause
|
||||
case EventResize:
|
||||
case console.KeyResize:
|
||||
payload := e.Payload.(ui.Resize)
|
||||
self.Layout.ChangeDimensions(payload.Width, payload.Height)
|
||||
case "a":
|
||||
self.Layout.GetComponent(0).DisableSelection()
|
||||
case EventKeyboardLeft:
|
||||
self.Layout.GetComponent(0).MoveSelection(-1)
|
||||
case EventKeyboardRight:
|
||||
self.Layout.GetComponent(0).MoveSelection(+1)
|
||||
case EventKeyboardDown:
|
||||
//layout.GetItem(0).Move(0, 1)
|
||||
case EventKeyboardUp:
|
||||
//layout.GetItem(0).Move(0, -1)
|
||||
//case "a":
|
||||
// self.Layout.GetComponent(0).DisableSelection()
|
||||
default:
|
||||
self.Layout.HandleConsoleEvent(e.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
5
main.go
5
main.go
|
@ -17,12 +17,13 @@ func main() {
|
|||
csl.Init()
|
||||
defer csl.Close()
|
||||
|
||||
layout := widgets.NewLayout(ui.TerminalDimensions())
|
||||
width, height := ui.TerminalDimensions()
|
||||
layout := widgets.NewLayout(width, height, widgets.NewMenu())
|
||||
|
||||
for _, chartConfig := range cfg.RunCharts {
|
||||
|
||||
chart := widgets.NewRunChart(chartConfig.Title, chartConfig.Precision, chartConfig.RefreshRateMs)
|
||||
layout.AddComponent(chart, chartConfig.Position, chartConfig.Size, widgets.TypeRunChart)
|
||||
layout.AddComponent(chart, chartConfig.Title, chartConfig.Position, chartConfig.Size, widgets.TypeRunChart)
|
||||
|
||||
for _, item := range chartConfig.Items {
|
||||
data.NewSampler(chart, item, chartConfig.RefreshRateMs)
|
||||
|
|
|
@ -6,15 +6,17 @@ import (
|
|||
|
||||
type Component struct {
|
||||
Drawable Drawable
|
||||
Title string
|
||||
Position Position
|
||||
Size Size
|
||||
Type ComponentType
|
||||
}
|
||||
|
||||
type ComponentType string
|
||||
type ComponentType rune
|
||||
|
||||
const (
|
||||
TypeRunChart ComponentType = "runchart"
|
||||
TypeRunChart ComponentType = 0
|
||||
TypeBarChart ComponentType = 1
|
||||
)
|
||||
|
||||
type Position struct {
|
||||
|
|
|
@ -1,39 +1,57 @@
|
|||
package widgets
|
||||
|
||||
import (
|
||||
. "github.com/sqshq/termui"
|
||||
"github.com/sqshq/sampler/console"
|
||||
ui "github.com/sqshq/termui"
|
||||
)
|
||||
|
||||
type Layout struct {
|
||||
Block
|
||||
ui.Block
|
||||
components []Component
|
||||
menu *Menu
|
||||
mode Mode
|
||||
selection int
|
||||
}
|
||||
|
||||
type Mode rune
|
||||
|
||||
const (
|
||||
ModeDefault Mode = 0
|
||||
ModeComponentSelect Mode = 1
|
||||
ModeMenuOptionSelect Mode = 2
|
||||
ModeComponentMove Mode = 3
|
||||
ModeComponentResize Mode = 4
|
||||
ModeChartPinpoint Mode = 5
|
||||
)
|
||||
|
||||
const (
|
||||
columnsCount = 30
|
||||
rowsCount = 30
|
||||
)
|
||||
|
||||
func NewLayout(width, height int) *Layout {
|
||||
func NewLayout(width, height int, menu *Menu) *Layout {
|
||||
|
||||
block := *NewBlock()
|
||||
block := *ui.NewBlock()
|
||||
block.SetRect(0, 0, width, height)
|
||||
|
||||
return &Layout{
|
||||
Block: block,
|
||||
components: make([]Component, 0),
|
||||
menu: menu,
|
||||
mode: ModeDefault,
|
||||
selection: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Layout) AddComponent(drawable Drawable, position Position, size Size, Type ComponentType) {
|
||||
self.components = append(self.components, Component{drawable, position, size, Type})
|
||||
func (l *Layout) AddComponent(drawable ui.Drawable, title string, position Position, size Size, Type ComponentType) {
|
||||
l.components = append(l.components, Component{drawable, title, position, size, Type})
|
||||
}
|
||||
|
||||
func (self *Layout) GetComponents(Type ComponentType) []Drawable {
|
||||
func (l *Layout) GetComponents(Type ComponentType) []ui.Drawable {
|
||||
|
||||
var components []Drawable
|
||||
var components []ui.Drawable
|
||||
|
||||
for _, component := range self.components {
|
||||
for _, component := range l.components {
|
||||
if component.Type == Type {
|
||||
components = append(components, component.Drawable)
|
||||
}
|
||||
|
@ -42,21 +60,127 @@ func (self *Layout) GetComponents(Type ComponentType) []Drawable {
|
|||
return components
|
||||
}
|
||||
|
||||
// temp function until ui item selection is implemented
|
||||
func (self *Layout) GetComponent(i int) *RunChart {
|
||||
return self.components[i].Drawable.(*RunChart)
|
||||
// TODO func to get prev/next component navigating left/right/top/bottom
|
||||
func (l *Layout) getComponent(i int) Component {
|
||||
return l.components[i]
|
||||
}
|
||||
|
||||
func (self *Layout) ChangeDimensions(width, height int) {
|
||||
self.SetRect(0, 0, width, height)
|
||||
func (l *Layout) getSelectedComponent() *Component {
|
||||
return &l.components[l.selection]
|
||||
}
|
||||
|
||||
func (self *Layout) Draw(buffer *Buffer) {
|
||||
func (l *Layout) HandleConsoleEvent(e string) {
|
||||
switch e {
|
||||
case console.KeyEnter:
|
||||
switch l.mode {
|
||||
case ModeComponentSelect:
|
||||
l.menu.choose()
|
||||
l.mode = ModeMenuOptionSelect
|
||||
case ModeMenuOptionSelect:
|
||||
option := l.menu.getSelectedOption()
|
||||
switch option {
|
||||
case MenuOptionMove:
|
||||
l.mode = ModeComponentMove
|
||||
l.menu.moveOrResize()
|
||||
case MenuOptionResize:
|
||||
l.mode = ModeComponentResize
|
||||
l.menu.moveOrResize()
|
||||
case MenuOptionPinpoint:
|
||||
l.mode = ModeChartPinpoint
|
||||
l.menu.idle()
|
||||
chart := l.getSelectedComponent().Drawable.(*RunChart)
|
||||
chart.MoveSelection(0)
|
||||
case MenuOptionExit:
|
||||
l.mode = ModeDefault
|
||||
l.menu.idle()
|
||||
}
|
||||
case ModeComponentMove:
|
||||
fallthrough
|
||||
case ModeComponentResize:
|
||||
l.menu.idle()
|
||||
l.mode = ModeDefault
|
||||
}
|
||||
case console.KeyEsc:
|
||||
switch l.mode {
|
||||
case ModeChartPinpoint:
|
||||
chart := l.getSelectedComponent().Drawable.(*RunChart)
|
||||
chart.DisableSelection()
|
||||
fallthrough
|
||||
case ModeComponentSelect:
|
||||
fallthrough
|
||||
case ModeMenuOptionSelect:
|
||||
l.menu.idle()
|
||||
l.mode = ModeDefault
|
||||
}
|
||||
case console.KeyLeft:
|
||||
switch l.mode {
|
||||
case ModeDefault:
|
||||
l.mode = ModeComponentSelect
|
||||
l.selection = 0
|
||||
l.menu.highlight(l.getComponent(l.selection))
|
||||
case ModeChartPinpoint:
|
||||
chart := l.getSelectedComponent().Drawable.(*RunChart)
|
||||
chart.MoveSelection(-1)
|
||||
case ModeComponentSelect:
|
||||
if l.selection > 0 {
|
||||
l.selection--
|
||||
}
|
||||
l.menu.highlight(l.getComponent(l.selection))
|
||||
case ModeComponentMove:
|
||||
l.getSelectedComponent().Move(-1, 0)
|
||||
case ModeComponentResize:
|
||||
l.getSelectedComponent().Resize(-1, 0)
|
||||
}
|
||||
case console.KeyRight:
|
||||
switch l.mode {
|
||||
case ModeDefault:
|
||||
l.mode = ModeComponentSelect
|
||||
l.selection = 0
|
||||
l.menu.highlight(l.getComponent(l.selection))
|
||||
case ModeChartPinpoint:
|
||||
chart := l.getSelectedComponent().Drawable.(*RunChart)
|
||||
chart.MoveSelection(1)
|
||||
case ModeComponentSelect:
|
||||
if l.selection < len(l.components)-1 {
|
||||
l.selection++
|
||||
}
|
||||
l.menu.highlight(l.getComponent(l.selection))
|
||||
case ModeComponentMove:
|
||||
l.getSelectedComponent().Move(1, 0)
|
||||
case ModeComponentResize:
|
||||
l.getSelectedComponent().Resize(1, 0)
|
||||
}
|
||||
case console.KeyUp:
|
||||
switch l.mode {
|
||||
case ModeMenuOptionSelect:
|
||||
l.menu.up()
|
||||
case ModeComponentMove:
|
||||
l.getSelectedComponent().Move(0, -1)
|
||||
case ModeComponentResize:
|
||||
l.getSelectedComponent().Resize(0, -1)
|
||||
}
|
||||
case console.KeyDown:
|
||||
switch l.mode {
|
||||
case ModeMenuOptionSelect:
|
||||
l.menu.down()
|
||||
case ModeComponentMove:
|
||||
l.getSelectedComponent().Move(0, 1)
|
||||
case ModeComponentResize:
|
||||
l.getSelectedComponent().Resize(0, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
columnWidth := float64(self.GetRect().Dx()) / columnsCount
|
||||
rowHeight := float64(self.GetRect().Dy()) / rowsCount
|
||||
func (l *Layout) ChangeDimensions(width, height int) {
|
||||
l.SetRect(0, 0, width, height)
|
||||
}
|
||||
|
||||
for _, component := range self.components {
|
||||
func (l *Layout) Draw(buffer *ui.Buffer) {
|
||||
|
||||
columnWidth := float64(l.GetRect().Dx()) / columnsCount
|
||||
rowHeight := float64(l.GetRect().Dy()) / rowsCount
|
||||
|
||||
for _, component := range l.components {
|
||||
|
||||
x1 := float64(component.Position.X) * columnWidth
|
||||
y1 := float64(component.Position.Y) * rowHeight
|
||||
|
@ -66,4 +190,6 @@ func (self *Layout) Draw(buffer *Buffer) {
|
|||
component.Drawable.SetRect(int(x1), int(y1), int(x2), int(y2))
|
||||
component.Drawable.Draw(buffer)
|
||||
}
|
||||
|
||||
l.menu.Draw(buffer)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
package widgets
|
||||
|
||||
import (
|
||||
"github.com/sqshq/sampler/console"
|
||||
ui "github.com/sqshq/termui"
|
||||
"image"
|
||||
)
|
||||
|
||||
type Menu struct {
|
||||
ui.Block
|
||||
options []MenuOption
|
||||
component Component
|
||||
mode MenuMode
|
||||
option MenuOption
|
||||
}
|
||||
|
||||
type MenuMode rune
|
||||
|
||||
const (
|
||||
MenuModeIdle MenuMode = 0
|
||||
MenuModeHighlight MenuMode = 1
|
||||
MenuModeOptionSelect MenuMode = 2
|
||||
MenuModeMoveAndResize MenuMode = 3
|
||||
)
|
||||
|
||||
type MenuOption string
|
||||
|
||||
const (
|
||||
MenuOptionMove MenuOption = "MOVE"
|
||||
MenuOptionResize MenuOption = "RESIZE"
|
||||
MenuOptionPinpoint MenuOption = "PINPOINT"
|
||||
MenuOptionExit MenuOption = "EXIT"
|
||||
)
|
||||
|
||||
func NewMenu() *Menu {
|
||||
block := *ui.NewBlock()
|
||||
block.Border = true
|
||||
block.BorderStyle = ui.NewStyle(console.ColorDarkGrey)
|
||||
return &Menu{
|
||||
Block: block,
|
||||
options: []MenuOption{MenuOptionMove, MenuOptionResize, MenuOptionPinpoint, MenuOptionExit},
|
||||
mode: MenuModeIdle,
|
||||
option: MenuOptionMove,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) getSelectedOption() MenuOption {
|
||||
return m.option
|
||||
}
|
||||
|
||||
func (m *Menu) highlight(component Component) {
|
||||
m.component = component
|
||||
m.updateDimensions()
|
||||
m.mode = MenuModeHighlight
|
||||
m.Title = component.Title
|
||||
}
|
||||
|
||||
func (m *Menu) choose() {
|
||||
m.mode = MenuModeOptionSelect
|
||||
}
|
||||
|
||||
func (m *Menu) idle() {
|
||||
m.mode = MenuModeIdle
|
||||
}
|
||||
|
||||
func (m *Menu) up() {
|
||||
for i := 1; i < len(m.options); i++ {
|
||||
if m.options[i] == m.option {
|
||||
m.option = m.options[i-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) down() {
|
||||
for i := 0; i < len(m.options)-1; i++ {
|
||||
if m.options[i] == m.option {
|
||||
m.option = m.options[i+1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) moveOrResize() {
|
||||
m.mode = MenuModeMoveAndResize
|
||||
}
|
||||
|
||||
func (m *Menu) Draw(buffer *ui.Buffer) {
|
||||
|
||||
if m.mode == MenuModeIdle {
|
||||
return
|
||||
}
|
||||
|
||||
m.updateDimensions()
|
||||
|
||||
buffer.Fill(
|
||||
ui.NewCell(' ', ui.NewStyle(ui.ColorClear, ui.ColorBlack)),
|
||||
m.GetRect(),
|
||||
)
|
||||
|
||||
switch m.mode {
|
||||
case MenuModeHighlight:
|
||||
m.renderHighlight(buffer)
|
||||
case MenuModeMoveAndResize:
|
||||
m.renderMoveAndResize(buffer)
|
||||
case MenuModeOptionSelect:
|
||||
m.renderOptions(buffer)
|
||||
}
|
||||
|
||||
m.drawInnerBorder(buffer)
|
||||
m.Block.Draw(buffer)
|
||||
}
|
||||
|
||||
func (m *Menu) renderHighlight(buffer *ui.Buffer) {
|
||||
|
||||
m.printAllDirectionsArrowSign(buffer, -2)
|
||||
|
||||
arrowsText := "Use arrows for selection"
|
||||
buffer.SetString(
|
||||
arrowsText,
|
||||
ui.NewStyle(console.ColorDarkGrey),
|
||||
getMiddlePoint(m.Block, arrowsText, 2),
|
||||
)
|
||||
|
||||
optionsText := "<ENTER> to view options"
|
||||
buffer.SetString(
|
||||
optionsText,
|
||||
ui.NewStyle(console.ColorDarkGrey),
|
||||
getMiddlePoint(m.Block, optionsText, 3),
|
||||
)
|
||||
|
||||
resumeText := "<ESC> to resume"
|
||||
buffer.SetString(
|
||||
resumeText,
|
||||
ui.NewStyle(console.ColorDarkGrey),
|
||||
getMiddlePoint(m.Block, resumeText, 4),
|
||||
)
|
||||
}
|
||||
|
||||
func (m *Menu) renderMoveAndResize(buffer *ui.Buffer) {
|
||||
|
||||
m.printAllDirectionsArrowSign(buffer, -2)
|
||||
|
||||
saveText := "<ENTER> to save changes"
|
||||
textPoint := getMiddlePoint(m.Block, saveText, 4)
|
||||
if textPoint.In(m.Rectangle) {
|
||||
buffer.SetString(
|
||||
saveText,
|
||||
ui.NewStyle(console.ColorDarkGrey),
|
||||
textPoint,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) {
|
||||
|
||||
arrows := []string{
|
||||
" ↑ ",
|
||||
"←· →",
|
||||
" ↓ ",
|
||||
}
|
||||
|
||||
for i, a := range arrows {
|
||||
buffer.SetString(
|
||||
a,
|
||||
ui.NewStyle(console.ColorOlive),
|
||||
getMiddlePoint(m.Block, a, i+y),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) renderOptions(buffer *ui.Buffer) {
|
||||
|
||||
// TODO extract styles to console.Palette
|
||||
highlightedStyle := ui.NewStyle(console.ColorWhite, console.ColorClear, ui.ModifierReverse)
|
||||
regularStyle := ui.NewStyle(console.ColorWhite)
|
||||
|
||||
offset := 1
|
||||
for _, option := range m.options {
|
||||
|
||||
style := regularStyle
|
||||
if m.option == option {
|
||||
style = highlightedStyle
|
||||
}
|
||||
|
||||
if option != MenuOptionPinpoint || m.component.Type == TypeRunChart {
|
||||
offset += 2
|
||||
buffer.SetString(
|
||||
string(option),
|
||||
style,
|
||||
getMiddlePoint(m.Block, string(option), offset-5),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) updateDimensions() {
|
||||
r := m.component.Drawable.GetRect()
|
||||
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))
|
||||
}
|
||||
|
||||
func getMiddlePoint(block ui.Block, text string, offset int) image.Point {
|
||||
return image.Pt(block.Min.X+block.Dx()/2-len(text)/2, block.Max.Y-block.Dy()/2+offset)
|
||||
}
|
Loading…
Reference in New Issue