Quick start


Because this project is under development and many things can change, there is no complete documentation. The following is just basic information to help understand how the examples work and to enabling the use of certain elements of the framework.


How to create class

To create a class, you must create two files ClassName.h and ClassName.c. In the first one, you must put the class declaration

proto_class (ClassName);

Additionally, the following elements may also occur:

  • Methods declarations
    proto_method (PrefixNameMethods, return type or void, type of the first argument, type of second argument, etc.);
  • Setters declarations
    proto_setter (Prefix, PropertyName, property_type);
  • Getters declarations
    proto_getter (Prefix, PropertyName, property_type);

In the ClassName.c file, the following elements must be present:

  • Definition of class fields
        class_data (PrefixClassName)
        {
            type1 field1;
            type2 field2;
            etc.
        };
    
  • Definitions of constructors
        PrefixClassName *PrefixClassNameConstructor(class_arg, more arguments)
        {
            PrefixClassName *self = (PrefixClassName*) PrefixSuperClassNameConstructor(clazz, more arguments);
    
            using_data;
    
            // Constructor code
    
            return self;
        }
    
  • Definitions of methods
        typ PrefixMethodName(object_arg, more arguments)
        {
            using_data;
    
            // Metody code
        }
    
  • Class definition
        class_begin (PrefixClassName, PrefixSuperClassName)
        {
            getter (Prefix, PropertyName, function implementing getter, optional metadata);
            setter (Prefix, PropertyName, function implementing setter, optional metadata);
            method (MethodName, function implementing method, optional metadata);
        }
        class_end
    

Because C does not have namespaces, prefixes are used to prevent name conflicts. They should be written in large letters, do not be too long preferably 2 or 3 characters. All prefixes containing F as the second letter are reserved for the framework.

Is it possible to create a class even easier and faster? Yes! We have created a tool and we will make it available in one of subsequent editions, which creates class' .h and .c files based on definition file and allows regeneration of this files without losing added content.

Sample class definition file:

    class TR::TimeoutButton : AF::Button
    {
        constructor();

        object AF::ProgressBar *progressBar;
        object AF::TextView *textView;
        object AF::Animation *animation;
        type TRState state;
        type float progressBarValue;
        type float progressBarPreviousValue;

        object AF::String *actionText var set;
        object AF::String *onTimeText var set;
        object AF::String *tooLateText var set;

        override void AF::draw(object AF::Graphics *graphics);
        override void AF::mouseUp(object AF::MouseEventArguments *mouseEventArguments);
        override void AF::setupComponent(object AF::Application *application);

        void TR::reset();
    }

There is a variable self accessible inside every method which points to the object in context of which the method was called. Additionally there is a variable clazz accessible in a ClassName.c file that points to the class defined in it. To access the class fields, use using_data; inside of a method, it adds data variable, which points to the structure containing the class data. This structure is of the PrefixClassNameData type. Inside the method, you can call the base class method by adding the suffix Super to the method's name:

AFDrawSuper(graphics);

To be able to use a created class, you must first register it using the following command:

register_class (PrefixClassName);

It must be done before the first instance of the class, or the class that inherits it is created.

Note! In one *.c file there can be only one class definition.


Using of classes

To create a class instance, use the following command:

var classInstance = PrefixCreateClassName(arguments);

Calling the method looks like this:

PrefixMethodName(obiect, arguments);

If the object does not implement the given method, an exception will be thrown.


Exceptions

Exceptions are reported using raise (objectInformationofCodeException); command

To catch an exception, use the following command:

    on_error
    {
        // Code
    }
    resume (type1)
    {
        // type1 exception handling
    }
    resume (type2)
    {
        // type2 exception handling
    }

    etc.

    end_resume

There is exception variable accessible in every resume clauses, which points to the object used in the raise command.


Collections

Collections are objects which keep other objects inside of themselves.

AFMutableArrayList is a modifiable array based list, its use is as follows:

    var list = AFCreateMutableArrayList(); // Collection creation

    AFAppendObject(list, object); // Adding an objest after the last element
    var pobranyobiect = AFGetObjectAtIndex(list, 0); // Get an object of index 0
    AFRemoveObject(list, object); // Removal of the object
    size_t size = AFGetSize(list); // The number of elements of the collection

