-
-
Notifications
You must be signed in to change notification settings - Fork 135
FAQ
In this chapter you find many issues, new users may face with.
Work in progress! Feel free to post any suggestions in this issue
Q: I see build constraints exclude all Go files in <some cimgui-go path>
when trying to build.
A: Check the following:
- ensure you have CGO enabled (
CGO_ENABLED=1
). Also make sure you have C/C++ compilers installed. - there was a bug for giu versions prior to v0.9.0. If your project requires giu <= v0.8.x and cimgui-go >= v1.0.0, you will experience this error. Upgrade giu to v0.9.0 or later to fix this issue.
Q: What is Master Window (giu.MasterWindow
)?
A: Master Window is a native application window in you OS.This is hosted (currently)
by GLFW. Master window is a workspace for imgui windows created by giu.
Q: Is there a way to open two (or more) Master Windows?
A: No. Current implementation does not allow to have more than one native windows in paralel.
You can however have many imgui windows.
Q: What is Run function?
A: It is the most important method of "MasterWindow".
You use this to specify, which function should be treated as loop function.
Q: So what is the loop
function?
A: This function is responsible for doing everything about imgui.
Its may task is to draw widgets that will be visible in MasterWindow.
For more details, refer to examples
Q: How to close Master Window from code?
A: There is (*MasterWindow).Close()
method. You can also use (*MasterWindow).SetShouldClose(true)
Q: How to use (*MasterWindow).SetCloseCallback
?
A: Use it before calling Run
. func() bool
argument, is a callback
called, whnever window needs to be closed (by user of via SetShouldClose).
Return value of this callback says, whether the window really should be closed.
If false
is returned, window remains opened.
Q: My app is refreshed only when I move my mouse or type something, so my constantly changing Widgets doesn't work
A: Giu implements Power Saving Mode. UI is not re-rendered if no event happens. To baypass
this, you need to call giu.Update()
whenever you want to redraw UI.
Q: What is a Window?
A: Window is a place where widgets are actually rendered.
Windows are placed inside of MasterWindow.
Q: What are the types of Windows?
A: Dear ImGui has 3 types of windows:
- Window - couldb be moved around workspace. You can have as many Windows as you wish.
- Popup - is a special kind of window. It appears only when some specified action happens (e.g. Tooltip)
- Popup Modal - when this window appears, everything else becomes grayed as long as it is open. (e.g. Yes/No dialog)
GIU separates one more window type:
- Single Window - covers whole workspace. May be used as an alternative to many Windows in simple apps.
Q: How to use popups? I can't open them anyhow...
A: Generally poups are being refactored. Some useful information you can find in
this issue.
Especially, the code here describes
a nice in use wrapper for cimgui-go popups system.
Q: I can drag my Window out of the MasterWindow! I don't want that!
A: This is a new Dear ImGui feature from the docking branch that is enabled by default in cimgui-go.
To disable it, do the following after NewMasterWindow
:
io := imgui.CurrentIO()
io.SetConfigFlags(io.ConfigFlags() & ^imgui.ConfigFlagsViewportsEnable)
Q: What is Widget?
A: Widget is a single unit of GIU system. It usually represens a single item (like button, text field)
or some more complex structure (like SplitLayout or Date Picker)
Refer to wiki.
Q: What is Layout?
A: Layout is a group of Widgets. Technically it is a widget too.
Q: How to handle double-click event on any widget?
A: To do this, you simply need to use EventHandler
giu.Button("Double-click me"),
giu.Event().OnDClick(giu.MouseButtonLeft, func() {fmt.Println("I was double clicked!")}),
Q: Is it possible to wrap text in the InputTextMultilineWidget
?
A: Unfortunately, there is no such a way implemented in giu
yet.
However there is a code written by @rasteric postend
here. You can implement
it in your project!
Q: Whats the difference between MenuBar
and MainMenuBar
?
A: You use MainMenuBar
with a standard setup when you use multiple WindowWidgets
.
However if you use SingleWindow
and you want a menubar, you should use
SingleWiowWithMenuBar
and MenuBar
.
Check out this code
package main
import "github.com/AllenDang/giu"
var singleWindow bool
func menubarLayout() giu.Widget {
return giu.Layout{
giu.Menu("File").Layout(
giu.MenuItem("Save"),
),
}
}
func loop() {
if singleWindow {
giu.SingleWindowWithMenuBar().Layout(
giu.MenuBar().Layout(menubarLayout()),
giu.Checkbox("Show single window", &singleWindow),
)
} else {
giu.MainMenuBar().Layout(
menubarLayout(),
).Build()
giu.Window("Window 1").Layout(
giu.Label("I am a window 1"),
)
giu.Window("Window 2").Layout(
giu.Label("I am a window 2"),
giu.Checkbox("Show single window", &singleWindow),
)
}
}
func main() {
wnd := giu.NewMasterWindow("Menubar usage", 640, 480, 0)
wnd.Run(loop)
}
Q: CustomWidget inside of RowWidget?
A: Generally, you should avoid using CustomWidget as long as you can, especially inside of RowWidget.
Reason for that is, that our Layout system has no control over what happens inside of the CustomWidget
.
What you need to know about RowWidget is that this widget is only a wrap for imgui.SameLine
call after each widget inside it.
The opposite to imgui.SameLine
is imgui.NewLine
which you can use to undo the effect of imgui.SameLine
if you really need it.
Here is an issue about RowWidget
Q: What is state stystem?
A: You may notice some widgets uses Context.Get/SetState
. Widgets in giu are created dynamically - every frame giu calls widget's creator e.g. giu.Button(...)
.
Some widgets (most probably your custom widgets, but some giu's widgets too) needs to store their internal data somewhere. Consider the example below.
Example
You want to create widget called CatWidget
and whenever you call Cat()
in giu.Layout
you want to see "The name of the cat is: [input field]".
To do this you can of course create a global variable for name of each cat, but assume you want to avoid createing so many global variables (we don't like them) for each of your cats (what if you have 100 cats? 🐱 🐱 🐱 ... 🐱).
You cannot do like this:
type CatWidget struct {
catName string // DON'T DO THIS
}
func Cat() CatWidget {
return CatWidget{}
}
func (c *CatWidget) Build() {
giu.Layout{
giu.Label("The name of the cat is:"),
giu.InputText(&c.catName),
}.Build()
}
you can't do this because you'd probably want to use this widget like:
giu.SingleWindow().Layout(Cat(), Cat(), Cat())
If you run the above code you'll notice, that you can't type anything in the input field. This is because every time Cat()
is called, new CatWidget
is created and catName
is empty. And this is called every frame so pretty often 😄.
This is where state system comes. Go to the next example for olution.
Q: How to use state system?
A: In short: Create struct, use Context.SetState
to set it and Context.GetState
to get it when you need.
You also need to have a unique key called ID
. Consider the next part of an example below.
Example part. 2
So, you have our cat 🐱.
now create a new struct called catState
(it does not need to be public)
type catState struct {
catName string
}
This state also needs to have a Dispose
function (explained in the next question). Our Dispose
could be empty.
func (c *catState) Dispose() {
// nothing to do here
}
Below, is a really useful code that you may really want to include in your programm:
func (w *CatWidget) getState() *catState {
if s := giu.GetState[catState](giu.Context, w.stateID()); s != nil {
return s
}
newState := w.newState()
giu.SetState(giu.Context, w.stateID(), newState)
return w.getState()
}
func (w *CatWidget) newState() *catState {
return &catState{
// initialize here
}
}
func (w *CatWidget) stateID() giu.ID {
return w.id
}
We also need to edit our CatWidget
struct in the following way:
type CatWidget struct {
id giu.ID // this should be unique for each cat
}
func Cat() *CatWidget {
return &CatWidget{
id: giu.GenAutoID("cat"), // this guarants an unique value
}
}
It is also recommended to add the following method:
func (w *CatWidget) ID(id giu.ID) *CatWidget {
w.id = id
return w
}
Because it may happen that giu.AutoID
system doesn't work as expected.
ℹ️ Alternatively you can request id
in the Cat
method but we don't recommend it.
The Build
method should look as follows:
func (c *CatWidget) Build() {
state := c.getState()
giu.Layout{
giu.Label("The name of the cat is:"),
giu.InputText(&state.catName),
}.Build()
}
Below is the whole code. Note that it also adds an example usage of newState
Full code
package main
import (
"github.com/AllenDang/giu"
)
type catState struct {
catName string
}
func (c *catState) Dispose() {
// nothing to do here
}
func (w *CatWidget) getState() *catState {
if s := giu.GetState[catState](giu.Context, w.stateID()); s != nil {
return s
}
newState := w.newState()
giu.Context.SetState(w.stateID(), newState)
return w.getState()
}
func (w *CatWidget) newState() *catState {
return &catState{
catName: w.defaultName,
}
}
func (w *CatWidget) stateID() giu.ID {
return w.id
}
type CatWidget struct {
id giu.ID // this should be unique for each cat
defaultName string
}
func Cat() *CatWidget {
return &CatWidget{
id: giu.GenAutoID("cat"), // this guarants an unique value
}
}
func (w *CatWidget) ID(id giu.ID) *CatWidget {
w.id = id
return w
}
func (w *CatWidget) DefaultName(name string) *CatWidget {
w.defaultName = name
return w
}
func (c *CatWidget) Build() {
state := c.getState()
giu.Layout{
giu.Label("The name of the cat is:"),
giu.InputText(&state.catName),
}.Build()
}
func loop() {
giu.SingleWindow().Layout(
Cat().DefaultName("Luna"),
Cat(),
Cat(),
)
}
func main() {
giu.NewMasterWindow("Cats example [state, custom widet].", 800, 600, 0).Run(loop)
}
Q: How Dispose
function works?
A: Dispose is called when state is getting removed. It happens, when it wasn't accessed in some frame.
At the beginning of the frame a bool value on all states in Context
is set to false
. During the loop call, whenever GetState
is called on a specific
state this bool is set to true
. At the end of the frame, bools are checked and if some state still has false
it gets removed.
If you find anything you'd like to talk about in reference to this wiki, Don't hesitate to hit dedicated Discussion