From dd9db1c14586ecec7e9783f09cceb86fd04825ce Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 26 Aug 2018 17:26:53 -0400 Subject: And migrated the examples back; also fixed a spot I missed. --- BBB_GOFILES/zz_controls.go | 222 -------------------------------------- BBB_GOFILES/zz_drawtext.go | 167 ----------------------------- BBB_GOFILES/zz_histogram.go | 253 -------------------------------------------- draw.go | 2 +- zz_controls.go | 222 ++++++++++++++++++++++++++++++++++++++ zz_drawtext.go | 167 +++++++++++++++++++++++++++++ zz_histogram.go | 253 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 643 insertions(+), 643 deletions(-) delete mode 100644 BBB_GOFILES/zz_controls.go delete mode 100644 BBB_GOFILES/zz_drawtext.go delete mode 100644 BBB_GOFILES/zz_histogram.go create mode 100644 zz_controls.go create mode 100644 zz_drawtext.go create mode 100644 zz_histogram.go diff --git a/BBB_GOFILES/zz_controls.go b/BBB_GOFILES/zz_controls.go deleted file mode 100644 index d77bebe..0000000 --- a/BBB_GOFILES/zz_controls.go +++ /dev/null @@ -1,222 +0,0 @@ -// 12 august 2018 - -// +build OMIT - -package main - -import ( - "github.com/andlabs/ui" -) - -var mainwin *ui.Window - -func makeBasicControlsPage() ui.Control { - vbox := ui.NewVerticalBox() - vbox.SetPadded(true) - - hbox := ui.NewHorizontalBox() - hbox.SetPadded(true) - vbox.Append(hbox, false) - - hbox.Append(ui.NewButton("Button"), false) - hbox.Append(ui.NewCheckbox("Checkbox"), false) - - vbox.Append(ui.NewLabel("This is a label. Right now, labels can only span one line."), false) - - vbox.Append(ui.NewHorizontalSeparator(), false) - - group := ui.NewGroup("Entries") - group.SetMargined(true) - vbox.Append(group, true) - -group.SetChild(ui.NewNonWrappingMultilineEntry()) - - entryForm := ui.NewForm() - entryForm.SetPadded(true) - group.SetChild(entryForm) - - entryForm.Append("Entry", ui.NewEntry(), false) - entryForm.Append("Password Entry", ui.NewPasswordEntry(), false) - entryForm.Append("Search Entry", ui.NewSearchEntry(), false) - entryForm.Append("Multiline Entry", ui.NewMultilineEntry(), true) - entryForm.Append("Multiline Entry No Wrap", ui.NewNonWrappingMultilineEntry(), true) - - return vbox -} - -func makeNumbersPage() ui.Control { - hbox := ui.NewHorizontalBox() - hbox.SetPadded(true) - - group := ui.NewGroup("Numbers") - group.SetMargined(true) - hbox.Append(group, true) - - vbox := ui.NewVerticalBox() - vbox.SetPadded(true) - group.SetChild(vbox) - - spinbox := ui.NewSpinbox(0, 100) - slider := ui.NewSlider(0, 100) - pbar := ui.NewProgressBar() - spinbox.OnChanged(func(*ui.Spinbox) { - slider.SetValue(spinbox.Value()) - pbar.SetValue(spinbox.Value()) - }) - slider.OnChanged(func(*ui.Slider) { - spinbox.SetValue(slider.Value()) - pbar.SetValue(slider.Value()) - }) - vbox.Append(spinbox, false) - vbox.Append(slider, false) - vbox.Append(pbar, false) - - ip := ui.NewProgressBar() - ip.SetValue(-1) - vbox.Append(ip, false) - - group = ui.NewGroup("Lists") - group.SetMargined(true) - hbox.Append(group, true) - - vbox = ui.NewVerticalBox() - vbox.SetPadded(true) - group.SetChild(vbox) - - cbox := ui.NewCombobox() - cbox.Append("Combobox Item 1") - cbox.Append("Combobox Item 2") - cbox.Append("Combobox Item 3") - vbox.Append(cbox, false) - - ecbox := ui.NewEditableCombobox() - ecbox.Append("Editable Item 1") - ecbox.Append("Editable Item 2") - ecbox.Append("Editable Item 3") - vbox.Append(ecbox, false) - - rb := ui.NewRadioButtons() - rb.Append("Radio Button 1") - rb.Append("Radio Button 2") - rb.Append("Radio Button 3") - vbox.Append(rb, false) - - return hbox -} - -func makeDataChoosersPage() ui.Control { - hbox := ui.NewHorizontalBox() - hbox.SetPadded(true) - - vbox := ui.NewVerticalBox() - vbox.SetPadded(true) - hbox.Append(vbox, false) - - vbox.Append(ui.NewDatePicker(), false) - vbox.Append(ui.NewTimePicker(), false) - vbox.Append(ui.NewDateTimePicker(), false) - vbox.Append(ui.NewFontButton(), false) - vbox.Append(ui.NewColorButton(), false) - - hbox.Append(ui.NewVerticalSeparator(), false) - - vbox = ui.NewVerticalBox() - vbox.SetPadded(true) - hbox.Append(vbox, true) - - grid := ui.NewGrid() - grid.SetPadded(true) - vbox.Append(grid, false) - - button := ui.NewButton("Open File") - entry := ui.NewEntry() - entry.SetReadOnly(true) - button.OnClicked(func(*ui.Button) { - filename := ui.OpenFile(mainwin) - if filename == "" { - filename = "(cancelled)" - } - entry.SetText(filename) - }) - grid.Append(button, - 0, 0, 1, 1, - false, ui.AlignFill, false, ui.AlignFill) - grid.Append(entry, - 1, 0, 1, 1, - true, ui.AlignFill, false, ui.AlignFill) - - button = ui.NewButton("Save File") - entry2 := ui.NewEntry() - entry2.SetReadOnly(true) - button.OnClicked(func(*ui.Button) { - filename := ui.SaveFile(mainwin) - if filename == "" { - filename = "(cancelled)" - } - entry2.SetText(filename) - }) - grid.Append(button, - 0, 1, 1, 1, - false, ui.AlignFill, false, ui.AlignFill) - grid.Append(entry2, - 1, 1, 1, 1, - true, ui.AlignFill, false, ui.AlignFill) - - msggrid := ui.NewGrid() - msggrid.SetPadded(true) - grid.Append(msggrid, - 0, 2, 2, 1, - false, ui.AlignCenter, false, ui.AlignStart) - - button = ui.NewButton("Message Box") - button.OnClicked(func(*ui.Button) { - ui.MsgBox(mainwin, - "This is a normal message box.", - "More detailed information can be shown here.") - }) - msggrid.Append(button, - 0, 0, 1, 1, - false, ui.AlignFill, false, ui.AlignFill) - button = ui.NewButton("Error Box") - button.OnClicked(func(*ui.Button) { - ui.MsgBoxError(mainwin, - "This message box describes an error.", - "More detailed information can be shown here.") - }) - msggrid.Append(button, - 1, 0, 1, 1, - false, ui.AlignFill, false, ui.AlignFill) - - return hbox -} - -func setupUI() { - mainwin = ui.NewWindow("libui Control Gallery", 640, 480, true) - mainwin.OnClosing(func(*ui.Window) bool { - ui.Quit() - return true - }) - ui.OnShouldQuit(func() bool { - mainwin.Destroy() - return true - }) - - tab := ui.NewTab() - mainwin.SetChild(tab) - mainwin.SetMargined(true) - - tab.Append("Basic Controls", makeBasicControlsPage()) - tab.SetMargined(0, true) - - tab.Append("Numbers and Lists", makeNumbersPage()) - tab.SetMargined(1, true) - - tab.Append("Data Choosers", makeDataChoosersPage()) - tab.SetMargined(2, true) - - mainwin.Show() -} - -func main() { - ui.Main(setupUI) -} diff --git a/BBB_GOFILES/zz_drawtext.go b/BBB_GOFILES/zz_drawtext.go deleted file mode 100644 index a32b14b..0000000 --- a/BBB_GOFILES/zz_drawtext.go +++ /dev/null @@ -1,167 +0,0 @@ -// 19 august 2018 - -// +build OMIT - -package main - -// TODO probably a bug in libui: changing the font away from skia leads to a crash - -import ( - "github.com/andlabs/ui" -) - -var ( - fontButton *ui.FontButton - alignment *ui.Combobox - - attrstr *ui.AttributedString -) - -func appendWithAttributes(what string, attrs ...ui.Attribute) { - start := len(attrstr.String()) - end := start + len(what) - attrstr.AppendUnattributed(what) - for _, a := range attrs { - attrstr.SetAttribute(a, start, end) - } -} - -func makeAttributedString() { - attrstr = ui.NewAttributedString( - "Drawing strings with package ui is done with the ui.AttributedString and ui.DrawTextLayout objects.\n" + - "ui.AttributedString lets you have a variety of attributes: ") - - appendWithAttributes("font family", ui.TextFamily("Courier New")) - attrstr.AppendUnattributed(", ") - - appendWithAttributes("font size", ui.TextSize(18)) - attrstr.AppendUnattributed(", ") - - appendWithAttributes("font weight", ui.TextWeightBold) - attrstr.AppendUnattributed(", ") - - appendWithAttributes("font italicness", ui.TextItalicItalic) - attrstr.AppendUnattributed(", ") - - appendWithAttributes("font stretch", ui.TextStretchCondensed) - attrstr.AppendUnattributed(", ") - - appendWithAttributes("text color", ui.TextColor{0.75, 0.25, 0.5, 0.75}) - attrstr.AppendUnattributed(", ") - - appendWithAttributes("text background color", ui.TextBackground{0.5, 0.5, 0.25, 0.5}) - attrstr.AppendUnattributed(", ") - - appendWithAttributes("underline style", ui.UnderlineSingle) - attrstr.AppendUnattributed(", ") - - attrstr.AppendUnattributed("and ") - appendWithAttributes("underline color", - ui.UnderlineDouble, - ui.UnderlineColorCustom{1.0, 0.0, 0.5, 1.0}) - attrstr.AppendUnattributed(". ") - - attrstr.AppendUnattributed("Furthermore, there are attributes allowing for ") - appendWithAttributes("special underlines for indicating spelling errors", - ui.UnderlineSuggestion, - ui.UnderlineColorSpelling) - attrstr.AppendUnattributed(" (and other types of errors) ") - - attrstr.AppendUnattributed("and control over OpenType features such as ligatures (for instance, ") - appendWithAttributes("afford", ui.OpenTypeFeatures{ - ui.ToOpenTypeTag('l', 'i', 'g', 'a'): 0, - }) - attrstr.AppendUnattributed(" vs. ") - appendWithAttributes("afford", ui.OpenTypeFeatures{ - ui.ToOpenTypeTag('l', 'i', 'g', 'a'): 1, - }) - attrstr.AppendUnattributed(").\n") - - attrstr.AppendUnattributed("Use the controls opposite to the text to control properties of the text.") -} - -type areaHandler struct{} - -func (areaHandler) Draw(a *ui.Area, p *ui.AreaDrawParams) { - tl := ui.DrawNewTextLayout(&ui.DrawTextLayoutParams{ - String: attrstr, - DefaultFont: fontButton.Font(), - Width: p.AreaWidth, - Align: ui.DrawTextAlign(alignment.Selected()), - }) - defer tl.Free() - p.Context.Text(tl, 0, 0) -} - -func (areaHandler) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) { - // do nothing -} - -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() { - makeAttributedString() - - mainwin := ui.NewWindow("libui Text-Drawing 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) - - area := ui.NewArea(areaHandler{}) - - fontButton = ui.NewFontButton() - fontButton.OnChanged(func(*ui.FontButton) { - area.QueueRedrawAll() - }) - vbox.Append(fontButton, false) - - form := ui.NewForm() - form.SetPadded(true) - // TODO on OS X if this is set to 1 then the window can't resize; does the form not have the concept of stretchy trailing space? - vbox.Append(form, false) - - alignment = ui.NewCombobox() - // note that the items match with the values of the uiDrawTextAlign values - alignment.Append("Left") - alignment.Append("Center") - alignment.Append("Right") - alignment.SetSelected(0) // start with left alignment - alignment.OnSelected(func(*ui.Combobox) { - area.QueueRedrawAll() - }) - form.Append("Alignment", alignment, false) - - hbox.Append(area, true) - - mainwin.Show() -} - -func main() { - ui.Main(setupUI) -} diff --git a/BBB_GOFILES/zz_histogram.go b/BBB_GOFILES/zz_histogram.go deleted file mode 100644 index eb0c8c4..0000000 --- a/BBB_GOFILES/zz_histogram.go +++ /dev/null @@ -1,253 +0,0 @@ -// 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.DrawBrushTypeSolid - 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.DrawFillModeWinding) - - 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.DrawFillModeWinding) - 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.DrawFillModeWinding) - 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.DrawBrushTypeSolid - 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.DrawFillModeWinding) - 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) -} diff --git a/draw.go b/draw.go index 59f8e5d..4e02e65 100644 --- a/draw.go +++ b/draw.go @@ -190,7 +190,7 @@ const ( ) // TODO document -const DefaultMiterLimit = 10.0 +const DrawDefaultMiterLimit = 10.0 // TODO type DrawBrush struct { diff --git a/zz_controls.go b/zz_controls.go new file mode 100644 index 0000000..d77bebe --- /dev/null +++ b/zz_controls.go @@ -0,0 +1,222 @@ +// 12 august 2018 + +// +build OMIT + +package main + +import ( + "github.com/andlabs/ui" +) + +var mainwin *ui.Window + +func makeBasicControlsPage() ui.Control { + vbox := ui.NewVerticalBox() + vbox.SetPadded(true) + + hbox := ui.NewHorizontalBox() + hbox.SetPadded(true) + vbox.Append(hbox, false) + + hbox.Append(ui.NewButton("Button"), false) + hbox.Append(ui.NewCheckbox("Checkbox"), false) + + vbox.Append(ui.NewLabel("This is a label. Right now, labels can only span one line."), false) + + vbox.Append(ui.NewHorizontalSeparator(), false) + + group := ui.NewGroup("Entries") + group.SetMargined(true) + vbox.Append(group, true) + +group.SetChild(ui.NewNonWrappingMultilineEntry()) + + entryForm := ui.NewForm() + entryForm.SetPadded(true) + group.SetChild(entryForm) + + entryForm.Append("Entry", ui.NewEntry(), false) + entryForm.Append("Password Entry", ui.NewPasswordEntry(), false) + entryForm.Append("Search Entry", ui.NewSearchEntry(), false) + entryForm.Append("Multiline Entry", ui.NewMultilineEntry(), true) + entryForm.Append("Multiline Entry No Wrap", ui.NewNonWrappingMultilineEntry(), true) + + return vbox +} + +func makeNumbersPage() ui.Control { + hbox := ui.NewHorizontalBox() + hbox.SetPadded(true) + + group := ui.NewGroup("Numbers") + group.SetMargined(true) + hbox.Append(group, true) + + vbox := ui.NewVerticalBox() + vbox.SetPadded(true) + group.SetChild(vbox) + + spinbox := ui.NewSpinbox(0, 100) + slider := ui.NewSlider(0, 100) + pbar := ui.NewProgressBar() + spinbox.OnChanged(func(*ui.Spinbox) { + slider.SetValue(spinbox.Value()) + pbar.SetValue(spinbox.Value()) + }) + slider.OnChanged(func(*ui.Slider) { + spinbox.SetValue(slider.Value()) + pbar.SetValue(slider.Value()) + }) + vbox.Append(spinbox, false) + vbox.Append(slider, false) + vbox.Append(pbar, false) + + ip := ui.NewProgressBar() + ip.SetValue(-1) + vbox.Append(ip, false) + + group = ui.NewGroup("Lists") + group.SetMargined(true) + hbox.Append(group, true) + + vbox = ui.NewVerticalBox() + vbox.SetPadded(true) + group.SetChild(vbox) + + cbox := ui.NewCombobox() + cbox.Append("Combobox Item 1") + cbox.Append("Combobox Item 2") + cbox.Append("Combobox Item 3") + vbox.Append(cbox, false) + + ecbox := ui.NewEditableCombobox() + ecbox.Append("Editable Item 1") + ecbox.Append("Editable Item 2") + ecbox.Append("Editable Item 3") + vbox.Append(ecbox, false) + + rb := ui.NewRadioButtons() + rb.Append("Radio Button 1") + rb.Append("Radio Button 2") + rb.Append("Radio Button 3") + vbox.Append(rb, false) + + return hbox +} + +func makeDataChoosersPage() ui.Control { + hbox := ui.NewHorizontalBox() + hbox.SetPadded(true) + + vbox := ui.NewVerticalBox() + vbox.SetPadded(true) + hbox.Append(vbox, false) + + vbox.Append(ui.NewDatePicker(), false) + vbox.Append(ui.NewTimePicker(), false) + vbox.Append(ui.NewDateTimePicker(), false) + vbox.Append(ui.NewFontButton(), false) + vbox.Append(ui.NewColorButton(), false) + + hbox.Append(ui.NewVerticalSeparator(), false) + + vbox = ui.NewVerticalBox() + vbox.SetPadded(true) + hbox.Append(vbox, true) + + grid := ui.NewGrid() + grid.SetPadded(true) + vbox.Append(grid, false) + + button := ui.NewButton("Open File") + entry := ui.NewEntry() + entry.SetReadOnly(true) + button.OnClicked(func(*ui.Button) { + filename := ui.OpenFile(mainwin) + if filename == "" { + filename = "(cancelled)" + } + entry.SetText(filename) + }) + grid.Append(button, + 0, 0, 1, 1, + false, ui.AlignFill, false, ui.AlignFill) + grid.Append(entry, + 1, 0, 1, 1, + true, ui.AlignFill, false, ui.AlignFill) + + button = ui.NewButton("Save File") + entry2 := ui.NewEntry() + entry2.SetReadOnly(true) + button.OnClicked(func(*ui.Button) { + filename := ui.SaveFile(mainwin) + if filename == "" { + filename = "(cancelled)" + } + entry2.SetText(filename) + }) + grid.Append(button, + 0, 1, 1, 1, + false, ui.AlignFill, false, ui.AlignFill) + grid.Append(entry2, + 1, 1, 1, 1, + true, ui.AlignFill, false, ui.AlignFill) + + msggrid := ui.NewGrid() + msggrid.SetPadded(true) + grid.Append(msggrid, + 0, 2, 2, 1, + false, ui.AlignCenter, false, ui.AlignStart) + + button = ui.NewButton("Message Box") + button.OnClicked(func(*ui.Button) { + ui.MsgBox(mainwin, + "This is a normal message box.", + "More detailed information can be shown here.") + }) + msggrid.Append(button, + 0, 0, 1, 1, + false, ui.AlignFill, false, ui.AlignFill) + button = ui.NewButton("Error Box") + button.OnClicked(func(*ui.Button) { + ui.MsgBoxError(mainwin, + "This message box describes an error.", + "More detailed information can be shown here.") + }) + msggrid.Append(button, + 1, 0, 1, 1, + false, ui.AlignFill, false, ui.AlignFill) + + return hbox +} + +func setupUI() { + mainwin = ui.NewWindow("libui Control Gallery", 640, 480, true) + mainwin.OnClosing(func(*ui.Window) bool { + ui.Quit() + return true + }) + ui.OnShouldQuit(func() bool { + mainwin.Destroy() + return true + }) + + tab := ui.NewTab() + mainwin.SetChild(tab) + mainwin.SetMargined(true) + + tab.Append("Basic Controls", makeBasicControlsPage()) + tab.SetMargined(0, true) + + tab.Append("Numbers and Lists", makeNumbersPage()) + tab.SetMargined(1, true) + + tab.Append("Data Choosers", makeDataChoosersPage()) + tab.SetMargined(2, true) + + mainwin.Show() +} + +func main() { + ui.Main(setupUI) +} diff --git a/zz_drawtext.go b/zz_drawtext.go new file mode 100644 index 0000000..a32b14b --- /dev/null +++ b/zz_drawtext.go @@ -0,0 +1,167 @@ +// 19 august 2018 + +// +build OMIT + +package main + +// TODO probably a bug in libui: changing the font away from skia leads to a crash + +import ( + "github.com/andlabs/ui" +) + +var ( + fontButton *ui.FontButton + alignment *ui.Combobox + + attrstr *ui.AttributedString +) + +func appendWithAttributes(what string, attrs ...ui.Attribute) { + start := len(attrstr.String()) + end := start + len(what) + attrstr.AppendUnattributed(what) + for _, a := range attrs { + attrstr.SetAttribute(a, start, end) + } +} + +func makeAttributedString() { + attrstr = ui.NewAttributedString( + "Drawing strings with package ui is done with the ui.AttributedString and ui.DrawTextLayout objects.\n" + + "ui.AttributedString lets you have a variety of attributes: ") + + appendWithAttributes("font family", ui.TextFamily("Courier New")) + attrstr.AppendUnattributed(", ") + + appendWithAttributes("font size", ui.TextSize(18)) + attrstr.AppendUnattributed(", ") + + appendWithAttributes("font weight", ui.TextWeightBold) + attrstr.AppendUnattributed(", ") + + appendWithAttributes("font italicness", ui.TextItalicItalic) + attrstr.AppendUnattributed(", ") + + appendWithAttributes("font stretch", ui.TextStretchCondensed) + attrstr.AppendUnattributed(", ") + + appendWithAttributes("text color", ui.TextColor{0.75, 0.25, 0.5, 0.75}) + attrstr.AppendUnattributed(", ") + + appendWithAttributes("text background color", ui.TextBackground{0.5, 0.5, 0.25, 0.5}) + attrstr.AppendUnattributed(", ") + + appendWithAttributes("underline style", ui.UnderlineSingle) + attrstr.AppendUnattributed(", ") + + attrstr.AppendUnattributed("and ") + appendWithAttributes("underline color", + ui.UnderlineDouble, + ui.UnderlineColorCustom{1.0, 0.0, 0.5, 1.0}) + attrstr.AppendUnattributed(". ") + + attrstr.AppendUnattributed("Furthermore, there are attributes allowing for ") + appendWithAttributes("special underlines for indicating spelling errors", + ui.UnderlineSuggestion, + ui.UnderlineColorSpelling) + attrstr.AppendUnattributed(" (and other types of errors) ") + + attrstr.AppendUnattributed("and control over OpenType features such as ligatures (for instance, ") + appendWithAttributes("afford", ui.OpenTypeFeatures{ + ui.ToOpenTypeTag('l', 'i', 'g', 'a'): 0, + }) + attrstr.AppendUnattributed(" vs. ") + appendWithAttributes("afford", ui.OpenTypeFeatures{ + ui.ToOpenTypeTag('l', 'i', 'g', 'a'): 1, + }) + attrstr.AppendUnattributed(").\n") + + attrstr.AppendUnattributed("Use the controls opposite to the text to control properties of the text.") +} + +type areaHandler struct{} + +func (areaHandler) Draw(a *ui.Area, p *ui.AreaDrawParams) { + tl := ui.DrawNewTextLayout(&ui.DrawTextLayoutParams{ + String: attrstr, + DefaultFont: fontButton.Font(), + Width: p.AreaWidth, + Align: ui.DrawTextAlign(alignment.Selected()), + }) + defer tl.Free() + p.Context.Text(tl, 0, 0) +} + +func (areaHandler) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) { + // do nothing +} + +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() { + makeAttributedString() + + mainwin := ui.NewWindow("libui Text-Drawing 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) + + area := ui.NewArea(areaHandler{}) + + fontButton = ui.NewFontButton() + fontButton.OnChanged(func(*ui.FontButton) { + area.QueueRedrawAll() + }) + vbox.Append(fontButton, false) + + form := ui.NewForm() + form.SetPadded(true) + // TODO on OS X if this is set to 1 then the window can't resize; does the form not have the concept of stretchy trailing space? + vbox.Append(form, false) + + alignment = ui.NewCombobox() + // note that the items match with the values of the uiDrawTextAlign values + alignment.Append("Left") + alignment.Append("Center") + alignment.Append("Right") + alignment.SetSelected(0) // start with left alignment + alignment.OnSelected(func(*ui.Combobox) { + area.QueueRedrawAll() + }) + form.Append("Alignment", alignment, false) + + hbox.Append(area, true) + + mainwin.Show() +} + +func main() { + ui.Main(setupUI) +} diff --git a/zz_histogram.go b/zz_histogram.go new file mode 100644 index 0000000..610d65a --- /dev/null +++ b/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.DrawBrush { + brush := new(ui.DrawBrush) + brush.Type = ui.DrawBrushTypeSolid + 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.DrawPath { + xs, ys := pointLocations(width, height) + path := ui.DrawNewPath(ui.DrawFillModeWinding) + + 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.DrawNewPath(ui.DrawFillModeWinding) + 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.DrawStrokeParams{ + Cap: ui.DrawLineCapFlat, + Join: ui.DrawLineJoinMiter, + Thickness: 2, + MiterLimit: ui.DrawDefaultMiterLimit, + } + + // draw the axes + brush = mkSolidBrush(colorBlack, 1.0) + path = ui.DrawNewPath(ui.DrawFillModeWinding) + 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.DrawNewMatrix() + 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.DrawBrushTypeSolid + 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.DrawNewPath(ui.DrawFillModeWinding) + 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) +} -- cgit v1.2.3