Fenestra User's Guide (Chapter 3) -- contents | previous | next


3 The `Windows' cluster

windows cluster class diagram

The preceding figure shows all classes of the Windows cluster. The notation follows loosely the style proposed in [walden95].

Diagram conventions

This class diagram follows some conventions, like all the other in this manual. First, a few remarkable client relations are shown as a guide, but there is no extensive coverage of all client relations.

Not all inheritance relations are necessarily shown, because they either are implementation inheritance relations that the client need not know about, or it would have made the drawing unclear so minor relations may have been omitted for clarity.

Some inheritance relations shown as direct may be indirect when implementation inheritance is used to implement inheritance from an abstract class (the relation shown) through a more concrete class, whose implementation is partially used.

Generally, in this cluster as in the others, the user should rely only on documented inheritance relations -- either from the diagrams or the documentation text. Extended inheritance relations introduced by the implementation should not be relied upon.

3.1 Event model and event processing

Graphical user interface programming generally implies an event-oriented programming model. That is, instead of having one entry point -- the creation procedure of the creation object -- the operating system sends the system various events in response to user interaction. The user will typically open a window, select an operation in a menu, move the mouse, click the mouse button or enter data using the keyboard. Each of these user actions will have a corresponding event sent to the application.

There are also more abstract events independent of user actions, such as window bookkeeping, timer events or other events generated by the system. The application may also have to process these events.

In order to be compatible with the non-GUI model of programming, GUI programs usually start with a `main' procedure, which, after initialisation is going to handle window processing. Given an os object representing the operating system API, the `main' procedure of the application will do something conceptually similar to the following code, representing a typical event loop.

from
until not os.has_event loop
    process_event(os.last_event)
    os.next_event
end

The function os.has_event is going to return false only when the application is finished, and os.next_event will yield control to the operating system and will return when there really is an event waiting, so that an idle application does not waste processor cycles in an empty loop.

The reality under Windows is actually more complex See appendix (see section D.2) for a low-level explanation. than the event loop model because not all events go through the main event loop. Some events are delivered more directly to their recipient, although this is conceptually more or less equivalent to the event loop model.

It has consequences on the ordering of events, as a normal queue can be bypassed when delivering events directly. Another consequence is that an event may be triggered and processed during a passive library operation. For example, if a window is resized, the `windows resized' event may have to be processed during the call to the resize method of the window object.

Event distribution management

In an object-oriented context, the events can be associated with their recipient object. This means that events associated with a particular window will be dispatched to a given instance of the window class. Events are associated with various other types of objects such as timers or menu items.

The event dispatching, sending the event to the appropriate instance of the object is is associated with, is implemented by the library itself, in the class NOTIFIER. There is only one instance of this class created when the GUI is initialised -- it is a once object, introduced in COMMON_NOTIFIER. At the time of writing NOTIFIER has no public features, but it could be extended in the future if straightforward access to the event dispatching was required. Clients would then inherit from COMMON_NOTIFIER to reach the event dispatching system.

Live objects and garbage collection

Developers used to traditional programming may be tempted to think that objects which receive events, being somewhat active, need to be referenced consistently up to their inactivation. It is of course not the case in Eiffel for a user of the library, once a window or menu item has been created, a reference may be kept if external access is required, but it can otherwise perfectly stand on its own -- the notifier object will have directly or indirectly a reference to all live objects. It is therefore perfectly correct, and indeed common, to use short-lived local variables to create such objects.

System initialisation

The notifier class is initialised, and the event loop is started in the creation procedure of the APPLICATION class (see section (see section 3.3.3) below). APPLICATION is a kind of window, that is the application's main window. The root class of a GUI application will typically be a descendant of APPLICATION, using this class' creation procedure -- normally the original one, otherwise the descendant own creation procedure must call the original creation procedure.

It is possible to use some parts of the library independently of APPLICATION and NOTIFIER -- notably the `System' cluster -- for programs without a graphical user interface such as console programs, as long as no event handling is required. Otherwise a main window is required It would be possible to implement event-processing without an user-interface using an invisible window for event processing, but this feature was not deemed useful enough in the current version of the library..

Event processing

Once the notifier class has been started, event are dispatched to active objects registered with it. Event-handling objects are registered transparently with the notifier when they are created.

Library classes that correspond to objects that will receive events provide event handling procedures: either procedures prefixed with when_ and exported to PUBLIC_NONE (see appendix (see section A)) or command classes (descendants of GUI_COMMAND) that can be associated with the class. The generic system to attach events to library object was introduced in section (see section 2.3.1).

The library generally provides default implementations for events -- most commonly an empty function. The client needs only to redefine the event procedures or attach commands for the events which actually require processing. In consequence, most event procedures are not deferred and have to be explicitly redefined.

3.2 The fundamental window class

The basic abstraction of a windowed environment is, of course, the window. A window is seen as a rectangular area that can have attributes managed by the system (such as a menu bar, scrollbars or a title bar) and receives various events following user actions such as resizing or moving the window, entering characters in it, etc.

