API2


API2 is a framework used to create applications for the AmigaOS and compatible systems. It has/will have the following features:

  • Is a set of components and functions that implement the functionality used to write applications.
  • Just as BOOPSI (MUI, Reaction) is based on the concept of binary objects, but implements it in a different, more efficient and more convenient to use way.
  • Unlike BOOPSI, method calls and properties do not require the use of DoMethod, SetAttr, etc., and parameters' types of these calls are checked during compilation.
  • Manages memory by counting references to objects.
  • Allows access to metadata and reflection.
  • Allows to fully control the appearance and structure of UI elements.
  • Provides source code compatibility between all AmigaOS like systems.
  • Is written in C and expands the syntax of this language with classes, exceptions and other features.
  • Is simple to use, does not require knowledge of pointers arithmetic, so can be easily used even by novice developers.

An example program that opens a window with one button:

#include <api2/api2.h>

void buttonMouseClick(not_used void *context, not_used uint32_t index, not_used AFObject *sender,
    not_used AFObject *eventArguments)
{
    printf("Button was pressed!\n");
}

int main()
{
    var application = AFCreateApplication();
    var window = AFCreateWindow();
    var button = AFCreateButton();

    AFAppendComponent(application, window);

    AFSetCaption(window, AFS("Button"));
    AFSetContent(window, button);

    AFSetCaption(button, AFS("Button"));
    AFAddEventHandlerFunction(button, AFMouseClick, NULL, buttonMouseClick);

    AFShow(window);
    AFRunMainLoop(application);

    return 0;
}
screenshots/Button.png

A program that creates a class and uses its instance as window content:

#ifndef TRTIMEOUTBUTTON_H
#define TRTIMEOUTBUTTON_H

#include "UnderworldXF.h"
#include "AFButton.h"

BEGIN_EXTERN_C

proto_class (TRTimeoutButton);

proto_ctor (TR, TimeoutButton, );
proto_getter (TR, ActionText, AFString*);
proto_setter (TR, ActionText, AFString*);
proto_getter (TR, OnTimeText, AFString*);
proto_setter (TR, OnTimeText, AFString*);
proto_getter (TR, TooLateText, AFString*);
proto_setter (TR, TooLateText, AFString*);
proto_method (TRAnimationHasEnded, void, AFObject*, AFObject*);
proto_method (TRReset, void);

END_EXTERN_C

#endif /* TRTIMEOUTBUTTON_H */
#include "api2/api2.h"
#include "TRTimeoutButton.h"

typedef enum TRState
{
    cTRStateStopped,
    cTRStateWaiting,
    cTRStateYouDidIt,
    cTRStateTooLate

} TRState;

class_data (TRTimeoutButton)
{
    AFString *actionText;
    AFString *onTimeText;
    AFString *tooLateText;
    AFProgressBar *progressBar;
    AFTextView *textView;
    AFAnimation *animation;
    TRState state;
    float progressBarValue;
    float progressBarPreviousValue;
};

void animationFunction(void *self, float delta)
{
    using_data

    AFSetValue(data->progressBar, 
        data->progressBarPreviousValue  + ((data->progressBarValue - data->progressBarPreviousValue) * delta));
}

TRTimeoutButton *TRTimeoutButtonConstructor(class_arg)
{
    TRTimeoutButton *self = (TRTimeoutButton*) AFButtonConstructor(clazz);

    using_data;

    data->state = cTRStateStopped;
    data->actionText = NULL;
    data->onTimeText = NULL;
    data->tooLateText = NULL;

    data->progressBar = AFCreateProgressBar();

    AFSetOrientation(data->progressBar, cAFOrientationVertical);
    AFSetMinimum(data->progressBar, 0);
    AFSetMaximum(data->progressBar, 100);
    AFSetValue(data->progressBar, 100);
    AFSetFrameWithRectangle(data->progressBar, AFRectangleMake(0, 0, 12, 35));

    data->textView = AFCreateTextView();

    AFSetVerticalAlignmentWithInt32(data->textView, cAFVerticalAlignmentBottom);

    var panel = AFCreateFlowGridPanel();

    AFSetColumnsCount(panel, 2);
    AFSetRowsCount(panel, 1);
    AFSetHorizontalSpacing(panel, 5);
    AFAppendComponent(panel, data->progressBar);
    AFAppendComponent(panel, data->textView);

    AFSetPadding(self, AFMakeSpacing(10, 10, 10, 10));
    AFSetContentVerticalAlignmentWithInt32(self, cAFHorizontalAlignmentCenter);
    AFSetContent(self, panel);

    data->animation = AFCreateAnimation(3000, AFLinear, animationFunction, self);

    AFAddEventHandlerMethod(data->animation, AFAnimationHasEnded, self, TRAnimationHasEnded);

    return self;
}

