API2


API2 to framework służący do tworzenia aplikacji dla systemu AmigaOS i kompatybilnych. Posiada/będzie posiadał następujące cechy:

  • Jest zbiorem komponentów i funkcji realizujących funkcjonalności używane przy pisaniu aplikacji.
  • Tak samo jak BOOPSI (MUI, Reaction) bazuje na koncepcji obiektów binarnych, implementuje jej jednak w inny, bardziej wydajny i wygodniejszy w użyciu, sposób.
  • W przeciwieństwie do BOOPSI, wywołania metod i właściwości nie wymagają użycia funkcji DoMethod, SetAttr itd, a parametry tych wywołań są sprawdzane, pod kontem zgodności typów, podczas kompilacji.
  • Zarządza pamięcią poprzez liczenie referencji do obiektów.
  • Umożliwia dostęp do metadanych i użycie refleksji.
  • Pozwala w pełni kontrolować wygląd i budowę elementów UI.
  • Zapewnia kompatybilność na poziomie kodu źródłowego, napisanych w nim aplikacji, pomiędzy wszystkimi amisystemami.
  • Jest napisany w C i rozszerza składnię tego języka o możliwość tworzenia klas i wyjątki.
  • Jest prosty w użyciu, nie wymaga znajomości arytmetyki wskaźników, przez co łatwo mogą z niego korzystać nawet początkujący programiści.

Przykładowy program otwierający okno, którego zawartością jest jeden przycisk:

#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

Program tworzący klasę i używający jej instancji jako zawartości okna:

#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 dalszego rozwoju:

  • Podstawowe komponenty UI (window, button, radio button, chceck box, list, drop down list, label, panel, text box, menu itp.), kontenery (array list, linked list, dictionary, set, stack itp.) i ich enumeratory, komponenty niewizualne (aplikacja, timer, wyjątki, argumenty zdarzeń, logger, testy jednostkowe itp.).
  • Zaawansowane komponenty UI (grid, drzewo, toolbar, rich edit, animacje itp.).
  • Wsparcie dla tworzenia dokumentów (MVC, undo/redo, ORM, workflow, wstrzykiwanie zależności, serializacja i deserializacja drzewa obiektów itp.).
  • Co podsunie wyobraźnia.

Framework nie jest jeszcze ukończony, wersja którą można pobrać to preview pozwalające ocenić sposób jego działania i kierunki rozwoju. Na chwilę obecną dostępne są następujące klasy (nie wszystkie mają pełną planowaną funkcjonalność):

  • AFAbstractCollection - klasa bazowa dla kolekcji,
  • AFAbstractCollectionEnumerator - klasa bazowa dla enumeratorów kolekcji,
  • AFAbstractList - klasa bazowa dla list,
  • AFAbstractListEnumerator - klasa bazowa dla enumeratorów list,
  • AFAbstractMutableCollection - klasa bazowa dla modyfikowalnych kolekcji,
  • AFAbstractMutableList - klasa bazowa dla modyfikowalnych list,
  • AFAnimation - UI, klasa realizująca animacje,
  • AFApplication - klasa reprezentująca aplikację,
  • AFArrayList - niemodyfikowalna lista bazująca na tablicy,
  • AFBrush - Gfx, klasa bazowa dla szczotek,
  • AFButton - UI, przycisk,
  • AFClass - metadane klasy,
  • AFComponent - komponent, klasa bazowa dla elementów UI i nie wizualnych,
  • AFComponentList - kolekcja komponentów,
  • AFComponentProperty - zawiera w sobie właściwość dodaną do komponentu,
  • AFComponentPropertyEventArguments - zawiera parametry zdarzenia zmiany zawartości właściwości,
  • AFContentControl - UI, klasa bazowa dla kontrolek posiadających zawartość,
  • AFContentPresenter - UI, przechowuje w sobie zawartość i ją wyświetla,
  • AFControl - UI, podstawowy element interfejsu użytkownika, będący klasą bazową dla innych elementów,
  • AFEventArguments - klasa bazowa dla parametrów zdarzeń,
  • AFException - klasa bazowa dla wyjątków,
  • AFFlowGridLayoutManager - UI, klasa realizująca automatyczne rozmieszczenie elementów,
  • AFFlowGridPanel - UI, panel automatycznie rozmieszczający elementy,
  • AFGraphics - Gfx, umożliwia rysowanie,
  • AFGraphicsContext - Gfx, kontekst w jakim będzie rysowana grafika,
  • AFIllegalArgumentException - Wyjątek mówiący o przekazaniu niewłaściwego argumentu,
  • AFIllegalOperationException - Wyjątek mówiący o wykonaniu niewłaściwej operacji,
  • AFIndexOutOfRangeException - Wyjątek mówiący o wyjściu poza zakres,
  • AFInt32 - niemodyfikowalna wartość int 32 bity,
  • AFLabel - UI, etykieta,
  • AFLayoutException - UI, wyjątek mówiący o problemach związanych z realizacją automatycznego layoutu,
  • AFLayoutManager - UI, klasa bazowa dla klas realizujących automatyczne rozmieszczenie elementów,
  • AFMouseEventArguments - UI, parametry zdarzenia związanego z użyciem myszy,
  • AFMutableArrayList - modyfikowalna lista bazująca na tablicy,
  • AFMutableDictionary - modyfikowalny słownik,
  • AFMutableListObservableDecorator - dekorator dodający funkcjonalność obserwacji do modyfikowalnej listy,
  • AFMutableString - modyfikowalny łańcuch tekstowy,
  • AFNotImplementedException - wyjątek mówiący o braku implementacji danej funkcjonalności,
  • AFObject - klasa bazowa dla wszystkich innych klas,
  • AFObservable - umożliwia obserwację zmiany wartości obiektu,
  • AFOutOfMemoryException - wyjątek mówiący o braku pamięci,
  • AFPanel - UI, klasa bazowa dla paneli,
  • AFProgressBar - UI, wskaźnik postępu,
  • AFRandomAccessListEnumerator - enumerator służący do pobierania danych z kolekcji o dostępie swobodnym,
  • AFRectangleBox - zawiera w sobie strukturę opisującą prostokąt,
  • AFSolidColorBrush - Gfx, szczotka o danym kolorze,
  • AFString - niemodyfikowalny łańcuch tekstowy,
  • AFTextView - UI, wyświetlanie tekstu,
  • AFTimer - licznik odmierzający czas,
  • AFUnableToAllocateResourceException - wyjątek mówiący o braku możliwości uzyskania zasobu,
  • AFVisual - UI, klasa bazowa dla wszystkich komponentów wizualnych,
  • AFVisualComponentPropertyFeatures - zawiera cech danego AFComponentProperty,
  • AFWindow - UI, okno.

Amiga i AmigaOS są zastrzeżonymi znakami towarowymi lub znakami towarowymi ich właściciela.