The fundamental window class introduces features common to all windows, and then the special types of window such as child windows -- windows constrained into the client area of their parent -- and independent overlapping windows.

All windows are descendants of the common class WINDOW. They will be used by library clients either as simple instance of a predefined window type, or by inheriting and specialising a simpler type provided by the library.

Inheritance is necessary to be able to specialise the reply to the numerous events a window can receive. Window events are procedures exported to PUBLIC_NONE that have to be redefined by the descendant when necessary -- default handling is provided for all events.

3.2.1 Initialisation and destruction

Most windows are related to another window, the parent window. The creation procedure of a window (except the root application window) will receive the parent as one of its parameter, which will be used to set the parent reference. The consequence of the relationship a window has with its parent will depend on the kind of window, as detailed later.

Creation

Windows provided by the library usually have their own creation procedure or set of procedures for initialisation and registration with the event system. After the window object has been created, it becomes a valid window -- is_valid is true -- on which operations may be performed. A valid window is not necessarily a visible window: It exists for the operating system without being necessarily visible on the screen yet.

While the library client may introduce its own creator -- which must call the default creator provided by the system -- it is not recommended to do so. The initialisation of an heir to WINDOW can and should be done in reply to the event when_created.

This event is the first that is sent to the window. After it has been processed, the library will set the attribute is_created to true, so that other events or assertions are able to do some processing depending on the window initialisation status.

Closing the window

The close procedure is used to close the window, or the user may close the window by clicking on the close box for instance.

When the window is closed, the when_closed event occurs. If after this event has been processed, the is_close_ready attribute -- set by set_close_ready -- is true, then the window will be destroyed, that is, it will become invalid and disappear from the screen. This is the default case. Otherwise, as long as it is possible for a given window, the window will not be closed when is_close_ready is not true.

The procedure destroy may be used to destroy directly the window without conditions and without issuing a when_closed event.

3.2.2 Characteristics

Window size

The window is a rectangular area whose size can be described as a rectangle. The basic class RECTANGLE from the `Graphics' cluster is used to set or retrieve the size of the window. The function size retrieves the size of the external frame of the window. The coordinates are in device units, that is screen pixels with the top left corner as origin.

The meaning of the position of the rectangle depends on the kind of window: it is the position on the screen for an overlapping window, and the position inside the parent window's client area for a child window, as shown below.

The size of the client area can be retrieved from client_size. The client area is the part of the window controlled by the application, excluding the title bar, the window borders, and other optional attributes of a window such as a menu bar. Only the width and the height of the client size are meaningful and the top-left coordinate of the client size rectangle is always the origin.

The size and client size can be modified using, respectively, set_size and set_client_size. When it is changed, either using these functions or by the user or as a result of parent resizing, the window will receive the event when_resized.

Window text

A character string -- the window text -- is associated with each window. It is typically used for the text displayed in the title bar, although child windows without a title can use it for other purposes. The routines text and set_text are used to access the window text.

Window status

Several value are used to make accessible the current status of a window.

A window can be the top window displayed above the other window -- the active window. This state is tested with is_active and changed with activate.

It is also possible for a window to be displayed or kept hidden. This state is changed with the show and hide procedures and the status can be checked thanks to the is_visible function. Visibility is logical: a window can be `visible' without the user seeing it physically, if it is completely covered by a bigger or full-screen window.

A window can be disabled, that is user input suspended, so that no events such as mouse clicks or keyboard entry will be sent to it and the user will be prevented from activating the window. This characteristic is associated with is_enabled and changed with the procedures enable and disable.

A window which is reduced to an icon on the desktop, when it has been minimised, will have its is_iconic value set to true.

3.2.3 Keyboard events

When building the user interface, data entry zones may be associated with a window or child window. Keyboard entry then needs to be directed to the appropriate window through keyboard events.

Two different types or events are received by a window for each keyboard action, although for a given user entry only one will be normally processed. The first type is a character event, when_character_entered, indicates that a character (an Eiffel CHARACTER) has been typed. It may be the result of several keystrokes such as a combination of a modifier key (such as Shift or Control) and a letter key, or two keys associated to produce an extended character. The operating system's keyboard driver makes the conversion between the keystrokes and the characters.

The second type of keyboard event, when_key_pressed, is a lower level event corresponding to actual key strokes. The event procedure parameter is a VIRTUAL_KEY object, as documented later. The application can use this event to process operations associated with the arrow keys for example. Modifier keys, or any other key, can also be checked using the VIRTUAL_KEY class if key combinations are used. Of particular interest is that combinations including the `alternate' key, which are used for menu shortcuts, do not produce events because the operating system captures them for its own interface.

Focus

Only one window can receive the keyboard events at any given time, this window is said to have the keyboard focus -- the current status is shown by has_focus. The window with the keyboard focus is either the active window (the top window highlighted by the system) or a child window of the active window.

The focus can be moved when the active window changes as a consequence of the user action. An application window can itself pass the window focus, typically between different child windows inside an active parent window, using the focus procedure. For example, a dialog box can pass the focus to its first control which accepts keyboard entry. A control itself can pass the focus to the next control when the user requests it.

A window will receive focus events when it acquires (when_focus_given) or loses (when_focus_lost) the keyboard focus.

3.2.4 Mouse events

When the mouse is moved or a mouse button clicked, the window in whose client area the mouse pointer is located receives mouse events.

The simplest events are mouse clicks and double clicks. The events when_mouse_clicked and when_mouse_doubleclicked are associated with the main mouse button, usually the left mouse button. The corresponding events for the right (or secondary) mouse button, often associated with context menus, are when_mouse_rclicked and when_mouse_rdoubleclicked. These events have an instance of POINT (from the `Graphics' cluster) as a parameter which indicate the position, in client area coordinates, where the click or double click occurred.

