whispervis/widgets/simulation.go

156 lines
3.6 KiB
Go

package widgets
import (
"github.com/gopherjs/vecty"
"github.com/gopherjs/vecty/elem"
"github.com/gopherjs/vecty/event"
"github.com/gopherjs/vecty/prop"
)
// Simulation represents configuration panel for propagation simulation.
type Simulation struct {
vecty.Core
startSimulation func() error
replay func()
address string // backend host address
errMsg string
hasResults bool
inProgress bool
}
// NewSimulation creates new simulation configuration panel. If simulation
// backend host address is not specified, it'll use 'localhost:8084' as a default.
func NewSimulation(address string, startSimulation func() error, replay func()) *Simulation {
if address == "" {
address = "http://localhost:8084"
}
return &Simulation{
address: address,
startSimulation: startSimulation,
replay: replay,
}
}
// Render implements vecty.Component interface for Simulation.
func (s *Simulation) Render() vecty.ComponentOrHTML {
return elem.Div(
elem.Div(
elem.Heading3(vecty.Text("Simulation backend:")),
vecty.Markup(
vecty.Class("pure-markup-group", "pure-u-1"),
),
elem.Div(
vecty.Markup(
vecty.MarkupIf(s.inProgress,
// disable
vecty.Style("pointer-events", "none"),
vecty.Style("opacity", "0.4"),
),
),
elem.Label(
vecty.Markup(
vecty.Class("pure-u-1-2"),
),
vecty.Text("Host address:"),
),
elem.Input(
vecty.Markup(
prop.Value(s.address),
event.Input(s.onEditInput),
vecty.Class("pure-input-1-3"),
vecty.Style("float", "right"),
vecty.Style("margin-right", "10px"),
vecty.Style("text-align", "right"),
),
),
),
),
elem.Div(
vecty.Markup(
vecty.Class("pure-markup-group", "pure-u-1"),
),
elem.Button(
vecty.Markup(
vecty.MarkupIf(s.inProgress,
// disable
vecty.Style("pointer-events", "none"),
vecty.Style("opacity", "0.4"),
),
vecty.Class("pure-button"),
vecty.Class("pure-u-1-2"),
vecty.Style("background", "rgb(28, 184, 65)"),
vecty.Style("color", "white"),
vecty.Style("border-radius", "4px"),
event.Click(s.onSimulateClick),
),
vecty.Text("Start simulation"),
),
vecty.If(s.hasResults,
elem.Button(
vecty.Markup(
vecty.Class("pure-button"),
vecty.Class("pure-u-1-3"),
vecty.Style("background", "rgb(28, 184, 65)"),
vecty.Style("color", "white"),
vecty.Style("margin", "10px"),
vecty.Style("border-radius", "4px"),
event.Click(s.onRestartClick),
),
vecty.Text("Replay"),
),
),
elem.Break(),
vecty.If(s.inProgress, elem.Heading5(
vecty.Text("Running simulation..."),
)),
elem.Div(
vecty.If(s.errMsg != "", elem.Paragraph(
vecty.Markup(
vecty.Style("background", "rgb(202, 60, 60)"),
vecty.Style("color", "white"),
vecty.Style("border-radius", "4px"),
vecty.Style("margin-right", "5px"),
vecty.Style("padding", "5px"),
),
vecty.Text(s.errMsg),
)),
),
),
)
}
func (s *Simulation) onEditInput(event *vecty.Event) {
value := event.Target.Get("value").String()
s.address = value
}
// Address returns the current backend address.
func (s *Simulation) Address() string {
return s.address
}
func (s *Simulation) onSimulateClick(e *vecty.Event) {
go func() {
s.errMsg = ""
s.hasResults = false
s.inProgress = true
vecty.Rerender(s)
err := s.startSimulation()
if err != nil {
s.errMsg = err.Error()
}
s.hasResults = err == nil
s.inProgress = false
vecty.Rerender(s)
}()
}
func (s *Simulation) onRestartClick(e *vecty.Event) {
go s.replay()
}