static void TRTimeoutButtonSetupComponent(object_arg, AFApplication *application)
{
    using_data;

    AFAppendComponent(application, data->animation);

    AFSetupComponentSuper(clazz, self, application);
}

static AFString *TRTimeoutButtonGetActionText(object_arg)
{
    using_data;

    return data->actionText;
}

static void TRTimeoutButtonSetActionText(object_arg, AFString *actionText)
{
    using_data;

    AFObtainIf(actionText);
    AFReleaseIf(data->actionText);

    data->actionText = actionText;
    
    I(data->state);
    
    if (data->state == cTRStateStopped)
    {
        AFSetText(data->textView, actionText);
    }
}

static AFString *TRTimeoutButtonGetOnTimeText(object_arg)
{
    using_data;

    return data->onTimeText;
}

static void TRTimeoutButtonSetOnTimeText(object_arg, AFString *onTimeText)
{
    using_data;

    AFObtainIf(onTimeText);
    AFReleaseIf(data->onTimeText);

    data->onTimeText = onTimeText;
}

static AFString *TRTimeoutButtonGetTooLateText(object_arg)
{
    using_data;

    return data->tooLateText;
}

static void TRTimeoutButtonSetTooLateText(object_arg, AFString *tooLateText)
{
    using_data;

    AFObtainIf(tooLateText);
    AFReleaseIf(data->tooLateText);

    data->tooLateText = tooLateText;
}

static void TRTimeoutButtonMouseClick(object_arg, AFMouseEventArguments *mouseEventArguments)
{
    using_data;

    if (data->state == cTRStateWaiting)
    {
        AFStopAnimation(data->animation);
        AFSetText(data->textView, TRGetOnTimeText(self));

        data->state = cTRStateYouDidIt;

        AFExecuteEventHandlers(self, TRYouDidItClick, mouseEventArguments);
    }
    else
    {
        AFExecuteEventHandlers(self, TRSubsequentClick, mouseEventArguments);
    }
}

static void TRTimeoutButtonReset(object_arg)
{
    using_data;

    if (data->state == cTRStateYouDidIt || data->state == cTRStateTooLate || data->state == cTRStateStopped)
    {
        data->state = cTRStateWaiting;
        data->progressBarPreviousValue = 100;
        data->progressBarValue = 0;

        AFSetText(data->textView, TRGetActionText(self));
        AFStartAnimation(data->animation);
    }
}

static void TRTimeoutButtonAnimationHasEnded(object_arg, not_used AFObject *sender, not_used AFObject *eventArguments)
{
    using_data

    AFSetText(data->textView, TRGetTooLateText(self));
    data->state = cTRStateTooLate;

    AFExecuteEventHandlers(self, TRTooLate, NULL);
}

class_begin (TRTimeoutButton, AFButton)
{
    getter (TR, ActionText, TRTimeoutButtonGetActionText, object_ptr_t, AFString);
    setter (TR, ActionText, TRTimeoutButtonSetActionText, object_ptr_t, AFString);
    getter (TR, OnTimeText, TRTimeoutButtonGetOnTimeText, object_ptr_t, AFString);
    setter (TR, OnTimeText, TRTimeoutButtonSetOnTimeText, object_ptr_t, AFString);
    getter (TR, TooLateText, TRTimeoutButtonGetTooLateText, object_ptr_t, AFString);
    setter (TR, TooLateText, TRTimeoutButtonSetTooLateText, object_ptr_t, AFString);
    method (AFMouseClick, TRTimeoutButtonAFMouseClick);
    method (AFSetupComponent, TRTimeoutButtonAFSetupComponent);
    method (TRAnimationHasEnded, TRTimeoutButtonAnimationHasEnded, void, object_ptr_t, AFObject, object_ptr_t, AFObject);
    method (TRReset, TRTimeoutButtonTRReset, void);
}
class_end
#include "api2/api2.h"
#include "TRTimeoutButton.h"

void buttonYouDidItClick(not_used void *context, not_used uint32_t index, AFObject *sender, not_used AFObject *eventArguments)
{
    printf("%s\n", AFToCString(TRGetOnTimeText(sender)));
}

void tooLate(not_used void *context, not_used uint32_t index, AFObject *sender, not_used AFObject *eventArguments)
{
    printf("%s\n", AFToCString(TRGetTooLateText(sender)));
}

void buttonSubsequentClick(not_used void *context, not_used uint32_t index, AFObject *sender, not_used AFObject *eventArguments)
{
    TRReset(sender);
}