More complex mouse handling can be obtained, for each button, by setting the corresponding mouse handler -- a specialised instance of the class MOUSE_HANDLER, detailed below -- using the procedures set_left_mouse_manager and and set_right_mouse_manager. Specialised mouse handling include support for dragging and tracking mouse movement inside the client area, for example the selection of a block of text in a text editor.

Advanced mouse handling has been moved out of the main WINDOW class to avoid overloading an already large interface. The more extensive processing required in this case also benefits from a separated class.

3.2.5 Drawing the window's content

Thus far, all the methods reviewed allow to reply to events and setup the window. The result of these interaction has to produce some effect that will be displayed in the window -- unless it only contains child windows implementing the actual interface.

In order to display output in the window client area, a graphic device, the device attribute, is associated with each window and enables the drawing of graphical output into its client area. While the details on how to use a graphic device, associated with a window or not, will be studied in chapter (see section 5), it is important to know how and when to draw in the window.

The system issues when_drawn events when a part of the window has been hidden by another window and needs redrawing; when the window is maximised of made into a full screen window, or, for that matter, when the window is first shown. Most of the time, an application will do all its drawing in reply to this event, and indeed should do so. Unless the application requires animation or rapid changes, all the drawing can be done during normal events, which guarantees consistency when the window is moved and modified. If a part or all of the window is modified by the application -- because of a scroll operation or data entry for instance -- without the system requiring a redraw, a drawing event can be forced by the client code.

On the receiving side, while their is only one event, the part of the window that is to be redrawn -- possibly the whole window -- is specified using by the clipping facility of a graphic device. The window's graphic device is prepared for output and the output restricted to the required rectangle. Output outside this area does not appear on the screen.

Drawing events can be forced for either the whole window with paint, or for a part of it with paint_rectangle which takes the corresponding rectangle, in client area coordinates, as a parameter.

When implementing vertical or horizontal scrolling, the window class provides assistance. The procedures horizontal_scroll and vertical_scroll can be used to move a part of the window -- the part of the display that is scrolled (that is moves but remains displayed) will be copied by the system -- so that only the new rectangle need be redrawn. The procedures will generate the appropriate message for redrawing the corresponding rectangle. The scrolling procedure's parameter can take a negative value to distinguish between scrolling upwards or downwards -- or to the left or right for horizontal scrolling. If the requested scroll increment is bigger than the current corresponding dimension of the window, the whole window is redrawn.

3.3 Specialised windows

The deferred class WINDOW is the ancestor of several more concrete classes, presented in this section, and associated with the basic types of window the library user can inherit from for implementing their own window classes.

3.3.1 Child windows

A child window is a window that is enclosed in its parent. Its position is relative to the client area of the parent. It is not usually resizable, and has no resizing controls or title bar.

Child windows may be used to implement several distinct zones inside the parent window, such as controls in a dialog box. Adjacent child windows can be used to implement multiple access to the data. A reference work's main window could have a toolbar, a text window, and a contents tree display, each being inside a child window.

This library provides support for optional resizing of such stacked child windows. The window can be positionned relatively to each other and their parent, and therefore be automatically resized whenever the parent frame is resized.

Another option, which can be combined with the above, is the use of a split window. This is a child window which itself contains two other child windows, separated by a split-bar. The user can move the split bar and thus change the size of the enclosed windows, or even make one of them completely hidden. An extension cluster provides a sample implementation of such a facility.

Scrollbars

Another feature introduced in child windows is the optional horizontal and vertical scrollbars Basic or overlapped windows cannot have a scrollbar in this library -- although they can at the API level -- to avoid encumbering the interface for a rarely needed feature as most window will need to use child windows anyway, if only to add a toolbar or status bar. It is nevertheless possible to have a single child window set to follow the size of its parent to emulate an overlapped window's scrollbar -- this scheme is easily extendable.. A choice of creation procedures is provided depending on the combination of scrollbars required. An application class extending CHILD_WINDOW will select the appropriate procedure for its creation clause.

If relevant, scrollbars can be accessed through the attributeshorizontal_scrollbar and vertical_scrollbar. These scrollbars are descendants of the abstract scrollbar type introduced in section (see section 4) whose movement event has been redirected to CHILD_WINDOW's when_horizontal_scrolled and when_vertical_scrolled.

