add intro page and storage initialization
This commit is contained in:
parent
8fa382e37d
commit
911be1ba00
|
@ -0,0 +1,8 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import "github.com/sqshq/sampler/storage"
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
func loadLicense(key string) *storage.License {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -44,7 +44,7 @@ func RenderAlert(alert *data.Alert, area image.Rectangle, buffer *ui.Buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
block := *ui.NewBlock()
|
block := *ui.NewBlock()
|
||||||
block.SetRect(getRectCoordinates(area, width, len(lines)))
|
block.SetRect(util.GetRectCoordinates(area, width, len(lines)))
|
||||||
block.BorderStyle = ui.Style{Fg: color, Bg: ui.ColorClear}
|
block.BorderStyle = ui.Style{Fg: color, Bg: ui.ColorClear}
|
||||||
block.Draw(buffer)
|
block.Draw(buffer)
|
||||||
|
|
||||||
|
@ -52,13 +52,6 @@ func RenderAlert(alert *data.Alert, area image.Rectangle, buffer *ui.Buffer) {
|
||||||
|
|
||||||
for i := 0; i < len(lines); i++ {
|
for i := 0; i < len(lines); i++ {
|
||||||
buffer.SetString(lines[i],
|
buffer.SetString(lines[i],
|
||||||
ui.NewStyle(color), getMiddlePoint(block.Inner, lines[i], i-1))
|
ui.NewStyle(color), util.GetMiddlePoint(block.Inner, lines[i], i-1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO move to utils
|
|
||||||
func getRectCoordinates(area image.Rectangle, width int, height int) (int, int, int, int) {
|
|
||||||
x1 := area.Min.X + area.Dx()/2 - width/2
|
|
||||||
y1 := area.Min.Y + area.Dy()/2 - height
|
|
||||||
return x1, y1, x1 + width, y1 + height + 2
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
package component
|
||||||
|
|
||||||
|
import (
|
||||||
|
ui "github.com/gizak/termui/v3"
|
||||||
|
"github.com/sqshq/sampler/component/util"
|
||||||
|
"github.com/sqshq/sampler/console"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Intro struct {
|
||||||
|
*ui.Block
|
||||||
|
page IntroPage
|
||||||
|
option introOption
|
||||||
|
palette console.Palette
|
||||||
|
}
|
||||||
|
|
||||||
|
type IntroPage rune
|
||||||
|
|
||||||
|
const (
|
||||||
|
IntroPageWelcome IntroPage = 0
|
||||||
|
IntroPageCommercial IntroPage = 1
|
||||||
|
IntroPagePersonal IntroPage = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
type introOption rune
|
||||||
|
|
||||||
|
const (
|
||||||
|
introOptionCommercial introOption = 0
|
||||||
|
introOptionPersonal introOption = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
buttonCommercial string = " COMMERCIAL USE "
|
||||||
|
buttonPersonal string = " PERSONAL USE "
|
||||||
|
buttonOk string = " OK "
|
||||||
|
)
|
||||||
|
|
||||||
|
func (intro *Intro) Up() {
|
||||||
|
intro.option = introOptionCommercial
|
||||||
|
}
|
||||||
|
|
||||||
|
func (intro *Intro) Down() {
|
||||||
|
intro.option = introOptionPersonal
|
||||||
|
}
|
||||||
|
|
||||||
|
func (intro *Intro) NextPage() {
|
||||||
|
if intro.option == introOptionCommercial {
|
||||||
|
intro.page = IntroPageCommercial
|
||||||
|
} else {
|
||||||
|
intro.page = IntroPagePersonal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (intro *Intro) GetSelectedPage() IntroPage {
|
||||||
|
return intro.page
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIntro(palette console.Palette) *Intro {
|
||||||
|
return &Intro{
|
||||||
|
Block: NewBlock("", false, palette),
|
||||||
|
palette: palette,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (intro *Intro) Draw(buffer *ui.Buffer) {
|
||||||
|
|
||||||
|
logo := []string{
|
||||||
|
" __ ",
|
||||||
|
" _________ ____ ___ ____ / /__ _____",
|
||||||
|
" / ___/ __ `/ __ `__ \\/ __ \\/ / _ \\/ ___/",
|
||||||
|
" (__ ) /_/ / / / / / / /_/ / / __/ / ",
|
||||||
|
"/____/\\__,_/_/ /_/ /_/ .___/_/\\___/_/ ",
|
||||||
|
" /_/ ",
|
||||||
|
}
|
||||||
|
|
||||||
|
introText := append(logo, []string{
|
||||||
|
"", "", "",
|
||||||
|
"Welcome.",
|
||||||
|
"Sampler is free of charge for personal use, but license must be purchased to use it for business purposes.",
|
||||||
|
"Clicking below indicates you agree to the terms of the license agreement and privacy policy: www.sampler.dev/license",
|
||||||
|
"", "", "",
|
||||||
|
"How do you plan to use Sampler?",
|
||||||
|
}...)
|
||||||
|
|
||||||
|
commericalText := append(logo, []string{
|
||||||
|
"", "", "", "",
|
||||||
|
"Please visit www.sampler.dev to purchase a license and then start Sampler with --license flag",
|
||||||
|
}...)
|
||||||
|
|
||||||
|
personalText := append(logo, []string{
|
||||||
|
"", "", "", "",
|
||||||
|
"Sampler is always free for non-commercial use, but you can support the project and buy a personal license:",
|
||||||
|
"www.sampler.dev",
|
||||||
|
}...)
|
||||||
|
|
||||||
|
text := introText
|
||||||
|
|
||||||
|
switch intro.page {
|
||||||
|
case IntroPageWelcome:
|
||||||
|
text = introText
|
||||||
|
case IntroPageCommercial:
|
||||||
|
text = commericalText
|
||||||
|
case IntroPagePersonal:
|
||||||
|
text = personalText
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, a := range text {
|
||||||
|
util.PrintString(
|
||||||
|
a,
|
||||||
|
ui.NewStyle(intro.palette.BaseColor),
|
||||||
|
util.GetMiddlePoint(intro.Block.Rectangle, a, i-15),
|
||||||
|
buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightedStyle := ui.NewStyle(intro.palette.ReverseColor, intro.palette.BaseColor)
|
||||||
|
regularStyle := ui.NewStyle(intro.palette.BaseColor, intro.palette.ReverseColor)
|
||||||
|
|
||||||
|
if intro.page == IntroPageWelcome {
|
||||||
|
|
||||||
|
commercialButtonStyle := highlightedStyle
|
||||||
|
if intro.option == introOptionPersonal {
|
||||||
|
commercialButtonStyle = regularStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
personalButtonStyle := highlightedStyle
|
||||||
|
if intro.option == introOptionCommercial {
|
||||||
|
personalButtonStyle = regularStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.SetString(string(buttonCommercial), commercialButtonStyle,
|
||||||
|
util.GetMiddlePoint(intro.Block.Rectangle, string(buttonCommercial), 6))
|
||||||
|
buffer.SetString(string(buttonPersonal), personalButtonStyle,
|
||||||
|
util.GetMiddlePoint(intro.Block.Rectangle, string(buttonPersonal), 8))
|
||||||
|
} else {
|
||||||
|
buffer.SetString(string(buttonOk), highlightedStyle,
|
||||||
|
util.GetMiddlePoint(intro.Block.Rectangle, string(buttonOk), 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
intro.Block.Draw(buffer)
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import (
|
||||||
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/component/runchart"
|
"github.com/sqshq/sampler/component/runchart"
|
||||||
|
"github.com/sqshq/sampler/component/util"
|
||||||
"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"
|
"github.com/sqshq/sampler/data"
|
||||||
|
@ -16,6 +17,7 @@ type Layout struct {
|
||||||
Components []*component.Component
|
Components []*component.Component
|
||||||
statusbar *component.StatusBar
|
statusbar *component.StatusBar
|
||||||
menu *component.Menu
|
menu *component.Menu
|
||||||
|
intro *component.Intro
|
||||||
ChangeModeEvents chan Mode
|
ChangeModeEvents chan Mode
|
||||||
mode Mode
|
mode Mode
|
||||||
selection int
|
selection int
|
||||||
|
@ -25,12 +27,13 @@ type Mode rune
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ModeDefault Mode = 0
|
ModeDefault Mode = 0
|
||||||
ModePause Mode = 1
|
ModeIntro Mode = 1
|
||||||
ModeComponentSelect Mode = 2
|
ModePause Mode = 2
|
||||||
ModeMenuOptionSelect Mode = 3
|
ModeComponentSelect Mode = 3
|
||||||
ModeComponentMove Mode = 4
|
ModeMenuOptionSelect Mode = 4
|
||||||
ModeComponentResize Mode = 5
|
ModeComponentMove Mode = 5
|
||||||
ModeChartPinpoint Mode = 6
|
ModeComponentResize Mode = 6
|
||||||
|
ModeChartPinpoint Mode = 7
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -38,10 +41,11 @@ const (
|
||||||
statusbarHeight = 1
|
statusbarHeight = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewLayout(width, height int, statusline *component.StatusBar, menu *component.Menu) *Layout {
|
func NewLayout(width, height int, statusline *component.StatusBar, menu *component.Menu, intro *component.Intro) *Layout {
|
||||||
|
|
||||||
block := *ui.NewBlock()
|
block := *ui.NewBlock()
|
||||||
block.SetRect(0, 0, width, height)
|
block.SetRect(0, 0, width, height)
|
||||||
|
intro.SetRect(0, 0, width, height)
|
||||||
statusline.SetRect(0, height-statusbarHeight, width, height)
|
statusline.SetRect(0, height-statusbarHeight, width, height)
|
||||||
|
|
||||||
return &Layout{
|
return &Layout{
|
||||||
|
@ -49,6 +53,7 @@ func NewLayout(width, height int, statusline *component.StatusBar, menu *compone
|
||||||
Components: make([]*component.Component, 0),
|
Components: make([]*component.Component, 0),
|
||||||
statusbar: statusline,
|
statusbar: statusline,
|
||||||
menu: menu,
|
menu: menu,
|
||||||
|
intro: intro,
|
||||||
mode: ModeDefault,
|
mode: ModeDefault,
|
||||||
selection: 0,
|
selection: 0,
|
||||||
ChangeModeEvents: make(chan Mode, 10),
|
ChangeModeEvents: make(chan Mode, 10),
|
||||||
|
@ -59,12 +64,19 @@ func (l *Layout) AddComponent(cpt *component.Component) {
|
||||||
l.Components = append(l.Components, cpt)
|
l.Components = append(l.Components, cpt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Layout) RunIntro() {
|
||||||
|
l.mode = ModeIntro
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Layout) changeMode(m Mode) {
|
func (l *Layout) changeMode(m Mode) {
|
||||||
l.mode = m
|
l.mode = m
|
||||||
l.ChangeModeEvents <- m
|
l.ChangeModeEvents <- m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Layout) HandleMouseClick(x int, y int) {
|
func (l *Layout) HandleMouseClick(x int, y int) {
|
||||||
|
if l.mode == ModeIntro {
|
||||||
|
return
|
||||||
|
}
|
||||||
l.menu.Idle()
|
l.menu.Idle()
|
||||||
selected, i := l.findComponentAtPoint(image.Point{X: x, Y: y})
|
selected, i := l.findComponentAtPoint(image.Point{X: x, Y: y})
|
||||||
if selected == nil {
|
if selected == nil {
|
||||||
|
@ -118,6 +130,14 @@ func (l *Layout) HandleKeyboardEvent(e string) {
|
||||||
case ModeComponentResize:
|
case ModeComponentResize:
|
||||||
l.menu.Idle()
|
l.menu.Idle()
|
||||||
l.changeMode(ModeDefault)
|
l.changeMode(ModeDefault)
|
||||||
|
break
|
||||||
|
case ModeIntro:
|
||||||
|
page := l.intro.GetSelectedPage()
|
||||||
|
if page == component.IntroPageWelcome {
|
||||||
|
l.intro.NextPage()
|
||||||
|
} else {
|
||||||
|
l.changeMode(ModeDefault)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case console.KeyEsc:
|
case console.KeyEsc:
|
||||||
l.resetAlerts()
|
l.resetAlerts()
|
||||||
|
@ -180,6 +200,8 @@ func (l *Layout) HandleKeyboardEvent(e string) {
|
||||||
selected.Move(0, -1)
|
selected.Move(0, -1)
|
||||||
case ModeComponentResize:
|
case ModeComponentResize:
|
||||||
selected.Resize(0, -1)
|
selected.Resize(0, -1)
|
||||||
|
case ModeIntro:
|
||||||
|
l.intro.Up()
|
||||||
}
|
}
|
||||||
case console.KeyDown:
|
case console.KeyDown:
|
||||||
switch l.mode {
|
switch l.mode {
|
||||||
|
@ -195,6 +217,8 @@ func (l *Layout) HandleKeyboardEvent(e string) {
|
||||||
selected.Move(0, 1)
|
selected.Move(0, 1)
|
||||||
case ModeComponentResize:
|
case ModeComponentResize:
|
||||||
selected.Resize(0, 1)
|
selected.Resize(0, 1)
|
||||||
|
case ModeIntro:
|
||||||
|
l.intro.Down()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,21 +256,21 @@ func (l *Layout) moveSelection(direction string) {
|
||||||
|
|
||||||
switch direction {
|
switch direction {
|
||||||
case console.KeyLeft:
|
case console.KeyLeft:
|
||||||
previouslySelectedCornerPoint = component.GetRectLeftSideCenter(previouslySelected.GetRect())
|
previouslySelectedCornerPoint = util.GetRectLeftSideCenter(previouslySelected.GetRect())
|
||||||
newlySelectedCornerPoint = component.GetRectRightSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
newlySelectedCornerPoint = util.GetRectRightSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||||
currentCornerPoint = component.GetRectRightSideCenter(current.GetRect())
|
currentCornerPoint = util.GetRectRightSideCenter(current.GetRect())
|
||||||
case console.KeyRight:
|
case console.KeyRight:
|
||||||
previouslySelectedCornerPoint = component.GetRectRightSideCenter(previouslySelected.GetRect())
|
previouslySelectedCornerPoint = util.GetRectRightSideCenter(previouslySelected.GetRect())
|
||||||
newlySelectedCornerPoint = component.GetRectLeftSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
newlySelectedCornerPoint = util.GetRectLeftSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||||
currentCornerPoint = component.GetRectLeftSideCenter(current.GetRect())
|
currentCornerPoint = util.GetRectLeftSideCenter(current.GetRect())
|
||||||
case console.KeyUp:
|
case console.KeyUp:
|
||||||
previouslySelectedCornerPoint = component.GetRectTopSideCenter(previouslySelected.GetRect())
|
previouslySelectedCornerPoint = util.GetRectTopSideCenter(previouslySelected.GetRect())
|
||||||
newlySelectedCornerPoint = component.GetRectBottomSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
newlySelectedCornerPoint = util.GetRectBottomSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||||
currentCornerPoint = component.GetRectBottomSideCenter(current.GetRect())
|
currentCornerPoint = util.GetRectBottomSideCenter(current.GetRect())
|
||||||
case console.KeyDown:
|
case console.KeyDown:
|
||||||
previouslySelectedCornerPoint = component.GetRectBottomSideCenter(previouslySelected.GetRect())
|
previouslySelectedCornerPoint = util.GetRectBottomSideCenter(previouslySelected.GetRect())
|
||||||
newlySelectedCornerPoint = component.GetRectTopSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
newlySelectedCornerPoint = util.GetRectTopSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||||
currentCornerPoint = component.GetRectTopSideCenter(current.GetRect())
|
currentCornerPoint = util.GetRectTopSideCenter(current.GetRect())
|
||||||
}
|
}
|
||||||
|
|
||||||
switch direction {
|
switch direction {
|
||||||
|
@ -279,6 +303,12 @@ func (l *Layout) Draw(buffer *ui.Buffer) {
|
||||||
columnWidth := float64(l.GetRect().Dx()) / float64(console.ColumnsCount)
|
columnWidth := float64(l.GetRect().Dx()) / float64(console.ColumnsCount)
|
||||||
rowHeight := float64(l.GetRect().Dy()-statusbarHeight) / float64(console.RowsCount)
|
rowHeight := float64(l.GetRect().Dy()-statusbarHeight) / float64(console.RowsCount)
|
||||||
|
|
||||||
|
if l.mode == ModeIntro {
|
||||||
|
l.intro.SetRect(l.Min.X, l.Min.Y, l.Max.X, l.Max.Y)
|
||||||
|
l.intro.Draw(buffer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, c := range l.Components {
|
for _, c := range l.Components {
|
||||||
rectangle := calculateComponentCoordinates(c, columnWidth, rowHeight)
|
rectangle := calculateComponentCoordinates(c, columnWidth, rowHeight)
|
||||||
c.SetRect(rectangle.Min.X, rectangle.Min.Y, rectangle.Max.X, rectangle.Max.Y)
|
c.SetRect(rectangle.Min.X, rectangle.Min.Y, rectangle.Max.X, rectangle.Max.Y)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package component
|
||||||
|
|
||||||
import (
|
import (
|
||||||
ui "github.com/gizak/termui/v3"
|
ui "github.com/gizak/termui/v3"
|
||||||
|
"github.com/sqshq/sampler/component/util"
|
||||||
"github.com/sqshq/sampler/config"
|
"github.com/sqshq/sampler/config"
|
||||||
"github.com/sqshq/sampler/console"
|
"github.com/sqshq/sampler/console"
|
||||||
"image"
|
"image"
|
||||||
|
@ -130,14 +131,14 @@ func (m *Menu) renderHighlight(buffer *ui.Buffer) {
|
||||||
buffer.SetString(
|
buffer.SetString(
|
||||||
optionsText,
|
optionsText,
|
||||||
ui.NewStyle(console.ColorDarkGrey),
|
ui.NewStyle(console.ColorDarkGrey),
|
||||||
getMiddlePoint(m.Block.Rectangle, optionsText, -1),
|
util.GetMiddlePoint(m.Block.Rectangle, optionsText, -1),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.printAllDirectionsArrowSign(buffer, -2)
|
m.printAllDirectionsArrowSign(buffer, -2)
|
||||||
|
|
||||||
arrowsTextPoint := getMiddlePoint(m.Block.Rectangle, arrowsText, 2)
|
arrowsTextPoint := util.GetMiddlePoint(m.Block.Rectangle, arrowsText, 2)
|
||||||
if arrowsTextPoint.Y+1 < m.Inner.Max.Y {
|
if arrowsTextPoint.Y+1 < m.Inner.Max.Y {
|
||||||
buffer.SetString(
|
buffer.SetString(
|
||||||
arrowsText,
|
arrowsText,
|
||||||
|
@ -146,16 +147,16 @@ func (m *Menu) renderHighlight(buffer *ui.Buffer) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
optionsTextPoint := getMiddlePoint(m.Block.Rectangle, optionsText, 3)
|
optionsTextPoint := util.GetMiddlePoint(m.Block.Rectangle, optionsText, 3)
|
||||||
if optionsTextPoint.Y+1 < m.Inner.Max.Y {
|
if optionsTextPoint.Y+1 < m.Inner.Max.Y {
|
||||||
buffer.SetString(
|
buffer.SetString(
|
||||||
optionsText,
|
optionsText,
|
||||||
ui.NewStyle(console.ColorDarkGrey),
|
ui.NewStyle(console.ColorDarkGrey),
|
||||||
getMiddlePoint(m.Block.Rectangle, optionsText, 3),
|
util.GetMiddlePoint(m.Block.Rectangle, optionsText, 3),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
resumeTextPoint := getMiddlePoint(m.Block.Rectangle, resumeText, 4)
|
resumeTextPoint := util.GetMiddlePoint(m.Block.Rectangle, resumeText, 4)
|
||||||
if resumeTextPoint.Y+1 < m.Inner.Max.Y {
|
if resumeTextPoint.Y+1 < m.Inner.Max.Y {
|
||||||
buffer.SetString(
|
buffer.SetString(
|
||||||
resumeText,
|
resumeText,
|
||||||
|
@ -170,12 +171,12 @@ func (m *Menu) renderMoveAndResize(buffer *ui.Buffer) {
|
||||||
saveText := "<ENTER> to save changes"
|
saveText := "<ENTER> to save changes"
|
||||||
|
|
||||||
if m.Dy() <= minimalMenuHeight {
|
if m.Dy() <= minimalMenuHeight {
|
||||||
buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), getMiddlePoint(m.Block.Rectangle, saveText, -1))
|
buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), util.GetMiddlePoint(m.Block.Rectangle, saveText, -1))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.printAllDirectionsArrowSign(buffer, -1)
|
m.printAllDirectionsArrowSign(buffer, -1)
|
||||||
buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), getMiddlePoint(m.Block.Rectangle, saveText, 3))
|
buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), util.GetMiddlePoint(m.Block.Rectangle, saveText, 3))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) {
|
func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) {
|
||||||
|
@ -187,10 +188,10 @@ func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, a := range arrows {
|
for i, a := range arrows {
|
||||||
printString(
|
util.PrintString(
|
||||||
a,
|
a,
|
||||||
ui.NewStyle(console.ColorOlive),
|
ui.NewStyle(console.ColorOlive),
|
||||||
getMiddlePoint(m.Block.Rectangle, a, i+y),
|
util.GetMiddlePoint(m.Block.Rectangle, a, i+y),
|
||||||
buffer,
|
buffer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -211,7 +212,7 @@ func (m *Menu) renderOptions(buffer *ui.Buffer) {
|
||||||
|
|
||||||
if option != MenuOptionPinpoint || m.component.Type == config.TypeRunChart {
|
if option != MenuOptionPinpoint || m.component.Type == config.TypeRunChart {
|
||||||
offset += 2
|
offset += 2
|
||||||
point := getMiddlePoint(m.Block.Rectangle, string(option), offset-6)
|
point := util.GetMiddlePoint(m.Block.Rectangle, string(option), offset-6)
|
||||||
buffer.SetString(string(option), style, point)
|
buffer.SetString(string(option), style, point)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,15 +240,3 @@ func (m *Menu) drawInnerBorder(buffer *ui.Buffer) {
|
||||||
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_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))
|
buffer.SetCell(ui.Cell{ui.BOTTOM_RIGHT, m.BorderStyle}, image.Pt(m.Max.X-3, m.Max.Y-2))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO move to utils
|
|
||||||
func getMiddlePoint(rectangle image.Rectangle, text string, offset int) image.Point {
|
|
||||||
return image.Pt(rectangle.Min.X+rectangle.Dx()/2-len(text)/2, rectangle.Max.Y-rectangle.Dy()/2+offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO move to utils
|
|
||||||
func printString(s string, style ui.Style, p image.Point, buffer *ui.Buffer) {
|
|
||||||
for i, char := range s {
|
|
||||||
buffer.SetCell(ui.Cell{Rune: char, Style: style}, image.Pt(p.X+i, p.Y))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ type TextBox struct {
|
||||||
alert *data.Alert
|
alert *data.Alert
|
||||||
text string
|
text string
|
||||||
border bool
|
border bool
|
||||||
|
style ui.Style
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTextBox(c config.TextBoxConfig, palette console.Palette) *TextBox {
|
func NewTextBox(c config.TextBoxConfig, palette console.Palette) *TextBox {
|
||||||
|
@ -22,6 +23,7 @@ func NewTextBox(c config.TextBoxConfig, palette console.Palette) *TextBox {
|
||||||
box := TextBox{
|
box := TextBox{
|
||||||
Block: component.NewBlock(c.Title, *c.Border, palette),
|
Block: component.NewBlock(c.Title, *c.Border, palette),
|
||||||
Consumer: data.NewConsumer(),
|
Consumer: data.NewConsumer(),
|
||||||
|
style: ui.NewStyle(palette.BaseColor),
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -54,6 +56,7 @@ func (t *TextBox) Draw(buffer *ui.Buffer) {
|
||||||
row = ui.TrimCells(row, t.Inner.Dx()-2)
|
row = ui.TrimCells(row, t.Inner.Dx()-2)
|
||||||
for _, cx := range ui.BuildCellWithXArray(row) {
|
for _, cx := range ui.BuildCellWithXArray(row) {
|
||||||
x, cell := cx.X, cx.Cell
|
x, cell := cx.X, cx.Cell
|
||||||
|
cell.Style = t.style
|
||||||
buffer.SetCell(cell, image.Pt(x+1, y+1).Add(t.Inner.Min))
|
buffer.SetCell(cell, image.Pt(x+1, y+1).Add(t.Inner.Min))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
ui "github.com/gizak/termui/v3"
|
||||||
|
"image"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -74,3 +76,13 @@ func formatTrailingDigits(value string, scale int) string {
|
||||||
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetMiddlePoint(rectangle image.Rectangle, text string, offset int) image.Point {
|
||||||
|
return image.Pt(rectangle.Min.X+rectangle.Dx()/2-len(text)/2, rectangle.Max.Y-rectangle.Dy()/2+offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintString(s string, style ui.Style, p image.Point, buffer *ui.Buffer) {
|
||||||
|
for i, char := range s {
|
||||||
|
buffer.SetCell(ui.Cell{Rune: char, Style: style}, image.Pt(p.X+i, p.Y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package component
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
|
@ -38,3 +38,9 @@ func GetDistance(p1 image.Point, p2 image.Point) float64 {
|
||||||
y := math.Abs(float64(p1.Y - p2.Y))
|
y := math.Abs(float64(p1.Y - p2.Y))
|
||||||
return math.Sqrt(x*x + y*y)
|
return math.Sqrt(x*x + y*y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRectCoordinates(area image.Rectangle, width int, height int) (int, int, int, int) {
|
||||||
|
x1 := area.Min.X + area.Dx()/2 - width/2
|
||||||
|
y1 := area.Min.Y + area.Dy()/2 - height
|
||||||
|
return x1, y1, x1 + width, y1 + height + 2
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ type Config struct {
|
||||||
AsciiBoxes []AsciiBoxConfig `yaml:"asciiboxes,omitempty"`
|
AsciiBoxes []AsciiBoxConfig `yaml:"asciiboxes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Load() (Config, Options) {
|
func LoadConfig() (Config, Options) {
|
||||||
|
|
||||||
var opt Options
|
var opt Options
|
||||||
_, err := flags.Parse(&opt)
|
_, err := flags.Parse(&opt)
|
||||||
|
@ -114,7 +114,7 @@ func saveFile(config *Config, fileName string) {
|
||||||
log.Fatalf("Can't marshal config file: %v", err)
|
log.Fatalf("Can't marshal config file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ioutil.WriteFile(fileName, file, 0644)
|
err = ioutil.WriteFile(fileName, file, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Can't save config file: %v", err)
|
log.Fatalf("Can't save config file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const interactiveShellStartupTimeout = time.Second
|
const interactiveShellStartupTimeout = 100 * time.Millisecond
|
||||||
|
|
||||||
type Item struct {
|
type Item struct {
|
||||||
Label string
|
Label string
|
||||||
|
|
|
@ -29,7 +29,7 @@ func NewSampler(consumer *Consumer, items []*Item, triggers []*Trigger, options
|
||||||
go func() {
|
go func() {
|
||||||
for ; true; <-ticker.C {
|
for ; true; <-ticker.C {
|
||||||
for _, item := range sampler.items {
|
for _, item := range sampler.items {
|
||||||
go sampler.sample(item, options)
|
sampler.sample(item, options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -39,7 +39,7 @@ func NewSampler(consumer *Consumer, items []*Item, triggers []*Trigger, options
|
||||||
select {
|
select {
|
||||||
case sample := <-sampler.triggersChannel:
|
case sample := <-sampler.triggersChannel:
|
||||||
for _, t := range sampler.triggers {
|
for _, t := range sampler.triggers {
|
||||||
go t.Execute(sample)
|
t.Execute(sample)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
main.go
19
main.go
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/sqshq/sampler/console"
|
"github.com/sqshq/sampler/console"
|
||||||
"github.com/sqshq/sampler/data"
|
"github.com/sqshq/sampler/data"
|
||||||
"github.com/sqshq/sampler/event"
|
"github.com/sqshq/sampler/event"
|
||||||
|
"github.com/sqshq/sampler/storage"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,12 +32,12 @@ func (s *Starter) start(drawable ui.Drawable, consumer *data.Consumer, component
|
||||||
items := data.NewItems(itemsConfig, *componentConfig.RateMs)
|
items := data.NewItems(itemsConfig, *componentConfig.RateMs)
|
||||||
data.NewSampler(consumer, items, triggers, s.opt, s.cfg.Variables, *componentConfig.RateMs)
|
data.NewSampler(consumer, items, triggers, s.opt, s.cfg.Variables, *componentConfig.RateMs)
|
||||||
s.lout.AddComponent(cpt)
|
s.lout.AddComponent(cpt)
|
||||||
time.Sleep(100 * time.Millisecond) // desync coroutines
|
time.Sleep(10 * time.Millisecond) // desync coroutines
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
cfg, opt := config.Load()
|
cfg, opt := config.LoadConfig()
|
||||||
|
|
||||||
console.Init()
|
console.Init()
|
||||||
defer console.Close()
|
defer console.Close()
|
||||||
|
@ -47,10 +48,11 @@ func main() {
|
||||||
palette := console.GetPalette(*cfg.Theme)
|
palette := console.GetPalette(*cfg.Theme)
|
||||||
width, height := ui.TerminalDimensions()
|
width, height := ui.TerminalDimensions()
|
||||||
|
|
||||||
lout := layout.NewLayout(width, height, component.NewStatusLine(opt.ConfigFile, palette), component.NewMenu(palette))
|
lout := layout.NewLayout(width, height, component.NewStatusLine(opt.ConfigFile, palette), component.NewMenu(palette), component.NewIntro(palette))
|
||||||
|
|
||||||
starter := &Starter{lout, player, opt, cfg}
|
starter := &Starter{lout, player, opt, cfg}
|
||||||
|
|
||||||
|
license := storage.GetLicense()
|
||||||
|
|
||||||
for _, c := range cfg.RunCharts {
|
for _, c := range cfg.RunCharts {
|
||||||
cpt := runchart.NewRunChart(c, palette)
|
cpt := runchart.NewRunChart(c, palette)
|
||||||
starter.start(cpt, cpt.Consumer, c.ComponentConfig, c.Items, c.Triggers)
|
starter.start(cpt, cpt.Consumer, c.ComponentConfig, c.Items, c.Triggers)
|
||||||
|
@ -81,6 +83,15 @@ func main() {
|
||||||
starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Item}, c.Triggers)
|
starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Item}, c.Triggers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if license == nil {
|
||||||
|
lout.RunIntro()
|
||||||
|
storage.InitLicense()
|
||||||
|
} else if !license.Purchased /* && random */ {
|
||||||
|
// TODO lout.showNagWindow() with timeout and OK button
|
||||||
|
// TODO verify license
|
||||||
|
// TODO send stats
|
||||||
|
}
|
||||||
|
|
||||||
handler := event.NewHandler(lout, opt)
|
handler := event.NewHandler(lout, opt)
|
||||||
handler.HandleEvents()
|
handler.HandleEvents()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type License struct {
|
||||||
|
Purchased bool
|
||||||
|
Valid bool
|
||||||
|
Key *string
|
||||||
|
Username *string
|
||||||
|
Company *string
|
||||||
|
}
|
||||||
|
|
||||||
|
const licenseFileName = "license.yml"
|
||||||
|
|
||||||
|
func GetLicense() *License {
|
||||||
|
if !fileExists(licenseFileName) {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
file := readStorageFile(getPlatformStoragePath(licenseFileName))
|
||||||
|
|
||||||
|
license := new(License)
|
||||||
|
err := yaml.Unmarshal(file, license)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Can't read license file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return license
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitLicense() {
|
||||||
|
|
||||||
|
license := License{
|
||||||
|
Purchased: false,
|
||||||
|
Valid: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := yaml.Marshal(license)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Can't marshal config file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
initStorage()
|
||||||
|
saveStorageFile(file, getPlatformStoragePath(licenseFileName))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveLicense() {
|
||||||
|
// TODO
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package storage
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// version
|
||||||
|
// launch count
|
||||||
|
// components count by type
|
|
@ -0,0 +1,56 @@
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
macOSDir = "/Library/Application Support/Sampler"
|
||||||
|
linuxDir = "/.config/Sampler"
|
||||||
|
windowsDir = "%LOCALAPPDATA%\\Sampler"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fileExists(filename string) bool {
|
||||||
|
_, err := os.Stat(getPlatformStoragePath(filename))
|
||||||
|
return !os.IsNotExist(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPlatformStoragePath(filename string) string {
|
||||||
|
home, _ := os.UserHomeDir()
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
return filepath.Join(home, macOSDir, filename)
|
||||||
|
case "windows":
|
||||||
|
return filepath.Join(home, windowsDir, filename)
|
||||||
|
default:
|
||||||
|
return filepath.Join(linuxDir, filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initStorage() {
|
||||||
|
err := os.MkdirAll(getPlatformStoragePath(""), os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to init storage: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readStorageFile(path string) []byte {
|
||||||
|
|
||||||
|
file, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to the read storage file: %s", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveStorageFile(file []byte, fileName string) {
|
||||||
|
err := ioutil.WriteFile(fileName, file, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to save the storage file: %v", err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue