GUI library defines many data structures and procedures that together form something that conditionally can be called "OOP". It is object oriented, as long as it deals with GUI "objects" - forms, controls, menus etc. All these objects are in fact structures of data. For every created object, the library allocates some memory and fills this memory with object parameters data.
There are two types of data structures that describe GUI objects - classes and instances.
The class is a structure that contains data commonly used by all objects of given type - for example all buttons use one class structure CButton.
The instance is data structure that describes the properties and behavior of particular GUI object - for example button with icon "open file" that opens a file when the user click on it.
Classes
"Class" in FreshLib is a data structure, that have the following definition:
struct TObjectClass .ptrParent dd 0 .dataSize dd 0 .procCreate dd 0 .procDestroy dd 0 .procGetParam dd 0 .procSetParam dd 0 .procExecCmd dd 0 .procSysEventHandler dd 0 ends
.ptrParent is a pointer to other TObjectClass structure, that appears as a parent class for the given class.
.dataSize contains the size of the object instance structure.
The following fields are the pointers to procedures that provides the "work" of the object. All of these pointers as a rule can be NULL, if there is no need for such processing.
Create
.procCreate is a procedure that creates instance object of the given class. This field can be NULL. It has the following definition:
proc Create, .obj
This procedure sets needed values in the object instance data structure.
Destroy
.procDestroy is a procedure that destroys an instance of the given class.
proc Destroy, .obj
Destroys the object passed in [.obj] and frees all memory allocated for this object.
GetParam
.procGetParam is a pointer to the procedure that retrieves and returns the properties of the object.
proc GetParam, .obj, .paramID
Returns the value of the object [.obj] parameter with ID=[.paramID]
Set
.procSetParam is a pointer to the procedure that set the properties of the object.
proc Set, .obj, .paramID, .value
For object [.obj], set the value of the parameter with ID=[.paramID]
ExecCmd
.procExecCmd is a pointer to the procedure that executes object method.
proc ExecCmd, .obj, .method
For the object [.obj] this procedure executes the method with method ID in [.method].
The methods can have arbitrary number of arguments, that are defined in the "object" definition (see below). When the method is executed, the procedure [.procExecCmd] accepts pointer to the arguments array in [ebx]
The user is supposed to call methods of the object with the macro "execute" The macro is defined following way:
macro execute obj*, meth*, [arg]
SysEventHandler
.procSysEventHandler is a pointer to the procedure that process the system events that are send to the object, i.e. mouse events, keyboard events etc.
proc SysEventHandler, .obj, .pEvent
Process one system event for object [.obj]. [.pEvent] contains pointer to the system event.
All of these procedures are called internally and should not be used by the user of the library. How these procedure are called will be described later.
TObjectClass structure is defined statically in memory in compile time, only once for every object class. Its definition is located in the library for the respective GUI element. For example CButton class structure is defined in the file TButton.asm that contains the code and data of the object class Button.
In order to make construction of such structures easy, macro with name ObjectClass is defined in objects.asm
ObjectClass Macro
macro ObjectClass name*, parent*, procCreate*, procDestroy*, procGetParam*, procSetParam*, procExecCmd*, procSysEvents*
Every defined ObjectClass have a label that points to the begin of the structure. The name of this label is the name of the class, prefixed with "C".
One example of ObjectClass definition is the definition of Window object class:
ObjectClass Window, \ Object, \ TWindow.Create, \ TWindow.Destroy, \ TWindow.Get, \ TWindow.Set, \ TWindow.ExecCmd, \ TWindow.SysEventHandler
This definition creates following data structure:
CWindow: dd CObject dd sizeof.TWindow dd TWindow.Create dd TWindow.Destroy dd TWindow.Get dd TWindow.Set, dd TWindow.ExecCmd dd TWindow.SysEventHandler
Object structure
Object instance is data structure that contains different fields. By that it is very similar to the normal FASM structures. As structures, the object is only description of the data but not the data itself.
Objects can inherit field definitions by its parent objects. The memory instance of the object is allocated dynamically in runtime, when the object is created by call to the respective FreshLib functions.
The definition of the object looks like following:
object TObject .ptrClass dd ? .OnCreate dd ? .OnDestroy dd ? method .AddChild, .objchild endobj object TWindow, TObject .handle dd ? .Fcaption dd ? .Fcursor dd ? param .x param .y param .width param .height param .visible param .caption param .parent param .cursor method .Refresh endobj object TButton, TWindow .state dd ? .Ficon dd ? .FiconAlign dd ? .Ftextalign dd ? .OnClick dd ? param .TextAlign param .Icon param .IconPosition endobj
By convention the names of the objects begin with "T".
You can see that the object TWindow contains data fields, parameters and methods. The parameters defined by "param" macro are compile time constants which values are assigned automatically. There constants are local labels for the object structure. They are also inherited from the parent structure.
The methods are very similar to parameters, in that they are constants, defined in compile time. But besides the constant, the method also have list of arguments, passed to the method, when executed.
In the above example, TButton.width parameter is inherited from TWindow and have the same value as TWindow.width parameter.
Also, TWindow have all fields of TObject defined as well.
If we have to translate TWindow definition in plain FASM syntax it will looks like this:
struc TWindow { .ptrClass dd ? .OnCreate dd ? .OnDestroy dd ? .handle dd ? .Fcaption dd ? .Fcursor dd ? .x = $80000000 .y = $80000001 .width = $80000002 .height = $80000003 .visible = $80000004 .caption = $80000005 .parent = $80000006 .cursor = $80000007 } virtual at 0 TWindow TWindow sizeof.TWindow = $ end virtual
This directory contains the libraries providing portable GUI for assembly programming.
Note that this libraries are in very early stage of development, so the description in this chapter is preliminary and probably will be changed in one or another way in the near future.
Later in this text, the whole GUI subsystem of FreshLib will be called FreshGUI
FreshGUI structure
The main idea behind the FreshGUI is to make one small OS dependent layer of functions, that to serve as an interface between the OS and the OS independent layer of the library.
The first will translate OS events, such as mouse, keyboard, timers etc to one common standard of OS independent event handlers of the user interface objects – windows, buttons and other widgets.
The biggest advantage of this approach is that the portability of the library is very easy – most of the code is OS independent and only little part of it have to be write in order to port the whole library to a new OS.
The biggest drawback of this approach is the bigger size of the library, because, with this architecture, all controls in the library have to be created from scratch. It is impossible to use graphic controls that the OS provides – particularly Win32 controls - buttons, simple text editors, labels, combo boxes list and tree view controls etc.
FreshGUI is not aimed to use all complex GUI system of the target OS. At first time, the goal of FreshGUI is to provide minimal but decent functionality that will do the job – writing portable applications in assembly language.
Graphics library
The graphics library provides procedures that draw graphics images and text on the screen. The library is OS dependent and is placed in the directory "graphics" in the root directory of FreshLib. The main conception of this library is ".raster" - represented by handle, object where the drawing happens. The exact meaning for this object is different for the different OS – in Win32 it is named "device context", in Linux it is "drawable" - window or pixmap.
Event translation layer
Library "sysevents.asm"
This library contains event codes and data structures for FreshGUI OS independent events. For now only several events are defined:
seMouseMove seMouseEnter seMouseLeave seMouseBtnPress seMouseBtnRelease seMouseBtnClick seMouseBtnDblClick seTimer seKbdKeyPress seKbdKeyRelease seKbdStatusChanged seKbdChar sePaint
These events cover mouse, keyboard, timers and paint events.
Every event have some arguments that have to be sent to the recipient event handler. The event code and the event arguments are contained in data structure, defined for every kind of events.
The first dword of the event structure is the field .event that contains the event code.
Here are the structures defined in sysevents.asm
struct TSysEvent .event dd ? ends
The base event structure.
struct TMouseMoveEvent . TSysEvent .x dd ? .y dd ? ends
The event is generated when the mouse cursor moves over some window or control. .x and .y contains the coordinates of the mouse cursor relative to the control this message is sent to.
struct TMouseButtonEvent . TSysEvent .Button dd ? .kbdStatus dd ? ends
This event is generated when some of the mouse buttons changes its state. The button that changes its state is specified in the field .Button
This field can accept following values:
mbLeft | = 0 |
mbMiddle | = 1 |
mbRight | = 2 |
The field .kbdStatus contains the status of remaining mouse buttons and keyboard modifying buttons. These buttons are represented by bits in the field:
maskBtnLeft | = $01 |
maskBtnMiddle | = $02 |
maskBtnRight | = $04 |
maskCtrl | = $08 |
maskShift | = $10 |
struct TMouseEnterEvent . TSysEvent ends
This event is generated when the mouse cursor enters or leaves some control. There is no additional parameters besides the event code.
struct TKeyboardEvent . TSysEvent .key dd ? .kbdStatus dd ? ends
This event is generated on keyboard button press/release. The field .key contains the code of the pressed button. .kbdStatus have the same meaning and the same values as in TMouseButtonEvent.
struct TTimerEvent . TSysEvent ends
TTimerEvent is generated on timer events. :)
struct TPaintEvent . TSysEvent .raster dd ? ; ID of the raster where you should paint. .rect RECT ends
TPaintEvent is generated when given control have to be repainted. The field .raster contains the handle to the graphic surface where the program have to draw. This handle have different meanings in the different target OS, but it simply need to be understandable by the graphics procedures from the OS dependent library graphics.asm.
The field .rect is the rectangle of the control that needs to be repainted.
Library "main.asm"
proc Run
This procedure is the main program loop of the GUI application.
The procedure Run process all pending system events, then calls once the OnIdle event handler of the application object and then sleeps until new events are sent by the OS.
When the OS terminates the application – the procedure returns an exit code.
The user uses this procedure following way:
stdcall Run jmp ExitApplication
proc ProcessSystemEvents
This procedure process the events generated by the OS. If there are waiting events in the queue, the procedure reads them, translates them to FreshGUI event data structures and calls the event handlers of the respective controls.
If there is no pending events in the queue, ProcessSystemEvents ends with CF=0
The second task this procedure serves is to detect the end of the application. In this case it ends with CF=1.
This procedure is call from the main event loop of the application. Also, the user can periodically call this procedure in order to not allow hanging of the user interface during long processing of some data.
proc WaitForSystemEvent
This procedure waits until some system message is posted to the application event queue. Then it exits. During the wait, very low CPU power is consumed by the application.
proc Terminate
It provides all finalization tasks and ends the application. The exit code is provided in EAX.
Template engine
The template engine provides creation of complex window structures with tree layout from memory data structure, called template. The templates makes creation of dialog windows containing children windows and non visual objects.
Templates can be visually created and edited. The template format used by FreshLib is flexible and allows all parameters and fields of the objects to be set to needed values during creation of the window.
The template engine is located in the file ObjTemplates.asm
Template data structure
The template is consisted from one or more data structures of type TObjTemplate, defined following way:
struct TObjTemplate .flags dd ? .class dd ? .ptrVar dd ? .paramsize dd ? .params: ends
.flags – controls what is the place of the object in the whole tree structure.
Can accept one or both of the following values, combined with OR:
tfChild | =0 | means the object is child of the last object with tfParent set. |
tfParent | =1 | means the given object is parent and there will be next TObjTemplate structure that will be a child object. |
tfEnd | =2 | means the given object is the last child of its parent. Note, that one object can be parent and child in the same time. If the current template is at root level – the processing of template stops, after creating the current element and all its children. |
.class – pointer to TObjectClass data structure for the created object.
.ptrVar – pointer to dword variable that to accept the pointer to the created object.
.paramsize – the size of the additional data to the end of the template. Note, that TObjTemplate is variable length structure, not fixed. sizeof.TObjTemplate contains the size of the header part of the structure.
.params: after the header fields there can be arbitrary count of dword pairs: (paramID, Value) that to be set the the object during creation. This sequence ends with dword $FFFFFF (-1) value for paramID.
Easy creation of templates is provided with macro ObjTemplate:
macro ObjTemplate flags, class, name, [id, param]
This macro allows use of string values for params and computes automatically the values for TObjTemplate.paramsize
flags – set of (tfParent, tfEnd) constants.
class – the base name of the object class (without prefix C) – i.e. Form, Window, Button, etc.
name – label of the variable to receive the pointer to the created object.
id – parameter ID or offset in the object structure.
param – value of the parameter. Can be dword number or string constant. In the case the parameter value is string, it will be automatically created in the memory and the pointer to this string will be placed as a param value.
One simple example of template structure:
ObjTemplate tfParent or tfEnd, Form, frmMain, \ visible, TRUE, \ x, 100, \ y, 50, \ width, 640, \ height, 480, \ caption, 'Fresh portable Win32/Linux application test.' ObjTemplate tfChild, Button, btnChild1, \ visible, TRUE, \ x, 64, \ y, 48, \ width, 64, \ height, 24, \ caption, 'Button1', \ OnClick, Button1Click ObjTemplate tfChild or tfEnd, Button, btnChild2, \ x, 136, \ y, 48, \ width, 64, \ height, 24, \ caption, 'Button2' ,\ visible, TRUE
Template engine procedures
Actually the procedure is one:
proc CreateFromTemplate, .ptrTemplate, .parent
This procedure creates all objects from the template, pointed by [.ptrTemplate] as a parent of [.parent] argument.
.ptrTemplate points to TObjTemplate structure.
.parent points to TObject descendant structure. In most cases it will be actually descendant of TWindow or NULL if the created object is not a child of any window.
Returns: EBX contains a pointer to the topmost of the created object (it is first of the created objects)
All pointers of the objects are stored in the specified in the template variables ( i.e. [TObjTemplate.ptrVar])