Attributes

A child window adds a few options to a basic window. The procedure set_border allows to add a simple line border around the child window. The attributes next and previous are a reference to the corresponding sibling -- the nearest child window with the same parent. These references are always valid as child windows form a ring. If the current window is the first child, previous will be the last child. If the child window is an only child, next and previous will be equal to the current object. This enables a simple implementation of keyboard focus transfer for example.

The client area is the same as the window size, unless a border is used, so the client size can be used for drawing the background for instance. The size of the child window is understandably expressed in terms of the parent's client area coordinate space.

Background painting

Unlike overlapped window, basic child windows do not have their background repainted automatically, so unless the application fills the client area of the child window it will show what is under, such as the parent's client area or other child windows.

A variant of child window, CHILD_WINDOW_COLOR, can have their background colour set at creation time There is, of course, a reason for this apparent inflexibility. The operating system sets the colour of the background for whole classes of windows. Changing the background colour for one window changes it for all window of the same class (class in the OS sense, not Eiffel classes). This library hides window classes to the user, and creates one new class per unique colour used for CHILD_WINDOW_COLOR.. The plain colour is specified thanks to an additional parameter to the creation procedures. It is otherwise identical to the standard child window.

Automatic layout management

The relative position of a child window can be made to follow some layout guidelines. The parent window will typically, during its when_created event, call one or more of the layout procedures of its child windows after it has created and initialised them. The child windows will then be automatically resized when the parent window -- typically an overlapped window -- is resized. This can also be used recursively for child windows inside other child window.

The position can be set relatively to the border of the parent window client area using the procedures left_of_border, right_of_border, above_border or under_border. Calling all four of these procedures will make a child fill the entire client area of its parent.

With several child windows, the first child can be attached to the top left corner of the parent window, and then have its width or height made proportional to the size of the client area of the parent, by using proportional_width_of_parent or proportional_height_of_parent. The related procedures proportional_width_of or proportional_height_of enables various child windows to have related size. The proportionality is specified using a ratio expressed as a real number between 0 and 1. The procedures width_of and height_of provide for simple equal sides.

Windows can also have their border attached to a previously created child window, using left_of, right_of, under and above procedures.

Some care should be taken to use sensible layout rules. If two windows have a size proportional to each other, the result may be unpredictable. Generally, a given child window should refer only to the parent or a sibling created earlier.

Finally, some windows can be marked as being of fixed size or width using the procedures fixed_width and fixed_height. Toolbars and status bars are typical fixed height windows. Only one dimension is normally set as fixed.

3.3.2 Overlapped windows

Overlapped windows are the generic independent windows that are displayed on the desktop and can be moved, and generally resized, by the user. They ordinarily have a title bar, with modification icons to minimise, close, or maximise them; and possibly a menu bar.

In addition to an appropriate creation procedure, make_overlapped, the class OVERLAPPED_WINDOW augments the basic window with features to resize an overlapped window: the procedures minimize, maximize and restore to bring a minimised window to its previous size.

After creation, an overlapped window will be shown only after the event when_created has been processed so that the dependent parts of the window can be properly initialised before display.

Unlike basic child windows, the background of an overlapped window will be painted before drawing events, that is the rectangle to be redrawn will be filled with the appropriate brush. The background colour of an overlapped window is an application-wide settingFor the reasons explained in the description of CHILD_WINDOW_COLOR.. An overlapped window must have a default background because it has nothing but other applications or the desktop behind its background, unlike basic child windows, which also more often need a customised background.

The class POPUP_WINDOW is like an overlapped window but one that will always stay on top of its parent, while other kinds of overlapped windows can operate independently of their parent. A popup window is minimised at the same time as its parent: a normal overlapped window and all its related popup windows appear as a single symbol when minimised.

For the library user, the only difference between a popup window and an ordinary overlapped window is the creation procedure.

3.3.3 The application class

A special kind of overlapped window is the class APPLICATION. It implements the application main window. Its creation procedure is in charge of starting the event loop. Therefore, a descendant to this class will commonly be the root class of a system with a GUI interface. Yet, this is not an absolute requirement, and a system may perfectly start with another class and do some task which do not involve the user interface, and then enter the system by creating an application window object. Still, the creation procedure will not return until the GUI is terminated, that is normally when the user chooses to quit the application.

An application can only have one main window and consequently the system can only have one and one only active descendant of APPLICATION.

A variant of this class is APPLICATION_DIALOG, introduced in the `Controls' chapter, section (see section 4.3), which allows the application root window to be a dialog box.

The application window is able to receive drag-and-drop events when files are dropped from the system file browser onto the application window. If an application is able to accept dropped files, it will first call, at initialisation time, the procedure accept_dropped_files and redefine the event procedure when_files_dropped. Several files may be dropped at the same time, so the event's parameter is a list of file names.

In addition to properties specific to the application main window, the class APPLICATION has support for some system-wide settings, that are global to the whole user interface of the library. For instance, the application window's icon can be set using set_icon.

The background brush is a filling pattern -- normally a plain colour -- used for all the applications overlapped windows' background and changed with set_background_color. The default colour is specified by the user as a preference at the operating system level. Like the class ICON used by set_icon, the class BRUSH and its descendants are introduced in the chapter about the `Graphics' cluster, chapter (see section 5).

