Windows
The window management part of the UI library is built around windows, containers, frames, and dialogs. In the context of the UI library, a window is a rectangle on the screen. It is typically embedded inside another window to represent some component, such as a button. A container is a window that may contain other child windows. A frame is a container that has a border, and can be used as a top-level window. As such, the root of a window hierarchy is typically a frame, not a window. Finally, a dialog is a frame that might have a parent frame (i.e. it is displayed "on top of" another window).
The terminology above follows the naming in the Windows API (which is what the UI library was initially developed for). Gtk uses other terms. Gtk uses the term widget for what the UI library calls a window.
Each of these central classes are documented in more detail below. This page of the manual then concludes with an overview of the different UI components.
Threading
All operations on windows happen on the ui.Ui thread. All components described in this
section are thereby actors that are tied to this thread.
The ui.Ui thread is in charge of interfacing with the operating system. As such, it is a
good idea to not block the Ui thread if possible. In Basic Storm, this is fairly easy by using the
spawn keyword to create another thread. It is generally sufficient if the thread that called a
callback function returns to the caller quickly, even if another UThread is spawned on the same OS
thread. However, care should be taken not to execute heavy computations on the Ui thread without
periodically calling yield to let the UI library process messages from the operating system.
Computationally expensive operations are therefore typically better to delegate to other OS threads
entirely.
Usage
The UI library is designed with the intent that the core classes (i.e. Window, Container,
Frame, and Dialog) should be subclassed to create custom windows. As such, most events from the
windowing system are notified in the form of overloaded functions. Other components (e.g. Button)
are not designed to be subclassed, and instead provide callbacks in the form of function pointers.
This means that creating a custom window or dialog typically involves creating a subclass to Frame
or Dialog as desired, and let the subclass create all child components, and listen for callbacks
from them using callbacks from function pointers.
Creation of Windows
Due to restrictions in the underlying APIs, it is not always possible to create individual windows
without first creating their parents. In order to not restrict the UI library needlessly, the UI
library does not impose such restrictions (e.g. it is possible to create a Button without first
creating a parent Window). This does, however, mean that the UI library creates the actual windows
lazily, whenever the classes are attached to a parent.
In most cases, this is transparent to the user. It does, however, mean that some features (such as
focus management) may not be fully functional until the windows have actually been created (Gtk uses
the term realized to describe this). It also means that some care needs to be taken for top-level
windows, since they do not have a parent. The UI library thus requires top-level windows to be
explicitly created by calling the create member. This creates the entire window in one operation,
and has the benefit that it lets the underlying system present the window as a unit, and avoid
partially drawn windows as far as possible.
This model also means that the system can clean up any resources associated with the created windows as soon as the top-level window is closed. It is therefore not necessary to explicitly destroy windows, as long as the top-level window is closed.
Window
As mentioned above, a ui.Window is a rectangular region on the screen. By itself it
represents a window that has to be embedded inside another window. However, the subclass
ui.Frame lifts this restriction.
Coordinates in a window are always relative to the top-left edge of the window. The exception is the
coordinates returned by pos, which are relative to the window's parent.
The Window class has the following members:
-
init()Create an empty window.
-
core.Maybe<ui.ContainerBase> parent()Get the parent window. Null for frames.
-
core.Maybe<ui.Frame> rootFrame()Get the frame that is in the root of the hierarchy. Returns ourself for frames, returns
nullbefore attached. -
core.Bool visible()Check if the window is visible.
-
void visible(core.Bool show)Set if the window is visible or not. Assignment function, so
visiblecan be used as a member variable. -
core.Bool enabled()Check if the window is enabled.
-
void enabled(core.Bool enable)Set if the window is enabled. Generally only interesting to do for leaf windows. Assignment function, so it can be used as a member variable.
-
core.Str text()Get the window text. How this text is used depends on the window.
-
void text(core.Str str)Set the window text. Assignment function, so it can be used as a member variable.
-
core.geometry.Rect pos()Get the window position. Always relative to the client area of the parent (even in Frames).
-
void pos(core.geometry.Rect r)Set the window position.
-
core.geometry.Size minSize()Get the minimum size for this window. Note: This does not consider the size and position of any child windows in case this is a container. This function is mostly useful for determining the preferred size for various windows.
-
ui.Font font()Get the current font.
-
void font(ui.Font font)Set the current font. Assignment function, so it can be used as a member variable.
-
void focus()Set focus to this window.
-
void update()Update the window (ie repaint it) right now.
-
void repaint()Repaint the window when we have time.
-
void resized(core.geometry.Size size)Called when the window is resized.
-
void resized()Convenience function to trigger uptade of layouts easily.
-
void painter(core.Maybe<ui.Painter> to)Set window contents (custom drawing).
-
core.Maybe<ui.Painter> painter()Get the current painter.
-
void setTimer(core.Duration interval)Set the window timer. Causes
onTimerto be called regularly. -
void clearTimer()Stop timer.
The Window class also has a number of callbacks that are called when certain events occur. These
are member functions that can be overloaded by a subclass. Many of the functions return a boolean.
This indicates if the handler recognized the event, and signals to the UI library that the event
should not be processed further (e.g. by parent windows).
-
core.Bool onKey(core.Bool pressed, ui.Key keycode, ui.Modifiers modifiers)Called when a key is pressed or released (depending on
pressed). Should returntrueif the keypress was recognized and should not propagate further. -
core.Bool onChar(core.Nat charCode)Called when a key has been typed. Note that this is sometimes different from a key press event. A typical example is a dead key. The dead key will produce
onKeyevents as usual, but will not produce aonCharevent until the next keypress, when it might be combined with the next character. Another example is when using an IME. -
core.Bool onClick(core.Bool pressed, core.geometry.Point at, ui.MouseButton button)Called when a mouse button has been pressed or released (depending on
pressed) at the locationatin the window. -
core.Bool onDblClick(core.geometry.Point at, ui.MouseButton button)Called when a mouse button has been double-clicked in the window.
-
core.Bool onMouseMove(core.geometry.Point at)Called whenever the mouse is moved in the window.
-
void onMouseEnter()Called when the mouse entered this window. The mouse is considered to be inside the window only for as long as the mouse is directly on top of the window. For example, if the mouse moves over a child window, the mouse is no longer considered to be inside of this window.
-
void onMouseLeave()Called when the mouse has left this window.
-
core.Bool onMouseVScroll(core.geometry.Point at, core.Int delta)Called when the mouse has been scrolled in the vertical direction.
-
core.Bool onMouseHScroll(core.geometry.Point at, core.Int delta)Called when the mouse has been scrolled in the horizontal direction.
-
void onTimer()Called regularly if the
setTimerhas been called to start the timer.
Container
The ui.Container class is a subclass of the Window class and represents a window that
may contain child windows. To achieve this, the Container class provides the following additional
functions:
-
void add(ui.Window child)Add a child window. This may actually create it!
-
void remove(ui.Window child)Remove a child window. Silently fails if the child does not already exist.
Frame
The ui.Frame class represents a top-level window that can be a parent of a window
hierarchy. It inherits from the Container class and may therefore contain sub-windows. Since the
frame does not have a parent, it needs to be created manually. This is achieved with the create
function.
The Frame provides the following member functions:
-
init(core.Str title)Create a frame, specifying a window title. Note:
createmust be called to create the frame. -
init(core.Str title, core.geometry.Size size)Create a frame, specifying a window title and an initial size. Note:
createmust be called to create the frame. -
void create()Create the frame and show it.
-
void close()Close this frame.
-
void waitForClose()Wait until this frame is closed.
-
void size(core.geometry.Size s)Set the size of the frame.
-
void fullscreen(core.Bool f)Set fullscreen mode.
-
core.Bool fullscreen()Get fullscreen mode.
-
void cursorVisible(core.Bool v)Set if the cursor is visible when over this frame.
-
core.Bool cursorVisible()Get if the cursor is visible when over this frame.
-
ui.Accelerators accelerators()Get the accelerator table for this window.
-
void menu(core.Maybe<ui.MenuBar> menu)Set the menu for this window.
-
core.Maybe<ui.MenuBar> menu()Get the menu for this window.
-
void popupMenu(ui.PopupMenu menu)Show a popup menu at the cursor position. This menu may be a part of another menu.
-
core.Bool minimized()Check if the window is minimized (note that the window is still considered visible if minimized).
-
core.Maybe<ui.Icon> icon()Get/set the current icon. If null, we use the default icon set in the application itself.
-
void icon(core.Maybe<ui.Icon> icon)Get/set the current icon. If null, we use the default icon set in the application itself.
-
void icon(graphics.ImageSet icon)Get/set the current icon. If null, we use the default icon set in the application itself.
-
core.Bool inhibitScreenSaver()Inhibit the screen saver while this window is visible on the screen (= not minimized). Useful for applications that e.g. play video, where the screen should stay on even though not much user interaction is expected.
-
void inhibitScreenSaver(core.Bool inhibit)Inhibit the screen saver while this window is visible on the screen (= not minimized). Useful for applications that e.g. play video, where the screen should stay on even though not much user interaction is expected.
A note on icons: The global ui.App instance (accessible by calling ui.App app())
allows setting a default icon for the entire application. That way one can avoid setting icons on
individual windows manually. When loading icons, prefer to use loadSet and ImageSet whenever
possible, so that the windowing system can pick an appropriate size based on where the icon will
appear. The Graphics library automatically loads .ico
files into the name tree, so that the application's icon can be conveniently stored alongside its
source code and be easily accessible by the application.
Dialog
The class ui.Dialog class represents a frame that acts as a dialog. This means two
things: first, a dialog may have a default behavior for the enter and escape keys (typically OK and
Cancel respectively). Secondly, the dialog may be a modal dialog that blocks access to another
window.
It provides the following members:
-
init(core.Str title)Create the dialog. As with
Frames, the dialog is not shown untilshowis called. -
init(core.Str title, core.geometry.Size size)Create the dialog. As with
Frames, the dialog is not shown untilshowis called. -
core.Int show(ui.Frame parent)Show the dialog as a modal window. Don't call
createbefore callingshow, that is handled internally. Returns whatever is passed tocloseby the implementation, or -1 if the dialog was closed (or cancelled by a default button). -
void close(core.Int result)Call when the window is shown to close the dialog with a particular code.
-
void close()Override the default behavior to return -1.
-
void defaultChoice(ui.Button button)Set the button that acts as the default choice in this dialog. This button will be activated whenever "enter" is pressed. The button's handler will also be set by the implementation to return 1, but this may be overridden by the user at a later point if desired.
-
void onDestroy(core.Int code)Called when the dialog is about to be closed to give the implementation time to save things before they are destroyed.
Other Components
The UI library provides a number of UI components as follows:
-
ui.LabelA simple piece of text displayed in the window.
-
ui.EditA simple box that allows simple text editing.
-
ui.ButtonA button that can be pressed by the user.
-
ui.CheckButtonA checkmark that can be selected or deselected.
-
ui.RadioButtonA button that can be associated with a group of similar buttons. Only allows one button in the group to be selected at any one time.
-
ui.ListViewA component that shows a scrollable list. The list may contain columns with different contents.
-
ui.ScrollWindowProvides a viewport to another window, where the user can scroll the contents of the other window.
-
ui.TabViewProvides a set of tabs, where the user can select one out of many possible views.
-
ui.GroupA box that draws a box around its contents, optionally with a label. Used to group other components together.
-
ui.HSeparator,ui.VSeparatorHorizontal and vertical separator lines.
Additionally, the UI library provides the following convenience interfaces:
-
ui.FilePickerProvides access to the operating system's default open/save dialogs.
-
ui.MessageDialogDefault message dialogs. Use any of the following functions to easily create message dialogs:
-
void showMessage(ui.Frame parent, core.Str title, core.Str message)Show a notification. I.e. a box with only OK.
-
ui.MessageResponse showYesNoQuestion(ui.Frame parent, core.Str title, core.Str message, core.Str yes, core.Str no)Show a yes-no question.
-
ui.MessageResponse showYesNoCancelQuestion(ui.Frame parent, core.Str title, core.Str message, core.Str yes, core.Str no, core.Str cancel)Show a yes-no-cancel question.
-
-
void ui.showLicenseDialog(ui.Frame owner, ui.ProgramInfo info)Show a default dialog that contains the licenses of all currently used libraries. Useful to conveniently comply with requirements in license agreements for GUI applications.
