diff --git a/Canvas.go b/Canvas.go index b329291b..e4590628 100644 --- a/Canvas.go +++ b/Canvas.go @@ -75,7 +75,7 @@ func (c *Canvas) AddRectFilled(pMin, pMax image.Point, col color.Color, rounding // AddText draws text. func (c *Canvas) AddText(pos image.Point, col color.Color, text string) { - c.drawlist.AddText(ToVec2(pos), ToVec4Color(col), Context.FontAtlas.tStr(text)) + c.drawlist.AddText(ToVec2(pos), ToVec4Color(col), Context.FontAtlas.RegisterString(text)) } // AddBezierCubic draws bezier cubic. diff --git a/ClickableWidgets.go b/ClickableWidgets.go index 0181b0ae..3ad11e08 100644 --- a/ClickableWidgets.go +++ b/ClickableWidgets.go @@ -63,7 +63,7 @@ func (b *ButtonWidget) Build() { defer imgui.EndDisabled() } - if imgui.ButtonV(Context.FontAtlas.tStr(b.id), imgui.Vec2{X: b.width, Y: b.height}) && b.onClick != nil { + if imgui.ButtonV(Context.FontAtlas.RegisterString(b.id), imgui.Vec2{X: b.width, Y: b.height}) && b.onClick != nil { b.onClick() } } @@ -135,7 +135,7 @@ func (b *SmallButtonWidget) OnClick(onClick func()) *SmallButtonWidget { // Build implements Widget interface. func (b *SmallButtonWidget) Build() { - if imgui.SmallButton(Context.FontAtlas.tStr(b.id)) && b.onClick != nil { + if imgui.SmallButton(Context.FontAtlas.RegisterString(b.id)) && b.onClick != nil { b.onClick() } } @@ -182,7 +182,7 @@ func (b *InvisibleButtonWidget) ID(id string) *InvisibleButtonWidget { // Build implements Widget interface. func (b *InvisibleButtonWidget) Build() { - if imgui.InvisibleButton(Context.FontAtlas.tStr(b.id), imgui.Vec2{X: b.width, Y: b.height}) && b.onClick != nil { + if imgui.InvisibleButton(Context.FontAtlas.RegisterString(b.id), imgui.Vec2{X: b.width, Y: b.height}) && b.onClick != nil { b.onClick() } } @@ -371,7 +371,7 @@ func (c *CheckboxWidget) OnChange(onChange func()) *CheckboxWidget { // Build implements Widget interface. func (c *CheckboxWidget) Build() { - if imgui.Checkbox(Context.FontAtlas.tStr(c.text), c.selected) && c.onChange != nil { + if imgui.Checkbox(Context.FontAtlas.RegisterString(c.text), c.selected) && c.onChange != nil { c.onChange() } } @@ -404,7 +404,7 @@ func (r *RadioButtonWidget) OnChange(onChange func()) *RadioButtonWidget { // Build implements Widget interface. func (r *RadioButtonWidget) Build() { - if imgui.RadioButton(Context.FontAtlas.tStr(r.text), r.active) && r.onChange != nil { + if imgui.RadioButton(Context.FontAtlas.RegisterString(r.text), r.active) && r.onChange != nil { r.onChange() } } @@ -479,7 +479,7 @@ func (s *SelectableWidget) Build() { s.flags |= SelectableFlagsAllowDoubleClick } - if imgui.SelectableV(Context.FontAtlas.tStr(s.label), s.selected, int(s.flags), imgui.Vec2{X: s.width, Y: s.height}) && s.onClick != nil { + if imgui.SelectableV(Context.FontAtlas.RegisterString(s.label), s.selected, int(s.flags), imgui.Vec2{X: s.width, Y: s.height}) && s.onClick != nil { s.onClick() } @@ -503,7 +503,7 @@ type TreeNodeWidget struct { // TreeNode creates a new tree node widget. func TreeNode(label string) *TreeNodeWidget { return &TreeNodeWidget{ - label: Context.FontAtlas.tStr(label), + label: Context.FontAtlas.RegisterString(label), flags: 0, layout: nil, eventHandler: nil, diff --git a/CodeEditor.go b/CodeEditor.go index 5f2cdc61..426e8cfd 100644 --- a/CodeEditor.go +++ b/CodeEditor.go @@ -197,7 +197,7 @@ func (ce *CodeEditorWidget) Build() { s := ce.getState() // register text in font atlas - Context.FontAtlas.tStr(s.editor.GetText()) + Context.FontAtlas.RegisterString(s.editor.GetText()) // build editor s.editor.Render(ce.title, imgui.Vec2{X: ce.width, Y: ce.height}, ce.border) diff --git a/ExtraWidgets.go b/ExtraWidgets.go index 524ed6a7..8dddd302 100644 --- a/ExtraWidgets.go +++ b/ExtraWidgets.go @@ -192,10 +192,10 @@ func (ttr *TreeTableRowWidget) BuildTreeTableRow() { open := false if len(ttr.children) > 0 { - open = imgui.TreeNodeV(Context.FontAtlas.tStr(ttr.label), int(ttr.flags)) + open = imgui.TreeNodeV(Context.FontAtlas.RegisterString(ttr.label), int(ttr.flags)) } else { ttr.flags |= TreeNodeFlagsLeaf | TreeNodeFlagsNoTreePushOnOpen - imgui.TreeNodeV(Context.FontAtlas.tStr(ttr.label), int(ttr.flags)) + imgui.TreeNodeV(Context.FontAtlas.RegisterString(ttr.label), int(ttr.flags)) } for _, w := range ttr.layout { @@ -571,7 +571,7 @@ func (d *DatePickerWidget) Build() { const yearButtonSize = 25 Row( - Label(Context.FontAtlas.tStr(" Year")), + Label(Context.FontAtlas.RegisterString(" Year")), Labelf("%14d", d.date.Year()), Button("-##"+d.id+"year").OnClick(func() { *d.date = d.date.AddDate(-1, 0, 0) diff --git a/FontAtlasProsessor.go b/FontAtlasProsessor.go index 241b40ce..d009d160 100644 --- a/FontAtlasProsessor.go +++ b/FontAtlasProsessor.go @@ -14,7 +14,6 @@ import ( const ( preRegisterString = " \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" windows = "windows" - defaultFontSize = 14 ) // FontInfo represents a giu implementation of imgui font. @@ -61,7 +60,7 @@ func newFontAtlas() FontAtlas { } // Pre register numbers - result.tStr(preRegisterString) + result.RegisterString(preRegisterString) // Pre-register fonts switch runtime.GOOS { @@ -193,9 +192,9 @@ func (a *FontAtlas) registerDefaultFonts(fontInfos []FontInfo) { } } -// Register string to font atlas builder. +// RegisterString register string to font atlas builder. // Note only register strings that will be displayed on the UI. -func (a *FontAtlas) tStr(str string) string { +func (a *FontAtlas) RegisterString(str string) string { for _, s := range str { if _, ok := a.stringMap.Load(s); !ok { a.stringMap.Store(s, false) @@ -206,16 +205,17 @@ func (a *FontAtlas) tStr(str string) string { return str } -// Register string pointer to font atlas builder. +// RegisterStringPointer registers string pointer to font atlas builder. // Note only register strings that will be displayed on the UI. -func (a *FontAtlas) tStrPtr(str *string) *string { - a.tStr(*str) +func (a *FontAtlas) RegisterStringPointer(str *string) *string { + a.RegisterString(*str) return str } -func (a *FontAtlas) tStrSlice(str []string) []string { +// RegisterStringSlice calls RegisterString for each slice element +func (a *FontAtlas) RegisterStringSlice(str []string) []string { for _, s := range str { - a.tStr(s) + a.RegisterString(s) } return str diff --git a/ImageWidgets.go b/ImageWidgets.go index e411a1d2..11453011 100644 --- a/ImageWidgets.go +++ b/ImageWidgets.go @@ -21,7 +21,7 @@ type ImageWidget struct { texture *Texture width float32 height float32 - uv0, uv1 image.Point + uv0, uv1 imgui.Vec2 tintColor, borderColor color.Color onClick func() } @@ -32,16 +32,16 @@ func Image(texture *Texture) *ImageWidget { texture: texture, width: 100, height: 100, - uv0: image.Point{X: 0, Y: 0}, - uv1: image.Point{X: 1, Y: 1}, + uv0: imgui.Vec2{X: 0, Y: 0}, + uv1: imgui.Vec2{X: 1, Y: 1}, tintColor: color.RGBA{255, 255, 255, 255}, borderColor: color.RGBA{0, 0, 0, 0}, } } // Uv allows to specify uv parameters. -func (i *ImageWidget) Uv(uv0, uv1 image.Point) *ImageWidget { - i.uv0, i.uv1 = uv0, uv1 +func (i *ImageWidget) Uv(uv0X, uv0Y, uv1X, uv1Y float32) *ImageWidget { + i.uv0.X, i.uv0.Y, i.uv1.X, i.uv1.Y = uv0X, uv0Y, uv1X, uv1Y return i } @@ -88,7 +88,7 @@ func (i *ImageWidget) Build() { } // trick: detect click event - if i.onClick != nil && IsMouseClicked(MouseButtonLeft) { + if i.onClick != nil && IsMouseClicked(MouseButtonLeft) && IsWindowFocused(0) { cursorPos := GetCursorScreenPos() mousePos := GetMousePos() mousePos.Add(cursorPos) @@ -98,7 +98,7 @@ func (i *ImageWidget) Build() { } } - imgui.ImageV(i.texture.id, size, ToVec2(i.uv0), ToVec2(i.uv1), ToVec4Color(i.tintColor), ToVec4Color(i.borderColor)) + imgui.ImageV(i.texture.id, size, i.uv0, i.uv1, ToVec4Color(i.tintColor), ToVec4Color(i.borderColor)) } type imageState struct { @@ -138,6 +138,12 @@ func ImageWithRgba(rgba image.Image) *ImageWithRgbaWidget { } } +// ID sets the interval id of ImageWithRgba widgets. +func (i *ImageWithRgbaWidget) ID(id string) *ImageWithRgbaWidget { + i.id = id + return i +} + // Size sets image's size. func (i *ImageWithRgbaWidget) Size(width, height float32) *ImageWithRgbaWidget { i.img.Size(width, height) @@ -195,6 +201,12 @@ func ImageWithFile(imgPath string) *ImageWithFileWidget { } } +// ID sets the interval id of ImageWithFile widgets. +func (i *ImageWithFileWidget) ID(id string) *ImageWithFileWidget { + i.id = id + return i +} + // Size sets image's size. func (i *ImageWithFileWidget) Size(width, height float32) *ImageWithFileWidget { i.img.Size(width, height) diff --git a/InputHandler.go b/InputHandler.go index f951f773..c9172971 100644 --- a/InputHandler.go +++ b/InputHandler.go @@ -29,6 +29,8 @@ const ( LocalShortcut ShortcutType = false ) +type InputHandlerHandleCallback func(Key, Modifier, Action) + // InputHandler is an interface which needs to be implemented // by user-definied input handlers. type InputHandler interface { @@ -37,7 +39,7 @@ type InputHandler interface { // UnregisterKeyboardShortcuts removes iwndow shourtcuts from input handler UnregisterWindowShortcuts() // Handle handles a shortcut - Handle(Key, Modifier) + Handle(Key, Modifier, Action) } // --- Default implementation of giu input manager --- @@ -79,7 +81,11 @@ func (i *inputHandler) UnregisterWindowShortcuts() { } } -func (i *inputHandler) Handle(key Key, mod Modifier) { +func (i *inputHandler) Handle(key Key, mod Modifier, a Action) { + if a != Press { + return + } + for combo, cb := range i.shortcuts { if combo.key != key || combo.modifier != mod { continue diff --git a/InputHandler_test.go b/InputHandler_test.go index 544aedd9..87561cb3 100644 --- a/InputHandler_test.go +++ b/InputHandler_test.go @@ -86,13 +86,13 @@ func Test_InputHandler_Handle(t *testing.T) { i.RegisterKeyboardShortcuts(sh...) - i.Handle(Key(0), Modifier(0)) + i.Handle(Key(0), Modifier(0), Press) a.False(shortcut1, "Shortcut 1 was handled, but shouldn't.") a.False(shortcut2, "Shortcut 2 was handled, but shouldn't.") - i.Handle(Key(5), Modifier(0)) + i.Handle(Key(5), Modifier(0), Press) a.True(shortcut1, "Shortcut 1 was not handled, but shouldn be.") a.False(shortcut2, "Shortcut 2 was handled, but shouldn't.") - i.Handle(Key(8), Modifier(2)) + i.Handle(Key(8), Modifier(2), Press) a.True(shortcut1, "Shortcut 1 was not handled, but shouldn be.") a.True(shortcut2, "Shortcut 2 was not handled, but shouldn be.") } diff --git a/Keycode.go b/Keycode.go index e54a125c..a861814f 100644 --- a/Keycode.go +++ b/Keycode.go @@ -146,3 +146,11 @@ const ( ModCapsLock Modifier = Modifier(glfw.ModCapsLock) ModNumLock Modifier = Modifier(glfw.ModNumLock) ) + +type Action glfw.Action + +const ( + Release Action = Action(glfw.Release) + Press Action = Action(glfw.Press) + Repeat Action = Action(glfw.Repeat) +) diff --git a/Markdown.go b/Markdown.go index 71b80994..d14eb4ea 100644 --- a/Markdown.go +++ b/Markdown.go @@ -59,7 +59,7 @@ func (m *MarkdownWidget) Header(level int, font *FontInfo, separator bool) *Mark // Build implements Widget interface. func (m *MarkdownWidget) Build() { - imgui.Markdown(Context.FontAtlas.tStrPtr(m.md), m.linkCb, loadImage, m.headers) + imgui.Markdown(Context.FontAtlas.RegisterStringPointer(m.md), m.linkCb, loadImage, m.headers) } func loadImage(path string) imgui.MarkdownImageData { diff --git a/MasterWindow.go b/MasterWindow.go index ae7a8fbf..2c621c1c 100644 --- a/MasterWindow.go +++ b/MasterWindow.go @@ -44,6 +44,10 @@ type MasterWindow struct { context *imgui.Context io *imgui.IO updateFunc func() + + // possibility to expend InputHandler's stuff + // See SetAdditionalInputHandler + additionalInputCallback InputHandlerHandleCallback } // NewMasterWindow creates a new master window and initializes GLFW. @@ -376,8 +380,16 @@ func (w *MasterWindow) SetShouldClose(v bool) { func (w *MasterWindow) SetInputHandler(handler InputHandler) { Context.InputHandler = handler w.platform.SetInputCallback(func(key glfw.Key, modifier glfw.ModifierKey, action glfw.Action) { - if action == glfw.Press { - handler.Handle(Key(key), Modifier(modifier)) + k, m, a := Key(key), Modifier(modifier), Action(action) + handler.Handle(k, m, a) + if w.additionalInputCallback != nil { + w.additionalInputCallback(k, m, a) } }) } + +// SetAdditionalInputHandlerCallback allows to set an input callback to handle more events (not only these from giu.inputHandler). +// See examples/issue-501. +func (w *MasterWindow) SetAdditionalInputHandlerCallback(cb InputHandlerHandleCallback) { + w.additionalInputCallback = cb +} diff --git a/Plot.go b/Plot.go index 9cffd484..125eebc1 100644 --- a/Plot.go +++ b/Plot.go @@ -176,11 +176,11 @@ func (p *PlotCanvasWidget) Build() { } if imgui.ImPlotBegin( - Context.FontAtlas.tStr(p.title), Context.FontAtlas.tStr(p.xLabel), - Context.FontAtlas.tStr(p.yLabel), ToVec2(image.Pt(p.width, p.height)), + Context.FontAtlas.RegisterString(p.title), Context.FontAtlas.RegisterString(p.xLabel), + Context.FontAtlas.RegisterString(p.yLabel), ToVec2(image.Pt(p.width, p.height)), imgui.ImPlotFlags(p.flags), imgui.ImPlotAxisFlags(p.xFlags), imgui.ImPlotAxisFlags(p.yFlags), imgui.ImPlotAxisFlags(p.y2Flags), - imgui.ImPlotAxisFlags(p.y3Flags), Context.FontAtlas.tStr(p.y2Label), Context.FontAtlas.tStr(p.y3Label), + imgui.ImPlotAxisFlags(p.y3Flags), Context.FontAtlas.RegisterString(p.y2Label), Context.FontAtlas.RegisterString(p.y3Label), ) { for _, plot := range p.plots { plot.Plot() @@ -273,7 +273,7 @@ func (p *PlotBarHWidget) Offset(offset int) *PlotBarHWidget { // Plot implements plot interface. func (p *PlotBarHWidget) Plot() { - imgui.ImPlotBarsH(Context.FontAtlas.tStr(p.title), p.data, p.height, p.shift, p.offset) + imgui.ImPlotBarsH(Context.FontAtlas.RegisterString(p.title), p.data, p.height, p.shift, p.offset) } // PlotLineWidget represents a plot line (linear chart). @@ -323,7 +323,7 @@ func (p *PlotLineWidget) Offset(offset int) *PlotLineWidget { // Plot implements Plot interface. func (p *PlotLineWidget) Plot() { imgui.ImPlotSetPlotYAxis(imgui.ImPlotYAxis(p.yAxis)) - imgui.ImPlotLine(Context.FontAtlas.tStr(p.title), p.values, p.xScale, p.x0, p.offset) + imgui.ImPlotLine(Context.FontAtlas.RegisterString(p.title), p.values, p.xScale, p.x0, p.offset) } // PlotLineXYWidget adds XY plot line. @@ -359,7 +359,7 @@ func (p *PlotLineXYWidget) Offset(offset int) *PlotLineXYWidget { // Plot implements Plot interface. func (p *PlotLineXYWidget) Plot() { imgui.ImPlotSetPlotYAxis(imgui.ImPlotYAxis(p.yAxis)) - imgui.ImPlotLineXY(Context.FontAtlas.tStr(p.title), p.xs, p.ys, p.offset) + imgui.ImPlotLineXY(Context.FontAtlas.RegisterString(p.title), p.xs, p.ys, p.offset) } // PlotPieChartWidget represents a pie chart. @@ -392,8 +392,8 @@ func (p *PlotPieChartWidget) Normalize(n bool) *PlotPieChartWidget { } // LabelFormat sets format of labels. -func (p *PlotPieChartWidget) LabelFormat(fmtStr string) *PlotPieChartWidget { - p.labelFormat = fmtStr +func (p *PlotPieChartWidget) LabelFormat(fmContext.FontAtlas.RegisterString string) *PlotPieChartWidget { + p.labelFormat = fmContext.FontAtlas.RegisterString return p } @@ -403,7 +403,7 @@ func (p *PlotPieChartWidget) Angle0(a float64) *PlotPieChartWidget { } func (p *PlotPieChartWidget) Plot() { - imgui.ImPlotPieChart(Context.FontAtlas.tStrSlice(p.labels), p.values, p.x, p.y, p.radius, p.normalize, p.labelFormat, p.angle0) + imgui.ImPlotPieChart(Context.FontAtlas.RegisterStringSlice(p.labels), p.values, p.x, p.y, p.radius, p.normalize, p.labelFormat, p.angle0) } type PlotScatterWidget struct { @@ -439,7 +439,7 @@ func (p *PlotScatterWidget) Offset(offset int) *PlotScatterWidget { } func (p *PlotScatterWidget) Plot() { - imgui.ImPlotScatter(Context.FontAtlas.tStr(p.label), p.values, p.xscale, p.x0, p.offset) + imgui.ImPlotScatter(Context.FontAtlas.RegisterString(p.label), p.values, p.xscale, p.x0, p.offset) } type PlotScatterXYWidget struct { @@ -463,5 +463,5 @@ func (p *PlotScatterXYWidget) Offset(offset int) *PlotScatterXYWidget { } func (p *PlotScatterXYWidget) Plot() { - imgui.ImPlotScatterXY(Context.FontAtlas.tStr(p.label), p.xs, p.ys, p.offset) + imgui.ImPlotScatterXY(Context.FontAtlas.RegisterString(p.label), p.xs, p.ys, p.offset) } diff --git a/Popups.go b/Popups.go index b74c7b1f..7fa25dcb 100644 --- a/Popups.go +++ b/Popups.go @@ -29,7 +29,7 @@ type PopupWidget struct { // Popup creates new popup widget. func Popup(name string) *PopupWidget { return &PopupWidget{ - name: Context.FontAtlas.tStr(name), + name: Context.FontAtlas.RegisterString(name), flags: 0, layout: nil, } @@ -69,7 +69,7 @@ type PopupModalWidget struct { // PopupModal creates new popup modal widget. func PopupModal(name string) *PopupModalWidget { return &PopupModalWidget{ - name: Context.FontAtlas.tStr(name), + name: Context.FontAtlas.RegisterString(name), open: nil, flags: WindowFlagsNoResize, layout: nil, diff --git a/ProgressIndicator.go b/ProgressIndicator.go index db9b63d5..28128f18 100644 --- a/ProgressIndicator.go +++ b/ProgressIndicator.go @@ -95,7 +95,7 @@ func (p *ProgressIndicatorWidget) Build() { // Draw text if len(p.label) > 0 { - labelWidth, _ := CalcTextSize(Context.FontAtlas.tStr(p.label)) + labelWidth, _ := CalcTextSize(Context.FontAtlas.RegisterString(p.label)) labelPos := centerPt.Add(image.Pt(-1*int(labelWidth/2), int(p.radius+p.radius/5+8))) canvas.AddText(labelPos, rgba, p.label) } diff --git a/README.md b/README.md index 5e0eadcf..1461351e 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ brew install mingw-w64 on Linux: ```sh -sudo dnf install mingw64-gcc mingw64-gcc-c++ mingw-winpthreads-static +sudo dnf install mingw64-gcc mingw64-gcc-c++ mingw64-winpthreads-static ``` 2. Prepare and embed the application icon into the executable and build. diff --git a/SliderWidgets.go b/SliderWidgets.go index 24060076..e6ac798e 100644 --- a/SliderWidgets.go +++ b/SliderWidgets.go @@ -55,7 +55,7 @@ func (s *SliderIntWidget) OnChange(onChange func()) *SliderIntWidget { // Label sets slider label (id). func (s *SliderIntWidget) Label(label string) *SliderIntWidget { - s.label = Context.FontAtlas.tStr(label) + s.label = Context.FontAtlas.RegisterString(label) return s } @@ -71,7 +71,7 @@ func (s *SliderIntWidget) Build() { defer PopItemWidth() } - if imgui.SliderIntV(Context.FontAtlas.tStr(s.label), s.value, s.min, s.max, s.format) && s.onChange != nil { + if imgui.SliderIntV(Context.FontAtlas.RegisterString(s.label), s.value, s.min, s.max, s.format) && s.onChange != nil { s.onChange() } } @@ -131,7 +131,7 @@ func (vs *VSliderIntWidget) OnChange(onChange func()) *VSliderIntWidget { // Label sets slider's label (id). func (vs *VSliderIntWidget) Label(label string) *VSliderIntWidget { - vs.label = Context.FontAtlas.tStr(label) + vs.label = Context.FontAtlas.RegisterString(label) return vs } @@ -143,7 +143,7 @@ func (vs *VSliderIntWidget) Labelf(format string, args ...any) *VSliderIntWidget // Build implements Widget interface. func (vs *VSliderIntWidget) Build() { if imgui.VSliderIntV( - Context.FontAtlas.tStr(vs.label), + Context.FontAtlas.RegisterString(vs.label), imgui.Vec2{X: vs.width, Y: vs.height}, vs.value, vs.min, @@ -204,7 +204,7 @@ func (sf *SliderFloatWidget) Size(width float32) *SliderFloatWidget { // Label sets slider's label (id). func (sf *SliderFloatWidget) Label(label string) *SliderFloatWidget { - sf.label = Context.FontAtlas.tStr(label) + sf.label = Context.FontAtlas.RegisterString(label) return sf } @@ -220,7 +220,7 @@ func (sf *SliderFloatWidget) Build() { defer PopItemWidth() } - if imgui.SliderFloatV(Context.FontAtlas.tStr(sf.label), sf.value, sf.min, sf.max, sf.format, 1.0) && sf.onChange != nil { + if imgui.SliderFloatV(Context.FontAtlas.RegisterString(sf.label), sf.value, sf.min, sf.max, sf.format, 1.0) && sf.onChange != nil { sf.onChange() } } diff --git a/SplitLayout.go b/SplitLayout.go index 30969260..e74fedae 100644 --- a/SplitLayout.go +++ b/SplitLayout.go @@ -19,8 +19,7 @@ const ( var _ Disposable = &splitLayoutState{} type splitLayoutState struct { - delta float32 - sashPos float32 + delta float32 } // Dispose implements disposable interface. @@ -39,12 +38,12 @@ type SplitLayoutWidget struct { originItemSpacingY float32 originFramePaddingX float32 originFramePaddingY float32 - sashPos float32 + sashPos *float32 border bool } // SplitLayout creates split layout widget. -func SplitLayout(direction SplitDirection, sashPos float32, layout1, layout2 Widget) *SplitLayoutWidget { +func SplitLayout(direction SplitDirection, sashPos *float32, layout1, layout2 Widget) *SplitLayoutWidget { return &SplitLayoutWidget{ direction: direction, sashPos: sashPos, @@ -75,34 +74,34 @@ func (s *SplitLayoutWidget) Build() { var layout Layout - splitLayoutState.sashPos += splitLayoutState.delta - if splitLayoutState.sashPos < 1 { - splitLayoutState.sashPos = 1 + *s.sashPos += splitLayoutState.delta + if *s.sashPos < 1 { + *s.sashPos = 1 } switch s.direction { case DirectionHorizontal: - availableW, _ := GetAvailableRegion() - if splitLayoutState.sashPos >= availableW { - splitLayoutState.sashPos = availableW + _, availableH := GetAvailableRegion() + if *s.sashPos >= availableH { + *s.sashPos = availableH } layout = Layout{ - Row( - s.buildChild(splitLayoutState.sashPos, 0, s.layout1), - VSplitter(&(splitLayoutState.delta)).Size(s.originItemSpacingX, 0), + Column( + s.buildChild(Auto, *s.sashPos, s.layout1), + HSplitter(&(splitLayoutState.delta)).Size(0, s.originItemSpacingY), s.buildChild(Auto, Auto, s.layout2), ), } case DirectionVertical: - _, availableH := GetAvailableRegion() - if splitLayoutState.sashPos >= availableH { - splitLayoutState.sashPos = availableH + availableW, _ := GetAvailableRegion() + if *s.sashPos >= availableW { + *s.sashPos = availableW } layout = Layout{ - Column( - s.buildChild(Auto, splitLayoutState.sashPos, s.layout1), - HSplitter(&(splitLayoutState.delta)).Size(0, s.originItemSpacingY), + Row( + s.buildChild(*s.sashPos, 0, s.layout1), + VSplitter(&(splitLayoutState.delta)).Size(s.originItemSpacingX, 0), s.buildChild(Auto, Auto, s.layout2), ), } @@ -161,7 +160,7 @@ func (s *SplitLayoutWidget) buildChild(width, height float32, layout Widget) Wid func (s *SplitLayoutWidget) getState() (state *splitLayoutState) { if st := Context.GetState(s.id); st == nil { - state = &splitLayoutState{delta: 0.0, sashPos: s.sashPos} + state = &splitLayoutState{delta: 0.0} Context.SetState(s.id, state) } else { var isOk bool diff --git a/TableWidgets.go b/TableWidgets.go index 0a1a7ee5..ac18ff37 100644 --- a/TableWidgets.go +++ b/TableWidgets.go @@ -67,7 +67,7 @@ type TableColumnWidget struct { func TableColumn(label string) *TableColumnWidget { return &TableColumnWidget{ - label: Context.FontAtlas.tStr(label), + label: Context.FontAtlas.RegisterString(label), flags: 0, innerWidthOrWeight: 0, userID: 0, diff --git a/TextWidgets.go b/TextWidgets.go index b4ea6f17..c893d804 100644 --- a/TextWidgets.go +++ b/TextWidgets.go @@ -72,8 +72,8 @@ func (i *InputTextMultilineWidget) Size(width, height float32) *InputTextMultili // Build implements Widget interface. func (i *InputTextMultilineWidget) Build() { if imgui.InputTextMultilineV( - Context.FontAtlas.tStr(i.label), - Context.FontAtlas.tStrPtr(i.text), + Context.FontAtlas.RegisterString(i.label), + Context.FontAtlas.RegisterStringPtr(i.text), imgui.Vec2{ X: i.width, Y: i.height, @@ -111,7 +111,7 @@ type BulletTextWidget struct { // BulletText creates bulletTextWidget. func BulletText(text string) *BulletTextWidget { return &BulletTextWidget{ - text: Context.FontAtlas.tStr(text), + text: Context.FontAtlas.RegisterString(text), } } @@ -165,7 +165,7 @@ func InputText(value *string) *InputTextWidget { // Label adds label (alternatively you can use it to set widget's id). func (i *InputTextWidget) Label(label string) *InputTextWidget { - i.label = Context.FontAtlas.tStr(label) + i.label = Context.FontAtlas.RegisterString(label) return i } @@ -183,7 +183,7 @@ func (i *InputTextWidget) AutoComplete(candidates []string) *InputTextWidget { // Hint sets hint text. func (i *InputTextWidget) Hint(hint string) *InputTextWidget { - i.hint = Context.FontAtlas.tStr(hint) + i.hint = Context.FontAtlas.RegisterString(hint) return i } @@ -229,7 +229,7 @@ func (i *InputTextWidget) Build() { defer PopItemWidth() } - isChanged := imgui.InputTextWithHint(i.label, i.hint, Context.FontAtlas.tStrPtr(i.value), int(i.flags), i.cb) + isChanged := imgui.InputTextWithHint(i.label, i.hint, Context.FontAtlas.RegisterStringPtr(i.value), int(i.flags), i.cb) if isChanged && i.onChange != nil { i.onChange() @@ -295,7 +295,7 @@ func InputInt(value *int32) *InputIntWidget { // Label sets label (id). func (i *InputIntWidget) Label(label string) *InputIntWidget { - i.label = Context.FontAtlas.tStr(label) + i.label = Context.FontAtlas.RegisterString(label) return i } @@ -360,7 +360,7 @@ func InputFloat(value *float32) *InputFloatWidget { // Label sets label of input field. func (i *InputFloatWidget) Label(label string) *InputFloatWidget { - i.label = Context.FontAtlas.tStr(label) + i.label = Context.FontAtlas.RegisterString(label) return i } @@ -417,7 +417,7 @@ type LabelWidget struct { // Label constructs label widget. func Label(label string) *LabelWidget { return &LabelWidget{ - label: Context.FontAtlas.tStr(label), + label: Context.FontAtlas.RegisterString(label), wrapped: false, } } diff --git a/Texture.go b/Texture.go index 48dc6b64..b3ab2cc4 100644 --- a/Texture.go +++ b/Texture.go @@ -35,7 +35,6 @@ func EnqueueNewTextureFromRgba(rgba image.Image, loadCb func(t *Texture)) { // NewTextureFromRgba creates a new texture from image.Image and, when it is done, calls loadCallback(loadedTexture). func NewTextureFromRgba(rgba image.Image, loadCallback func(*Texture)) { - Assert(Context.isRunning, "", "NewTextureFromRgba", "cannot load texture befor (*MasterWindow).Run call!") loadTexture(rgba, loadCallback) } diff --git a/Widgets.go b/Widgets.go index 1434cf5f..54f5aa68 100644 --- a/Widgets.go +++ b/Widgets.go @@ -130,7 +130,7 @@ type ComboCustomWidget struct { func ComboCustom(label, previewValue string) *ComboCustomWidget { return &ComboCustomWidget{ label: GenAutoID(label), - previewValue: Context.FontAtlas.tStr(previewValue), + previewValue: Context.FontAtlas.RegisterString(previewValue), width: 0, flags: 0, layout: nil, @@ -162,7 +162,7 @@ func (cc *ComboCustomWidget) Build() { defer imgui.PopItemWidth() } - if imgui.BeginComboV(Context.FontAtlas.tStr(cc.label), cc.previewValue, int(cc.flags)) { + if imgui.BeginComboV(Context.FontAtlas.RegisterString(cc.label), cc.previewValue, int(cc.flags)) { cc.layout.Build() imgui.EndCombo() } @@ -186,8 +186,8 @@ type ComboWidget struct { func Combo(label, previewValue string, items []string, selected *int32) *ComboWidget { return &ComboWidget{ label: GenAutoID(label), - previewValue: Context.FontAtlas.tStr(previewValue), - items: Context.FontAtlas.tStrSlice(items), + previewValue: Context.FontAtlas.RegisterString(previewValue), + items: Context.FontAtlas.RegisterStringSlice(items), selected: selected, flags: 0, width: 0, @@ -202,7 +202,7 @@ func (c *ComboWidget) Build() { defer imgui.PopItemWidth() } - if imgui.BeginComboV(Context.FontAtlas.tStr(c.label), c.previewValue, int(c.flags)) { + if imgui.BeginComboV(Context.FontAtlas.RegisterString(c.label), c.previewValue, int(c.flags)) { for i, item := range c.items { if imgui.Selectable(item) { *c.selected = int32(i) @@ -307,7 +307,7 @@ func (d *DragIntWidget) Format(format string) *DragIntWidget { // Build implements Widget interface. func (d *DragIntWidget) Build() { - imgui.DragIntV(Context.FontAtlas.tStr(d.label), d.value, d.speed, d.min, d.max, d.format) + imgui.DragIntV(Context.FontAtlas.RegisterString(d.label), d.value, d.speed, d.min, d.max, d.format) } var _ Widget = &ColumnWidget{} @@ -422,7 +422,7 @@ func (m *MenuItemWidget) OnClick(onClick func()) *MenuItemWidget { // Build implements Widget interface. func (m *MenuItemWidget) Build() { - if imgui.MenuItemV(Context.FontAtlas.tStr(m.label), "", m.selected, m.enabled) && m.onClick != nil { + if imgui.MenuItemV(Context.FontAtlas.RegisterString(m.label), "", m.selected, m.enabled) && m.onClick != nil { m.onClick() } } @@ -459,7 +459,7 @@ func (m *MenuWidget) Layout(widgets ...Widget) *MenuWidget { // Build implements Widget interface. func (m *MenuWidget) Build() { - if imgui.BeginMenuV(Context.FontAtlas.tStr(m.label), m.enabled) { + if imgui.BeginMenuV(Context.FontAtlas.RegisterString(m.label), m.enabled) { m.layout.Build() imgui.EndMenu() } @@ -489,7 +489,7 @@ func (p *ProgressBarWidget) Size(width, height float32) *ProgressBarWidget { } func (p *ProgressBarWidget) Overlay(overlay string) *ProgressBarWidget { - p.overlay = Context.FontAtlas.tStr(overlay) + p.overlay = Context.FontAtlas.RegisterString(overlay) return p } @@ -553,7 +553,7 @@ type TabItemWidget struct { func TabItem(label string) *TabItemWidget { return &TabItemWidget{ - label: Context.FontAtlas.tStr(label), + label: Context.FontAtlas.RegisterString(label), open: nil, flags: 0, layout: nil, @@ -649,7 +649,7 @@ func (t *TooltipWidget) Build() { func Tooltip(tip string) *TooltipWidget { return &TooltipWidget{ - tip: Context.FontAtlas.tStr(tip), + tip: Context.FontAtlas.RegisterString(tip), layout: nil, } } @@ -724,7 +724,7 @@ func (ce *ColorEditWidget) Build() { } if imgui.ColorEdit4V( - Context.FontAtlas.tStr(ce.label), + Context.FontAtlas.RegisterString(ce.label), &col, int(ce.flags), ) { diff --git a/Window.go b/Window.go index c8c0cfdc..2b3a5748 100644 --- a/Window.go +++ b/Window.go @@ -134,7 +134,7 @@ func (w *WindowWidget) Layout(widgets ...Widget) { }), ) - showed := imgui.BeginV(Context.FontAtlas.tStr(w.title), w.open, int(w.flags)) + showed := imgui.BeginV(Context.FontAtlas.RegisterString(w.title), w.open, int(w.flags)) if showed { Layout(widgets).Build() diff --git a/examples/canvas/gopher.png b/examples/canvas/gopher.png index 2f1e3c42..e607ceac 100644 Binary files a/examples/canvas/gopher.png and b/examples/canvas/gopher.png differ diff --git a/examples/gifdecode/golang.gif b/examples/gifdecode/golang.gif index 23355aa1..a571f4aa 100644 Binary files a/examples/gifdecode/golang.gif and b/examples/gifdecode/golang.gif differ diff --git a/examples/imguidemo/screenshot.png b/examples/imguidemo/screenshot.png index eeee34d7..952c77c8 100644 Binary files a/examples/imguidemo/screenshot.png and b/examples/imguidemo/screenshot.png differ diff --git a/examples/issue-501/main.go b/examples/issue-501/main.go new file mode 100644 index 00000000..a9ff8412 --- /dev/null +++ b/examples/issue-501/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "github.com/AllenDang/giu" +) + +var ( + command string + shouldFocus bool +) + +func loop() { + giu.SingleWindow().Layout( + giu.Custom(func() { + if shouldFocus { + shouldFocus = false + giu.SetKeyboardFocusHere() + } + }), + giu.Row( + giu.InputText(&command).Size(200), + giu.Label("<- press any key to start typing here!"), + ), + ) +} + +func onAnyKeyPressed(key giu.Key, mod giu.Modifier, action giu.Action) { + if action == giu.Press { + shouldFocus = true + } +} + +func main() { + wnd := giu.NewMasterWindow("Handle any key event", 640, 480, 0) + wnd.SetAdditionalInputHandlerCallback(onAnyKeyPressed) + wnd.Run(loop) +} diff --git a/examples/loadimage/gopher.png b/examples/loadimage/gopher.png index 2f1e3c42..80355628 100644 Binary files a/examples/loadimage/gopher.png and b/examples/loadimage/gopher.png differ diff --git a/examples/markdown/gopher.png b/examples/markdown/gopher.png index 2f1e3c42..9b8980b3 100644 Binary files a/examples/markdown/gopher.png and b/examples/markdown/gopher.png differ diff --git a/examples/markdown/markdown.go b/examples/markdown/markdown.go index 7c569e4c..aae88401 100644 --- a/examples/markdown/markdown.go +++ b/examples/markdown/markdown.go @@ -6,7 +6,10 @@ import ( "github.com/AllenDang/giu" ) -var markdown string = getExampleMarkdownText() +var ( + markdown string = getExampleMarkdownText() + splitLayoutPos float32 = 320 +) func getExampleMarkdownText() string { return strings.Join([]string{ @@ -49,7 +52,7 @@ func getExampleMarkdownText() string { func loop() { giu.SingleWindow().Layout( - giu.SplitLayout(giu.DirectionHorizontal, 320, + giu.SplitLayout(giu.DirectionHorizontal, &splitLayoutPos, giu.Layout{ giu.Row( giu.Label("Markdown Edition:"), diff --git a/examples/splitter/SplitLayout.gif b/examples/splitter/SplitLayout.gif index b7142e9a..eb8e2e81 100644 Binary files a/examples/splitter/SplitLayout.gif and b/examples/splitter/SplitLayout.gif differ diff --git a/examples/splitter/splitter.go b/examples/splitter/splitter.go index a48b7be8..2afa211e 100644 --- a/examples/splitter/splitter.go +++ b/examples/splitter/splitter.go @@ -4,18 +4,25 @@ import ( g "github.com/AllenDang/giu" ) +var ( + sashPos1 float32 = 200 + sashPos2 float32 = 200 + sashPos3 float32 = 200 + sashPos4 float32 = 100 +) + func loop() { g.SingleWindow().Layout( - g.SplitLayout(g.DirectionHorizontal, 200, + g.SplitLayout(g.DirectionHorizontal, &sashPos1, g.Layout{ g.Label("Left panel"), g.Row(g.Button("Button1"), g.Button("Button2")), }, - g.SplitLayout(g.DirectionVertical, 200, + g.SplitLayout(g.DirectionVertical, &sashPos2, g.Layout{}, - g.SplitLayout(g.DirectionHorizontal, 200, + g.SplitLayout(g.DirectionHorizontal, &sashPos3, g.Layout{}, - g.SplitLayout(g.DirectionVertical, 100, + g.SplitLayout(g.DirectionVertical, &sashPos4, g.Layout{}, g.Layout{}, ), diff --git a/screenshots/SqlPower.png b/screenshots/SqlPower.png index d9dcfb2c..d0a58455 100644 Binary files a/screenshots/SqlPower.png and b/screenshots/SqlPower.png differ