TILE GROUP WINDOW DESKTOP SIZABLE_WINDOW DESKTOP_ELEMENT APPLICATION DIALOG CONTROL
A window in an application written for the Windows operating system is a rectangular area of the screen where the application displays output and receives input from User. A window shares the screen with other windows including those from other applications. Only one window at a time can receive input from User. User can use the mouse, keyboard, or other input device to interact with this window and the application that owns it.
It is important to understand that from a programmer's viewpoint a window is only a rectangular area on the screen. It may even not to have a frame border, title bar or menu. It's only a screen area that can draw itself and process user actions. Some windows may have several child windows on it. Some may have an ability to resize or move itself.
In the first part of this chapter we describe some window classes. Later in the second part we will explain a simple example demonstrating the stuff discussed. For more information on how windows react on different events (creating, painting, etc.) see the next chapters. Here we consider only the classes dealing directly with the windowed conception and such classes as CONTROL and many other window classes.
In GRAPE we have a pretty window classes hierarchy that corresponds to different kind of window objects.
The basic class is class TILE. It is a simple window object that has such attributes as position and size.
Class GROUP inherits from TILE and acts as the container of tiles. Class GROUP has basic functionality for managing TILE objects. The main idea of this class is propagation of all operations upon the group to its tiles.
The next in our hierarchy is class WINDOW that presents a tile object that can
contain a group of tiles. In contrast with GROUP this class represents not only the
container of tiles but a tile object itself.
Tips for advanced programmers: It is important to differ a window in terminology of Microsoft® WindowsTM API (in GRAPE this term corresponds to instances of class TILE) and class WINDOW here.
Class DESKTOP serves as a windows manager of an application.
Class SIZABLE_WINDOW presents a window that can be resized. It can be minimized or maximized and has resizable thick frame.
Class APPLICATION serves as the primary interface between a program and User. Every GRAPE application creates at least one window inherited from class application, called the main window that serves as the main window for the application.
Class DESKTOP_ELEMENT is the basic class for DESKTOP members (so called children windows) according to the Multiple Document Interface (MDI) in Microsoft® Windows.
Class DIALOG presents a custom dialog box - a window containing one or more
controls to retrieve user input. Here is a typical windowed application and tile's objects
compounding it.
Figure 2.1 Application's tiles.
Each visible element of a GRAPE application, except the application itself, has a parent window.
One of the class TILE attributes is the parent property. It contains a reference to another tile object called the tile's parent. Usually parent object inherits (directly or not) from class GROUP. Generally speaking relations are the following:
Application Desktop Desktop Element Desktop Element Children Children of Desktop Element Children ...etc.
This means that an application's tile is the parent (direct) of desktop. Desktop is the parent of all desktop elements and so on.
When you create your own tile object (e.g. by inheriting from DESKTOP_ ELEMENT) you should add it to one of the existing groups (e.g. DESKTOP). GROUP feature add inserts the object to the group's internal container. Also this feature sets the parent attribute of the tile. It points to the current group.
All operations upon a group are being propagated to its members. For example, when a group is repainting all its members are repainting.
There are several restrictions that follow:
As you may see, the application windows hierarchy looks like a tree. It is possible to retrieve the root of this tree - APPLICATION itself at any moment.
There is a difference between an Eiffel object and its visible vis-a-vis (or partner). When you create an object by invoking its creation procedure, the visible partner is not created immediately. The visible vis-a-vis of an Eiffel object is created when you add it to something visible.
For example, when you add a Desktop_Element to the Desktop
(which may be considered to be always visible) it also becomes visible.
Note It is not enough to create custom window object. To put it in work, visualize it you should add this object into some group that have APPLICATION object as parent (or parent of parent, and so on).
The common rule is: "When you add a logical sub-tree of windows to the already visible node of the application window's tree, all this sub-tree becomes visible."
When a tile object is going to be destroyed due to the internal logic or user action:
All window objects with a caption bar, resizable frame and menus have two window areas: system and client as shown in picture below.
Figure 2.2 Window areas.
Normally when you specify window size you specify a size of system area rectangle. With GRAPE all window output you can produce only inside client area. There is one feature resize_client_area in class WINDOW that allows you to take in mind only client area window size.
A tile's size and position are expressed as a bounding rectangle, given in coordinates relative to the screen or the parent window.
Figure 2.3 Tile coordinates.
The coordinates of an APPLICATION window are relative to the upper left corner of
the screen; the coordinates of a child tile are relative to the upper left corner of the
parent's tile client area. An application specifies a tile's initial size and
position when it creates the tile, but it can change the tile's size and position at any
time.
GRAPE supports a flexible scheme of positioning child windows inside their parent window. Coordinates expressed as REAL numbers. The REALs you specify as the child's coordinates are not used directly - they are interpreted by GRAPE.
Here are the rules of this interpretation. You specify the 4 parameters: x, y, width
and height of the child window.
< 0 |
0 .. 1 |
> 1 |
|
X |
parent.w - abs(x) |
parent.w * x |
x |
Y |
parent.h - abs(y) |
parent.w * y |
y |
W |
parent.w - abs(w) |
parent.w * w |
w |
H |
parent.h - abs(h) |
parent.w * z |
h |
X and Y are calculated from the upper left corner of the parent client area,
X - horizontally; Y - vertically;
Thus, if you want to occupy the right half of the parent's window client area you should specify its coordinates in the following way:
x = 0.5 y = 0 w = 0.5 h = 1.
The child window will follow the parent window resizing.
For example, the following formulas are used for a SpeedBar and StatusLine
SpeedBar : x = 0, y = 0, w = 1, h = 40
StatusLine: x = 0, y = -20, w = 1, h = 20
Note This does not refer to positioning desktop elements inside the desktop.
In this section we discuss some meaningful details dealt with a tile's creation, initialization, and basic attributes of each the TILE descendant. There are a lot of useful features that are not presented here, but some of them considered later in this manual. As you may suppose the full list of the class properties is explained in GRAPE's On-Line Help Reference.
As you may suppose all attributes available in class TILE are available for all GRAPE windowed classes. This is the base of the GRAPE class hierarchy. It contains the basic properties of an object that may be visible and responds to user actions.
name : STRING
Each tile object has its name. For some classes such as TILE attribute name is only an internal property that identifies tile object uniquely. For some tile's descendants attribute name is the caption string of its title bar. Name of tile is specified by the first parameter of tile creation procedure and can be changed during tiles life by the set_name feature.
parent : GROUP
Contains the parent window object of this TILE.
rect : RECT
Contains the logical coordinates of TILE inside the parent window. There is one feature logical_to_physical that converts logical coordinate to physical according to the GRAPE conversion scheme.
prect : RECT
Contains physical coordinates of TILE's client area inside it's parent's window client area. The correct values appear only after first on_move and on_size callbacks, i.e. before first on_paint callback. There are two features screen_to_client and client_to_screen that convert screen coordinates into physical coordinates inside object's client area and back. You can change tile size and position using the resize and move features.
on_parent_resize ( parent_w, parent_h : INTEGER )
Due to the GRAPE logical coordinate scheme you can set tile size depended from size of the tile's parent. This feature adjusts tile size when parent has been resized.
context : INTEGER
Contains the help context of the APPLICATION when the current object is active. See the chapter dedicated to the application help.
makeTile ( tile_name : STRING; r : RECT; ctx : INTEGER)
Creates a TILE object. The tile_name parameter contains name
of tile object,
r determines logical tile's coordinates and ctx - tile's help context.
not_processed : INTEGER is 0; processed : INTEGER is 1;
These two constants play important role in GRAPE tile features. They are discussed in the following chapter.
activate()
This feature activates the tile object. The tile being activated is received from the user input (keyboard keys and mouse events). Only one tile can be active at one moment. Thus, when the tile has been activated the system deactivate-s the previous active tile object by calling its deactivate feature. You can check this state by calling the is_active function.
hide()
This feature hides the tile object. After the tile has been hidden it disappears from the screen. To return it back to the visible state you should call the show feature. When a tile is hidden it cannot be active. You can check the tile visibility by calling the is_visible function.
disable()
This feature disable-s the tile object. After the tile has been disabled it is still visible on the screen (if it was shown before) but cannot be active. It looks as if the tile object ignores the user action. To revert the tile to the normal state you should call the enable feature. You can check this state by calling the is_enabled function.
Note After a tile has been disabled it can still receive messages from the system.
set_interface_style ( style_code : INTEGER, state : BOOLEAN ) get_interface_style ( style_code : INTEGER ) : BOOLEAN
Sometimes you do not need to redefine tile's initialization features. You can set the particular interface style and achieve the same result. There are some style codes available in class TILE (See also class WINDOW interface styles).
Style code |
Meaning |
STYLE_DISABLED | This predefined style code means that the newly created window object will be initially disabled. |
STYLE_VISIBLE | This predefined style code means that the newly created window object will be initially visible (default style). |
STYLE_GROUP | This predefined style code controls the keyboard interface of object when used in dialogs. |
STYLE_TABSTOP | This predefined style code controls the keyboard interface of object when used in dialogs. If the style is set then the object may be selected in a dialog by using Tab key. |
For example, feature enable might look something like this:
enable() is do set_interface_style ( STYLE_DISABLED, False ); end;
The next two features determine the tile border style.
border_style : INTEGER set_border_style ( border_style_code : INTEGER )
A tile object can have a border. This feature sets one of the
predefined border styles.
Border code |
Meaning |
NO_FRAME | Tile will not have any border. |
SIMPLE_FRAME | Tile will have a thin non-resizable border. |
RESIZABLE_FRAME | Tile will have a resizable border. |
MODAL_FRAME | Tile will have a modal border provided by windowing platform. |
destroy()
This feature destroys the tile object. The window is closed and removed from the parent's group. All future reference to object may be fatal.
can_destroy()
When the application executes the destroy feature it calls this very function. This is "Are_you_sure_to_exit?" conformation for the tile object. If the tile object does not want to be closed it must return constant not_processed otherwise it returns processed. For example you can redefine this feature to get exit confirmation from User.
can_destroy : INTEGER is local msg_box : MESSAGE_BOX; do !!msg_box.make ("Are you sure to close tile?", "Exit", msg_box.YES_NO, msg_box.ICON_QUESTION); if execute( msg_box ) = msg_box.YES_BUTTON then Result := not_processed; else Result := processed; end; end -- on_destroy
Feature above shows the exit conformation message box to User.
init()
This is a special feature that establishes a link from the GRAPE tile object to a physical window object (vis-a-vis) in your operating system.
Note This feature is called automatically from the GRAPE kernel and must not be called by User. You can only redefine it with special care.
Tips for Advanced programmers: There is one tile's attribute sys_id that contains the window handler (
HWND) for the current tile object after feature init() has been called.All window operations - painting, timer callbacks, mouse movements are valid only after init() has been completed. There is special function is_valid that returns True if it happens.
As was noted above class GROUP is used as a container for its child tiles object. It propagates all operation upon the group to its children.
make ()
Creates a GROUP object. Performs some initializations.
Note The creation procedure of class GROUP does not call the creation procedure of its ancestor - class TILE. Thus, the object of class GROUP is not a tile. GROUP redefines most of TILE's features to support its basic idea - the propagation of events. See class WINDOW.
childs : ARRAY [ TILE ]
This array contains the group of children. Function number_of_childs() contains the total number of children in the group. One of the children may be the current one - the special state of a child when it is active - it receives User input. Attribute cchild contains the index of the current tile in the group. Although array childs is exported to {ANY} we strongly recommend to use function child ( I : INTEGER) to obtain the particular group member.
add ( t : TILE ), insert ( t : TILE; before_tile : TILE )
Appends the specified child to the end of the group. Appended child becomes the current in the group. Attribute parent of the appended child is set to point to this GROUP object. After tile has been inserted it can be removed by procedure remove.
can_destroy() : INTEGER
When someone wants to close and destroy a GROUP object the feature "asks" every group's child "what they are thinking about their death". If one of them against - the group returns not_processed - otherwise processed.
Other features which were redefined from class TILE: enable, disable, etc. have the same "broadcasting" effect.
init ()
This is the feature which is redefined from class TILE and does the following things. For every child t of the group the feature performs the following actions:
t.init -- initializes the child t.on_create -- forces the creation callback t.show -- sets the visible state t.repaint -- forces repainting t.on_parent_resize -- forces repositioning inside group
Thus, a group performs all actions to wake a child tile object up.
As was noted above class WINDOW unites the group functionality and the tile behavior. In addition WINDOW has a menu and title bar.
make ( tile_name : STRING; r :RECT)
Creates a WINDOW object. Creates an empty group of children, creates a tile object with the specified name and position. Normally tile_name appears on the window title bar.
Class WINDOW brings some new interface styles in addition to ones defined in TILE.
Style code |
Meaning |
STYLE_CAPTION | This predefined style value means that window has a caption in its system area. |
STYLE_SYSTEM_MENU | This predefined style value means that window has a system menu button in its non-client area. |
STYLE_MAXIMIZE_BUTTON | This predefined style value means that window has a maximize button in its non-client area. |
STYLE_MINIMIZE_BUTTON | This predefined style value means that window has a minimize button in its non-client area. |
add ( child : TILE )
If window is already initialized and attribute auto_create_child is True then this feature in addition to adding children into the group also initializes the tile just inserted. So it produces all the following initializations:
child.init child.on_create child.show child.repaint child.on_parent_resize
menu : MENU, set_menu (m : MENU)
You can attach your own menu object to the window. See the chapter about menus.
As was noted above class DESKTOP operates with its child windows - the Desktop elements. It brings the MDI (Multiple Document Interface) manager functionality to class WINDOW - it can arrange, cascade, tile the children, etc.
make ()
Creates a DESKTOP object. The size of desktop is determined by the size of it's parent - class APPLICATION.
add ( child : DESKTOP_ELEMENT )
In addition to the window functionality this feature activates inserted child. Child must conform to class DESKTOP_ ELEMENT.
Class SIZABLE_WINDOW adds an ability to minimize, maximize,
resize a window object. This window object has its own icon displayed while being
minimized.
Based on class SIZABLE_WINDOW this class has some low-level
differences in its behavior compared with one of the ancestors. For example an object of
this class cannot have user menu. To be more precise - the menu of current desktop element
is attached to the APPLICATION menu. The default desktop element has the system
menu, minimize and maximize buttons and resizable frame.
make ( app_name : STRING ), make_at_pos ( app_name : STRING, pos : RECT )
Create an APPLICATION object.
make_speedbar : SPEEDBAR make_statusline : STATUS_LINE make_desktop : DESKTOP make_help : HELP make_menu : MENU
Creates a standard APPLICATION attributes SPEEDBAR, STATUS_LINE, DESKTOP, MENU, HELP.
run
You always must call it to start the application object just created. This feature is very important and that's why we would like to describe it here more precisely. It performs exactly the following job (the real code is so brief and expressive):
desktop := make_desktop() add(desktop) statusline := make_statusline() add(statusline) speedbar := make_speedbar() add(speedbar)
init()
set_icon(icon) refresh_background()
user_menu := make_menu if user_menu /= Void then user_menu.set_parent(current) set_menu (user_menu) end
if desktop /= Void then desktop.init() tmp := desktop.on_create() end -- if statusline /= Void then statusline.init() i := statusline.on_create() statusline.show() statusline.repaint() statusline.on_parent_resize(prect.w, prect.h) end -- if speedbar /= Void then speedbar.init() i := speedbar.on_create() speedbar.show() speedbar.repaint() end
coord_setup() -- taking into account -- presents of all components
help := make_help()
on_create()
application_run() -- Run-time library Windows -- message loop
Now it's time to include some examples.
Here is an example of the simplest application. Class SIMPLE_ APPLICATION is the Root class and feature make is its creation procedure.
class SIMPLE_APPLICATION inherit APPLICATION rename make as app_make end creation make feature make is do app_make ("Simplest application") run end end -- class SIMPLE_APPLICATION
You can find its code in the EXAMPLES\SIMPLEST directory. This program creates the following simple application window.
Figure 2.4 The simplest application.
Most applications also create many other windows - directly or indirectly - to perform tasks related to the main window. Each window plays a part in displaying output and receiving input from User.
The following example is more complicated one. You can find its code in the EXAMPLES\WINDOWS directory.
Figure 2.5 A simple MDI application.
There is class WINDOWS_APP which is the GRAPE application that has its own menu with several items, feature on_command processing the menu commands and an exit confirmation dialog box.
-- -- This application demonstrates the basic window classes hierarchy. -- class WINDOWS_APP inherit APPLICATION rename make as app_make; redefine on_command, make_menu, can_destroy select on_command, make_menu, can_destroy, init end creation make feature ---------------------------------------------------------------- make is do app_make ( "Windows application" ); -- name of the application run end ---------------------------------------------------------------- make_menu () : MENU is -- See chapter on menus local menus : MENU; popup : SUB_MENU_ITEM; entry : MENU_ENTRY; item : MENU_ITEM do !!Result.make_root; !!menus.make; !!item.make("&New child window", 0, IDM_NEW ); menus.add(item); !!entry.make_separator; menus.add(entry); !!item.make("&Close", 0, IDM_CLOSE ); menus.add(item); !!item.make("Close Al&l childs", 0, IDM_CLOSE_ALL); menus.add(item); !!item.make("E&xit", 0, IDM_QUIT ); menus.add(item); !!popup.make("&File", 0, menus ); Result.add(popup); !!menus.make; !!item.make("&Cascade", 0, IDM_CASCADE ); menus.add(item); !!item.make("&Tile", 0, IDM_TILE ); menus.add(item); !!item.make("Arrange &Icons", 0, IDM_ARRANGE ); menus.add(item); !!popup.make("&Window", 0, menus ); Result.add(popup); end; ---------------------------------------------------------------- -- This feature executes every time when User selects some item -- from the application menu. on_command ( cmd : INTEGER ) : INTEGER is -- local desktop_el : CHILD_WINDOW ; do Result := processed; inspect cmd when IDM_NEW then -- when User selects "New" from menu... !!desktop_el.make ( "Child" ); desktop.add ( desktop_el ); when IDM_TILE then desktop.tile(); when IDM_CASCADE then desktop.cascade(); when IDM_ARRANGE then desktop.arrange(); when IDM_CLOSE_ALL then desktop.wipe(); when IDM_CLOSE then if desktop.get_current /= VOID then desktop.get_current.destroy(); end; -- if when IDM_QUIT then terminate(); else Result := not_processed; end; -- inspect end; -- on_command ---------------------------------------------------------------- can_destroy : INTEGER is local msg_box : MESSAGE_BOX; do !!msg_box.make ("Are you sure to exit?", "Exit", msg_box.YES_NO, msg_box.ICON_QUESTION); if execute( msg_box ) = msg_box.YES_BUTTON then Result := not_processed; else Result := processed; -- do not exit end end -- on_destroy ---------------------------------------------------------------- feature -- menu commands IDM_NEW, IDM_CLOSE, IDM_CLOSE_ALL, IDM_QUIT, IDM_CASCADE, IDM_TILE, IDM_ARRANGE : INTEGER is unique; end -- class WINDOWS_APP
When User selects the New command from the File menu a new desktop element of type EDIT_WINDOW is being created. Desktop elements can be arranged or closed.
The following is the class EDIT_WINDOW. It is the heir of DESKTOP_ELEMENT. It contains the child window of type MEMO_EDIT. It looks like a simple text editor window.
class EDIT_WINDOW inherit DESKTOP_ELEMENT rename make as de_make end creation make feature edit_text : MEMO_ENTRY ; make ( str : STRING ) is local r : RECT; -- rectangle do de_make ( str ); -- create itself !!r.make ( 0, 0, 1, 1 ); -- entire parent window !!edit_text.make ( "Memo", r, 0 ); -- create edit control add ( edit_text); -- insert it end end -- class EDIT_WINDOW
When object EDIT_WINDOW is being created it creates the edit_text control and inserts it into the children group. When EDIT_WINDOW is added into Desktop it becomes visible with its child's edit_text.