Runtime and Lifetime
A UIng application creates its controls between UIng.init and UIng.main.
The main loop then waits for native events and invokes the callbacks registered
by the application.
Application lifecycle
UIng.initinitializes libui-ng.window.showmakes a completed window visible.UIng.mainruns the native event loop.UIng.quitasks that loop to stop.UIng.uninitreleases application-wide resources after the loop ends.
Make sure to call UIng.uninit after UIng.main so the matching
UIng.uninit is not forgotten:
UIng.init
# Build and show the interface here.
UIng.main
UIng.uninit
UIng.init also accepts a block. In that form, UIng.uninit is called
automatically after the event loop returns:
UIng.init do
# Build and show the interface here.
UIng.main
end
Closing a single window
Normally, you do not need to destroy controls yourself. Stop the event loop
and return true from on_closing; libui-ng destroys the Window and its
children.
window.on_closing do
UIng.quit
true
end
Do not call window.destroy in this callback.
Control ownership
Some controls contain other controls. The containing control is the parent, and an attached control is its child. Destroying a parent automatically destroys all of its children, so normally only the top-level parent needs to be destroyed.
window = UIng::Window.new("App", 400, 300)
box = UIng::Box.new(:vertical)
button = UIng::Button.new("OK")
box.append(button)
window.child = box
window.destroy # also destroys box and button
UIng marks the Crystal wrappers for those children as released. They cannot be used after their parent is destroyed.
Detach a child before reusing it elsewhere:
button.detach
other_box.append(button)
Detach a child before destroying it individually:
button.detach
button.destroy
Calling destroy on an attached child raises an exception and leaves the
child intact.
WindowandGrouphave one child. Assigningnilor a new child detaches the old child without destroying it.Box,Form,Tab, andGridsupportdelete(child);Box,Form, andTabalso supportdelete(index).- A control without a parent can be destroyed directly.
Closing a window or application
UIng.quit stops the event loop; it does not destroy windows. UIng.uninit
releases application-wide resources but does not destroy windows created by
the application. Make sure every top-level window has been destroyed before
calling UIng.uninit.
Window#on_closing handles the close button. Return true to close the
Window or false to keep it open. With multiple Windows, do not call
UIng.quit unconditionally whenever one Window closes.
UIng.on_should_quit handles application-wide requests such as a Quit menu.
Destroy every top-level Window, then return true:
UIng.on_should_quit do
window.destroy unless window.released?
true
end
For multiple Windows, repeat this for every top-level Window. released?
prevents double destruction.
Other resources
Objects that are not controls follow the cleanup convention associated with how they were obtained:
- An object created with
.newor returned directly from a method usually needs to be freed after use. - An object used through
.openor another block form is freed automatically when the block ends. - An object passed to a callback is usually valid only until that callback returns; UIng handles its cleanup.
Specific resource rules are:
Table::Model: request destruction of allTablecontrols using the model before callingmodel.free. If native destruction is pending, the wrapper becomes unavailable immediately and the native model is freed after the last Table destruction completes.Image: callfreewhen it is no longer needed. It can be freed after passing it toImageView#image=, but must remain alive while a table orToolbaruses it.Toolbar: detach it from its window before callingfree.Draw::Path,Draw::TextLayout, andAttributedString: prefer.openwhere available so cleanup occurs when the block ends.Table::Selection: block and callback forms free the selection automatically. A directtable.selectionresult must be freed after use.Table::Selection.new(rows)is managed by Crystal's GC.Table::Value: a value returned fromcell_valueis managed by libui-ng. A value passed toset_cell_valueis valid only until that callback returns.Attribute: afterset_attribute, the receivingAttributedStringowns it. An attribute yielded by enumeration is valid only for that block.OpenTypeFeaturesandAttributedStringmay be read recursively during enumeration, but cannot be freed or structurally modified until enumeration finishes.- A draw context is valid only during its draw callback.
Calling destroy or free makes the corresponding wrapper unavailable for
further use.