diff --git a/Alignment.go b/Alignment.go index f961f224..f48b949d 100644 --- a/Alignment.go +++ b/Alignment.go @@ -24,10 +24,9 @@ type AlignmentSetter struct { // Align sets widgets alignment. // usage: see examples/align // -// FIXME: DONOT put giu widgets inside of CustomWidget function in -// Align setter. CustomWidgets will be skip in alignment process -// -// BUG: DatePickerWidget doesn't work properly +// - BUG: DatePickerWidget doesn't work properly +// - BUG: there is some bug with SelectableWidget +// - BUG: ComboWidget and ComboCustomWidgets doesn't work properly func Align(at AlignmentType) *AlignmentSetter { return &AlignmentSetter{ alignType: at, @@ -53,34 +52,28 @@ func (a *AlignmentSetter) Build() { return } - // WORKAROUND: get widgets widths rendering them with 100% transparency - // to align them later a.layout.Range(func(item Widget) { // if item is inil, just skip it if item == nil { return } - // exclude some widgets from alignment process - // nolint:gocritic // could have more cases later switch item.(type) { + // ok, it doesn't make sense to align again :-) + case *AlignmentSetter: + item.Build() + return case *CustomWidget: item.Build() return + // there is a bug with selectables and combos, so skip them for now + case *SelectableWidget, *ComboWidget, *ComboCustomWidget: + item.Build() + return } - // save cursor position before rendering currentPos := GetCursorPos() - - // render widget in `dry` mode - imgui.PushStyleVarFloat(imgui.StyleVarAlpha, 0) - item.Build() - imgui.PopStyleVar() - - // save widget's width - size := imgui.GetItemRectSize() - w := size.X - + w := GetWidgetWidth(item) availableW, _ := GetAvailableRegion() // set cursor position to align the widget @@ -99,3 +92,61 @@ func (a *AlignmentSetter) Build() { item.Build() }) } + +// GetWidgetWidth returns a width of widget +// NOTE: THIS IS A BETA SOLUTION and may contain bugs +// in most cases, you may want to use supported by imgui GetItemRectSize. +// There is an upstream issue for this problem: +// https://github.com/ocornut/imgui/issues/3714 +// +// This function is just a workaround used in giu. +// +// NOTE: user-definied widgets, which contains more than one +// giu widget will be processed incorrectly (only width of the last built +// widget will be processed) +// +// here is a list of known bugs: +// - BUG: Custom widgets are skipped, so if user put some widgets +// inside of CustomWidget, its sizes will not be returned +// +// if you find anything else, please report it on +// https://github.com/AllenDang/giu Any contribution is appreciated! +func GetWidgetWidth(w Widget) (result float32) { + // save cursor position before rendering + currentPos := GetCursorPos() + // enumerate some special cases + switch typed := w.(type) { + // Don't process custom widgets + case *CustomWidget: + return 0 + // when row, sum all widget's sizes (adding spacing) + case *RowWidget: + isFirst := true + typed.widgets.Range(func(r Widget) { + result += GetWidgetWidth(r) + if !isFirst { + spacing, _ := GetItemSpacing() + result += spacing + } else { + isFirst = false + } + }) + return result + // panic if layout - cannot calculate width of multiple widgets + case Layout, *Layout: + panic("GetWidgetWidth: requires Widget argument, but []Widget (Layout) got") + default: + // render widget in `dry` mode + imgui.PushStyleVarFloat(imgui.StyleVarAlpha, 0) + w.Build() + imgui.PopStyleVar() + + // save widget's width + size := imgui.GetItemRectSize() + result = size.X + } + + SetCursorPos(currentPos) + + return result +} diff --git a/examples/align/align.go b/examples/align/align.go index 55b7abcf..76b4de32 100644 --- a/examples/align/align.go +++ b/examples/align/align.go @@ -24,6 +24,13 @@ func loop() { }, giu.Label("I'm the last label"), ), + giu.Label("Buttons in row:"), + giu.Align(giu.AlignCenter).To( + giu.Row( + giu.Button("button 1"), + giu.Button("button 2"), + ), + ), ) }