diff --git a/Alignment.go b/Alignment.go index 477c9f9b..51fae50e 100644 --- a/Alignment.go +++ b/Alignment.go @@ -32,18 +32,7 @@ type AlignmentSetter struct { // ) // will print the message two times per frame. // -// BUG: -// if the source layout (set by (*alignSetter).To(...) contains another Layout -// only the last widget from the embeded layout will be processed. -// Example: -// Align(AlignToRight).To( -// Label("I'm the label"), -// Layout( -// Label("I'm th e other label and I'll not be aligned to right"), -// Label("I'm the next label"), -// ), -// label("I'm the last label"), -// ) +// BUG: DatePickerWidget doesn't work properly func Align(at AlignmentType) *AlignmentSetter { return &AlignmentSetter{ alignType: at, @@ -74,7 +63,7 @@ func (a *AlignmentSetter) Build() { // render widgets with 0 alpha and store thems widths imgui.PushStyleVarFloat(imgui.StyleVarID(StyleVarAlpha), 0) - for _, item := range a.layout { + a.layout.Range(func(item Widget) { var width float32 if item != nil { item.Build() @@ -83,19 +72,20 @@ func (a *AlignmentSetter) Build() { } widgetsWidths = append(widgetsWidths, width) - } + }) imgui.PopStyleVar() // reset cursor pos SetCursorPos(startPos) // ALIGN WIDGETS - for i, item := range a.layout { + idx := 0o0 + a.layout.Range(func(item Widget) { if item == nil { - continue + return } - w := widgetsWidths[i] + w := widgetsWidths[idx] currentPos := GetCursorPos() availableW, _ := GetAvailableRegion() switch a.alignType { @@ -110,5 +100,7 @@ func (a *AlignmentSetter) Build() { } item.Build() - } + + idx++ + }) } diff --git a/Layout.go b/Layout.go index 6dcf863f..85703895 100644 --- a/Layout.go +++ b/Layout.go @@ -9,7 +9,10 @@ type Widget interface { Build() } -var _ Widget = Layout{} +var ( + _ Widget = Layout{} + _ Splitable = Layout{} +) type Layout []Widget @@ -20,3 +23,22 @@ func (l Layout) Build() { } } } + +// Splitable is implemented by widgets, which can be split (ranged) +// Layout implements Splitable. +type Splitable interface { + Range(func(w Widget)) +} + +// Range ranges ofer the Layout, calling rangeFunc +// on each loop iteration. +func (l Layout) Range(rangeFunc func(Widget)) { + for _, w := range l { + if splitable, canRange := w.(Splitable); canRange { + splitable.Range(rangeFunc) + continue + } + + rangeFunc(w) + } +} diff --git a/README.md b/README.md index 4d7ea896..2c51a315 100644 --- a/README.md +++ b/README.md @@ -24,20 +24,20 @@ giu is built upon GLFW v3.3, so ideally giu could support all platforms that GLF - Windows (Windows 10 x64 and Windows 11 x64) - macOS (macOS v10.15 and macOS Big Sur) -- Linux (thanks remeh to test it) -- Raspberry Pi 3B (thanks sndvaps to test it) +- Linux (thanks remeh for testing it) +- Raspberry Pi 3B (thanks sndvaps for testing it) ## Features -Compare to other Dear ImGui golang bindings, giu has following features: +Compared to other Dear ImGui golang bindings, giu has the following features: - Small executable file size (<3MB after UPX compression for the example/helloworld demo). -- Live-updating during the resizing of OS window (implemented on GLFW 3.3 and OpenGL 3.2). +- Live-updating during the resizing of the OS window (implemented on GLFW 3.3 and OpenGL 3.2). - Support for displaying various languages without any font setting. Giu will rebuild font atlas incrementally according to texts in UI between frames. -- Redraws only when user event occurred. Costs only 0.5% CPU usage with 60FPS. -- Declarative UI (see examples for more detail). -- DPI awareness (auto scaling font and UI to adapt high DPI monitor). -- Drop in usage, no need to implement render and platform. +- Redraws only when user event occurs. Costs only 0.5% CPU usage with 60FPS. +- Declarative UI (see examples for more details). +- DPI awareness (auto scaling font and UI to adapt to high DPI monitors). +- Drop in usage; no need to implement render and platform. - OS clipboard support. ![Screenshot](https://github.com/AllenDang/giu/raw/master/examples/imguidemo/screenshot.png) @@ -79,11 +79,11 @@ func main() { } ``` -Here is result: +Here is the result: ![Helloworld](https://github.com/AllenDang/giu/raw/master/examples/helloworld/helloworld.png) -## Quick intruduction +## Quick introduction ### What is immediate mode GUI? @@ -95,21 +95,21 @@ And the `loop` method in the _Hello world_ example is in charge of **drawing** a By default, any widget placed inside a container's `Layout` will be placed vertically. -To create a row of widgets (aka place widgets one by one horizontally), use the `Row()` method. For example `giu.Row(Label(...), Button(...))` will create a Label next to a Button. +To create a row of widgets (i.e. place widgets one by one horizontally), use the `Row()` method. For example `giu.Row(Label(...), Button(...))` will create a Label next to a Button. -To creata a column of widgets (aka place widgets one by one vertically) inside a row, use the `Column()` method. +To create a column of widgets (i.e. place widgets one by one vertically) inside a row, use the `Column()` method. -Any widget that has a `Size()` method, could set its size explicitly. Note that you could pass a negative value to `Size()`, which will fill the remaining width/height value. For example, `InputText(...).Size(giu.Auto)` will create a input text box with longest width that its container has left. +Any widget that has a `Size()` method, can set its size explicitly. Note that you can pass a negative value to `Size()`, which will fill the remaining width/height value. For example, `InputText(...).Size(giu.Auto)` will create an input text box with the longest width that its container has left. ### Containers #### MasterWindow -A `MasterWindow` means the platform native window implemented by OS. All subwindows and widgets will be placed inside it. +A `MasterWindow` means the platform native window implemented by the OS. All subwindows and widgets will be placed inside it. #### Window -A `Window` is a container with a title bar, and can be collapsed. `SingleWindow` is a special kind of window that will occupy all available space of `MasterWindow`. +A `Window` is a container with a title bar, and can be collapsed. `SingleWindow` is a special kind of window that will occupy all the available space of `MasterWindow`. #### Child @@ -121,7 +121,7 @@ Check `examples/widgets` for all kinds of widgets. ## Install -The backend of giu depends on OpenGL 3.3, make sure your environment supports it (so far as I known some Virtual Machines like VirualBox doesn't support it). +The backend of giu depends on OpenGL 3.3, make sure your environment supports it (as far as I know, some Virtual Machines like VirtualBox doesn't support it). ### MacOS @@ -140,7 +140,7 @@ Or, install [TDM-GCC](https://jmeubank.github.io/tdm-gcc/). ### Linux -First you need to install required dependencies: +First you need to install the required dependencies: ```bash # apt install libx11-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libglx-dev libgl1-mesa-dev libxxf86vm-dev @@ -148,7 +148,7 @@ First you need to install required dependencies: Then, a simple `go build` will work. -Cross-compiling is a bit more complicated. Let's say that you want to build for arm64. That's what you would need to do: +Cross-compiling is a bit more complicated. Let's say that you want to build for arm64. This is what you would need to do: ```bash # dpkg --add-architecture arm64 @@ -180,7 +180,7 @@ go build -ldflags "-s -w -H=windowsgui -extldflags=-static" . brew install mingw-w64 ``` -2. Prepare and embed application icon to executable and build. +2. Prepare and embed the application icon into the executable and build. ```sh cat > YourExeName.rc << EOL @@ -201,4 +201,4 @@ Check [Wiki](https://github.com/AllenDang/giu/wiki) ## Contribution -All kinds of pull request (document, demo, screenshots, code, etc.) are more then welcome! +All kinds of pull requests (document, demo, screenshots, code, etc.) are more than welcome! diff --git a/examples/align/align.go b/examples/align/align.go index 1a0f1ada..cdc2099f 100644 --- a/examples/align/align.go +++ b/examples/align/align.go @@ -15,6 +15,15 @@ func loop() { giu.Label("I'm a alined to right label"), giu.InputText(&text), ), + + giu.Align(giu.AlignRight).To( + giu.Label("I'm the label"), + giu.Layout{ + giu.Label("I'm th e other label embeded in another layout"), + giu.Label("I'm the next label"), + }, + giu.Label("I'm the last label"), + ), ) }