For implementation reasons (see Appendix (see section D.3) and notes in this chapter), all overlapping windows share the same icon when minimized and the same background colour. Specific background colours can be obtained by redrawing the background during the draw event. It is not an issue if the whole client area of the overlapped window is covered by child windows as it is often the case -- ordinary child windows do not have their background painted by the system, or otherwise the colour may be selected individually.

3.4 Complementary classes for windows

The following classes have been mentioned in the previous section and are used to implement part of the capabilities associated with windows.

3.4.1 Virtual key

The class VIRTUAL_KEY is used to represent keyboard keys. A series of boolean values can be used to test which key a virtual key object represents. For instance, is_escape will be true for the escape key. Only one of these functions will be true at any one time.

A symmetric series of procedures (set_escape for the previous example) corresponding to each key allows to change the key associated with an object. This is useful for checking if a given key is currently down, by using the boolean function is_key_down.

Particularly useful keys are the arrow keys, is_cursor_left, is_cursor_right, is_cursor_down, is_cursor_up, the page keys is_previous and is_next. The modifier keys, shift (is_shift) and control (is_control) and alternate (is_alt) and the usual escape, delete, backspace, return, etc.

3.4.2 Mouse handler

Descendants of the class MOUSE_HANDLER may be associated with a window to provide complete management of mouse actions. A mouse handler instance is associated with one mouse button, and the object is linked with its parent window by calling for example set_left_mouse_manager from the corresponding WINDOW object, generally during its initialisation although the mode can be changed dynamically for modal behaviour. Separate classes are needed for controlling more than one button.

This class has its own set of events associated with mouse actions. The attributes, point and is_down are set before these events happen. The position is, like for simple mouse events in WINDOW, relative to the client area of the parent window. The associated parent window attribute can possibly be redefined to a more specialised type as a way for this class to communicate with its corresponding window.

The basic events, when_down and when_up, occur when the mouse button status changes. When the mouse moves inside the window's client area, numerous when_moved events occur.

An important use for the mouse is to drag the mouse pointer with a mouse button down. Special events when_drag_started and when_drag_finished mark the start and the end of the a dragging operation. When the mouse moves during dragging, when_dragged events reflect the mouse movements. When dragging, the mouse pointer is captured. It means that all mouse events, even outside the associated window client area, are sent to the window where the drag operation was started, up to the end of the drag. The mouse position can then be outside the client area, but still in client area coordinates, so if the mouse pointer is to the left or the top of the window, coordinates may have a negative value.

3.4.3 Caret

The caret is an optional small rectangular pointer, in some cases blinking, showing the current keyboard entry point. There can be only one caret per system, associated with the window currently having the focus. The window enables its caret when it gets or has the focus, and disables it when it loses the focus.

A unique instance of the class CARET will be created when the window has or gets the focus and needs a caret. The creation procedure requires the size (width and height) of the caret and its parent window. When the focus is lost, typically in reply to the when_focus_lost event, the caret must be destroyed using destroy.

Once created and active a caret may be displayed or disabled using the procedures show and hide. The position where it is displayed is changed using set_position using client area coordinates.

3.4.4 Mouse cursor

A mouse cursor is used in CHILD_WINDOW_CURSOR to change the shape of the cursor when it is inside one of the corresponding child window, which is a normal CHILD_WINDOW with a new procedure set_cursorto change the current cursor displayed in the client area of the window.

The class MOUSE_CURSOR is an heir to RESOURCE_OBJECT. Another set of creation procedures represents standard shapes: make_arrow (the standard arrow) and make_cross make_i_beam (keyboard entry) and make_no (when the mouse is disabled) and make_up_arrow and make_wait (for lengthy operations) and make_app_starting.

The procedures show_cursor and hide_cursor also found in this class can be used to remove or display the current cursor.

3.5 Command classes

As it has been mentioned previously (section (see section 2.3.1)), there are two ways for clients of the library to receive events from active objects. In addition to inheritance, command classes enable the client to receive events for simpler objects, for example menu items in this cluster. The facility is also used by classes from other clusters.

The basic command class is the deferred class GUI_COMMAND which is a very simple class with a single deferred feature, execute. This class can be used directly by the actual client class to implement the reply to a single event. For example, an object processing a single menu command associated with a menu selection could inherit from GUI_COMMAND, initialise the event with menu_item.set_command(Current) and add the action in an effective version of execute.

When several commands have to be associated with a single class, the command class can be used through a small lightweight class to redirect the event to the class that has the actual replies to events. For this purpose, the class BOOMERANG_COMMAND is implemented, and a redirection class will typically look like the following:

class MY_COMMAND
inherit BOOMERANG_COMMAND[PARENT_TYPE]
creation make
feature execute is do parent.my_parent_command end
end

