Fresh IDE . Documentation
Not logged in

This repository is a mirror!

The original is located on: https://fresh.flatassembler.net/fossil/repo/fresh
If you want to follow the project, please update your remote-url

FreshLib directory: GUI

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])