The easiest way to iterate all elements of the collection is to use for_each command

    for_each (obiect in list)
    {
        // The variable object will contain subsequent elements of the collection
    }

or

    for_each (obiect, index in list)
    {
        // The variable object will contain subsequent elements of the collection
        // The variable index will contain the index of the current element
    }

AFMutableDictionary is a dictionary, it stores key-value pairs. Its use looks like this:

    var dictionary = AFCreateMutableDictionary();

    AFAppendObjectForKey(dictionary, key, value); // Appends value for given key
    var value = AFGetObjectForKey(dictionary, key); // Retrieves value for given key
    AFRemoveObjectForKey(dictionary, key); // Remove value of given key

Components

Different components are used to create programs. Some of them are UI controls, and some are non-graphic elements. A few of them are listed below.

  • AFApplication is responsible for message processing and other aspects of application operation.
  • AFAnimation allows to animate visual objects.
  • AFTimer allows to call a given function at specific intervals.

User interface

To build an UI, one creates the appropriate controls and connect them together. Each control can have one parent. AFWindow, AFButton, AFLabel like controls can have content set. In the case of AFWindow it will be usually the panel, in the case of AFButton and AFLabel it will be a text. To set content, create an object that will represent it and use AFSetContent(control, contentObject) method.

The situation is slightly different in the case of panels. You can connect any number of controls to them using AFAppendComponent (panel, control) method. Depending on the type of panel, they will be arranged in a certain way. As of now, only one panel is available, i.e. AFFlowGridPanel.

Controls report events such as mouse down, mouse up, etc AFAddEventHandlerFunction and AFAddEventHandlerMethod methods are used to get notification about this events. The AFAddEventHandlerFunction method takes the following parameters:

void AFAddEventHandlerFunction(
   AFObject *object,
   AFString *eventName,
   void *context,
   AFEventHandlerFunctionEntryPoint functionEntryPoint);
  • object - the control affected by the event,
  • eventName - event name,
  • context - a pointer to any data,
  • functionEntryPoint - a pointer to the function that will be called when an event occurs.

The event handler will be called with the following parameters:

void eventHandlerFunction(void* context, uint32_t index, AFObject *sender, AFObject *eventArguments);
  • context - value of the context argument passed in the AFAddEventHandlerFunctionWithName call,
  • index - not used,
  • sender - pointer to the control this event refers to,
  • eventArguments - event data (e.g., mouse pointer location).

The AFAddEventHandlerMethod method takes the following parameters:

void AFAddEventHandlerMethod(AFObject *object, AFString *eventHandlerName, AFObject *object, AFString *methodName);
  • object - the control affected by the event,
  • eventName - event name,
  • context - a pointer to any data,
  • methodName - name of the method that will be called when the event occurs.

The event handler will be called with the following parameters:

void eventHandlerMethod(AFObject *sender, AFObject *eventArguments);
  • sender - pointer to the control this event refers to,
  • eventArguments - event data (e.g., mouse pointer location).

The window object should be connected to the previously created application object (AFApplication) using the AFAppendComponent(applicationObject, windowObject) method. When UI is constructed the AFShow(windowObject) method causes the window to appear. AFRunMainLoop(applicationObject) method starts events processing.


Memory management

Each object has a reference counter, which indicates in how many places the pointer to it is stored. Immediately after creation, this counter is set to 1. The AFObtain(object) method increases the value of this counter, the AFRelease(object) method decreases it. When the value reaches 0, the object is deleted - its destructor is called and the memory is released. There is also a pool of objects to be released. Object is appended to the pool during its creation. The pool is processed just before the application is finished or if an application has created the AFApplication object and called the AFRunMainLoop method, then the pool processing takes place in message loop every time the application goes idle. For each object in the pool the AFRelease method is called and object is removed from the pool. If, therefore, the AFObtain operation has never been performed, the object will be deleted. If every assignment is accompanied by the appropriate AFObtain and AFRelease, all objects will be released when they are no longer used, and consequently there will be no memory leaks.

The current version of the framework

The library containing framework's functionality is currently prepared for static linking. The consequence of this is large size of executable files using it. This will change when the library is converted into a dynamic one. There are also a lot of optimization possibilities regarding speed of implemented methods and amount of memory they use. Therefore, no conclusions should be drawn on these matters based on the current version.