The generic type associated with BOOMERANG_COMMAND is used to set the type of parent and of the parameter to the creation procedure, make, which is used to set parent.

Such redirection classes can be easily generated using a small script or macro in a text editor, and they can be associated with the main class in the same Eiffel source file for convenience if the Eiffel compiler allows it Few compilers unfortunately allow several classes in a source file at the time of writing, therefore portability may be a concern..

Otherwise, the full implementation of the function can be in a separate object. Although this may appear verbose at first, the extra classes often prove valuable for associated capabilities, like the reverse operation for an undo facility, or for using the function from several points in the system.

3.6 Menu system

Most applications will allow the user to select options using menus. A menu bar can be associated with an overlapped window. An application normally has a single menu bar associated with its main window, the descendant of the class APPLICATION.

3.6.1 Popup menus and the menu bar

An abstract menu (class MENU) contains a list of menu items, separators -- a line to separate several menu items -- and other menus. There are two kinds of menus, popup menus (class POPUP_MENU) which may appear stand alone on the screen or as part of another menu, and a menu bar, MENU_BAR which can only be attached to a window.

Base menu class

A MENU takes its associated overlapped window as a parameter of its creation procedure. Then items can be added using add_item, add_popup and add_separator, which take respectively a menu item (as described below) or a popup menu or no parameters in the case of the separator line.

In addition, the specialised descendant POPUP_MENU can have its name set using set_name. This name will be displayed if the popup menu is part of another menu.

Popup menu

An independent popup menu can be displayed on the screen, usually in the client area of its associated overlapped window, using the pop_up procedure which takes the position in client area coordinates of the top left corner of the menu -- the system may interpret this position to fit the menu in the screen. A popup menu can be used concurrently as an independent menu and as part of the menu bar or another menu -- a typical case is when a menu is used as a context menu displayed in reply to a right mouse button event, and is also accessible from the menu bar.

An independent popup menu not used as part of a menu bar should be destroyed using destroy when it is not used anymore.

Menu bar

A menu bar works like a popup menu but does not have to be destroyed and does not need a name. When it is completed -- finished popup menus have been added -- it shall be attached to its window using the procedure attach. If it is later modified it may have to be redrawn using paint.

3.6.2 Menu items

A menu items is the part of the menu which will have corresponding actions. The creation procedure, make, takes the name of the item, which will be displayed in the parent menu.

A menu item can be associated with any parent menu, but only one at a time. After the item has been added to a menu (using add_item), it becomes valid (is_valid is set) and can be used and updated. The item can be removed from its parent using the procedure detach.

The name of a valid menu item can be changed using set_name.

Events

A command may be attached using set_command and an heir to GUI_COMMAND. Alternatively, it is possible to inherit from a menu item and redefine when_selected (which calls the command by default) although this is not the preferred method.

Similarly, a command can be associated with the menu and called before the menu is displayed (using set_prepare_comand, or redefining when_prepared). This can be useful to update a menu item synchronised with the current state of the application -- a `undo' item could be updated to display which operation can be reversed.

The event when_touched is called when the user passes over the menu item. The default implementation is to change the help string associated with the item, if any, and to transmit it to the parent window for display.

Help string

This optional help string can be set using set_help. The corresponding events in OVERLAPPED_WINDOW are when_menu_help_changed and when_menu_help_reset which are used to update for instance a status bar with the help strings. The reset event allows to restore the normal status.

Attributes

A menu item can be disabled, that is made impossible to select by the user and `greyed out', using disable and conversely enable. This state is shown by the boolean function is_enabled.

Similarly the function is_checked allows to see if a check mark is displayed next to the menu. The check mark state can be changed using check_mark and uncheck_mark.

If a set of menu items is used to select a unique option among a set, like a group of radio buttons in a dialog box, it is possible to have automatic management of the check mark -- user or program selection (with check_mark or uncheck_mark) of an item will disable the check mark of the previously selected item on the group, which will always have one and one only item checked. The default item in this case must be an instance of HEAD_MENU_ITEM, an heir to MENU_ITEM. All other items in the group simply have to use set_leader with a reference to the leading menu item.

Menu keyboard shortcut

