From 91647e3b27cbc4fa8f2680ca273dcad76b1d4ad0 Mon Sep 17 00:00:00 2001 From: AllenDang Date: Fri, 1 Jan 2021 20:57:43 +0800 Subject: [PATCH] Breaking change! Refactor widget construction methods. --- Msgbox.go | 16 +- ProgressIndicator.go | 2 +- SplitLayout.go | 6 +- Widgets.go | 1125 +++++++++++------ Window.go | 106 +- examples/canvas/canvas.go | 4 +- examples/codeeditor/codeeditor.go | 10 +- examples/customwidget/customwidget.go | 6 +- examples/dragdrop/dragdrop.go | 10 +- examples/dynmiacloadfont/dynamicloadfont.go | 4 +- examples/extrawidgets/extrawidgets.go | 8 +- examples/helloworld/helloworld.go | 10 +- examples/hugelist/hugelist.go | 8 +- examples/imguidemo/imguidemo.go | 2 +- examples/loadimage/loadimage.go | 33 +- examples/multiwindow/multiwindow.go | 24 +- examples/ondrop/ondrop.go | 6 +- examples/plot/main.go | 4 +- examples/rangebuilder/rangebuilder.go | 8 +- examples/setstyle/setstyle.go | 6 +- examples/splitter/splitter.go | 6 +- examples/texturefiltering/texturefiltering.go | 40 +- examples/transparent/transparent.go | 4 +- examples/update/update.go | 4 +- examples/widgets/widgets.go | 132 +- 25 files changed, 996 insertions(+), 588 deletions(-) diff --git a/Msgbox.go b/Msgbox.go index e6a47476..eb933d11 100644 --- a/Msgbox.go +++ b/Msgbox.go @@ -44,17 +44,17 @@ func buildMsgboxButtons(buttons MsgboxButtons, callback DialogResultCallback) La switch buttons { case MsgboxButtonsOk: return Layout{ - Button(" Ok ", func() { + Button(" Ok ").OnClick(func() { msgboxInvokeCallback(DialogResultOK, callback) }), } case MsgboxButtonsOkCancel: return Layout{ Line( - Button(" Ok ", func() { + Button(" Ok ").OnClick(func() { msgboxInvokeCallback(DialogResultOK, callback) }), - Button("Cancel", func() { + Button("Cancel").OnClick(func() { msgboxInvokeCallback(DialogResultCancel, callback) }), ), @@ -62,17 +62,17 @@ func buildMsgboxButtons(buttons MsgboxButtons, callback DialogResultCallback) La case MsgboxButtonsYesNo: return Layout{ Line( - Button(" Yes ", func() { + Button(" Yes ").OnClick(func() { msgboxInvokeCallback(DialogResultYes, callback) }), - Button(" No ", func() { + Button(" No ").OnClick(func() { msgboxInvokeCallback(DialogResultNo, callback) }), ), } default: return Layout{ - Button(" Ok ", func() { + Button(" Ok ").OnClick(func() { msgboxInvokeCallback(DialogResultOK, callback) }), } @@ -102,12 +102,12 @@ func PrepareMsgbox() Layout { state.open = false } SetNextWindowSize(300, 0) - PopupModal(fmt.Sprintf("%s%s", state.title, msgboxId), Layout{ + PopupModal(fmt.Sprintf("%s%s", state.title, msgboxId)).Layout(Layout{ Custom(func() { // Ensure the state is valid. Context.GetState(msgboxId) }), - LabelWrapped(state.content), + Label(state.content).Wrapped(true), buildMsgboxButtons(state.buttons, state.resultCallback), }).Build() }), diff --git a/ProgressIndicator.go b/ProgressIndicator.go index 40f90b50..64b55415 100644 --- a/ProgressIndicator.go +++ b/ProgressIndicator.go @@ -63,7 +63,7 @@ func (p *ProgressIndicatorWidget) Build() { } else { state := s.(*ProgressIndicatorState) - child := Child(fmt.Sprintf("%s-container", p.id), false, p.width, p.height, 0, Layout{ + child := Child(fmt.Sprintf("%s-container", p.id)).Border(false).Size(p.width, p.height).Layout(Layout{ Custom(func() { // Process width and height width, height := GetAvaiableRegion() diff --git a/SplitLayout.go b/SplitLayout.go index 5026647c..2823c3eb 100644 --- a/SplitLayout.go +++ b/SplitLayout.go @@ -65,7 +65,7 @@ func (s *SplitLayoutWidget) buildChild(id string, width, height float32, layout PushFramePadding(0, 0) } }), - Child(id, !isSplitLayoutWidget && s.border, width, height, 0, s.restoreItemSpacing(layout)), + Child(id).Border(!isSplitLayoutWidget && s.border).Size(width, height).Layout(s.restoreItemSpacing(layout)), Custom(func() { if isSplitLayoutWidget || !s.border { PopStyle() @@ -100,14 +100,14 @@ func (s *SplitLayoutWidget) Build() { layout = Layout{ Line( s.buildChild(fmt.Sprintf("%s_layout1", stateId), splitLayoutState.sashPos, 0, s.layout1), - VSplitter(fmt.Sprintf("%s_vsplitter", stateId), itemSpacingX, 0, &(splitLayoutState.delta)), + VSplitter(fmt.Sprintf("%s_vsplitter", stateId), &(splitLayoutState.delta)).Size(itemSpacingX, 0), s.buildChild(fmt.Sprintf("%s_layout2", stateId), 0, 0, s.layout2), ), } } else { layout = Layout{ s.buildChild(fmt.Sprintf("%s_layout1", stateId), 0, splitLayoutState.sashPos, s.layout1), - HSplitter(fmt.Sprintf("%s_hsplitter", stateId), 0, itemSpacingY, &(splitLayoutState.delta)), + HSplitter(fmt.Sprintf("%s_hsplitter", stateId), &(splitLayoutState.delta)).Size(0, itemSpacingY), s.buildChild(fmt.Sprintf("%s_layout2", stateId), 0, 0, s.layout2), } } diff --git a/Widgets.go b/Widgets.go index 130d462f..206f8783 100644 --- a/Widgets.go +++ b/Widgets.go @@ -28,7 +28,6 @@ func (l *LineWidget) Build() { for _, w := range l.widgets { _, isTooltip := w.(*TooltipWidget) - _, isTooltipAdvance := w.(*TooltipAdvanceWidget) _, isContextMenu := w.(*ContextMenuWidget) _, isPopupModal := w.(*PopupModalWidget) _, isPopup := w.(*PopupWidget) @@ -40,7 +39,7 @@ func (l *LineWidget) Build() { AlignTextToFramePadding() } - if index > 0 && !isTooltip && !isTooltipAdvance && !isContextMenu && !isPopupModal && !isPopup && !isTabItem && !isCustom { + if index > 0 && !isTooltip && !isContextMenu && !isPopupModal && !isPopup && !isTabItem && !isCustom { imgui.SameLine() } @@ -71,15 +70,36 @@ func (i *InputTextMultilineWidget) Build() { } } -func InputTextMultiline(label string, text *string, width, height float32, flags InputTextFlags, cb imgui.InputTextCallback, onChange func()) *InputTextMultilineWidget { +func (i *InputTextMultilineWidget) Flags(flags InputTextFlags) *InputTextMultilineWidget { + i.flags = flags + return i +} + +func (i *InputTextMultilineWidget) Callback(cb imgui.InputTextCallback) *InputTextMultilineWidget { + i.cb = cb + return i +} + +func (i *InputTextMultilineWidget) OnChange(onChange func()) *InputTextMultilineWidget { + i.onChange = onChange + return i +} + +func (i *InputTextMultilineWidget) Size(width, height float32) *InputTextMultilineWidget { + scale := Context.platform.GetContentScale() + i.width, i.height = width*scale, height*scale + return i +} + +func InputTextMultiline(label string, text *string) *InputTextMultilineWidget { return &InputTextMultilineWidget{ label: label, text: text, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - flags: flags, - cb: cb, - onChange: onChange, + width: 0, + height: 0, + flags: 0, + cb: nil, + onChange: nil, } } @@ -96,16 +116,23 @@ func (b *ButtonWidget) Build() { } } -func Button(id string, onClick func()) *ButtonWidget { - return ButtonV(id, 0, 0, onClick) +func (b *ButtonWidget) OnClick(onClick func()) *ButtonWidget { + b.onClick = onClick + return b +} + +func (b *ButtonWidget) Size(width, height float32) *ButtonWidget { + scale := Context.platform.GetContentScale() + b.width, b.height = width*scale, height*scale + return b } -func ButtonV(id string, width, height float32, onClick func()) *ButtonWidget { +func Button(id string) *ButtonWidget { return &ButtonWidget{ id: id, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - onClick: onClick, + width: 0, + height: 0, + onClick: nil, } } @@ -169,11 +196,16 @@ type ArrowButtonWidget struct { onClick func() } -func ArrowButton(id string, dir Direction, onClick func()) *ArrowButtonWidget { +func (b *ArrowButtonWidget) OnClick(onClick func()) *ArrowButtonWidget { + b.onClick = onClick + return b +} + +func ArrowButton(id string, dir Direction) *ArrowButtonWidget { return &ArrowButtonWidget{ id: id, dir: dir, - onClick: onClick, + onClick: nil, } } @@ -188,10 +220,15 @@ type SmallButtonWidget struct { onClick func() } -func SmallButton(id string, onClick func()) *SmallButtonWidget { +func (b *SmallButtonWidget) OnClick(onClick func()) *SmallButtonWidget { + b.onClick = onClick + return b +} + +func SmallButton(id string) *SmallButtonWidget { return &SmallButtonWidget{ id: id, - onClick: onClick, + onClick: nil, } } @@ -208,12 +245,23 @@ type InvisibleButtonWidget struct { onClick func() } -func InvisibleButton(id string, width, height float32, onClick func()) *InvisibleButtonWidget { +func (b *InvisibleButtonWidget) Size(width, height float32) *InvisibleButtonWidget { + scale := Context.platform.GetContentScale() + b.width, b.height = width*scale, height*scale + return b +} + +func (b *InvisibleButtonWidget) OnClick(onClick func()) *InvisibleButtonWidget { + b.onClick = onClick + return b +} + +func InvisibleButton(id string) *InvisibleButtonWidget { return &InvisibleButtonWidget{ id: id, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - onClick: onClick, + width: 0, + height: 0, + onClick: nil, } } @@ -243,31 +291,48 @@ func (i *ImageButtonWidget) Build() { } } -func ImageButton(texture *Texture, width, height float32, onClick func()) *ImageButtonWidget { +func (b *ImageButtonWidget) Size(width, height float32) *ImageButtonWidget { + scale := Context.platform.GetContentScale() + b.width, b.height = width*scale, height*scale + return b +} + +func (b *ImageButtonWidget) OnClick(onClick func()) *ImageButtonWidget { + b.onClick = onClick + return b +} + +func (b *ImageButtonWidget) UV(uv0, uv1 image.Point) *ImageButtonWidget { + b.uv0, b.uv1 = uv0, uv1 + return b +} + +func (b *ImageButtonWidget) BgColor(bgColor color.RGBA) *ImageButtonWidget { + b.bgColor = bgColor + return b +} + +func (b *ImageButtonWidget) TintColor(tintColor color.RGBA) *ImageButtonWidget { + b.tintColor = tintColor + return b +} + +func (b *ImageButtonWidget) FramePadding(padding int) *ImageButtonWidget { + b.framePadding = padding + return b +} + +func ImageButton(texture *Texture) *ImageButtonWidget { return &ImageButtonWidget{ texture: texture, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), + width: 50 * Context.platform.GetContentScale(), + height: 50 * Context.platform.GetContentScale(), uv0: image.Point{X: 0, Y: 0}, uv1: image.Point{X: 1, Y: 1}, framePadding: -1, bgColor: color.RGBA{0, 0, 0, 0}, tintColor: color.RGBA{255, 255, 255, 255}, - onClick: onClick, - } -} - -func ImageButtonV(texture *Texture, width, height float32, uv0, uv1 image.Point, framePadding int, bgColor, tintColor color.RGBA, onClick func()) *ImageButtonWidget { - return &ImageButtonWidget{ - texture: texture, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - uv0: uv0, - uv1: uv1, - framePadding: framePadding, - bgColor: bgColor, - tintColor: tintColor, - onClick: onClick, + onClick: nil, } } @@ -283,11 +348,16 @@ func (c *CheckboxWidget) Build() { } } -func Checkbox(text string, selected *bool, onChange func()) *CheckboxWidget { +func (c *CheckboxWidget) OnChange(onChange func()) *CheckboxWidget { + c.onChange = onChange + return c +} + +func Checkbox(text string, selected *bool) *CheckboxWidget { return &CheckboxWidget{ text: text, selected: selected, - onChange: onChange, + onChange: nil, } } @@ -303,11 +373,16 @@ func (r *RadioButtonWidget) Build() { } } -func RadioButton(text string, active bool, onChange func()) *RadioButtonWidget { +func (r *RadioButtonWidget) OnChange(onChange func()) *RadioButtonWidget { + r.onChange = onChange + return r +} + +func RadioButton(text string, active bool) *RadioButtonWidget { return &RadioButtonWidget{ text: text, active: active, - onChange: onChange, + onChange: nil, } } @@ -328,14 +403,35 @@ func (c *ChildWidget) Build() { imgui.EndChild() } -func Child(id string, border bool, width, height float32, flags WindowFlags, layout Layout) *ChildWidget { +func (c *ChildWidget) Border(border bool) *ChildWidget { + c.border = border + return c +} + +func (c *ChildWidget) Size(width, height float32) *ChildWidget { + scale := Context.platform.GetContentScale() + c.width, c.height = width*scale, height*scale + return c +} + +func (c *ChildWidget) Flags(flags WindowFlags) *ChildWidget { + c.flags = flags + return c +} + +func (c *ChildWidget) Layout(layout Layout) *ChildWidget { + c.layout = layout + return c +} + +func Child(id string) *ChildWidget { return &ChildWidget{ id: id, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - border: border, - flags: flags, - layout: layout, + width: 0, + height: 0, + border: true, + flags: 0, + layout: nil, } } @@ -347,16 +443,31 @@ type ComboCustomWidget struct { layout Layout } -func ComboCustom(label, previewValue string, width float32, flags ComboFlags, layout Layout) *ComboCustomWidget { +func ComboCustom(label, previewValue string) *ComboCustomWidget { return &ComboCustomWidget{ label: label, previewValue: previewValue, - width: width * Context.GetPlatform().GetContentScale(), - flags: flags, - layout: layout, + width: 0, + flags: 0, + layout: nil, } } +func (cc *ComboCustomWidget) Layout(layout Layout) *ComboCustomWidget { + cc.layout = layout + return cc +} + +func (cc *ComboCustomWidget) Flags(flags ComboFlags) *ComboCustomWidget { + cc.flags = flags + return cc +} + +func (cc *ComboCustomWidget) Size(width float32) *ComboCustomWidget { + cc.width = width * Context.platform.GetContentScale() + return cc +} + func (cc *ComboCustomWidget) Build() { if cc.width > 0 { imgui.PushItemWidth(cc.width) @@ -384,6 +495,23 @@ type ComboWidget struct { onChange func() } +func Combo(label, previewValue string, items []string, selected *int32) *ComboWidget { + return &ComboWidget{ + label: label, + previewValue: previewValue, + items: items, + selected: selected, + flags: 0, + width: 0, + onChange: nil, + } +} + +func (c *ComboWidget) Flags(flags ComboFlags) *ComboWidget { + c.flags = flags + return c +} + func (c *ComboWidget) Build() { if c.width > 0 { imgui.PushItemWidth(c.width) @@ -407,16 +535,14 @@ func (c *ComboWidget) Build() { } } -func Combo(label, previewValue string, items []string, selected *int32, width float32, flags ComboFlags, onChange func()) *ComboWidget { - return &ComboWidget{ - label: label, - previewValue: previewValue, - items: items, - selected: selected, - flags: flags, - width: width * Context.platform.GetContentScale(), - onChange: onChange, - } +func (c *ComboWidget) Size(width float32) *ComboWidget { + c.width = width * Context.platform.GetContentScale() + return c +} + +func (c *ComboWidget) OnChange(onChange func()) *ComboWidget { + c.onChange = onChange + return c } type ContextMenuWidget struct { @@ -425,6 +551,24 @@ type ContextMenuWidget struct { layout Layout } +func ContextMenu(label string) *ContextMenuWidget { + return &ContextMenuWidget{ + label: label, + mouseButton: MouseButtonRight, + layout: nil, + } +} + +func (c *ContextMenuWidget) Layout(layout Layout) *ContextMenuWidget { + c.layout = layout + return c +} + +func (c *ContextMenuWidget) MouseButton(mouseButton MouseButton) *ContextMenuWidget { + c.mouseButton = mouseButton + return c +} + func (c *ContextMenuWidget) Build() { if imgui.BeginPopupContextItemV(c.label, int(c.mouseButton)) { if c.layout != nil { @@ -434,18 +578,6 @@ func (c *ContextMenuWidget) Build() { } } -func ContextMenu(layout Layout) *ContextMenuWidget { - return ContextMenuV("", MouseButtonRight, layout) -} - -func ContextMenuV(label string, mouseButton MouseButton, layout Layout) *ContextMenuWidget { - return &ContextMenuWidget{ - label: label, - mouseButton: mouseButton, - layout: layout, - } -} - type DragIntWidget struct { label string value *int32 @@ -455,29 +587,46 @@ type DragIntWidget struct { format string } -func (d *DragIntWidget) Build() { - imgui.DragIntV(d.label, d.value, d.speed, d.min, d.max, d.format) -} - -func DragInt(label string, value *int32) *DragIntWidget { - return DragIntV(label, value, 1.0, 0, 0, "%d") -} - -func DragIntV(label string, value *int32, speed float32, min, max int32, format string) *DragIntWidget { +func DragInt(label string, value *int32, min, max int32) *DragIntWidget { return &DragIntWidget{ label: label, value: value, - speed: speed, + speed: 1.0, min: min, max: max, - format: format, + format: "%d", } } +func (d *DragIntWidget) Speed(speed float32) *DragIntWidget { + d.speed = speed + return d +} + +func (d *DragIntWidget) Format(format string) *DragIntWidget { + d.format = format + return d +} + +func (d *DragIntWidget) Build() { + imgui.DragIntV(d.label, d.value, d.speed, d.min, d.max, d.format) +} + type GroupWidget struct { layout Layout } +func Group() *GroupWidget { + return &GroupWidget{ + layout: nil, + } +} + +func (g *GroupWidget) Layout(layout Layout) *GroupWidget { + g.layout = layout + return g +} + func (g *GroupWidget) Build() { imgui.BeginGroup() if g.layout != nil { @@ -486,37 +635,44 @@ func (g *GroupWidget) Build() { imgui.EndGroup() } -func Group(layout Layout) *GroupWidget { - return &GroupWidget{ - layout: layout, - } +type ImageWidget struct { + texture *Texture + width float32 + height float32 + uv0, uv1 image.Point + tintColor, borderColor color.RGBA } -type ImageWidget struct { - texture *Texture - width float32 - height float32 - uv0, uv1 imgui.Vec2 - tintCol, borderCol imgui.Vec4 +func Image(texture *Texture) *ImageWidget { + return &ImageWidget{ + texture: texture, + width: 100 * Context.platform.GetContentScale(), + height: 100 * Context.platform.GetContentScale(), + uv0: image.Point{X: 0, Y: 0}, + uv1: image.Point{X: 1, Y: 1}, + tintColor: color.RGBA{255, 255, 255, 255}, + borderColor: color.RGBA{0, 0, 0, 0}, + } } -func (i *ImageWidget) Uv0(x, y float32) *ImageWidget { - i.uv0.Set(x, y) +func (i *ImageWidget) Uv(uv0, uv1 image.Point) *ImageWidget { + i.uv0, i.uv1 = uv0, uv1 return i } -func (i *ImageWidget) Uv1(x, y float32) *ImageWidget { - i.uv1.Set(x, y) +func (i *ImageWidget) TintColor(tintColor color.RGBA) *ImageWidget { + i.tintColor = tintColor return i } -func (i *ImageWidget) TintCol(x, y, z, w float32) *ImageWidget { - i.tintCol.Set(x, y, z, w) +func (i *ImageWidget) BorderCol(borderColor color.RGBA) *ImageWidget { + i.borderColor = borderColor return i } -func (i *ImageWidget) BorderCol(x, y, z, w float32) *ImageWidget { - i.borderCol.Set(x, y, z, w) +func (i *ImageWidget) Size(width, height float32) *ImageWidget { + scale := Context.platform.GetContentScale() + i.width, i.height = width*scale, height*scale return i } @@ -530,24 +686,12 @@ func (i *ImageWidget) Build() { size.Y = rect.Y } if i.texture != nil && i.texture.id != 0 { - imgui.ImageV(i.texture.id, size, i.uv0, i.uv1, i.tintCol, i.borderCol) + imgui.ImageV(i.texture.id, size, ToVec2(i.uv0), ToVec2(i.uv1), ToVec4Color(i.tintColor), ToVec4Color(i.borderColor)) } else { Dummy(i.width, i.height).Build() } } -func Image(texture *Texture, width, height float32) *ImageWidget { - return &ImageWidget{ - texture: texture, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - uv0: imgui.Vec2{X: 0, Y: 0}, - uv1: imgui.Vec2{X: 1, Y: 1}, - tintCol: imgui.Vec4{X: 1, Y: 1, Z: 1, W: 1}, - borderCol: imgui.Vec4{X: 0, Y: 0, Z: 0, W: 0}, - } -} - type ImageState struct { loading bool failure bool @@ -564,14 +708,19 @@ type ImageWithFileWidget struct { height float32 } -func ImageWithFile(imgPath string, width, height float32) *ImageWithFileWidget { +func ImageWithFile(imgPath string) *ImageWithFileWidget { return &ImageWithFileWidget{ imgPath: imgPath, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), + width: 100, + height: 100, } } +func (i *ImageWithFileWidget) Size(width, height float32) *ImageWithFileWidget { + i.width, i.height = width, height + return i +} + func (i *ImageWithFileWidget) Build() { stateId := fmt.Sprintf("ImageWithFile_%s", i.imgPath) state := Context.GetState(stateId) @@ -579,7 +728,7 @@ func (i *ImageWithFileWidget) Build() { var widget *ImageWidget if state == nil { - widget = Image(nil, i.width, i.height) + widget = Image(nil).Size(i.width, i.height) //Prevent multiple invocation to LoadImage. Context.SetState(stateId, &ImageState{}) @@ -595,7 +744,7 @@ func (i *ImageWithFileWidget) Build() { } } else { imgState := state.(*ImageState) - widget = Image(imgState.texture, i.width, i.height) + widget = Image(imgState.texture).Size(i.width, i.height) } widget.Build() @@ -610,25 +759,35 @@ type ImageWithUrlWidget struct { whenFailure Layout } -func ImageWithUrlV(url string, downloadTimeout time.Duration, width, height float32, whenLoading Layout, whenFailure Layout) *ImageWithUrlWidget { +func ImageWithUrl(url string) *ImageWithUrlWidget { return &ImageWithUrlWidget{ imgUrl: url, - downloadTimeout: downloadTimeout, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - whenLoading: whenLoading, - whenFailure: whenFailure, + downloadTimeout: 10 * time.Second, + width: 100, + height: 100, + whenLoading: Layout{Dummy(100, 100)}, + whenFailure: Layout{Dummy(100, 100)}, } } -func ImageWithUrl(url string, downloadTimeout time.Duration, width, height float32) *ImageWithUrlWidget { - return ImageWithUrlV(url, downloadTimeout, width, height, - Layout{ - Dummy(width, height), - }, - Layout{ - Dummy(width, height), - }) +func (i *ImageWithUrlWidget) Timeout(downloadTimeout time.Duration) *ImageWithUrlWidget { + i.downloadTimeout = downloadTimeout + return i +} + +func (i *ImageWithUrlWidget) Size(width, height float32) *ImageWithUrlWidget { + i.width, i.height = width, height + return i +} + +func (i *ImageWithUrlWidget) LayoutForLoading(layout Layout) *ImageWithUrlWidget { + i.whenLoading = layout + return i +} + +func (i *ImageWithUrlWidget) LayoutForFailure(layout Layout) *ImageWithUrlWidget { + i.whenFailure = layout + return i } func (i *ImageWithUrlWidget) Build() { @@ -638,7 +797,7 @@ func (i *ImageWithUrlWidget) Build() { var widget *ImageWidget if state == nil { - widget = Image(nil, i.width, i.height) + widget = Image(nil).Size(i.width, i.height) //Prevent multiple invocation to download image. Context.SetState(stateId, &ImageState{loading: true}) @@ -683,7 +842,7 @@ func (i *ImageWithUrlWidget) Build() { return } - widget = Image(imgState.texture, i.width, i.height) + widget = Image(imgState.texture).Size(i.width, i.height) } widget.Build() @@ -698,6 +857,37 @@ type InputTextWidget struct { onChange func() } +func InputText(label string, value *string) *InputTextWidget { + return &InputTextWidget{ + label: label, + value: value, + width: 0, + flags: 0, + cb: nil, + onChange: nil, + } +} + +func (i *InputTextWidget) Size(width float32) *InputTextWidget { + i.width = width * Context.platform.GetContentScale() + return i +} + +func (i *InputTextWidget) Flags(flags InputTextFlags) *InputTextWidget { + i.flags = flags + return i +} + +func (i *InputTextWidget) Callback(cb imgui.InputTextCallback) *InputTextWidget { + i.cb = cb + return i +} + +func (i *InputTextWidget) OnChange(onChange func()) *InputTextWidget { + i.onChange = onChange + return i +} + func (i *InputTextWidget) Build() { if i.width != 0 { PushItemWidth(i.width) @@ -712,21 +902,6 @@ func (i *InputTextWidget) Build() { } } -func InputText(label string, width float32, value *string) *InputTextWidget { - return InputTextV(label, width, value, 0, nil, nil) -} - -func InputTextV(label string, width float32, value *string, flags InputTextFlags, cb imgui.InputTextCallback, onChange func()) *InputTextWidget { - return &InputTextWidget{ - label: label, - value: value, - width: width * Context.platform.GetContentScale(), - flags: flags, - cb: cb, - onChange: onChange, - } -} - type InputIntWidget struct { label string value *int32 @@ -735,20 +910,31 @@ type InputIntWidget struct { onChange func() } -func InputInt(label string, width float32, value *int32) *InputIntWidget { - return InputIntV(label, width, value, 0, nil) -} - -func InputIntV(label string, width float32, value *int32, flags InputTextFlags, onChange func()) *InputIntWidget { +func InputIntV(label string, value *int32) *InputIntWidget { return &InputIntWidget{ label: label, value: value, - width: width, - flags: flags, - onChange: onChange, + width: 0, + flags: 0, + onChange: nil, } } +func (i *InputIntWidget) Size(width float32) *InputIntWidget { + i.width = width * Context.platform.GetContentScale() + return i +} + +func (i *InputIntWidget) Flags(flags InputTextFlags) *InputIntWidget { + i.flags = flags + return i +} + +func (i *InputIntWidget) OnChange(onChange func()) *InputIntWidget { + i.onChange = onChange + return i +} + func (i *InputIntWidget) Build() { if i.width != 0 { PushItemWidth(i.width) @@ -772,21 +958,32 @@ type InputFloatWidget struct { onChange func() } -func InputFloat(label string, width float32, value *float32) *InputFloatWidget { - return InputFloatV(label, width, value, "%.3f", 0, nil) -} - -func InputFloatV(label string, width float32, value *float32, format string, flags InputTextFlags, onChange func()) *InputFloatWidget { +func InputFloatV(label string, value *float32) *InputFloatWidget { return &InputFloatWidget{ label: label, - width: width, + width: 0, value: value, - format: format, - flags: flags, - onChange: onChange, + format: "%.3f", + flags: 0, + onChange: nil, } } +func (i *InputFloatWidget) Size(width float32) *InputFloatWidget { + i.width = width * Context.platform.GetContentScale() + return i +} + +func (i *InputFloatWidget) Flags(flags InputTextFlags) *InputFloatWidget { + i.flags = flags + return i +} + +func (i *InputFloatWidget) Format(format string) *InputFloatWidget { + i.format = format + return i +} + func (i *InputFloatWidget) Build() { if i.width != 0 { PushItemWidth(i.width) @@ -808,6 +1005,30 @@ type LabelWidget struct { font *imgui.Font } +func Label(label string) *LabelWidget { + return &LabelWidget{ + label: label, + wrapped: false, + color: nil, + font: nil, + } +} + +func (l *LabelWidget) Wrapped(wrapped bool) *LabelWidget { + l.wrapped = wrapped + return l +} + +func (l *LabelWidget) Color(color *color.RGBA) *LabelWidget { + l.color = color + return l +} + +func (l *LabelWidget) Font(font *imgui.Font) *LabelWidget { + l.font = font + return l +} + func (l *LabelWidget) Build() { if l.color != nil { PushColorText(*l.color) @@ -836,25 +1057,19 @@ func (l *LabelWidget) Build() { } } -func Label(label string) *LabelWidget { - return LabelV(label, false, nil, nil) -} - -func LabelWrapped(label string) *LabelWidget { - return LabelV(label, true, nil, nil) +type MainMenuBarWidget struct { + layout Layout } -func LabelV(label string, wrapped bool, color *color.RGBA, font *imgui.Font) *LabelWidget { - return &LabelWidget{ - label: label, - wrapped: wrapped, - color: color, - font: font, +func MainMenuBar() *MainMenuBarWidget { + return &MainMenuBarWidget{ + layout: nil, } } -type MainMenuBarWidget struct { - layout Layout +func (m *MainMenuBarWidget) Layout(layout Layout) *MainMenuBarWidget { + m.layout = layout + return m } func (m *MainMenuBarWidget) Build() { @@ -866,14 +1081,19 @@ func (m *MainMenuBarWidget) Build() { } } -func MainMenuBar(layout Layout) *MainMenuBarWidget { - return &MainMenuBarWidget{ - layout: layout, +type MenuBarWidget struct { + layout Layout +} + +func MenuBar() *MenuBarWidget { + return &MenuBarWidget{ + layout: nil, } } -type MenuBarWidget struct { - layout Layout +func (m *MenuBarWidget) Layout(layout Layout) *MenuBarWidget { + m.layout = layout + return m } func (m *MenuBarWidget) Build() { @@ -885,12 +1105,6 @@ func (m *MenuBarWidget) Build() { } } -func MenuBar(layout Layout) *MenuBarWidget { - return &MenuBarWidget{ - layout: layout, - } -} - type MenuItemWidget struct { label string selected bool @@ -898,22 +1112,33 @@ type MenuItemWidget struct { onClick func() } -func (m *MenuItemWidget) Build() { - if imgui.MenuItemV(m.label, "", m.selected, m.enabled) && m.onClick != nil { - m.onClick() +func MenuItem(label string) *MenuItemWidget { + return &MenuItemWidget{ + label: label, + selected: false, + enabled: true, + onClick: nil, } } -func MenuItem(label string, onClick func()) *MenuItemWidget { - return MenuItemV(label, false, true, onClick) +func (m *MenuItemWidget) Selected(s bool) *MenuItemWidget { + m.selected = s + return m } -func MenuItemV(label string, selected, enabled bool, onClick func()) *MenuItemWidget { - return &MenuItemWidget{ - label: label, - selected: selected, - enabled: enabled, - onClick: onClick, +func (m *MenuItemWidget) Enabled(e bool) *MenuItemWidget { + m.enabled = e + return m +} + +func (m *MenuItemWidget) OnClick(onClick func()) *MenuItemWidget { + m.onClick = onClick + return m +} + +func (m *MenuItemWidget) Build() { + if imgui.MenuItemV(m.label, "", m.selected, m.enabled) && m.onClick != nil { + m.onClick() } } @@ -923,6 +1148,24 @@ type MenuWidget struct { layout Layout } +func Menu(label string) *MenuWidget { + return &MenuWidget{ + label: label, + enabled: true, + layout: nil, + } +} + +func (m *MenuWidget) Enabled(e bool) *MenuWidget { + m.enabled = e + return m +} + +func (m *MenuWidget) Layout(layout Layout) *MenuWidget { + m.layout = layout + return m +} + func (m *MenuWidget) Build() { if imgui.BeginMenuV(m.label, m.enabled) { if m.layout != nil { @@ -932,22 +1175,28 @@ func (m *MenuWidget) Build() { } } -func Menu(label string, layout Layout) *MenuWidget { - return MenuV(label, true, layout) +type PopupWidget struct { + name string + flags WindowFlags + layout Layout } -func MenuV(label string, enabled bool, layout Layout) *MenuWidget { - return &MenuWidget{ - label: label, - enabled: enabled, - layout: layout, +func Popup(name string) *PopupWidget { + return &PopupWidget{ + name: name, + flags: 0, + layout: nil, } } -type PopupWidget struct { - name string - flags WindowFlags - layout Layout +func (p *PopupWidget) Flags(flags WindowFlags) *PopupWidget { + p.flags = flags + return p +} + +func (p *PopupWidget) Layout(layout Layout) *PopupWidget { + p.layout = layout + return p } func (p *PopupWidget) Build() { @@ -960,14 +1209,6 @@ func (p *PopupWidget) Build() { } } -func Popup(name string, flags WindowFlags, layout Layout) *PopupWidget { - return &PopupWidget{ - name: name, - flags: flags, - layout: layout, - } -} - type PopupModalWidget struct { name string open *bool @@ -975,19 +1216,30 @@ type PopupModalWidget struct { layout Layout } -func PopupModal(name string, layout Layout) *PopupModalWidget { - return PopupModalV(name, nil, WindowFlagsNoResize, layout) -} - -func PopupModalV(name string, open *bool, flags WindowFlags, layout Layout) *PopupModalWidget { +func PopupModal(name string) *PopupModalWidget { return &PopupModalWidget{ name: name, - open: open, - flags: flags, - layout: layout, + open: nil, + flags: WindowFlagsNoResize, + layout: nil, } } +func (p *PopupModalWidget) IsOpen(open *bool) *PopupModalWidget { + p.open = open + return p +} + +func (p *PopupModalWidget) Flags(flags WindowFlags) *PopupModalWidget { + p.flags = flags + return p +} + +func (p *PopupModalWidget) Layout(layout Layout) *PopupModalWidget { + p.layout = layout + return p +} + func (p *PopupModalWidget) Build() { if imgui.BeginPopupModalV(p.name, p.open, int(p.flags)) { if p.layout != nil { @@ -1013,19 +1265,30 @@ type ProgressBarWidget struct { overlay string } -func (p *ProgressBarWidget) Build() { - imgui.ProgressBarV(p.fraction, imgui.Vec2{X: p.width, Y: p.height}, p.overlay) -} - -func ProgressBar(fraction float32, width, height float32, overlay string) *ProgressBarWidget { +func ProgressBar(fraction float32) *ProgressBarWidget { return &ProgressBarWidget{ fraction: fraction, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - overlay: overlay, + width: 0, + height: 0, + overlay: "", } } +func (p *ProgressBarWidget) Size(width, height float32) *ProgressBarWidget { + scale := Context.platform.GetContentScale() + p.width, p.height = width*scale, height*scale + return p +} + +func (p *ProgressBarWidget) Overlay(overlay string) *ProgressBarWidget { + p.overlay = overlay + return p +} + +func (p *ProgressBarWidget) Build() { + imgui.ProgressBarV(p.fraction, imgui.Vec2{X: p.width, Y: p.height}, p.overlay) +} + type SelectableWidget struct { label string selected bool @@ -1035,24 +1298,41 @@ type SelectableWidget struct { onClick func() } -func (s *SelectableWidget) Build() { - if imgui.SelectableV(s.label, s.selected, int(s.flags), imgui.Vec2{X: s.width, Y: s.height}) && s.onClick != nil { - s.onClick() +func Selectable(label string) *SelectableWidget { + return &SelectableWidget{ + label: label, + selected: false, + flags: 0, + width: 0, + height: 0, + onClick: nil, } } -func Selectable(label string, onClick func()) *SelectableWidget { - return SelectableV(label, false, 0, 0, 0, onClick) +func (s *SelectableWidget) Selected(selected bool) *SelectableWidget { + s.selected = selected + return s } -func SelectableV(label string, selected bool, flags SelectableFlags, width, height float32, onClick func()) *SelectableWidget { - return &SelectableWidget{ - label: label, - selected: selected, - flags: flags, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - onClick: onClick, +func (s *SelectableWidget) Flags(flags SelectableFlags) *SelectableWidget { + s.flags = flags + return s +} + +func (s *SelectableWidget) Size(width, height float32) *SelectableWidget { + scale := Context.platform.GetContentScale() + s.width, s.height = width*scale, height*scale + return s +} + +func (s *SelectableWidget) OnClick(onClick func()) *SelectableWidget { + s.onClick = onClick + return s +} + +func (s *SelectableWidget) Build() { + if imgui.SelectableV(s.label, s.selected, int(s.flags), imgui.Vec2{X: s.width, Y: s.height}) && s.onClick != nil { + s.onClick() } } @@ -1074,20 +1354,25 @@ type SliderIntWidget struct { format string } -func (s *SliderIntWidget) Build() { - imgui.SliderIntV(s.label, s.value, s.min, s.max, s.format) -} - -func SliderInt(label string, value *int32, min, max int32, format string) *SliderIntWidget { +func SliderInt(label string, value *int32, min, max int32) *SliderIntWidget { return &SliderIntWidget{ label: label, value: value, min: min, max: max, - format: format, + format: "%d", } } +func (s *SliderIntWidget) Format(format string) *SliderIntWidget { + s.format = format + return s +} + +func (s *SliderIntWidget) Build() { + imgui.SliderIntV(s.label, s.value, s.min, s.max, s.format) +} + type SliderFloatWidget struct { label string value *float32 @@ -1096,16 +1381,21 @@ type SliderFloatWidget struct { format string } -func SliderFloat(label string, value *float32, min, max float32, format string) *SliderFloatWidget { +func SliderFloat(label string, value *float32, min, max float32) *SliderFloatWidget { return &SliderFloatWidget{ label: label, value: value, min: min, max: max, - format: format, + format: "%.3f", } } +func (s *SliderFloatWidget) Format(format string) *SliderFloatWidget { + s.format = format + return s +} + func (sf *SliderFloatWidget) Build() { imgui.SliderFloatV(sf.label, sf.value, sf.min, sf.max, sf.format, 1.0) } @@ -1143,22 +1433,33 @@ type HSplitterWidget struct { delta *float32 } -func HSplitter(id string, width, height float32, delta *float32) *HSplitterWidget { +func HSplitter(id string, delta *float32) *HSplitterWidget { + + return &HSplitterWidget{ + id: id, + width: 0, + height: 0, + delta: delta, + } +} + +func (h *HSplitterWidget) Size(width, height float32) *HSplitterWidget { + scale := Context.platform.GetContentScale() aw, ah := GetAvaiableRegion() + if width == 0 { - width = aw / Context.GetPlatform().GetContentScale() + h.width = aw / scale + } else { + h.width = width * scale } if height == 0 { - height = ah / Context.GetPlatform().GetContentScale() + h.height = ah / scale + } else { + h.height = height * scale } - return &HSplitterWidget{ - id: id, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - delta: delta, - } + return h } func (h *HSplitterWidget) Build() { @@ -1201,20 +1502,32 @@ type VSplitterWidget struct { delta *float32 } -func VSplitter(id string, width, height float32, delta *float32) *VSplitterWidget { +func VSplitter(id string, delta *float32) *VSplitterWidget { + return &VSplitterWidget{ + id: id, + width: 0, + height: 0, + delta: delta, + } +} + +func (v *VSplitterWidget) Size(width, height float32) *VSplitterWidget { aw, ah := GetAvaiableRegion() + scale := Context.platform.GetContentScale() + if width == 0 { - width = aw / Context.GetPlatform().GetContentScale() + v.width = aw / scale + } else { + v.width = width * scale } + if height == 0 { - height = ah / Context.GetPlatform().GetContentScale() - } - return &VSplitterWidget{ - id: id, - width: width * Context.platform.GetContentScale(), - height: height * Context.platform.GetContentScale(), - delta: delta, + v.height = ah / scale + } else { + v.height = height * scale } + + return v } func (v *VSplitterWidget) Build() { @@ -1257,6 +1570,30 @@ type TabItemWidget struct { layout Layout } +func TabItem(label string) *TabItemWidget { + return &TabItemWidget{ + label: label, + open: nil, + flags: 0, + layout: nil, + } +} + +func (t *TabItemWidget) IsOpen(open *bool) *TabItemWidget { + t.open = open + return t +} + +func (t *TabItemWidget) Flags(flags TabItemFlags) *TabItemWidget { + t.flags = flags + return t +} + +func (t *TabItemWidget) Layout(layout Layout) *TabItemWidget { + t.layout = layout + return t +} + func (t *TabItemWidget) Build() { if imgui.BeginTabItemV(t.label, t.open, int(t.flags)) { if t.layout != nil { @@ -1266,23 +1603,28 @@ func (t *TabItemWidget) Build() { } } -func TabItem(label string, layout Layout) *TabItemWidget { - return TabItemV(label, nil, 0, layout) +type TabBarWidget struct { + id string + flags TabBarFlags + layout Layout } -func TabItemV(label string, open *bool, flags TabItemFlags, layout Layout) *TabItemWidget { - return &TabItemWidget{ - label: label, - open: open, - flags: flags, - layout: layout, +func TabBar(id string) *TabBarWidget { + return &TabBarWidget{ + id: id, + flags: 0, + layout: nil, } } -type TabBarWidget struct { - id string - flags TabBarFlags - layout Layout +func (t *TabBarWidget) Flags(flags TabBarFlags) *TabBarWidget { + t.flags = flags + return t +} + +func (t *TabBarWidget) Layout(layout Layout) *TabBarWidget { + t.layout = layout + return t } func (t *TabBarWidget) Build() { @@ -1294,18 +1636,6 @@ func (t *TabBarWidget) Build() { } } -func TabBar(id string, layout Layout) *TabBarWidget { - return TabBarV(id, 0, layout) -} - -func TabBarV(id string, flags TabBarFlags, layout Layout) *TabBarWidget { - return &TabBarWidget{ - id: id, - flags: flags, - layout: layout, - } -} - type RowWidget struct { layout Layout } @@ -1337,14 +1667,24 @@ type TabelWidget struct { rows Rows } -func Table(label string, border bool, rows Rows) *TabelWidget { +func Table(label string) *TabelWidget { return &TabelWidget{ label: label, - border: border, - rows: rows, + border: true, + rows: nil, } } +func (t *TabelWidget) Border(b bool) *TabelWidget { + t.border = b + return t +} + +func (t *TabelWidget) Rows(rows Rows) *TabelWidget { + t.rows = rows + return t +} + func (t *TabelWidget) Build() { if len(t.rows) > 0 && len(t.rows[0].layout) > 0 { imgui.ColumnsV(len(t.rows[0].layout), t.label, t.border) @@ -1377,14 +1717,24 @@ type FastTabelWidget struct { // Create a fast table which only render visible rows. // Note this only works with all rows have same height. -func FastTable(label string, border bool, rows Rows) *FastTabelWidget { +func FastTable(label string) *FastTabelWidget { return &FastTabelWidget{ label: label, - border: border, - rows: rows, + border: true, + rows: nil, } } +func (t *FastTabelWidget) Border(b bool) *FastTabelWidget { + t.border = b + return t +} + +func (t *FastTabelWidget) Rows(rows Rows) *FastTabelWidget { + t.rows = rows + return t +} + func (t *FastTabelWidget) Build() { if len(t.rows) > 0 && len(t.rows[0].layout) > 0 { imgui.ColumnsV(len(t.rows[0].layout), t.label, t.border) @@ -1419,37 +1769,32 @@ func (t *FastTabelWidget) Build() { } type TooltipWidget struct { - tip string + tip string + layout Layout } func (t *TooltipWidget) Build() { if imgui.IsItemHovered() { - imgui.SetTooltip(t.tip) + if t.layout != nil { + imgui.BeginTooltip() + t.layout.Build() + imgui.EndTooltip() + } else { + imgui.SetTooltip(t.tip) + } } } func Tooltip(tip string) *TooltipWidget { return &TooltipWidget{ - tip: tip, + tip: tip, + layout: nil, } } -type TooltipAdvanceWidget struct { - layout Layout -} - -func TooltipAdvance(layout Layout) *TooltipAdvanceWidget { - return &TooltipAdvanceWidget{ - layout: layout, - } -} - -func (t *TooltipAdvanceWidget) Build() { - if imgui.IsItemHovered() && t.layout != nil { - imgui.BeginTooltip() - t.layout.Build() - imgui.EndTooltip() - } +func (t *TooltipWidget) Layout(layout Layout) *TooltipWidget { + t.layout = layout + return t } type TreeNodeWidget struct { @@ -1459,6 +1804,32 @@ type TreeNodeWidget struct { eventHandler func() } +func TreeNode(label string) *TreeNodeWidget { + return &TreeNodeWidget{ + label: label, + flags: 0, + layout: nil, + eventHandler: nil, + } +} + +func (t *TreeNodeWidget) Flags(flags TreeNodeFlags) *TreeNodeWidget { + t.flags = flags + return t +} + +// Create TreeNode with eventHandler +// You could detect events (e.g. IsItemClicked IsMouseDoubleClicked etc...) and handle them for TreeNode inside eventHandler +func (t *TreeNodeWidget) Event(handler func()) *TreeNodeWidget { + t.eventHandler = handler + return t +} + +func (t *TreeNodeWidget) Layout(layout Layout) *TreeNodeWidget { + t.layout = layout + return t +} + func (t *TreeNodeWidget) Build() { open := imgui.TreeNodeV(t.label, int(t.flags)) @@ -1476,21 +1847,6 @@ func (t *TreeNodeWidget) Build() { } } -func TreeNode(label string, flags TreeNodeFlags, layout Layout) *TreeNodeWidget { - return TreeNodeV(label, flags, nil, layout) -} - -// Create TreeNode with eventHandler -// You could detect events (e.g. IsItemClicked IsMouseDoubleClicked etc...) and handle them for TreeNode inside eventHandler -func TreeNodeV(label string, flags TreeNodeFlags, eventHandler func(), layout Layout) *TreeNodeWidget { - return &TreeNodeWidget{ - label: label, - flags: flags, - layout: layout, - eventHandler: eventHandler, - } -} - type SpacingWidget struct{} func (s *SpacingWidget) Build() { @@ -1582,24 +1938,51 @@ type ListBoxWidget struct { onMenu func(selectedIndex int, menu string) } -func ListBox(id string, items []string, onChange func(selectedIndex int), onDClick func(selectedIndex int)) *ListBoxWidget { - return ListBoxV(id, 0, 0, true, items, nil, onChange, onDClick, nil) -} - -func ListBoxV(id string, width, height float32, border bool, items []string, menus []string, onChange func(selectedIndex int), onDClick func(selectedIndex int), onMenu func(selectedIndex int, menu string)) *ListBoxWidget { +func ListBox(id string, items []string) *ListBoxWidget { return &ListBoxWidget{ id: id, - width: width, - height: height, - border: border, + width: 0, + height: 0, + border: true, items: items, - menus: menus, - onChange: onChange, - onDClick: onDClick, - onMenu: onMenu, + menus: nil, + onChange: nil, + onDClick: nil, + onMenu: nil, } } +func (l *ListBoxWidget) Size(width, height float32) *ListBoxWidget { + scale := Context.platform.GetContentScale() + l.width, l.height = width*scale, height*scale + return l +} + +func (l *ListBoxWidget) Border(b bool) *ListBoxWidget { + l.border = b + return l +} + +func (l *ListBoxWidget) ContextMenu(menuItems []string) *ListBoxWidget { + l.menus = menuItems + return l +} + +func (l *ListBoxWidget) OnChange(onChange func(selectedIndex int)) *ListBoxWidget { + l.onChange = onChange + return l +} + +func (l *ListBoxWidget) OnDClick(onDClick func(selectedIndex int)) *ListBoxWidget { + l.onDClick = onDClick + return l +} + +func (l *ListBoxWidget) OnMenu(onMenu func(selectedIndex int, menu string)) *ListBoxWidget { + l.onMenu = onMenu + return l +} + func (l *ListBoxWidget) Build() { var state *ListBoxState if s := Context.GetState(l.id); s == nil { @@ -1609,7 +1992,7 @@ func (l *ListBoxWidget) Build() { state = s.(*ListBoxState) } - child := Child(l.id, l.border, l.width, l.height, 0, Layout{ + child := Child(l.id).Border(l.border).Size(l.width, l.height).Layout(Layout{ Custom(func() { var clipper imgui.ListClipper clipper.Begin(len(l.items)) @@ -1618,7 +2001,7 @@ func (l *ListBoxWidget) Build() { for i := clipper.DisplayStart; i < clipper.DisplayEnd; i++ { selected := i == state.selectedIndex item := l.items[i] - SelectableV(item, selected, SelectableFlagsAllowDoubleClick, 0, 0, func() { + Selectable(item).Selected(selected).Flags(SelectableFlagsAllowDoubleClick).OnClick(func() { if state.selectedIndex != i { state.selectedIndex = i if l.onChange != nil { @@ -1636,7 +2019,7 @@ func (l *ListBoxWidget) Build() { for _, m := range l.menus { index := i menu := m - menus = append(menus, MenuItem(fmt.Sprintf("%s##%d", menu, index), func() { + menus = append(menus, MenuItem(fmt.Sprintf("%s##%d", menu, index)).OnClick(func() { if l.onMenu != nil { l.onMenu(index, menu) } @@ -1644,7 +2027,7 @@ func (l *ListBoxWidget) Build() { } if len(menus) > 0 { - ContextMenuV(fmt.Sprintf("%d_contextmenu", i), MouseButtonRight, menus).Build() + ContextMenu(fmt.Sprintf("%d_contextmenu", i)).Layout(menus).Build() } } } @@ -1663,15 +2046,25 @@ type DatePickerWidget struct { onChange func() } -func DatePicker(id string, date *time.Time, width float32, onChange func()) *DatePickerWidget { +func DatePicker(id string, date *time.Time) *DatePickerWidget { return &DatePickerWidget{ id: id, date: date, - width: width * Context.GetPlatform().GetContentScale(), - onChange: onChange, + width: 100 * Context.GetPlatform().GetContentScale(), + onChange: nil, } } +func (d *DatePickerWidget) Size(width float32) *DatePickerWidget { + d.width = width * Context.platform.GetContentScale() + return d +} + +func (d *DatePickerWidget) OnChange(onChange func()) *DatePickerWidget { + d.onChange = onChange + return d +} + func (d *DatePickerWidget) Build() { if d.date != nil { imgui.PushID(d.id) @@ -1784,7 +2177,7 @@ func (d *DatePickerWidget) Build() { imgui.PushStyleColor(imgui.StyleColorText, highlightColor) } - SelectableV(fmt.Sprintf("%02d", day), day == int(d.date.Day()), 0, 0, 0, func() { + Selectable(fmt.Sprintf("%02d", day)).Selected(day == int(d.date.Day())).OnClick(func() { *d.date, _ = time.ParseInLocation( "2006-01-02", fmt.Sprintf("%d-%02d-%02d", @@ -1809,7 +2202,7 @@ func (d *DatePickerWidget) Build() { rows = append(rows, Row(row...)) } - Table("DayTable", true, rows).Build() + Table("DayTable").Rows(rows).Build() imgui.EndCombo() } diff --git a/Window.go b/Window.go index b3d1d309..98d4631e 100644 --- a/Window.go +++ b/Window.go @@ -4,60 +4,78 @@ import ( "github.com/AllenDang/giu/imgui" ) -func Window(title string, x, y, width, height float32, layout Layout) { - WindowV( - title, - nil, - 0, - x, y, - width, height, - layout, - ) +func SingleWindow(title string) *WindowWidget { + size := Context.platform.DisplaySize() + return Window(title). + Flags( + imgui.WindowFlagsNoTitleBar| + imgui.WindowFlagsNoCollapse| + imgui.WindowFlagsNoScrollbar| + imgui.WindowFlagsNoMove| + imgui.WindowFlagsNoResize). + Size(size[0], size[1]) } -func SingleWindow(title string, layout Layout) { +func SingleWindowWithMenuBar(title string) *WindowWidget { size := Context.platform.DisplaySize() - WindowV( - title, - nil, - imgui.WindowFlagsNoTitleBar| - imgui.WindowFlagsNoCollapse| - imgui.WindowFlagsNoScrollbar| - imgui.WindowFlagsNoMove| - imgui.WindowFlagsNoResize, - 0, 0, - size[0], size[1], - layout, - ) + return Window(title). + Flags( + imgui.WindowFlagsNoTitleBar| + imgui.WindowFlagsNoCollapse| + imgui.WindowFlagsNoScrollbar| + imgui.WindowFlagsNoMove| + imgui.WindowFlagsMenuBar| + imgui.WindowFlagsNoResize).Size(size[0], size[1]) } -func SingleWindowWithMenuBar(title string, layout Layout) { - size := Context.platform.DisplaySize() - WindowV( - title, - nil, - imgui.WindowFlagsNoTitleBar| - imgui.WindowFlagsNoCollapse| - imgui.WindowFlagsNoScrollbar| - imgui.WindowFlagsNoMove| - imgui.WindowFlagsMenuBar| - imgui.WindowFlagsNoResize, - 0, 0, - size[0], size[1], - layout, - ) +type WindowWidget struct { + title string + open *bool + flags WindowFlags + x, y float32 + width, height float32 +} + +func Window(title string) *WindowWidget { + return &WindowWidget{ + title: title, + } +} + +func (w *WindowWidget) IsOpen(open *bool) *WindowWidget { + w.open = open + return w } -func WindowV(title string, open *bool, flags WindowFlags, x, y, width, height float32, layout Layout) { - if flags&imgui.WindowFlagsNoMove != 0 && flags&imgui.WindowFlagsNoResize != 0 { - imgui.SetNextWindowPos(imgui.Vec2{X: x, Y: y}) - imgui.SetNextWindowSize(imgui.Vec2{X: width, Y: height}) +func (w *WindowWidget) Flags(flags WindowFlags) *WindowWidget { + w.flags = flags + return w +} + +func (w *WindowWidget) Size(width, height float32) *WindowWidget { + w.width, w.height = width, height + return w +} + +func (w *WindowWidget) Pos(x, y float32) *WindowWidget { + w.x, w.y = x, y + return w +} + +func (w *WindowWidget) Layout(layout Layout) { + if layout == nil { + return + } + + if w.flags&imgui.WindowFlagsNoMove != 0 && w.flags&imgui.WindowFlagsNoResize != 0 { + imgui.SetNextWindowPos(imgui.Vec2{X: w.x, Y: w.y}) + imgui.SetNextWindowSize(imgui.Vec2{X: w.width, Y: w.height}) } else { - imgui.SetNextWindowPosV(imgui.Vec2{X: x, Y: y}, imgui.ConditionFirstUseEver, imgui.Vec2{X: 0, Y: 0}) - imgui.SetNextWindowSizeV(imgui.Vec2{X: width, Y: height}, imgui.ConditionFirstUseEver) + imgui.SetNextWindowPosV(imgui.Vec2{X: w.x, Y: w.y}, imgui.ConditionFirstUseEver, imgui.Vec2{X: 0, Y: 0}) + imgui.SetNextWindowSizeV(imgui.Vec2{X: w.width, Y: w.height}, imgui.ConditionFirstUseEver) } - imgui.BeginV(title, open, int(flags)) + imgui.BeginV(w.title, w.open, int(w.flags)) layout.Build() diff --git a/examples/canvas/canvas.go b/examples/canvas/canvas.go index c203a29c..8860806d 100644 --- a/examples/canvas/canvas.go +++ b/examples/canvas/canvas.go @@ -12,7 +12,7 @@ var ( ) func loop() { - g.SingleWindow("canvas", g.Layout{ + g.SingleWindow("canvas").Layout(g.Layout{ g.Label("Canvas demo"), g.Custom(func() { canvas := g.GetCanvas() @@ -61,5 +61,5 @@ func main() { texture, _ = g.NewTextureFromRgba(img) }() - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/codeeditor/codeeditor.go b/examples/codeeditor/codeeditor.go index cf1b3bd3..a283b3a9 100644 --- a/examples/codeeditor/codeeditor.go +++ b/examples/codeeditor/codeeditor.go @@ -13,9 +13,9 @@ var ( ) func loop() { - g.SingleWindow("Code Editor", g.Layout{ + g.SingleWindow("Code Editor").Layout(g.Layout{ g.Line( - g.Button("Get Text", func() { + g.Button("Get Text").OnClick(func() { if editor.HasSelection() { fmt.Println(editor.GetSelectedText()) } else { @@ -30,10 +30,10 @@ func loop() { fmt.Println("Current line is", editor.GetCurrentLineText()) }), - g.Button("Set Text", func() { + g.Button("Set Text").OnClick(func() { editor.SetText("Set text") }), - g.Button("Set Error Marker", func() { + g.Button("Set Error Marker").OnClick(func() { errMarkers.Clear() errMarkers.Insert(1, "Error message") fmt.Println("ErrMarkers Size:", errMarkers.Size()) @@ -57,5 +57,5 @@ func main() { editor.SetLanguageDefinitionSQL() wnd := g.NewMasterWindow("Code Editor", 800, 600, 0, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/customwidget/customwidget.go b/examples/customwidget/customwidget.go index 8d443f63..85f3b2b2 100644 --- a/examples/customwidget/customwidget.go +++ b/examples/customwidget/customwidget.go @@ -31,7 +31,7 @@ func (c *CircleButtonWidget) Build() { // Place a invisible button to be a placeholder for events buttonWidth := float32(radius) * 2 - g.InvisibleButton(c.id, buttonWidth, buttonWidth, c.clicked).Build() + g.InvisibleButton(c.id).Size(buttonWidth, buttonWidth).OnClick(c.clicked).Build() // If button is hovered drawActive := g.IsItemHovered() @@ -62,7 +62,7 @@ func onCircleButton() { } func loop() { - g.SingleWindow("custom widget", g.Layout{ + g.SingleWindow("custom widget").Layout(g.Layout{ g.Line(CircleButton("Hello", onHello), CircleButton("World", onWorld)), CircleButton("Circle Button", onCircleButton), }) @@ -70,5 +70,5 @@ func loop() { func main() { wnd := g.NewMasterWindow("Custom Widget", 400, 300, g.MasterWindowFlagsNotResizable, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/dragdrop/dragdrop.go b/examples/dragdrop/dragdrop.go index 136e2140..68a9339e 100644 --- a/examples/dragdrop/dragdrop.go +++ b/examples/dragdrop/dragdrop.go @@ -12,9 +12,9 @@ var ( ) func loop() { - g.SingleWindow("Drag and Drop", g.Layout{ + g.SingleWindow("Drag and Drop").Layout(g.Layout{ g.Line( - g.Button("Drag me: 9", nil), + g.Button("Drag me: 9"), g.Custom(func() { if imgui.BeginDragDropSource() { imgui.SetDragDropPayload("DND_DEMO", 9) @@ -22,7 +22,7 @@ func loop() { imgui.EndDragDropSource() } }), - g.Button("Drag me: 10", nil), + g.Button("Drag me: 10"), g.Custom(func() { if imgui.BeginDragDropSource() { imgui.SetDragDropPayload("DND_DEMO", 10) @@ -31,7 +31,7 @@ func loop() { } }), ), - g.InputTextMultiline("##DropTarget", &dropTarget, -1, -1, g.InputTextFlagsReadOnly, nil, nil), + g.InputTextMultiline("##DropTarget", &dropTarget).Size(-1, -1).Flags(g.InputTextFlagsReadOnly), g.Custom(func() { if imgui.BeginDragDropTarget() { payload := imgui.AcceptDragDropPayload("DND_DEMO") @@ -46,5 +46,5 @@ func loop() { func main() { wnd := g.NewMasterWindow("Drag and Drop", 600, 400, g.MasterWindowFlagsNotResizable, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/dynmiacloadfont/dynamicloadfont.go b/examples/dynmiacloadfont/dynamicloadfont.go index 0c60cc03..10a7b58c 100644 --- a/examples/dynmiacloadfont/dynamicloadfont.go +++ b/examples/dynmiacloadfont/dynamicloadfont.go @@ -20,12 +20,12 @@ func loadFont() { } func loop() { - g.SingleWindow("dynamic load font", g.Layout{ + g.SingleWindow("dynamic load font").Layout(g.Layout{ g.Label("你好啊世界!铁憨憨"), }) } func main() { wnd := g.NewMasterWindow("Dynamic load font", 400, 200, g.MasterWindowFlagsNotResizable, loadFont) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/extrawidgets/extrawidgets.go b/examples/extrawidgets/extrawidgets.go index 311dee59..c1c1714e 100644 --- a/examples/extrawidgets/extrawidgets.go +++ b/examples/extrawidgets/extrawidgets.go @@ -10,10 +10,10 @@ var ( ) func loop() { - g.SingleWindow("Extra Widgets", g.Layout{ - g.Checkbox("Show ProgressIndicator", &showPD, nil), + g.SingleWindow("Extra Widgets").Layout(g.Layout{ + g.Checkbox("Show ProgressIndicator", &showPD), g.Condition(showPD, g.Layout{ - g.SliderFloat("Radius", &radius, 10, 100, ""), + g.SliderFloat("Radius", &radius, 10, 100), g.Line( g.ProgressIndicator("pd1", "", 20+radius, 20+radius, radius), g.ProgressIndicator("pd2", "", 20+radius, 20+radius, radius), @@ -25,5 +25,5 @@ func loop() { func main() { wnd := g.NewMasterWindow("Extra Widgets", 800, 600, g.MasterWindowFlagsNotResizable, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/helloworld/helloworld.go b/examples/helloworld/helloworld.go index 2417b433..fb5de4dc 100644 --- a/examples/helloworld/helloworld.go +++ b/examples/helloworld/helloworld.go @@ -20,17 +20,17 @@ func onQuit() { } func loop() { - g.SingleWindow("hello world", g.Layout{ + g.SingleWindow("hello world").Layout(g.Layout{ g.Label("Hello world from giu"), g.Line( - g.Button("Click Me", onClickMe), - g.Button("I'm so cute", onImSoCute), - g.Button("Quit", onQuit), + g.Button("Click Me").OnClick(onClickMe), + g.Button("I'm so cute").OnClick(onImSoCute), + g.Button("Quit").OnClick(onQuit), ), }) } func main() { wnd := g.NewMasterWindow("Hello world", 400, 200, g.MasterWindowFlagsNotResizable, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/hugelist/hugelist.go b/examples/hugelist/hugelist.go index 0b7fca36..2a06580d 100644 --- a/examples/hugelist/hugelist.go +++ b/examples/hugelist/hugelist.go @@ -24,11 +24,11 @@ func buildRows() []*g.RowWidget { } func loop() { - g.SingleWindow("Huge list demo", g.Layout{ + g.SingleWindow("Huge list demo").Layout(g.Layout{ g.Label("Use FastTable to display huge amount of rows"), g.Label("Note: FastTable only works if all rows have same height"), - g.Child("Container", true, 0, 0, 0, g.Layout{ - g.FastTable("Fast table", true, buildRows()), + g.Child("Container").Layout(g.Layout{ + g.FastTable("Fast table").Rows(buildRows()), }), }) } @@ -40,5 +40,5 @@ func main() { } wnd := g.NewMasterWindow("Huge list demo", 800, 600, 0, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/imguidemo/imguidemo.go b/examples/imguidemo/imguidemo.go index 9433edf9..2a5d7e27 100644 --- a/examples/imguidemo/imguidemo.go +++ b/examples/imguidemo/imguidemo.go @@ -11,5 +11,5 @@ func loop() { func main() { wnd := g.NewMasterWindow("Widgets", 1024, 768, 0, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/loadimage/loadimage.go b/examples/loadimage/loadimage.go index 10b6696f..9550bd10 100644 --- a/examples/loadimage/loadimage.go +++ b/examples/loadimage/loadimage.go @@ -9,32 +9,29 @@ import ( ) func loop() { - g.SingleWindow("load image", g.Layout{ + g.SingleWindow("load image").Layout(g.Layout{ g.Label("Display image from file"), - g.ImageWithFile("gopher.png", 300, 200), + g.ImageWithFile("gopher.png").Size(300, 200), g.Label("Display image from url (wait few seconds to download)"), - g.ImageWithUrl("https://png.pngitem.com/pimgs/s/3-36108_gopher-golang-hd-png-download.png", 10*time.Second, 300, 200), + g.ImageWithUrl("https://png.pngitem.com/pimgs/s/3-36108_gopher-golang-hd-png-download.png").Size(300, 200), g.Label("Display images from url with loading and fallback"), - g.ImageWithUrlV("https://png.pngitem.com/pimgs/s/424-4241958_transparent-gopher-png-golang-gopher-png-png-download.png", - 5*time.Second, 300, 200, - g.Layout{ - g.Child("Loading", true, 300, 200, 0, g.Layout{ + g.ImageWithUrl( + "https://png.pngitem.com/pimgs/s/424-4241958_transparent-gopher-png-golang-gopher-png-png-download.png"). + Timeout(5*time.Second). + Size(300, 200). + LayoutForLoading(g.Layout{ + g.Child("Loading").Size(300, 200).Layout(g.Layout{ g.Label("Loading..."), }), - }, - g.Layout{ - g.ImageWithFile("./fallback.png", 300, 200), - }, - ), + }). + LayoutForFailure(g.Layout{ + g.ImageWithFile("./fallback.png").Size(300, 200), + }), g.Label("Display image from url without placeholder (no size when loading)"), - g.ImageWithUrlV("https://www.pngitem.com/pimgs/m/424-4242405_go-lang-gopher-clipart-png-download-golang-gopher.png", - 10*time.Second, 300, 200, - nil, - nil, - ), + g.ImageWithUrl("https://www.pngitem.com/pimgs/m/424-4242405_go-lang-gopher-clipart-png-download-golang-gopher.png").Size(300, 200), g.Label("Footer"), }) @@ -42,5 +39,5 @@ func loop() { func main() { wnd := g.NewMasterWindow("Load Image", 600, 500, g.MasterWindowFlagsNotResizable, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/multiwindow/multiwindow.go b/examples/multiwindow/multiwindow.go index c6acb329..86d8192b 100644 --- a/examples/multiwindow/multiwindow.go +++ b/examples/multiwindow/multiwindow.go @@ -18,32 +18,32 @@ func onHideWindow2() { } func loop() { - g.MainMenuBar(g.Layout{ - g.Menu("File", g.Layout{ - g.MenuItem("Open", nil), + g.MainMenuBar().Layout(g.Layout{ + g.Menu("File").Layout(g.Layout{ + g.MenuItem("Open"), g.Separator(), - g.MenuItem("Exit", nil), + g.MenuItem("Exit"), }), - g.Menu("Misc", g.Layout{ - g.Checkbox("Enable Me", &checked, nil), - g.Button("Button", nil), + g.Menu("Misc").Layout(g.Layout{ + g.Checkbox("Enable Me", &checked), + g.Button("Button"), }), }).Build() - g.Window("Window 1", 10, 30, 200, 100, g.Layout{ + g.Window("Window 1").Pos(10, 30).Size(200, 100).Layout(g.Layout{ g.Label("I'm a label in window 1"), - g.Button("Show Window 2", onShowWindow2), + g.Button("Show Window 2").OnClick(onShowWindow2), }) if showWindow2 { - g.WindowV("Window 2", &showWindow2, g.WindowFlagsNone, 250, 30, 200, 100, g.Layout{ + g.Window("Window 2").IsOpen(&showWindow2).Flags(g.WindowFlagsNone).Pos(250, 30).Size(200, 100).Layout(g.Layout{ g.Label("I'm a label in window 2"), - g.Button("Hide me", onHideWindow2), + g.Button("Hide me").OnClick(onHideWindow2), }) } } func main() { wnd := g.NewMasterWindow("Multi sub window demo", 600, 400, 0, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/ondrop/ondrop.go b/examples/ondrop/ondrop.go index e1a5bb64..4cc8e056 100644 --- a/examples/ondrop/ondrop.go +++ b/examples/ondrop/ondrop.go @@ -12,9 +12,9 @@ var ( ) func loop() { - g.SingleWindow("On Drop Demo", g.Layout{ + g.SingleWindow("On Drop Demo").Layout(g.Layout{ g.Label("Drop file to this window"), - g.InputTextMultiline("#DroppedFiles", &dropInFiles, -1, -1, g.InputTextFlagsReadOnly, nil, nil), + g.InputTextMultiline("#DroppedFiles", &dropInFiles).Size(-1, -1).Flags(g.InputTextFlagsReadOnly), }) } @@ -31,5 +31,5 @@ func onDrop(names []string) { func main() { wnd := g.NewMasterWindow("On Drop Demo", 600, 400, g.MasterWindowFlagsNotResizable, nil) wnd.SetDropCallback(onDrop) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/plot/main.go b/examples/plot/main.go index b1d1ae0b..b0514e41 100644 --- a/examples/plot/main.go +++ b/examples/plot/main.go @@ -12,7 +12,7 @@ func loop() { for x := 0.0; len(plotdata) < 1000; x += delta { plotdata = append(plotdata, float32(math.Sin(x))) } - g.SingleWindow("hello world", g.Layout{ + g.SingleWindow("hello world").Layout(g.Layout{ g.Label("Hello world from giu"), g.Label("Simple sin(x) plot:"), g.PlotLines("testplot", plotdata), @@ -23,5 +23,5 @@ func loop() { func main() { wnd := g.NewMasterWindow("Hello world", 600, 400, g.MasterWindowFlagsNotResizable, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/rangebuilder/rangebuilder.go b/examples/rangebuilder/rangebuilder.go index ff55d89c..39993d7d 100644 --- a/examples/rangebuilder/rangebuilder.go +++ b/examples/rangebuilder/rangebuilder.go @@ -7,13 +7,13 @@ import ( ) func loop() { - g.SingleWindow("Container", g.Layout{ + g.SingleWindow("Container").Layout(g.Layout{ g.Label("Below buttons are generated by RangeBuilder in one line"), g.Line( g.RangeBuilder("Buttons in one line", []interface{}{"Button1", "Button2", "Button3"}, func(i int, v interface{}) g.Widget { str := v.(string) return g.Layout{ - g.Button(str, func() { + g.Button(str).OnClick(func() { fmt.Println(str, "is clicked", i) }), g.Tooltip("Tooltip for " + str), @@ -24,7 +24,7 @@ func loop() { g.Label("Below buttons are generated by RangeBuilder"), g.RangeBuilder("Buttons", []interface{}{"Button1", "Button2", "Button3"}, func(i int, v interface{}) g.Widget { str := v.(string) - return g.Button(str, func() { + return g.Button(str).OnClick(func() { fmt.Println(str, "is clicked") }) }), @@ -33,5 +33,5 @@ func loop() { func main() { wnd := g.NewMasterWindow("Range builder demo", 800, 600, 0, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/setstyle/setstyle.go b/examples/setstyle/setstyle.go index a3c137b0..dd730b5e 100644 --- a/examples/setstyle/setstyle.go +++ b/examples/setstyle/setstyle.go @@ -7,13 +7,13 @@ import ( ) func loop() { - giu.SingleWindow("set style", giu.Layout{ - giu.LabelV("I'm a styled label", false, &color.RGBA{0x36, 0x74, 0xD5, 255}, nil), + giu.SingleWindow("set style").Layout(giu.Layout{ + giu.Label("I'm a styled label").Color(&color.RGBA{0x36, 0x74, 0xD5, 255}), giu.Label("I'm a normal label"), }) } func main() { wnd := giu.NewMasterWindow("Set Style", 400, 200, giu.MasterWindowFlagsNotResizable, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/splitter/splitter.go b/examples/splitter/splitter.go index c8772d1e..f245bfb1 100644 --- a/examples/splitter/splitter.go +++ b/examples/splitter/splitter.go @@ -5,11 +5,11 @@ import ( ) func loop() { - g.SingleWindow("splitter", g.Layout{ + g.SingleWindow("splitter").Layout(g.Layout{ g.SplitLayout("Split", g.DirectionHorizontal, true, 200, g.Layout{ g.Label("Left panel"), - g.Line(g.Button("Button1", nil), g.Button("Button2", nil)), + g.Line(g.Button("Button1"), g.Button("Button2")), }, g.SplitLayout("Right panel", g.DirectionVertical, true, 200, g.Layout{}, @@ -27,5 +27,5 @@ func loop() { func main() { wnd := g.NewMasterWindow("Splitter", 800, 600, 0, nil) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/texturefiltering/texturefiltering.go b/examples/texturefiltering/texturefiltering.go index aee3180d..9adf7aff 100644 --- a/examples/texturefiltering/texturefiltering.go +++ b/examples/texturefiltering/texturefiltering.go @@ -13,46 +13,46 @@ var ( ) func loop() { - g.SingleWindow("load image", g.Layout{ - g.Group(g.Layout{ + g.SingleWindow("load image").Layout(g.Layout{ + g.Group().Layout(g.Layout{ g.Label("15x20 pixel image"), g.Line( - g.Group(g.Layout{ + g.Group().Layout(g.Layout{ g.Label("50%"), - g.Image(spriteTexture, 8, 10), + g.Image(spriteTexture).Size(8, 10), }), - g.Group(g.Layout{ + g.Group().Layout(g.Layout{ g.Label("100%"), - g.Image(spriteTexture, 15, 20), + g.Image(spriteTexture).Size(15, 20), }), - g.Group(g.Layout{ + g.Group().Layout(g.Layout{ g.Label("800%"), - g.Image(spriteTexture, 120, 160), + g.Image(spriteTexture).Size(120, 160), }), ), }), - g.Group(g.Layout{ + g.Group().Layout(g.Layout{ g.Label("215x140 image"), g.Line( - g.Group(g.Layout{ + g.Group().Layout(g.Layout{ g.Label("50%"), - g.Image(largeTexture, 215/2, 140/2), + g.Image(largeTexture).Size(215/2, 140/2), }), - g.Group(g.Layout{ + g.Group().Layout(g.Layout{ g.Label("100%"), - g.Image(largeTexture, 215, 140), + g.Image(largeTexture).Size(215, 140), }), - g.Group(g.Layout{ + g.Group().Layout(g.Layout{ g.Label("200%"), - g.Image(largeTexture, 215*2, 140*2), + g.Image(largeTexture).Size(215*2, 140*2), }), ), }), g.Line( - g.Button("Minify Filter Nearest", func() { + g.Button("Minify Filter Nearest").OnClick(func() { _ = g.Context.GetRenderer().SetTextureMinFilter(g.TextureFilterNearest) }), - g.Button("Minify Filter Linear", func() { + g.Button("Minify Filter Linear").OnClick(func() { _ = g.Context.GetRenderer().SetTextureMinFilter(g.TextureFilterLinear) }), /*g.Button("Nearest Mipmap Nearest", func() { @@ -69,10 +69,10 @@ func loop() { }),*/ ), g.Line( - g.Button("Magnify Filter Nearest", func() { + g.Button("Magnify Filter Nearest").OnClick(func() { _ = g.Context.GetRenderer().SetTextureMagFilter(g.TextureFilterNearest) }), - g.Button("Magnify Filter Linear", func() { + g.Button("Magnify Filter Linear").OnClick(func() { _ = g.Context.GetRenderer().SetTextureMagFilter(g.TextureFilterLinear) }), ), @@ -89,5 +89,5 @@ func main() { largeTexture, _ = g.NewTextureFromRgba(largeImg) }() - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/transparent/transparent.go b/examples/transparent/transparent.go index ab82b0cd..64b8a1d3 100644 --- a/examples/transparent/transparent.go +++ b/examples/transparent/transparent.go @@ -12,7 +12,7 @@ func loop() { imgui.PushStyleVarFloat(imgui.StyleVarWindowBorderSize, 0) g.PushColorWindowBg(color.RGBA{50, 50, 50, 0}) g.PushColorFrameBg(color.RGBA{10, 10, 10, 0}) - g.SingleWindow("transparent", g.Layout{ + g.SingleWindow("transparent").Layout(g.Layout{ g.Custom(func() { canvas := g.GetCanvas() pos := g.GetCursorScreenPos() @@ -46,5 +46,5 @@ func loop() { func main() { wnd := g.NewMasterWindow("transparent", 300, 200, g.MasterWindowFlagsNotResizable|g.MasterWindowFlagsFloating|g.MasterWindowFlagsFrameless|g.MasterWindowFlagsTransparent, nil) wnd.SetBgColor(color.RGBA{0, 0, 0, 0}) - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/update/update.go b/examples/update/update.go index 00a02c28..b32e5dd5 100644 --- a/examples/update/update.go +++ b/examples/update/update.go @@ -24,7 +24,7 @@ func refresh() { } func loop() { - giu.SingleWindow("Update", giu.Layout{ + giu.SingleWindow("Update").Layout(giu.Layout{ giu.Label("Below number is updated by a goroutine"), giu.Label(fmt.Sprintf("%d", counter)), }) @@ -35,5 +35,5 @@ func main() { go refresh() - wnd.Main(loop) + wnd.Run(loop) } diff --git a/examples/widgets/widgets.go b/examples/widgets/widgets.go index 537f2982..31bd7232 100644 --- a/examples/widgets/widgets.go +++ b/examples/widgets/widgets.go @@ -40,17 +40,17 @@ func btnPopupCLicked() { } func loop() { - g.SingleWindowWithMenuBar("Overview", g.Layout{ - g.MenuBar( + g.SingleWindowWithMenuBar("Overview").Layout(g.Layout{ + g.MenuBar().Layout( g.Layout{ - g.Menu("File", g.Layout{ - g.MenuItem("Open", nil), - g.MenuItem("Save", nil), + g.Menu("File").Layout(g.Layout{ + g.MenuItem("Open"), + g.MenuItem("Save"), // You could add any kind of widget here, not just menu item. - g.Menu("Save as ...", g.Layout{ - g.MenuItem("Excel file", nil), - g.MenuItem("CSV file", nil), - g.Button("Button inside menu", nil), + g.Menu("Save as ...").Layout(g.Layout{ + g.MenuItem("Excel file"), + g.MenuItem("CSV file"), + g.Button("Button inside menu"), }, ), }, @@ -58,44 +58,44 @@ func loop() { }, ), g.Label("One line label"), - g.LabelWrapped("Auto wrapped label with very long line...............................................this line should be wrapped."), + g.Label("Auto wrapped label with very long line...............................................this line should be wrapped.").Wrapped(true), g.Line( - g.InputText("##name", 0, &name), - g.Button("Click Me", btnClickMeClicked), + g.InputText("##name", &name), + g.Button("Click Me").OnClick(btnClickMeClicked), g.Tooltip("I'm a tooltip"), - g.Button("More tooltip", nil), - g.TooltipAdvance(g.Layout{ + g.Button("More tooltip"), + g.Tooltip("Advance Tooltip").Layout(g.Layout{ g.Label("I'm a label"), - g.Selectable("I'm a selectable", nil), - g.Button("I'm a button", nil), + g.Selectable("I'm a selectable"), + g.Button("I'm a button"), g.BulletText("I could be any widgets"), }), ), - g.DatePicker("Date Picker", &date, 100, func() { + g.DatePicker("Date Picker", &date).OnChange(func() { fmt.Println(date) }), g.Line( - g.Checkbox("Checkbox", &checked, func() { + g.Checkbox("Checkbox", &checked).OnChange(func() { fmt.Println(checked) }), - g.Checkbox("Checkbox 2", &checked2, func() { + g.Checkbox("Checkbox 2", &checked2).OnChange(func() { fmt.Println(checked2) }), g.Dummy(30, 0), - g.RadioButton("Radio 1", radioOp == 0, func() { radioOp = 0 }), - g.RadioButton("Radio 2", radioOp == 1, func() { radioOp = 1 }), - g.RadioButton("Radio 3", radioOp == 2, func() { radioOp = 2 }), + g.RadioButton("Radio 1", radioOp == 0).OnChange(func() { radioOp = 0 }), + g.RadioButton("Radio 2", radioOp == 1).OnChange(func() { radioOp = 1 }), + g.RadioButton("Radio 3", radioOp == 2).OnChange(func() { radioOp = 2 }), ), - g.ProgressBar(0.8, -1, 0, "Progress"), - g.DragInt("DragInt", &dragInt), - g.SliderInt("Slider", &dragInt, 0, 100, ""), + g.ProgressBar(0.8).Size(-1, 0).Overlay("Progress"), + g.DragInt("DragInt", &dragInt, 0, 100), + g.SliderInt("Slider", &dragInt, 0, 100), - g.Combo("Combo", items[itemSelected], items, &itemSelected, 0, 0, comboChanged), + g.Combo("Combo", items[itemSelected], items, &itemSelected).OnChange(comboChanged), g.Line( - g.Button("Button", nil), - g.SmallButton("SmallButton", nil), + g.Button("Button"), + g.SmallButton("SmallButton"), ), g.BulletText("Bullet1"), @@ -105,76 +105,76 @@ func loop() { g.Line( g.Label("Arrow buttons: "), - g.ArrowButton("arrow left", g.DirectionLeft, nil), - g.ArrowButton("arrow right", g.DirectionRight, nil), - g.ArrowButton("arrow up", g.DirectionUp, nil), - g.ArrowButton("arrow down", g.DirectionDown, nil), + g.ArrowButton("arrow left", g.DirectionLeft), + g.ArrowButton("arrow right", g.DirectionRight), + g.ArrowButton("arrow up", g.DirectionUp), + g.ArrowButton("arrow down", g.DirectionDown), ), g.Line( - g.Button("Popup Modal", btnPopupCLicked), - g.PopupModal("Confirm", g.Layout{ + g.Button("Popup Modal").OnClick(btnPopupCLicked), + g.PopupModal("Confirm").Layout(g.Layout{ g.Label("Confirm to close me?"), g.Line( - g.Button("Yes", func() { g.CloseCurrentPopup() }), - g.Button("No", nil), + g.Button("Yes").OnClick(func() { g.CloseCurrentPopup() }), + g.Button("No"), ), }), g.Label("Right click me to see the context menu"), - g.ContextMenu(g.Layout{ - g.Selectable("Context menu 1", contextMenu1Clicked), - g.Selectable("Context menu 2", contextMenu2Clicked), + g.ContextMenu("Context menu").Layout(g.Layout{ + g.Selectable("Context menu 1").OnClick(contextMenu1Clicked), + g.Selectable("Context menu 2").OnClick(contextMenu2Clicked), }), ), - g.TabBar("Tabbar Input", g.Layout{ - g.TabItem("Multiline Input", g.Layout{ + g.TabBar("Tabbar Input").Layout(g.Layout{ + g.TabItem("Multiline Input").Layout(g.Layout{ g.Label("This is first tab with a multiline input text field"), - g.InputTextMultiline("##multiline", &multiline, -1, -1, 0, nil, nil), + g.InputTextMultiline("##multiline", &multiline).Size(-1, -1), }), - g.TabItem("Tree", g.Layout{ - g.TreeNode("TreeNode1", g.TreeNodeFlagsCollapsingHeader|g.TreeNodeFlagsDefaultOpen, g.Layout{ + g.TabItem("Tree").Layout(g.Layout{ + g.TreeNode("TreeNode1").Flags(g.TreeNodeFlagsCollapsingHeader | g.TreeNodeFlagsDefaultOpen).Layout(g.Layout{ g.Custom(func() { if g.IsItemActive() && g.IsMouseClicked(g.MouseButtonLeft) { fmt.Println("Tree node clicked") } }), - g.Selectable("Tree node 1", func() { + g.Selectable("Tree node 1").OnClick(func() { fmt.Println("Click tree node 1") }), g.Label("Tree node 2"), g.Label("Tree node 3"), - g.Button("Button inside tree", nil), + g.Button("Button inside tree"), }), - g.TreeNodeV("TreeNode with event handler", 0, - func() { - if g.IsItemClicked(g.MouseButtonLeft) { - fmt.Println("Clicked") - } - }, + g.TreeNode("TreeNode with event handler").Layout( g.Layout{ - g.Selectable("Selectable 1", func() { fmt.Println(1) }), - g.Selectable("Selectable 2", func() { fmt.Println(2) }), - }), + g.Selectable("Selectable 1").OnClick(func() { fmt.Println(1) }), + g.Selectable("Selectable 2").OnClick(func() { fmt.Println(2) }), + }, + ).Event(func() { + if g.IsItemClicked(g.MouseButtonLeft) { + fmt.Println("Clicked") + } + }), }), - g.TabItem("ListBox", g.Layout{ - g.ListBox("ListBox1", []string{"List item 1", "List item 2", "List item 3"}, nil, nil), + g.TabItem("ListBox").Layout(g.Layout{ + g.ListBox("ListBox1", []string{"List item 1", "List item 2", "List item 3"}), }), - g.TabItem("Table", g.Layout{ - g.Table("Table", true, g.Rows{ - g.Row(g.LabelWrapped("Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog"), g.Label("Age"), g.Label("Loc")), - g.Row(g.LabelWrapped("Second Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog"), g.Label("Age"), g.Label("Loc")), + g.TabItem("Table").Layout(g.Layout{ + g.Table("Table").Rows(g.Rows{ + g.Row(g.Label("Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog").Wrapped(true), g.Label("Age"), g.Label("Loc")), + g.Row(g.Label("Second Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog").Wrapped(true), g.Label("Age"), g.Label("Loc")), g.Row(g.Label("Name"), g.Label("Age"), g.Label("Location")), g.Row(g.Label("Allen"), g.Label("33"), g.Label("Shanghai/China")), - g.Row(g.Checkbox("check me", &checked, nil), g.Button("click me", nil), g.Label("Anything")), + g.Row(g.Checkbox("check me", &checked), g.Button("click me"), g.Label("Anything")), }), }), - g.TabItem("Group", g.Layout{ + g.TabItem("Group").Layout(g.Layout{ g.Line( - g.Group(g.Layout{ + g.Group().Layout(g.Layout{ g.Label("I'm inside group 1"), }), - g.Group(g.Layout{ + g.Group().Layout(g.Layout{ g.Label("I'm inside group 2"), }), ), @@ -190,5 +190,5 @@ func main() { } w := g.NewMasterWindow("Overview", 800, 600, 0, nil) - w.Main(loop) + w.Run(loop) }