Skip to content
Allen Dang edited this page Sep 4, 2021 · 18 revisions

Welcome to the giu wiki!

giu is a immediate mode gui framework. Immediate mode gui is a concept of "GUI widgets doesn't retain any internal state", as a oppsite concept of retain mode gui (Qt, WxWidget, etc...).

Layout

giu uses a declerative layout system.

First of all, let's see giu.Widget interface.

type Widget interface {
  Build()
}

It defines a single method named "Build", which will be used to create the widget.

And the sencond concept is giu.Layout which is a simple []giu.Widget. It also implements the Widget interface and in it's Build method it will invoke Build method of all the widgets it contains.

So the layout system is very simple and easy to understand.

Each element of a giu.Layout will be place in a line.

If you want to place multiple widgets one next to another in a same line, use giu.Line widget.

With this system, if you want to create a part of UI dynamically, just create function returns giu.Layout or giu.Widget.

Split Layout

To create live resizing split layout (horizontal or vertical), check examples/splitter.

Split Layout Demo

Widgets

Most of the widgets are easy to understand by seeing it's function signiture.

If you want to know more about how to use a specified widget, check examples/widgets/, it contains the usage of all widgets.

To create custom widget, check examples/customwidget

To create a custom widget which needs to maintain it's own state, check ProgressIndicator, here is the demo examples/extrawidgets.

Another thing need to mention is the id of a interactable widget (button, InputText, selectable, etc...) should be unique.

To avoid the label becomes hard to read, add "##" in id string, any string after "##" will not be rendered, but still read a id.

For example, "Button##1", will be rendered as "Button". "##Button1" will be rendered as "".

Create widgets from loop

Use giu.RangeBuilder.

layout := g.Layout {
  g.RangeBuilder("Buttons", []interface{}{"Button1", "Button2", "Button3"}, func(i int, v interface{}) g.Widget {
    str := v.(string)
    return g.Button(str, func() {
      fmt.Println(str, "is clicked")
    })
  })
}

Event handling

To check key/mouse events against specified widget, place giu.Event() below the widget.

// Create a button
giu.Button("Click Me")
// Place the event handling APIs right after the button to capture key/mouse events.
giu.Event().OnDClick(func() {
    // Do event handling here. 
}

The tooltip and context menu works in the same way.

Multi-thread handling

giu.Call, giu.CallErr, giu.CallVar is provided to invoke GUI creation related code in another goroutine.

Since giu has a mechanism to only redraw the GUI when user events (keyboard/mouse) occurred, so if you update a variable in a goroutine, call giu.Update() to inform GUI to redraw immediately.

Check examples/update

Note that giu.NewTextureFromRgba should be called in a new goroutine to keep GUI alive.

Dialog

Messagebox

To use giu.Msgbox, you will need to embed giu.PrepareMsgbox in the end of the window layout.

giu.SingleWindow("Msgbox demo", giu.Layout{
  // You layout.
  ...
  giu.PrepareMsgbox(),
})

After that, you could invoke giu.Msgbox at anywhere to display a message box.

Custom dialogs

Use giu.PopupModal to build a custom dialog, and use giu.OpenPopup and giu.CloseCurrentPopup to control it.

OS related dialogs

If you need OS related dialogs like OpenFileDialog, SaveDialog and etc, check sqweek/dialog, it provides cross platform dialogs.

Drawing

Check examples/canvas for usage.

Font related

Check examples/dynamicfont for usage.

To use several fonts, do it like this:

var (
  font1 imgui.Font
  font2 imgui.Font
)
func initFont() {
  fonts := giu.Context.IO().Fonts()
  font1 = fonts.AddFontFromFileTTFV(
      "/System/Library/Fonts/STHeiti Light.ttc", <- Font file path
      14,                                        <- Font size
      imgui.DefaultFontConfig,                   <- Usually you don't need to modify this
      fonts.GlyphRangesChineseFull())            <- Add Chinese glyph ranges to display chinese characters

  font2 = fonts.AddFontFromFileTTFV(
      "/System/Library/Fonts/STHeiti Light.ttc", 
      24,
      imgui.DefaultFontConfig,
      fonts.GlyphRangesDefault())               <- Add a big font for ASCII
}

func loop() {
  ...
  giu.PushFont(font2)
  giu.Label("I'm a label with big font")
  giu.PopFont()
  ...
}

Style related

TBD

Deployment

Build Windows executable from MacOS

  1. Install mingw-w64. brew install mingw-w64

  2. Create a build script in your project's root, say build_win.sh like below, change the app icon path and YourExeName.

cat > YourExeName.rc << EOL
id ICON "./res/app_win.ico"
GLFW_ICON ICON "./res/app_win.ico"
EOL

x86_64-w64-mingw32-windres YourExeName.rc -O coff -o YourExeName.syso

GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ HOST=x86_64-w64-mingw32 go build -ldflags "-s -w -H=windowsgui -extldflags=-static" -p 4 -v -o YourExeName.exe

rm YourExeName.syso
rm YourExeName.rc
  1. Set build_win.sh to be executable.
chmod +x ./build_win.sh
  1. Run /.build_win.sh.
Clone this wiki locally