It is possible to associate keyboard shortcuts (or accelerators) with each item. First, all items can have a letter in their name prefixed with `&'. This letter will be displayed underlined and will allow easier navigation of the menu hierarchy from the keyboard in accordance with Windows conventions.

An accelerator -- represented by the class ACCELERATOR described below -- allows the user to issue commands without going through the menu system at all. An instance of this class can be associated with a menu item using set_accelerator.

3.6.3 Keyboard accelerators

An instance of ACCELERATOR represents a key combination that can be associated with a menu item to add a keyboard shortcut. After creating an object using make, a key and modifier key may be specified. The key must be either a case-sensitive letter (using set_character) or more commonly a virtual key (representing an actual key on the keyboard) set with set_virtual_key which takes an instance of VIRTUAL_KEY. An accelerator is normally a combination of this key or letter and a control key like Control, Alternate or Shift, or several of these. The procedures set_shift and set_control and set_alt add the corresponding control keys to the combination.

The mixin class KEYBOARD_ROUTINES can be used to make easier the creation of common keyboard accelerators objects. The function ascii_to_vkey returns a virtual key corresponding to an alphabetical character, allowing to produce an accelerator associated with a letter in a case insensitive way. This can be done by using control_x_accelerator for the common case of an accelerator combining the control key with a letter.

Effecting the accelerators

Once a menu system has been setup, the Windows implementation requires an internal accelerator table to be initialised. Tthis is done by calling the procedure apply_accelerators in the class OVERLAPPED_WINDOW. The instance of an overlapped window in question is of course the one which is the parent window of popup menus or the menu bar.

3.7 Help commands

The classes presented in this section enables access to the Windows online help facility. Help topics from a hypertext Windows help file (.hlp) can be shown from an application. The F1 key is often used to display contextual help, and the last menu of an application will typically contain access to the application's help system.

The basic class is HELP_COMMAND which is the abstract ancestor of all help commands. Its creation procedure takes an associated window has a parameter; when this window will be closed the associated help system's window will also close down if it is still displayed -- it may have been closed by the user beforehand. A help command must have an associated help file, the procedure set_helpfile is used to select the appropriate file name. The main procedure that will be used to launch the help system is execute. The result of this operation can optionally be consulted thanks to the last_command_success function. A help command is also a descendant of GUI_COMMAND, so it can be used anywhere a command is acceptable, for example with a menu item.

The class HELP_CONTENTS is used to display the contents page of an help file. The class HELP_KEYWORD can display a particular topic or a choice of topics if more than one topic are associated with the given keyword, which can be using the procedure set_key. Finally the command HELP_ON_HELP is used to display help on the help system itself, and is often associated with a menu item in the application's help menu.

3.8 Clipboard access

The clipboard is one of the methods provided by Windows to implement simple communication between applications. It enables data exchanges of several standard categories of data, such as text and images.

There is a clipboard class by data type, all inheriting from class CLIPBOARD. A clipboard is associated with a window, which is the parameter of the creation procedure, make. All clipboard classes have a procedure put to copy the data to the clipboard and a procedure get to retrieve the data of the relevant data type, if available. The availability can be checked using has_data a boolean value. After a successful retrieval (get) has_result is true. There is one clipboard per system -- that is more precisely per user -- and per data type. That is the clipboard may contain at most one text or one picture, at least logically. At the operating system level, several related data types such as Text and Unicode Text refer to the same data, which is converted appropriately by the system to what the client asks. This is transparent to the library user.

Text clipboard

The text clipboard is the commonest type of clipboard, allowing to exchange simple text -- a set of lines, represented as a list of strings. The class CLIPBOARD_TEXT adds the procedure set_text to prepare the for put, and the value last_text to retrieve the text after a successful get.

The type of both set_text's parameter and last_text is P_LIST[STRING]. The class P_LIST is the abstract ordered (but not sorted) list from the data structure library, see the Pylon manual for reference.

Bitmap clipboard

The remaining clipboard types are used to transfer graphic primitives and complement the `Graphics' cluster (see chapter (see section 5)).

The class CLIPBOARD_BITMAP is used to exchange instances of the BITMAP_DEVICE from the `Graphics' cluster, which represent bitmap pictures. Once a device has been set (using set_bitmap) and copied (using put) it becomes invalid as ownership is transferred to the clipboard. Conversely, the bitmap -- if there is one -- in the clipboard is retrieved from last_bitmap after get.

It may be useful to copy the associated colour palette on the palette clipboard (see below) in certain cases.

Metafile clipboard

The metafile clipboard does the same thing for metafiles -- vector graphics. The class is CLIPBOARD_METAFILE and is used to exchange instances of METAFILE_DEVICE when copying (procedure set_metafile) which is, like bitmap devices, invalidated after transfer of ownership. The object retrieved, last_metafile, is a drawable metafile object that can be displayed on another device. It is not a metafile device as these are write only. This is explained more extensively in chapter (see section 5).

Palette clipboard

The palette clipboard, class CLIPBOARD_PALETTE, is used to transfer palette objects, descendants from the `Graphics' cluster class PALETTE, describing the set of real colours associated with a restricted hardware palette. The class PALETTE is indeed the type of the parameter of the procedure set_palette and of the the function last_palette, used respectively to copy and retrieve from this type of clipboard.

3.9 Standard dialogs

Standard dialogs are a set of interactive dialog boxes provided by the operating system which are used to implement much needed features in a consistent manner for all applications. In addition to reusability, it permits a more consistent user interface for operations common to many applications.

The base class for standard dialogs is the deferred STANDARD_DIALOG. Every dialog is associated with a parent window, an overlapped window, because they are popup window staying on top of their parents. This is reflected by the creation procedure, make.

