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
null
before 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
visible
can 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
onTimer
to 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 returntrue
if 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
onKey
events as usual, but will not produce aonChar
event 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 locationat
in 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
setTimer
has 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:
create
must 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:
create
must 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.
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
Frame
s, the dialog is not shown untilshow
is called. -
init(core.Str title, core.geometry.Size size)
Create the dialog. As with
Frame
s, the dialog is not shown untilshow
is called. -
core.Int show(ui.Frame parent)
Show the dialog as a modal window. Don't call
create
before callingshow
, that is handled internally. Returns whatever is passed toclose
by 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.Label
A simple piece of text displayed in the window.
-
ui.Edit
A simple box that allows simple text editing.
-
ui.Button
A button that can be pressed by the user.
-
ui.CheckButton
A checkmark that can be selected or deselected.
-
ui.RadioButton
A 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.ListView
A component that shows a scrollable list. The list may contain columns with different contents.
-
ui.ScrollWindow
Provides a viewport to another window, where the user can scroll the contents of the other window.
-
ui.TabView
Provides a set of tabs, where the user can select one out of many possible views.
Additionally, the UI library provides the following convenience interfaces:
-
ui.FilePicker
Provides access to the operating system's default open/save dialogs.
-
ui.MessageDialog
Default 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.