combine common functionality in Component struct

This commit is contained in:
sqshq 2019-03-16 00:35:00 -04:00
parent dcfdc16a41
commit fec7eefd9f
13 changed files with 206 additions and 235 deletions

View File

@ -6,14 +6,11 @@ import (
"github.com/sqshq/sampler/asset" "github.com/sqshq/sampler/asset"
"github.com/sqshq/sampler/component" "github.com/sqshq/sampler/component"
"github.com/sqshq/sampler/config" "github.com/sqshq/sampler/config"
"github.com/sqshq/sampler/data"
"image" "image"
) )
type AsciiBox struct { type AsciiBox struct {
ui.Block *component.Component
data.Consumer
*component.Alerter
text string text string
ascii string ascii string
style ui.Style style ui.Style
@ -25,10 +22,6 @@ const asciiFontExtension = ".flf"
func NewAsciiBox(c config.AsciiBoxConfig) *AsciiBox { func NewAsciiBox(c config.AsciiBoxConfig) *AsciiBox {
consumer := data.NewConsumer()
block := *ui.NewBlock()
block.Title = c.Title
options := fl.NewRenderOptions() options := fl.NewRenderOptions()
options.FontName = string(*c.Font) options.FontName = string(*c.Font)
@ -36,33 +29,28 @@ func NewAsciiBox(c config.AsciiBoxConfig) *AsciiBox {
if err != nil { if err != nil {
panic("Can't load the font: " + err.Error()) panic("Can't load the font: " + err.Error())
} }
render := fl.NewAsciiRender() render := fl.NewAsciiRender()
_ = render.LoadBindataFont(fontStr, options.FontName) _ = render.LoadBindataFont(fontStr, options.FontName)
box := AsciiBox{ box := AsciiBox{
Block: block, Component: component.NewComponent(c.ComponentConfig, config.TypeAsciiBox),
Consumer: consumer,
Alerter: component.NewAlerter(consumer.AlertChannel),
style: ui.NewStyle(*c.Color), style: ui.NewStyle(*c.Color),
render: render, render: render,
options: options, options: options,
} }
go box.consume() go func() {
return &box
}
func (a *AsciiBox) consume() {
for { for {
select { select {
case sample := <-a.SampleChannel: case sample := <-box.SampleChannel:
a.text = sample.Value box.text = sample.Value
a.ascii, _ = a.render.RenderOpts(sample.Value, a.options) box.ascii, _ = box.render.RenderOpts(sample.Value, box.options)
//case alert := <-a.alertChannel:
// TODO base alerting mechanism
} }
} }
}()
return &box
} }
func (a *AsciiBox) Draw(buffer *ui.Buffer) { func (a *AsciiBox) Draw(buffer *ui.Buffer) {

View File

@ -5,6 +5,7 @@ import (
ui "github.com/gizak/termui/v3" ui "github.com/gizak/termui/v3"
rw "github.com/mattn/go-runewidth" rw "github.com/mattn/go-runewidth"
"github.com/sqshq/sampler/component" "github.com/sqshq/sampler/component"
"github.com/sqshq/sampler/config"
"github.com/sqshq/sampler/console" "github.com/sqshq/sampler/console"
"github.com/sqshq/sampler/data" "github.com/sqshq/sampler/data"
"image" "image"
@ -17,9 +18,7 @@ const (
) )
type BarChart struct { type BarChart struct {
ui.Block *component.Component
data.Consumer
*component.Alerter
bars []Bar bars []Bar
scale int scale int
maxValue float64 maxValue float64
@ -33,33 +32,29 @@ type Bar struct {
delta float64 delta float64
} }
func NewBarChart(title string, scale int) *BarChart { func NewBarChart(c config.BarChartConfig) *BarChart {
consumer := data.NewConsumer()
block := *ui.NewBlock()
block.Title = title
chart := BarChart{ chart := BarChart{
Block: block, Component: component.NewComponent(c.ComponentConfig, config.TypeBarChart),
Consumer: consumer,
Alerter: component.NewAlerter(consumer.AlertChannel),
bars: []Bar{}, bars: []Bar{},
scale: scale, scale: *c.Scale,
maxValue: -math.MaxFloat64, maxValue: -math.MaxFloat64,
} }
go chart.consume() for _, i := range c.Items {
chart.AddBar(*i.Label, *i.Color)
}
return &chart go func() {
}
func (b *BarChart) consume() {
for { for {
select { select {
case sample := <-b.SampleChannel: case sample := <-chart.SampleChannel:
b.consumeSample(sample) chart.consumeSample(sample)
//case alert := <-b.alertChannel:
// TODO base alerting mechanism
} }
} }
}()
return &chart
} }
func (b *BarChart) consumeSample(sample data.Sample) { func (b *BarChart) consumeSample(sample data.Sample) {

View File

@ -3,17 +3,38 @@ package component
import ( import (
ui "github.com/gizak/termui/v3" ui "github.com/gizak/termui/v3"
"github.com/sqshq/sampler/config" "github.com/sqshq/sampler/config"
"github.com/sqshq/sampler/data"
) )
type Component struct { type Component struct {
ui.Block
data.Consumer
*Alerter
Type config.ComponentType Type config.ComponentType
Drawable ui.Drawable
Title string Title string
Position config.Position Position config.Position
Size config.Size Size config.Size
RefreshRateMs int RefreshRateMs int
} }
func NewComponent(c config.ComponentConfig, t config.ComponentType) *Component {
consumer := data.NewConsumer()
block := *ui.NewBlock()
block.Title = c.Title
return &Component{
Block: block,
Consumer: consumer,
Alerter: NewAlerter(consumer.AlertChannel),
Type: t,
Title: c.Title,
Position: c.Position,
Size: c.Size,
RefreshRateMs: *c.RefreshRateMs,
}
}
func (c *Component) Move(x, y int) { func (c *Component) Move(x, y int) {
c.Position.X += x c.Position.X += x
c.Position.Y += y c.Position.Y += y

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
ui "github.com/gizak/termui/v3" ui "github.com/gizak/termui/v3"
"github.com/sqshq/sampler/component" "github.com/sqshq/sampler/component"
"github.com/sqshq/sampler/config"
"github.com/sqshq/sampler/console" "github.com/sqshq/sampler/console"
"github.com/sqshq/sampler/data" "github.com/sqshq/sampler/data"
"image" "image"
@ -18,49 +19,39 @@ const (
) )
type Gauge struct { type Gauge struct {
ui.Block *component.Component
data.Consumer
*component.Alerter
minValue float64 minValue float64
maxValue float64 maxValue float64
curValue float64 curValue float64
scale int
color ui.Color color ui.Color
scale int
} }
func NewGauge(title string, scale int, color ui.Color) *Gauge { func NewGauge(c config.GaugeConfig) *Gauge {
consumer := data.NewConsumer()
block := *ui.NewBlock()
block.Title = title
gauge := Gauge{ gauge := Gauge{
Block: block, Component: component.NewComponent(c.ComponentConfig, config.TypeGauge),
Consumer: consumer, scale: *c.Scale,
Alerter: component.NewAlerter(consumer.AlertChannel), color: *c.Color,
scale: scale,
color: color,
} }
go gauge.consume() go func() {
return &gauge
}
func (g *Gauge) consume() {
for { for {
select { select {
case sample := <-g.SampleChannel: case sample := <-gauge.SampleChannel:
g.ConsumeSample(sample) gauge.ConsumeSample(sample)
//case alert := <-g.alertChannel:
// TODO base alerting mechanism
} }
} }
}()
return &gauge
} }
func (g *Gauge) ConsumeSample(sample data.Sample) { func (g *Gauge) ConsumeSample(sample data.Sample) {
float, err := strconv.ParseFloat(sample.Value, 64) float, err := strconv.ParseFloat(sample.Value, 64)
if err != nil { if err != nil {
// TODO visual notification + check sample.Error // TODO handle in Component
} }
switch sample.Label { switch sample.Label {
@ -87,7 +78,7 @@ func (g *Gauge) Draw(buf *ui.Buffer) {
label := fmt.Sprintf("%v%% (%v)", formatValue(percent, g.scale), g.curValue) label := fmt.Sprintf("%v%% (%v)", formatValue(percent, g.scale), g.curValue)
// plot bar // draw bar
barWidth := int((percent / 100) * float64(g.Inner.Dx())) barWidth := int((percent / 100) * float64(g.Inner.Dx()))
if barWidth == 0 { if barWidth == 0 {
barWidth = 1 barWidth = 1
@ -99,7 +90,7 @@ func (g *Gauge) Draw(buf *ui.Buffer) {
image.Rect(g.Inner.Min.X+1, g.Inner.Min.Y, g.Inner.Min.X+barWidth, g.Inner.Max.Y), image.Rect(g.Inner.Min.X+1, g.Inner.Min.Y, g.Inner.Min.X+barWidth, g.Inner.Max.Y),
) )
// plot label // draw label
labelXCoordinate := g.Inner.Min.X + (g.Inner.Dx() / 2) - int(float64(len(label))/2) labelXCoordinate := g.Inner.Min.X + (g.Inner.Dx() / 2) - int(float64(len(label))/2)
labelYCoordinate := g.Inner.Min.Y + ((g.Inner.Dy() - 1) / 2) labelYCoordinate := g.Inner.Min.Y + ((g.Inner.Dy() - 1) / 2)
if labelYCoordinate < g.Inner.Max.Y { if labelYCoordinate < g.Inner.Max.Y {

View File

@ -5,28 +5,28 @@ import (
"math" "math"
) )
func GetRectLeftAgeCenter(rect image.Rectangle) image.Point { func GetRectLeftSideCenter(rect image.Rectangle) image.Point {
return image.Point{ return image.Point{
X: rect.Min.X, X: rect.Min.X,
Y: rect.Min.Y + rect.Dy()/2, Y: rect.Min.Y + rect.Dy()/2,
} }
} }
func GetRectRightAgeCenter(rect image.Rectangle) image.Point { func GetRectRightSideCenter(rect image.Rectangle) image.Point {
return image.Point{ return image.Point{
X: rect.Max.X, X: rect.Max.X,
Y: rect.Min.Y + rect.Dy()/2, Y: rect.Min.Y + rect.Dy()/2,
} }
} }
func GetRectTopAgeCenter(rect image.Rectangle) image.Point { func GetRectTopSideCenter(rect image.Rectangle) image.Point {
return image.Point{ return image.Point{
X: rect.Min.X + rect.Dx()/2, X: rect.Min.X + rect.Dx()/2,
Y: rect.Min.Y, Y: rect.Min.Y,
} }
} }
func GetRectBottomAgeCenter(rect image.Rectangle) image.Point { func GetRectBottomSideCenter(rect image.Rectangle) image.Point {
return image.Point{ return image.Point{
X: rect.Min.X + rect.Dx()/2, X: rect.Min.X + rect.Dx()/2,
Y: rect.Max.Y, Y: rect.Max.Y,

View File

@ -6,16 +6,17 @@ import (
"github.com/sqshq/sampler/component/runchart" "github.com/sqshq/sampler/component/runchart"
"github.com/sqshq/sampler/config" "github.com/sqshq/sampler/config"
"github.com/sqshq/sampler/console" "github.com/sqshq/sampler/console"
"github.com/sqshq/sampler/data"
"image" "image"
"math" "math"
) )
type Layout struct { type Layout struct {
ui.Block ui.Block
Components []component.Component Components []*component.Component
ChangeModeEvents chan Mode
statusbar *component.StatusBar statusbar *component.StatusBar
menu *component.Menu menu *component.Menu
ChangeModeEvents chan Mode
mode Mode mode Mode
selection int selection int
} }
@ -47,7 +48,7 @@ func NewLayout(width, height int, statusline *component.StatusBar, menu *compone
return &Layout{ return &Layout{
Block: block, Block: block,
Components: make([]component.Component, 0), Components: make([]*component.Component, 0),
statusbar: statusline, statusbar: statusline,
menu: menu, menu: menu,
mode: ModeDefault, mode: ModeDefault,
@ -56,28 +57,8 @@ func NewLayout(width, height int, statusline *component.StatusBar, menu *compone
} }
} }
func (l *Layout) AddComponent(Type config.ComponentType, drawable ui.Drawable, title string, position config.Position, size config.Size, refreshRateMs int) { func (l *Layout) AddComponent(cpt *component.Component, Type config.ComponentType) {
l.Components = append(l.Components, component.Component{ l.Components = append(l.Components, cpt)
Type: Type,
Drawable: drawable,
Title: title,
Position: position,
Size: size,
RefreshRateMs: refreshRateMs,
})
}
func (l *Layout) GetComponents(Type config.ComponentType) []component.Component {
var components []component.Component
for _, c := range l.Components {
if c.Type == Type {
components = append(components, c)
}
}
return components
} }
func (l *Layout) changeMode(m Mode) { func (l *Layout) changeMode(m Mode) {
@ -86,14 +67,16 @@ func (l *Layout) changeMode(m Mode) {
} }
func (l *Layout) HandleConsoleEvent(e string) { func (l *Layout) HandleConsoleEvent(e string) {
selected := l.getSelection()
switch e { switch e {
case console.KeyPause: case console.KeyPause:
if l.mode == ModePause { if l.mode == ModePause {
l.changeMode(ModeDefault) l.changeMode(ModeDefault)
} else { } else {
if l.getSelectedComponent().Type == config.TypeRunChart { if selected.Type == config.TypeRunChart {
chart := l.getSelectedComponent().Drawable.(*runchart.RunChart) selected.CommandChannel <- data.Command{Type: runchart.CommandDisableSelection}
chart.DisableSelection()
} }
l.menu.Idle() l.menu.Idle()
l.changeMode(ModePause) l.changeMode(ModePause)
@ -115,8 +98,7 @@ func (l *Layout) HandleConsoleEvent(e string) {
case component.MenuOptionPinpoint: case component.MenuOptionPinpoint:
l.changeMode(ModeChartPinpoint) l.changeMode(ModeChartPinpoint)
l.menu.Idle() l.menu.Idle()
chart := l.getSelectedComponent().Drawable.(*runchart.RunChart) selected.CommandChannel <- data.Command{Type: runchart.CommandMoveSelection, Value: 0}
chart.MoveSelection(0)
case component.MenuOptionResume: case component.MenuOptionResume:
l.changeMode(ModeDefault) l.changeMode(ModeDefault)
l.menu.Idle() l.menu.Idle()
@ -130,8 +112,7 @@ func (l *Layout) HandleConsoleEvent(e string) {
case console.KeyEsc: case console.KeyEsc:
switch l.mode { switch l.mode {
case ModeChartPinpoint: case ModeChartPinpoint:
chart := l.getSelectedComponent().Drawable.(*runchart.RunChart) selected.CommandChannel <- data.Command{Type: runchart.CommandDisableSelection}
chart.DisableSelection()
fallthrough fallthrough
case ModeComponentSelect: case ModeComponentSelect:
fallthrough fallthrough
@ -145,15 +126,14 @@ func (l *Layout) HandleConsoleEvent(e string) {
l.changeMode(ModeComponentSelect) l.changeMode(ModeComponentSelect)
l.menu.Highlight(l.getComponent(l.selection)) l.menu.Highlight(l.getComponent(l.selection))
case ModeChartPinpoint: case ModeChartPinpoint:
chart := l.getSelectedComponent().Drawable.(*runchart.RunChart) selected.CommandChannel <- data.Command{Type: runchart.CommandMoveSelection, Value: -1}
chart.MoveSelection(-1)
case ModeComponentSelect: case ModeComponentSelect:
l.moveSelection(e) l.moveSelection(e)
l.menu.Highlight(l.getComponent(l.selection)) l.menu.Highlight(l.getComponent(l.selection))
case ModeComponentMove: case ModeComponentMove:
l.getSelectedComponent().Move(-1, 0) selected.Move(-1, 0)
case ModeComponentResize: case ModeComponentResize:
l.getSelectedComponent().Resize(-1, 0) selected.Resize(-1, 0)
} }
case console.KeyRight: case console.KeyRight:
switch l.mode { switch l.mode {
@ -161,15 +141,14 @@ func (l *Layout) HandleConsoleEvent(e string) {
l.changeMode(ModeComponentSelect) l.changeMode(ModeComponentSelect)
l.menu.Highlight(l.getComponent(l.selection)) l.menu.Highlight(l.getComponent(l.selection))
case ModeChartPinpoint: case ModeChartPinpoint:
chart := l.getSelectedComponent().Drawable.(*runchart.RunChart) selected.CommandChannel <- data.Command{Type: runchart.CommandMoveSelection, Value: 1}
chart.MoveSelection(1)
case ModeComponentSelect: case ModeComponentSelect:
l.moveSelection(e) l.moveSelection(e)
l.menu.Highlight(l.getComponent(l.selection)) l.menu.Highlight(l.getComponent(l.selection))
case ModeComponentMove: case ModeComponentMove:
l.getSelectedComponent().Move(1, 0) selected.Move(1, 0)
case ModeComponentResize: case ModeComponentResize:
l.getSelectedComponent().Resize(1, 0) selected.Resize(1, 0)
} }
case console.KeyUp: case console.KeyUp:
switch l.mode { switch l.mode {
@ -182,9 +161,9 @@ func (l *Layout) HandleConsoleEvent(e string) {
case ModeMenuOptionSelect: case ModeMenuOptionSelect:
l.menu.Up() l.menu.Up()
case ModeComponentMove: case ModeComponentMove:
l.getSelectedComponent().Move(0, -1) selected.Move(0, -1)
case ModeComponentResize: case ModeComponentResize:
l.getSelectedComponent().Resize(0, -1) selected.Resize(0, -1)
} }
case console.KeyDown: case console.KeyDown:
switch l.mode { switch l.mode {
@ -197,9 +176,9 @@ func (l *Layout) HandleConsoleEvent(e string) {
case ModeMenuOptionSelect: case ModeMenuOptionSelect:
l.menu.Down() l.menu.Down()
case ModeComponentMove: case ModeComponentMove:
l.getSelectedComponent().Move(0, 1) selected.Move(0, 1)
case ModeComponentResize: case ModeComponentResize:
l.getSelectedComponent().Resize(0, 1) selected.Resize(0, 1)
} }
} }
} }
@ -209,16 +188,16 @@ func (l *Layout) ChangeDimensions(width, height int) {
} }
func (l *Layout) getComponent(i int) *component.Component { func (l *Layout) getComponent(i int) *component.Component {
return &l.Components[i] return l.Components[i]
} }
func (l *Layout) getSelectedComponent() *component.Component { func (l *Layout) getSelection() *component.Component {
return &l.Components[l.selection] return l.Components[l.selection]
} }
func (l *Layout) moveSelection(direction string) { func (l *Layout) moveSelection(direction string) {
previouslySelected := *l.getSelectedComponent() previouslySelected := l.getSelection()
newlySelectedIndex := l.selection newlySelectedIndex := l.selection
for i, current := range l.Components { for i, current := range l.Components {
@ -237,21 +216,21 @@ func (l *Layout) moveSelection(direction string) {
switch direction { switch direction {
case console.KeyLeft: case console.KeyLeft:
previouslySelectedCornerPoint = component.GetRectLeftAgeCenter(previouslySelected.Drawable.GetRect()) previouslySelectedCornerPoint = component.GetRectLeftSideCenter(previouslySelected.GetRect())
newlySelectedCornerPoint = component.GetRectRightAgeCenter(l.getComponent(newlySelectedIndex).Drawable.GetRect()) newlySelectedCornerPoint = component.GetRectRightSideCenter(l.getComponent(newlySelectedIndex).GetRect())
currentCornerPoint = component.GetRectRightAgeCenter(current.Drawable.GetRect()) currentCornerPoint = component.GetRectRightSideCenter(current.GetRect())
case console.KeyRight: case console.KeyRight:
previouslySelectedCornerPoint = component.GetRectRightAgeCenter(previouslySelected.Drawable.GetRect()) previouslySelectedCornerPoint = component.GetRectRightSideCenter(previouslySelected.GetRect())
newlySelectedCornerPoint = component.GetRectLeftAgeCenter(l.getComponent(newlySelectedIndex).Drawable.GetRect()) newlySelectedCornerPoint = component.GetRectLeftSideCenter(l.getComponent(newlySelectedIndex).GetRect())
currentCornerPoint = component.GetRectLeftAgeCenter(current.Drawable.GetRect()) currentCornerPoint = component.GetRectLeftSideCenter(current.GetRect())
case console.KeyUp: case console.KeyUp:
previouslySelectedCornerPoint = component.GetRectTopAgeCenter(previouslySelected.Drawable.GetRect()) previouslySelectedCornerPoint = component.GetRectTopSideCenter(previouslySelected.GetRect())
newlySelectedCornerPoint = component.GetRectBottomAgeCenter(l.getComponent(newlySelectedIndex).Drawable.GetRect()) newlySelectedCornerPoint = component.GetRectBottomSideCenter(l.getComponent(newlySelectedIndex).GetRect())
currentCornerPoint = component.GetRectBottomAgeCenter(current.Drawable.GetRect()) currentCornerPoint = component.GetRectBottomSideCenter(current.GetRect())
case console.KeyDown: case console.KeyDown:
previouslySelectedCornerPoint = component.GetRectBottomAgeCenter(previouslySelected.Drawable.GetRect()) previouslySelectedCornerPoint = component.GetRectBottomSideCenter(previouslySelected.GetRect())
newlySelectedCornerPoint = component.GetRectTopAgeCenter(l.getComponent(newlySelectedIndex).Drawable.GetRect()) newlySelectedCornerPoint = component.GetRectTopSideCenter(l.getComponent(newlySelectedIndex).GetRect())
currentCornerPoint = component.GetRectTopAgeCenter(current.Drawable.GetRect()) currentCornerPoint = component.GetRectTopSideCenter(current.GetRect())
} }
if component.GetDistance(previouslySelectedCornerPoint, currentCornerPoint) < if component.GetDistance(previouslySelectedCornerPoint, currentCornerPoint) <
@ -283,8 +262,8 @@ func (l *Layout) Draw(buffer *ui.Buffer) {
y2 = y1 + minDimension y2 = y1 + minDimension
} }
c.Drawable.SetRect(int(x1), int(y1), int(x2), int(y2)) c.SetRect(int(x1), int(y1), int(x2), int(y2))
c.Drawable.Draw(buffer) c.Draw(buffer)
} }
l.statusbar.SetRect( l.statusbar.SetRect(

View File

@ -219,7 +219,7 @@ func (m *Menu) renderOptions(buffer *ui.Buffer) {
} }
func (m *Menu) updateDimensions() { func (m *Menu) updateDimensions() {
r := m.component.Drawable.GetRect() r := m.component.Block.GetRect()
m.SetRect(r.Min.X, r.Min.Y, r.Max.X, r.Max.Y) m.SetRect(r.Min.X, r.Min.Y, r.Max.X, r.Max.Y)
} }

View File

@ -22,9 +22,7 @@ const (
xAxisGridWidth = xAxisLabelsIndent + xAxisLabelsWidth xAxisGridWidth = xAxisLabelsIndent + xAxisLabelsWidth
yAxisLabelsHeight = 1 yAxisLabelsHeight = 1
yAxisLabelsIndent = 1 yAxisLabelsIndent = 1
historyReserveMin = 20 historyReserveMin = 20
xBrailleMultiplier = 2 xBrailleMultiplier = 2
yBrailleMultiplier = 4 yBrailleMultiplier = 4
) )
@ -36,10 +34,13 @@ const (
ModePinpoint Mode = 1 ModePinpoint Mode = 1
) )
const (
CommandDisableSelection = "DISABLE_SELECTION"
CommandMoveSelection = "MOVE_SELECTION"
)
type RunChart struct { type RunChart struct {
ui.Block *component.Component
data.Consumer
*component.Alerter
lines []TimeLine lines []TimeLine
grid ChartGrid grid ChartGrid
timescale time.Duration timescale time.Duration
@ -75,38 +76,39 @@ type ValueExtrema struct {
min float64 min float64
} }
func NewRunChart(c config.RunChartConfig, l Legend) *RunChart { func NewRunChart(c config.RunChartConfig) *RunChart {
consumer := data.NewConsumer()
block := *ui.NewBlock()
block.Title = c.Title
chart := RunChart{ chart := RunChart{
Block: block, Component: component.NewComponent(c.ComponentConfig, config.TypeRunChart),
Consumer: consumer,
Alerter: component.NewAlerter(consumer.AlertChannel),
lines: []TimeLine{}, lines: []TimeLine{},
timescale: calculateTimescale(*c.RefreshRateMs), timescale: calculateTimescale(*c.RefreshRateMs),
mutex: &sync.Mutex{}, mutex: &sync.Mutex{},
scale: *c.Scale, scale: *c.Scale,
mode: ModeDefault, mode: ModeDefault,
legend: l, legend: Legend{Enabled: c.Legend.Enabled, Details: c.Legend.Details},
} }
go chart.consume() for _, i := range c.Items {
chart.AddLine(*i.Label, *i.Color)
}
return &chart go func() {
}
func (c *RunChart) consume() {
for { for {
select { select {
case sample := <-c.SampleChannel: case sample := <-chart.SampleChannel:
c.consumeSample(sample) chart.consumeSample(sample)
//case alert := <-c.alertChannel: case command := <-chart.CommandChannel:
// TODO base alerting mechanism switch command.Type {
case CommandDisableSelection:
chart.disableSelection()
case CommandMoveSelection:
chart.moveSelection(command.Value.(int))
} }
} }
}
}()
return &chart
} }
func (c *RunChart) newTimePoint(value float64) TimePoint { func (c *RunChart) newTimePoint(value float64) TimePoint {
@ -151,7 +153,11 @@ func (c *RunChart) consumeSample(sample data.Sample) {
float, err := strconv.ParseFloat(sample.Value, 64) float, err := strconv.ParseFloat(sample.Value, 64)
if err != nil { if err != nil {
// TODO visual notification c.AlertChannel <- data.Alert{
Title: "SAMPLING FAILURE",
Text: err.Error(),
Color: sample.Color,
}
} }
c.mutex.Lock() c.mutex.Lock()
@ -320,7 +326,7 @@ func (c *RunChart) getMaxValueLength() int {
return maxValueLength return maxValueLength
} }
func (c *RunChart) MoveSelection(shift int) { func (c *RunChart) moveSelection(shift int) {
if c.mode == ModeDefault { if c.mode == ModeDefault {
c.mode = ModePinpoint c.mode = ModePinpoint
@ -340,7 +346,7 @@ func (c *RunChart) MoveSelection(shift int) {
} }
} }
func (c *RunChart) DisableSelection() { func (c *RunChart) disableSelection() {
if c.mode == ModePinpoint { if c.mode == ModePinpoint {
c.mode = ModeDefault c.mode = ModeDefault
return return

View File

@ -24,16 +24,16 @@ type Flags struct {
func Load() (Config, Flags) { func Load() (Config, Flags) {
if len(os.Args) < 2 { //if len(os.Args) < 2 {
println("Please specify config file location. See www.github.com/sqshq/sampler for the reference") // println("Please specify config file location. See www.github.com/sqshq/sampler for the reference")
os.Exit(0) // os.Exit(0)
} //}
cfg := readFile(os.Args[1]) cfg := readFile("config.yml")
cfg.validate() cfg.validate()
cfg.setDefaults() cfg.setDefaults()
flg := Flags{ConfigFileName: os.Args[1]} flg := Flags{ConfigFileName: "config.yml"}
return *cfg, flg return *cfg, flg
} }

View File

@ -14,6 +14,10 @@ const (
AppVersion = "0.1.0" AppVersion = "0.1.0"
) )
const (
BellCharacter = "\a"
)
type AsciiFont string type AsciiFont string
const ( const (
@ -21,13 +25,7 @@ const (
AsciiFont3D AsciiFont = "3d" AsciiFont3D AsciiFont = "3d"
) )
type Console struct{} func Init() {
const (
BellCharacter = "\a"
)
func (self *Console) Init() {
fmt.Printf("\033]0;%s\007", AppTitle) fmt.Printf("\033]0;%s\007", AppTitle)
@ -36,6 +34,6 @@ func (self *Console) Init() {
} }
} }
func (self *Console) Close() { func Close() {
ui.Close() ui.Close()
} }

View File

@ -2,9 +2,11 @@ package data
import ui "github.com/gizak/termui/v3" import ui "github.com/gizak/termui/v3"
// TODO interface here, move fields declaration in the Component
type Consumer struct { type Consumer struct {
SampleChannel chan Sample SampleChannel chan Sample
AlertChannel chan Alert AlertChannel chan Alert
CommandChannel chan Command
} }
type Sample struct { type Sample struct {
@ -19,9 +21,15 @@ type Alert struct {
Color *ui.Color Color *ui.Color
} }
type Command struct {
Type string
Value interface{}
}
func NewConsumer() Consumer { func NewConsumer() Consumer {
return Consumer{ return Consumer{
SampleChannel: make(chan Sample), SampleChannel: make(chan Sample),
AlertChannel: make(chan Alert), AlertChannel: make(chan Alert),
CommandChannel: make(chan Command),
} }
} }

View File

@ -19,9 +19,9 @@ type Handler struct {
renderRate time.Duration renderRate time.Duration
} }
func NewHandler(layout *layout.Layout) Handler { func NewHandler(layout *layout.Layout) *Handler {
renderRate := calcMinRenderRate(layout) renderRate := calcMinRenderRate(layout)
return Handler{ return &Handler{
layout: layout, layout: layout,
consoleEvents: ui.PollEvents(), consoleEvents: ui.PollEvents(),
renderTicker: time.NewTicker(renderRate), renderTicker: time.NewTicker(renderRate),

47
main.go
View File

@ -18,57 +18,42 @@ import (
func main() { func main() {
cfg, flg := config.Load() cfg, flg := config.Load()
csl := console.Console{}
csl.Init()
defer csl.Close()
width, height := ui.TerminalDimensions() console.Init()
lout := layout.NewLayout(width, height, component.NewStatusLine(flg.ConfigFileName), component.NewMenu()) defer console.Close()
player := asset.NewAudioPlayer() player := asset.NewAudioPlayer()
defer player.Close() defer player.Close()
width, height := ui.TerminalDimensions()
lout := layout.NewLayout(width, height, component.NewStatusLine(flg.ConfigFileName), component.NewMenu())
for _, c := range cfg.RunCharts { for _, c := range cfg.RunCharts {
chart := runchart.NewRunChart(c)
legend := runchart.Legend{Enabled: c.Legend.Enabled, Details: c.Legend.Details}
chart := runchart.NewRunChart(c, legend)
lout.AddComponent(config.TypeRunChart, chart, c.Title, c.Position, c.Size, *c.RefreshRateMs)
triggers := data.NewTriggers(c.Triggers, chart.Consumer, player) triggers := data.NewTriggers(c.Triggers, chart.Consumer, player)
items := data.NewItems(c.Items) data.NewSampler(chart.Consumer, data.NewItems(c.Items), triggers, *c.RefreshRateMs)
data.NewSampler(chart.Consumer, items, triggers, *c.RefreshRateMs) lout.AddComponent(chart.Component, config.TypeRunChart)
for _, i := range c.Items {
chart.AddLine(*i.Label, *i.Color)
}
} }
for _, a := range cfg.AsciiBoxes { for _, a := range cfg.AsciiBoxes {
box := asciibox.NewAsciiBox(a) box := asciibox.NewAsciiBox(a)
item := data.Item{Label: *a.Label, Script: a.Script, Color: a.Color}
lout.AddComponent(config.TypeAsciiBox, box, a.Title, a.Position, a.Size, *a.RefreshRateMs)
triggers := data.NewTriggers(a.Triggers, box.Consumer, player) triggers := data.NewTriggers(a.Triggers, box.Consumer, player)
data.NewSampler(box.Consumer, []data.Item{item}, triggers, *a.RefreshRateMs) data.NewSampler(box.Consumer, data.NewItems([]config.Item{a.Item}), triggers, *a.RefreshRateMs)
lout.AddComponent(box.Component, config.TypeAsciiBox)
} }
for _, b := range cfg.BarCharts { for _, b := range cfg.BarCharts {
chart := barchart.NewBarChart(b)
chart := barchart.NewBarChart(b.Title, *b.Scale)
triggers := data.NewTriggers(b.Triggers, chart.Consumer, player) triggers := data.NewTriggers(b.Triggers, chart.Consumer, player)
lout.AddComponent(config.TypeBarChart, chart, b.Title, b.Position, b.Size, *b.RefreshRateMs) data.NewSampler(chart.Consumer, data.NewItems(b.Items), triggers, *b.RefreshRateMs)
items := data.NewItems(b.Items) lout.AddComponent(chart.Component, config.TypeBarChart)
data.NewSampler(chart.Consumer, items, triggers, *b.RefreshRateMs)
for _, i := range b.Items {
chart.AddBar(*i.Label, *i.Color)
}
} }
for _, gc := range cfg.Gauges { for _, gc := range cfg.Gauges {
g := gauge.NewGauge(gc.Title, *gc.Scale, *gc.Color) g := gauge.NewGauge(gc)
triggers := data.NewTriggers(gc.Triggers, g.Consumer, player) triggers := data.NewTriggers(gc.Triggers, g.Consumer, player)
lout.AddComponent(config.TypeGauge, g, gc.Title, gc.Position, gc.Size, *gc.RefreshRateMs) data.NewSampler(g.Consumer, data.NewItems(gc.Items), triggers, *gc.RefreshRateMs)
items := data.NewItems(gc.Items) lout.AddComponent(g.Component, config.TypeGauge)
data.NewSampler(g.Consumer, items, triggers, *gc.RefreshRateMs)
} }
handler := event.NewHandler(lout) handler := event.NewHandler(lout)