Displaying the dialog and having the user make their selection is the result of the procedure execute. Unlike dialog boxes implemented using this library which are all modeless from the programmers viewpoint, execute will return control only after the user is finished. Events may be received by other active objects in the meantime, so it should not be assumed that the system takes total control. If the user moves the dialog, the parent window may receive drawing events for instance. After execution the boolean attribute has_selection is set to true in case of success. The selection can then be retrieved in effective descendants.

3.9.1 File name dialogs

When an application needs to read from or write to a file, the file dialogs should be used if the user has to specify a file name. Two such dialog boxes are provided, one for saving data to a file, and one for opening an existing file or creating a new file. The former is the class FILE_SAVE_DIALOG and the latter FILE_OPEN_DIALOG. They both inherit from FILE_DIALOG.

The result of a file selection will be stored in the string last_file_name if the selection is successful.

Optionally, several options can be set before the user is shown the dialog box. It is possible to set the directory and default file name using, respectively, set_directory and set_file. The latter is the file name without a directory understandably. The title of the dialog can be changed, using set_title, from something generic like `Open as...' in the current language to something more detailed such as `Open Eiffel source file...'.

The last option, which generally should be used, relates to the extension filters. Filters allow the user to restrict the set of files they see to only those ending with a given file extension, or a set of extensions (generally, any file pattern can actually be used). Several sets of extensions may be presented to and then selected by the user. A single filter is made of a text label indicating to the user what kind of files the extensions correspond to and a pattern string with usual file wildcards like `*.ext'. Several extensions are separated using semicolons. An example filter may be a filter for `Text files' with `*.txt;*.asc' as the pattern. The procedure add_filter is used to add a single filter. The filters will be displayed in the same order as calls to this method. The filters may be reset using the procedure reset_filers.

3.9.2 Message box

A message box is used to inform the user of an action or ask a simple question requiring either no answer or a simple binary or ternary answer. The message box, implemented by the class MESSAGE_BOX, displays an informative sentence, set using set_text, and a title set using set_title -- a default title is provided by the system.

Next to the information, an icon is displayed and may be an exclamation point, typically for an error (set_icon_exclamation) or a question mark for a user choice (set_icon_question) or a stop sign (set_icon_stop) or an information sign (set_icon_information). The latter is the default.

The answer buttons can be selected from various possibilities shown in the following table. The buttons' labels are provided by the system, in the current language selected by the user.

Buttons
Setting procedure
[Yes] [No]
set_buttons_yes_no
[Yes] [No] [Cancel]
set_buttons_yes_no_cancel
[OK]
set_buttons_ok (default)
[OK] [Cancel]
set_buttons_ok_cancel
[Retry] [Cancel]
set_buttons_retry_cancel
[Abort] [Retry] [Ignore]
set_buttons_abort_retry_ignore

After the message box has been displayed the result can be retrieved from, respectively, is_yes for [Yes] and [OK] and [Retry]; is_no for [No] and [Ignore]; and is_cancel for [Cancel] and [Abort].

3.9.3 Font selection dialog

The font selection dialog, the class FONT_DIALOG, allows the user to select a font and its size and style. The program can change the default font presented when the dialog is displayed, using set_font. The result is a ready-to-use instance of LOGICAL_FONT (see chapter (see section 5)), that is set to the correct font size and style.

Optionally, it is possible to let the user set the colour which will subsequently be used to display the text. The procedure set_color is used to set the default colour and enable the colour choice -- this is reversed using no_color. The colour is retrieved using color.

3.9.4 Colour selection dialog

When the user needs to select a colour, it can be selected using the standard colour selection dialog, COLOR_DIALOG. Similarly to the colour in a font dialog box, the default may be set using the procedure set_color and the selected colour may be retrieved from color. The type is the abstract COLOR from the `Graphics' cluster (see chapter (see section 5)).

3.9.5 Print setup dialog box

The class PRINT_DIALOG is essential to implement the ability to print in an application. It presents a dialog box enabling the user to select the printer -- or printer compatible device -- to which the document will be printed. After successful execution, the class' feature device refers to a printer device ready for output. Graphic devices generally and printer devices in particular are covered in chapter (see section 5).

3.10 Miscellaneous classes

A few classes which did not fit in other clusters or sections are presented here.

Abstract clipboard object

CLIPBOARD_OBJECT is a deferred class representing an object that can have clipboard operations as typically seen in an `Edit' menu -- as opposed to clipboard access classes seen in section (see section 3.8). The boolean value has_selection is true when a selection is available for copy, etc. The operations are the procedures copy_selection and cut_selection and paste_selection and delete_selection and select_all. They are all deferred procedures but for cut_selection whose default implementation is made by copying and then deleting the selection.

Resource object

A resource object is the abstract class which is an ancestor of objects which can be initialised from data in the resource section of binary files. An example in this cluster is the mouse cursor class. These resources are identified with a string and the class RESOURCE_OBJECT simply adds the procedure make_resource to descendants. Its parameter is the string identifier of the resource.

The resources which are not associated with RESOURCE_OBJECT are string resources, because they are identified, in the operating system resource facility, with an integer identifier. They are documented in section (see section 6.7).