NAME
TUI::Manual::06 - Windows and Dialogs in TUI::Vision
WINDOWS AND DIALOGS
Most interactive work in a TUI::Vision application takes place within windows and dialogs.
Unlike menu bars and status lines, which form a permanent application framework, windows and dialogs occupy the desktop and represent the working environments of an application. They provide the space in which views are combined to create user interfaces, display data and interact with the user.
Although they often appear similar on screen, windows and dialogs are designed for different purposes. A window typically provides a persistent workspace, while a dialog usually accompanies a specific interaction such as entering data, changing options or confirming an operation.
Both build upon the same view architecture and share many of the same mechanisms. Understanding how they relate to one another is key to understanding how TUI::Vision applications are assembled from smaller views.
Windows as View Containers
A TWindow is much more than a rectangular area on the desktop. While it provides a frame, a title and the controls required for moving, resizing and managing a window, its primary purpose is to act as a container for other views.
Unlike TDesktop, TMenuBar and TStatusLine, which exist as permanent parts of the application framework, windows provide workspaces in which application-specific functionality is assembled from smaller building blocks.
A typical window might appear as follows:
Icon
╔═[■]══════════════ Title ═══════════════[↑]═╗
║ ▲
║ ▒
║ ▒
║ ▒ TScrollBar
║ ▒
║ ■
║ ▒
║ ▼
╚═══════════════════════════════════════════─┘
Frame
Viewed as a single screen element, this appears to be an ordinary window containing scrollable text. Internally, however, the visible result is typically composed from several cooperating views.
TWindow
|
+-- Window Frame
| |
| +-- Title
| +-- Number
| +-- Icon
| +-- Zoom Indicator
|
+-- TScroller
|
+-- TScrollBar (horizontal)
+-- TScrollBar (vertical)
It is useful to distinguish between the visual elements provided by the window itself and the additional views inserted into the window.
The frame, title and icon are part of the window representation and are managed by TWindow. Scrollbars, scroller's and application-specific controls, on the other hand, are typically implemented as separate views inserted into the window's view hierarchy.
As a result, a window often appears to be a single object while internally consisting of several cooperating views.
This distinction becomes important when constructing application interfaces. Features such as scrolling, list handling or custom data presentation are usually implemented through additional views inserted into a window rather than by extending the window itself.
A Typical Window
A newly created TWindow is usually only an empty workspace. It has a frame, a title and the mechanisms required to participate in the desktop environment, but it does not yet provide application-specific behavior.
The following example creates such a plain window and inserts it into the desktop:
sub newWindow {
my $self = shift;
my $r = new_TRect( 0, 0, 60, 20 );
my $win = new_TWindow( $r, 'Window', wnNoNumber );
$deskTop->insert( $win )
if $self->validView( $win );
return;
}
This code creates a visible window, but the resulting object is still largely a frame around an empty interior. It can be moved, selected and managed by the desktop, but it does not yet display any useful content.
Building a custom Window
In practical applications, a window normally becomes useful only after one or more additional views have been inserted into it.
TWindow
|
+-- application-specific TView
This is the point where the distinction between a window and the views contained within it becomes important. The window provides the workspace. The inserted view provides the behavior.
A simplified event viewer window might be organized as follows:
TEventViewer
|
+-- TWindow
|
+-- TScrollBar
|
+-- TTerminal
Here TEventViewer is a specialized window. It derives from TWindow, creates a vertical scrollbar and inserts a terminal-like view into its interior. The terminal view is responsible for displaying the event text, while the window provides the surrounding desktop object.
A reduced version of such an initialization may look like this:
package TUI::Gadgets::EventViewer;
extends TWindow;
sub BUILD {
my ( $self, $args ) = @_;
$self->{scrollBar} =
$self->standardScrollBar( sbVertical | sbHandleKeyboard );
my $r = $self->getExtent();
$r->grow( -1, -1 );
$self->{interior} = TTerminal->new(
bounds => $r,
hScrollBar => undef,
vScrollBar => $self->{scrollBar},
bufSize => $args->{bufSize},
);
$self->insert( $self->{interior} );
return;
}
The important detail is not the event viewer itself, but the way the window is assembled.
TWindow
|
+-- standardScrollBar(...)
|
+-- TTerminal
|
+-- uses vertical scrollbar
The TWindow does not print the events directly. Instead, it creates and owns a view that is responsible for displaying them. The window acts as the container and coordinator, while the embedded view brings the workspace to life.
The same approach can be seen throughout TUI::Vision. Application windows are often implemented as specialized subclasses of TWindow, while their contents are provided by additional views created and inserted during initialization.
This allows application-specific behavior, data presentation and user interaction to be separated into smaller, reusable components that can cooperate within the same window.
The window provides the workspace. The inserted views provide the functionality.
Dialogs as Specialized Windows
A TDialog is a specialized form of TWindow. Like ordinary windows, dialogs participate in the desktop environment and act as containers for other views.
The role of a dialog is usually more focused than that of a window. While windows often provide long-lived workspaces, dialogs typically support a specific interaction such as entering data, selecting options or confirming an action.
For this reason, dialogs are commonly assembled from many small views.
A simple dialog might appear as follows:
╔═[■]═══════ Parameter ═══════════╗
║ ║
║ ║
║ ║
║ ║
║ ║
║ ║
║ ║
║ ║
║ ║
║ ║
║ ║
║ [ OK ] »[Cancel]« ║
║ ║
╚═════════════════════════════════╝
Internally, even a very simple dialog is assembled from individual views. In this example the visible interface consists almost entirely of button views inserted into the dialog.
TDialog
|
+-- TButton "OK"
|
+-- TButton "Cancel"
A Typical Dialog
Dialogs are commonly used whenever an application needs to collect information, present a set of options or request confirmation before performing an action.
Unlike many windows, which often contain one or two specialized views, dialogs are usually assembled from a larger collection of smaller controls that work together to perform a specific task.
A typical parameter dialog might appear as follows:
╔═[■]═══════ Parameter ═══════════╗
║ ║
║ Print Font width ║
║ [X] File ( ) Big ║
║ [ ] Line ( ) Medium ║
║ [X] Date (•) Small ║
║ [ ] Time ║
║ ║
║ ║
║ Note ║
║ | Hello world | ║
║ ║
║ [ OK ] »[Cancel]« ║
║ ║
╚═════════════════════════════════╝
While the dialog appears as a single object on the desktop, the visible interface is produced by several cooperating views.
TDialog
|
+-- TCheckBoxes
|
+-- TRadioButtons
|
+-- TLabel
|
+-- TInputLine
|
+-- TButton "OK"
|
+-- TButton "Cancel"
Each control remains an independent view with its own responsibilities. The check boxes manage a collection of Boolean options, the radio buttons provide a mutually exclusive selection, the input line allows text entry and the buttons determine how the dialog is closed.
The dialog itself acts as the container that brings these views together into a coherent user interface. It provides the frame, coordinates focus handling and serves as the parent view for all controls inserted into it.
This style of composition is typical throughout TUI::Vision. Additional controls such as list boxes, history views, static text, scroll bars and custom application views can be added using the same mechanism. Regardless of complexity, the overall structure remains the same: the dialog provides the environment while the contained views provide the functionality.
The parameter dialog shown above will be used in the next section to demonstrate how dialogs are assembled in practice.
Building a Dialog
The parameter dialog shown in the previous section demonstrates the two fundamental tasks performed by most dialogs.
First, the dialog must be assembled from individual views. Second, the dialog must exchange data with the application.
Unlike ordinary windows, which frequently host a single specialized view, dialogs are commonly constructed from many smaller controls that cooperate to represent a single interaction.
The example discussed in this chapter uses the following data object:
TParameterData
|
+-- print
+-- font
+-- note
The values stored in this object correspond directly to the controls contained in the dialog. In TUI::Vision this data exchange is commonly performed using an array reference whose elements correspond to the controls displayed by the dialog.
Class::Struct is a convenient way to define a structured array-based data object for dialog exchange. Its use is optional; any array reference that follows the expected layout may be used instead.
use Class::Struct 'TParameterData' => [
print => '$',
font => '$',
note => '$',
];
The constructor loads the initial values presented when the dialog is opened.
$self->{parameterData} = TParameterData->new(
print => 0b0101,
font => 2,
note => 'Hello world',
);
The dialog itself is assembled by creating individual controls and inserting them into the dialog.
TDialog
|
+-- TCheckBoxes
|
+-- TRadioButtons
|
+-- TInputLine
|
+-- TButton "OK"
|
+-- TButton "Cancel"
Each control is created independently and added to the dialog using insert. While the controls appear as a single user interface on the screen, they remain individual views within the dialog's hierarchy.
The order in which controls are created is significant. When data is transferred using setData and getData, the dialog expects the data structure to match the order of the controls contained within the dialog.
Once all controls have been created, the dialog can be populated with application data.
$dlg->setData( $self->{parameterData} );
This call transfers the values stored in the data object into the individual controls. Check boxes, radio buttons and input lines update their visible state to reflect the supplied data.
The dialog is then executed:
my $result = $deskTop->execView( $dlg );
While the dialog is active, the user interacts exclusively with the controls contained within it. Depending on the control type, values may be selected, modified or entered.
When the dialog is closed using the OK button, the modified values are copied back into the application data object.
if ( $result == cmOK ) {
$dlg->getData( $self->{parameterData} );
}
The complete life cycle can therefore be viewed as:
Application Data
|
v
setData()
|
v
Dialog
|
v
User Interaction
|
v
getData()
|
v
Application Data
This model is one of the defining characteristics of Turbo Vision dialogs. Rather than accessing controls individually after a dialog has been closed, applications exchange a complete data object with the dialog. The dialog becomes responsible for presenting and editing the data, while the application remains responsible for interpreting and using the resulting values.
The following listing combines all of these elements into a complete working dialog.
use Class::Struct 'TParameterData' => [
print => '$',
font => '$',
note => '$',
];
sub BUILD {
my $self = shift;
$self->{parameterData} = TParameterData->new(
print => 0b0101,
font => 2,
note => 'Hello world',
);
return;
}
sub myParameter {
my $self = shift;
my $r = new_TRect( 0, 0, 35, 15 );
$r->move( 23, 3 );
my $dlg = new_TDialog( $r, 'Parameter' );
WITH: for ( $dlg ) {
# Check Boxes
$r->assign( 2, 3, 18, 7 );
my $view = new_TCheckBoxes( $r,
new_TSItem('~F~ile',
new_TSItem('~L~ine',
new_TSItem('~D~ate',
new_TSItem('~T~ime',
undef))))
);
$_->insert( $view );
# Label for Check Boxes.
$r->assign( 2, 2, 10, 3 );
$_->insert( new_TLabel( $R, '~P~rint', $view ) );
# Radio Buttons
$r->assign( 21, 3, 33, 6 );
$view = new_TRadioButtons( $r,
new_TSItem('~B~ig',
new_TSItem('~M~edium',
new_TSItem('~S~mall',
undef)))
);
$_->insert( $view );
# Label for Radio Buttons.
$r->assign( 20, 2, 31, 3 );
$_->insert( new_TLabel( $r, 'Font ~w~idth', $view ) );
# Input Line
$r->assign( 3, 10, 32, 11 );
$view = new_TInputLine( $r, 50 );
$_->insert( $view );
# Label for the Input Line
$r->assign( 2, 9, 10, 10 );
$_->insert( new_TLabel( $r, '~N~ote', $view ) );
# Ok-Button
$r->assign( 7, 12, 17, 14 );
$_->insert( new_TButton( $r, '~O~K', cmOK, bfDefault ) );
# Cancel-Button
$r->move( 12, 0 );
$_->insert( new_TButton( $r, '~C~ancel', cmCancel, bfNormal ) );
}
# Pass the parameters to the dialog and read them back unless the
# user has selected the Cancel-Button.
$dlg->setData( $self->{parameterData} );
my $dummy = $deskTop->execView( $dlg );
if ( $dummy == cmOK ) {
$dlg->getData( $self->{parameterData} );
}
return;
}
Although the dialog appears relatively simple on screen, it combines a surprisingly large number of views and demonstrates many of the fundamental concepts used throughout TUI::Vision.
The same techniques are used for larger dialogs containing list boxes, history controls, file selectors, custom views and application- specific components. Regardless of complexity, the overall pattern remains unchanged: the dialog acts as a container while individual views provide the functionality visible to the user.
Building User Interfaces from Views
A recurring theme throughout this chapter is that user interfaces in TUI::Vision are assembled from views.
Windows, dialogs, scrollbars, buttons, input lines, check boxes and many other controls all share a common foundation in the view hierarchy. Although they appear very different on screen, they are combined using the same mechanisms and participate in the same object model.
The examples shown in this chapter illustrate two common patterns.
TWindow
|
+-- TTerminal
|
+-- TScrollBar
and
TDialog
|
+-- TCheckBoxes
|
+-- TRadioButtons
|
+-- TInputLine
|
+-- TButton
|
+-- TButton
The first example demonstrates how a window can provide a workspace for a specialized view. The second demonstrates how a dialog can be assembled from many smaller controls that cooperate to perform a specific task.
From the perspective of the framework, these are variations of the same idea. Larger user interface elements are rarely implemented as monolithic objects. Instead, they are constructed by combining many smaller views, each responsible for a specific aspect of the overall behavior.
This approach encourages reuse and helps keep individual components focused on a single responsibility. A view that displays text can be used in many different windows. A button behaves identically whether it appears in a small confirmation dialog or a complex configuration screen.
As applications grow, the hierarchy may become larger, but the design principles remain unchanged:
TApplication
|
+-- TDeskTop
|
+-- TWindow
| |
| +-- application-specific views
|
+-- TDialog
|
+-- controls
Understanding this style of composition is fundamental to working with TUI::Vision. Most framework classes ultimately serve as specialized views or containers for views, and complex interfaces emerge from their cooperation rather than from a single large object.
Conclusion
Windows and dialogs represent the primary workspaces of a TUI::Vision application. Although they differ in purpose, both serve as containers in which views cooperate to provide the functionality visible to the user.
Throughout this chapter, windows and dialogs were shown not as standalone objects, but as compositions of smaller views. Scrollbars, input lines, buttons, check boxes, radio buttons and many other controls remain independent views that are combined to form complete user interfaces.
This approach is one of the defining characteristics of TUI::Vision. Rather than constructing large monolithic interfaces, applications are assembled from many specialized components, each responsible for a particular aspect of the overall behavior.
The next chapter examines two view classes that occupy a special place within every application. Unlike windows and dialogs, which appear and disappear during normal operation, menu bars and status lines remain present throughout the lifetime of the application and form the persistent framework surrounding the desktop.
next chapter.