int main()
{
    register_class (TRTimeoutButton);

    var application = AFCreateApplication();
    var window = AFCreateWindow();
    var button = TRCreateTimeoutButton();

    AFAppendComponent(application, window);

    AFSetCaption(window, AFS("CustomClass"));
    AFSetContent(window, button);
    AFSetContentHorizontalAlignmentWithInt32(window, cAFHorizontalAlignmentCenter);
    AFSetContentVerticalAlignmentWithInt32(window, cAFVerticalAlignmentCenter);

    TRSetActionText(button, AFS("Press me!"));
    TRSetOnTimeText(button, AFS("You did it! :-)"));
    TRSetTooLateText(button, AFS("Too late :-("));

    AFAddEventHandlerFunction(button, TRYouDidItClick, NULL, buttonYouDidItClick);
    AFAddEventHandlerFunction(button, TRTooLate, NULL, tooLate);
    AFAddEventHandlerFunction(button, TRSubsequentClick, NULL, buttonSubsequentClick);

    AFShow(window);

    TRReset(button);
    AFRunMainLoop(application);

    return 0;
}
screenshots/CustomClass.png

Plan for further development:

  • Basic UI components (window, button, radio button, check box, list, drop down list, label, panel, text box, menu, etc.), containers (array list, linked list, dictionary, set, stack etc. ) and their enumerators, other components (application, timer, exceptions, event arguments, logger, unit tests, etc.).
  • Advanced UI components (grid, tree, toolbar, rich edit, animations, etc.).
  • Support for creating documents (MVC, undo/redo, ORM, workflow, dependency injection, serialization and deserialization of objects tree, etc.).
  • The sky is the limit.

The framework is not yet complete, the version which can be downloaded is preview, allowing to evaluate the way it works and development directions. At the moment, the following classes are available (not all of them have full planned functionality yet):

  • AFAbstractCollection - base class for the collection,
  • AFAbstractCollectionEnumerator - base class for enumerators of the collection,
  • AFAbstractList - base class for lists,
  • AFAbstractListEnumerator - base class for list enumerators,
  • AFAbstractMutableCollection - base class for modifiable collections,
  • AFAbstractMutableList - base class for modifiable lists,
  • AFAnimation - UI, a class that performs animations,
  • AFApplication - a class that represents the application,
  • AFArrayList - a non-editable list based on an array,
  • AFBrush - Gfx, the base class for brushes,
  • AFButton - UI, button,
  • AFClass - class metadata,
  • AFComponent - component, base class for UI and non-visual elements,
  • AFComponentList - a collection of components,
  • AFComponentProperty - contains the property added to the component,
  • AFComponentPropertyEventArguments - contains the parameters for the property change event,
  • AFContentControl - UI, base class for controls with content,
  • AFContentPresenter - UI, stores content and displays it,
  • AFControl - UI, the basic element of the user interface, which is the base class for other elements,
  • AFEventArguments - base class for event parameters,
  • AFException - base class for exceptions,
  • AFFlowGridLayoutManager - UI, a class that performs the automatic placement of elements,
  • AFFlowGridPanel - UI, a panel that automatically arranges elements,
  • AFGraphics - Gfx, drawing,
  • AFGraphicsContext - Gfx, the context in which the graphic will be drawn,
  • AFIllegalArgumentException - exception informing about wrong argument,
  • AFIllegalOperationException - exception informing that wrong operation was performed,
  • AFIndexOutOfRangeException - exception informing about exceeding range,
  • AFInt32 - non-modifiable int 32bits value,
  • AFLabel - UI, label,
  • AFLayoutException - UI, an exception informing about problems related to the implementation of the automatic layout,
  • AFLayoutManager - UI, base class for classes that implement automatic placement of elements,
  • AFMouseEventArguments - UI, event parameters associated with using the mouse,
  • AFMutableArrayList - a modifiable list based on an array,
  • AFMutableDictionary - a modifiable dictionary,
  • AFMutableListObservableDecorator - decorator adding observation functionality to a modifiable list,
  • AFMutableString - modifiable text string,
  • AFNotImplementedException - exception informing about lack of implementation of a given functionality,
  • AFObject - base class for all other classes,
  • AFObservable - allows to observe the change in the value of the object,
  • AFOutOfMemoryException - exception informing about inability to allocate memory,
  • AFPanel - UI, the base class for panels,
  • AFProgressBar - UI, progress indicator,
  • AFRandomAccessListEnumerator - enumerator used to retrieve data from the random access collection,
  • AFRectangleBox - contains a structure describing the rectangle,
  • AFSolidColorBrush - Gfx, brush of a given color,
  • AFString - non-modifiable text string,
  • AFTextView - UI, text displaying,
  • AFTimer - counter measuring time,
  • AFUnableToAllocateResourceException - exception informing about inability to allocate resource,
  • AFVisual - UI, the base class for all visual components,
  • AFVisualComponentPropertyFeatures - contains the features of a given AFComponentProperty,
  • AFWindow - UI, window.

Amiga and AmigaOS are either registered trademarks or trademarks of their owner.