diff options
Diffstat (limited to 'BBB_GOFILES/zz_histogram.go')
| -rw-r--r-- | BBB_GOFILES/zz_histogram.go | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/BBB_GOFILES/zz_histogram.go b/BBB_GOFILES/zz_histogram.go new file mode 100644 index 0000000..fae5aae --- /dev/null +++ b/BBB_GOFILES/zz_histogram.go @@ -0,0 +1,253 @@ +// 12 august 2018 + +// +build OMIT + +package main + +import ( + "math/rand" + "time" + + "github.com/andlabs/ui" +) + +var ( + histogram *ui.Area + datapoints [10]*ui.Spinbox + colorButton *ui.ColorButton + + currentPoint = -1 +) + +// some metrics +const ( + xoffLeft = 20 // histogram margins + yoffTop = 20 + xoffRight = 20 + yoffBottom = 20 + pointRadius = 5 +) + +// helper to quickly set a brush color +func mkSolidBrush(color uint32, alpha float64) *ui.Brush { + brush := new(ui.Brush) + brush.Type = ui.BrushTypeSolid + component := uint8((color >> 16) & 0xFF) + brush.R = float64(component) / 255 + component = uint8((color >> 8) & 0xFF) + brush.G = float64(component) / 255 + component = uint8(color & 0xFF) + brush.B = float64(component) / 255 + brush.A = alpha + return brush +} + +// and some colors +// names and values from https://msdn.microsoft.com/en-us/library/windows/desktop/dd370907%28v=vs.85%29.aspx +const ( + colorWhite = 0xFFFFFF + colorBlack = 0x000000 + colorDodgerBlue = 0x1E90FF +) + +func pointLocations(width, height float64) (xs, ys [10]float64) { + xincr := width / 9 // 10 - 1 to make the last point be at the end + yincr := height / 100 + for i := 0; i < 10; i++ { + // get the value of the point + n := datapoints[i].Value() + // because y=0 is the top but n=0 is the bottom, we need to flip + n = 100 - n + xs[i] = xincr * float64(i) + ys[i] = yincr * float64(n) + } + return xs, ys +} + +func constructGraph(width, height float64, extend bool) *ui.Path { + xs, ys := pointLocations(width, height) + path := ui.NewPath(ui.Winding) + + path.NewFigure(xs[0], ys[0]) + for i := 1; i < 10; i++ { + path.LineTo(xs[i], ys[i]) + } + + if extend { + path.LineTo(width, height) + path.LineTo(0, height) + path.CloseFigure() + } + + path.End() + return path +} + +func graphSize(clientWidth, clientHeight float64) (graphWidth, graphHeight float64) { + return clientWidth - xoffLeft - xoffRight, + clientHeight - yoffTop - yoffBottom +} + +type areaHandler struct{} + +func (areaHandler) Draw(a *ui.Area, p *ui.AreaDrawParams) { + // fill the area with white + brush := mkSolidBrush(colorWhite, 1.0) + path := ui.NewPath(ui.Winding) + path.AddRectangle(0, 0, p.AreaWidth, p.AreaHeight) + path.End() + p.Context.Fill(path, brush) + path.Free() + + graphWidth, graphHeight := graphSize(p.AreaWidth, p.AreaHeight) + + sp := &ui.StrokeParams{ + Cap: ui.FlatCap, + Join: ui.MiterJoin, + Thickness: 2, + MiterLimit: ui.DefaultMiterLimit, + } + + // draw the axes + brush = mkSolidBrush(colorBlack, 1.0) + path = ui.NewPath(ui.Winding) + path.NewFigure(xoffLeft, yoffTop) + path.LineTo(xoffLeft, yoffTop + graphHeight) + path.LineTo(xoffLeft + graphWidth, yoffTop + graphHeight) + path.End() + p.Context.Stroke(path, brush, sp) + path.Free() + + // now transform the coordinate space so (0, 0) is the top-left corner of the graph + m := ui.NewMatrix() + m.Translate(xoffLeft, yoffTop) + p.Context.Transform(m) + + // now get the color for the graph itself and set up the brush + graphR, graphG, graphB, graphA := colorButton.Color() + brush.Type = ui.BrushTypeSolid + brush.R = graphR + brush.G = graphG + brush.B = graphB + // we set brush.A below to different values for the fill and stroke + + // now create the fill for the graph below the graph line + path = constructGraph(graphWidth, graphHeight, true) + brush.A = graphA / 2 + p.Context.Fill(path, brush) + path.Free() + + // now draw the histogram line + path = constructGraph(graphWidth, graphHeight, false) + brush.A = graphA + p.Context.Stroke(path, brush, sp) + path.Free() + + // now draw the point being hovered over + if currentPoint != -1 { + xs, ys := pointLocations(graphWidth, graphHeight) + path = ui.NewPath(ui.Winding) + path.NewFigureWithArc( + xs[currentPoint], ys[currentPoint], + pointRadius, + 0, 6.23, // TODO pi + false) + path.End() + // use the same brush as for the histogram lines + p.Context.Fill(path, brush) + path.Free() + } +} + +func inPoint(x, y float64, xtest, ytest float64) bool { + // TODO switch to using a matrix + x -= xoffLeft + y -= yoffTop + return (x >= xtest - pointRadius) && + (x <= xtest + pointRadius) && + (y >= ytest - pointRadius) && + (y <= ytest + pointRadius) +} + +func (areaHandler) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) { + graphWidth, graphHeight := graphSize(me.AreaWidth, me.AreaHeight) + xs, ys := pointLocations(graphWidth, graphHeight) + + currentPoint = -1 + for i := 0; i < 10; i++ { + if inPoint(me.X, me.Y, xs[i], ys[i]) { + currentPoint = i + break + } + } + + // TODO only redraw the relevant area + histogram.QueueRedrawAll() +} + +func (areaHandler) MouseCrossed(a *ui.Area, left bool) { + // do nothing +} + +func (areaHandler) DragBroken(a *ui.Area) { + // do nothing +} + +func (areaHandler) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled bool) { + // reject all keys + return false +} + +func setupUI() { + mainwin := ui.NewWindow("libui Histogram Example", 640, 480, true) + mainwin.SetMargined(true) + mainwin.OnClosing(func(*ui.Window) bool { + mainwin.Destroy() + ui.Quit() + return false + }) + ui.OnShouldQuit(func() bool { + mainwin.Destroy() + return true + }) + + hbox := ui.NewHorizontalBox() + hbox.SetPadded(true) + mainwin.SetChild(hbox) + + vbox := ui.NewVerticalBox() + vbox.SetPadded(true) + hbox.Append(vbox, false) + + histogram = ui.NewArea(areaHandler{}) + + rand.Seed(time.Now().Unix()) + for i := 0; i < 10; i++ { + datapoints[i] = ui.NewSpinbox(0, 100) + datapoints[i].SetValue(rand.Intn(101)) + datapoints[i].OnChanged(func(*ui.Spinbox) { + histogram.QueueRedrawAll() + }) + vbox.Append(datapoints[i], false) + } + + colorButton = ui.NewColorButton() + // TODO inline these + brush := mkSolidBrush(colorDodgerBlue, 1.0) + colorButton.SetColor(brush.R, + brush.G, + brush.B, + brush.A) + colorButton.OnChanged(func(*ui.ColorButton) { + histogram.QueueRedrawAll() + }) + vbox.Append(colorButton, false) + + hbox.Append(histogram, true) + + mainwin.Show() +} + +func main() { + ui.Main(setupUI) +} |
