Object / Element

The Element class implements style support, providing methods to obtain values from the stylesheet defined by the user through the preference editor, taking care of style-classes and styles which may have been defined by the developer (or the user) to override stylesheet declarations, with the Class and Style attributes.

The class also implements methods to load and save the contents of any object, provided the object has an Id. As an example, the position and size of a window can be saved between sessions using the Persist attribute and the "left top width height" attributes list, provided your application has its Base attribute defined.

Finaly, the class implements two fundamentals methods for all the GUI elements, namely the Setup and Cleanup method.

Types

Attributes

Implements

Macros

FElementPublic -- (01.00)

typedef struct FeelinElementPublic
{
    FObject                                     Application;
    FObject                                     Window;
    FObject                                     Parent;
}
FElementPublic;

One usualy uses attributes to get informations from elements, but sometimes you need faster ways to get these informations, more importantly if it's your own element. Unfortunately, since the Object class is opaque, you cannot peek and poke blindly. Fortunately, every Element object embends an informative public structure that you can get using the PublicData attribute.

It's recommanded to save the pointer to this structure during the New method, using the F_SAVE_ELEMENT_PUBLIC macro. Don't forget to add a ElementPublic member to your struct LocalObjectData using the F_MEMBER_ELEMENT_PUBLIC macro.

Members

Application (FObject)

The application of an element is set during the GlobalConnect method, and is valid until the GlobalDisconnect methods. You can get the application of an element by using the Application attribute, or by using the _element_application macro to get yours.

Window (FObject)

The window of an element is set during the GlobalConnect method, and is valid until the GlobalDisconnect methods. You can get the window of an element by using the Window attribute, or by using the _element_window macro to get yours.

Parent (FObject)

The parent of an element is set during the Connect method, and is valid until the Disconnect methods. You can get the parent of an element by using the Parent attribute, or by using the _element_parent macro to get yours.

Class -- (01.00) [I..], STRPTR

The style class of an element. Multiple classes may be specified by separating them with spaces.

Feelin doesn't provides a Button class, because the Text class and its super-class (the Widget class) already provide everything needed for this purpose. But neither of these two classes provide suitable styles to create buttons. The truth is that neither of these two classes provide any style at all. So how Feelin's buttons manage to look so good without inherited properties ? Thanks to the Class attribute of course !

The following code is used by the F_MakeObjA() function when you create buttons with the Button() macro :

return TextObject,
FA_Element_Class, "button",
FA_Area_SetMax, FV_SetMax_Height,
FA_Widget_Mode, FV_Widget_Mode_Release,
FA_Text_Contents, <button label>, FA_Text_HCenter, TRUE,
TAG_MORE, <additional tags>;

Another example might be the proportional object of a scrollbar object which is created with the "scrollbar-prop" style-class. The object inherits properties defined by the "prop" declaration of the stylesheet, which are then overriden by the properties of the "scrollbar-prop" declaration.

Example

preview
<?xml version="1.0" ?>

<Application>
    <Window Id="win" Title="Element Class" Open="true">
        <Group Orientation="vertical">
            <Button>button</Button>
            <Button Class="slider-knob">button with 'slider-knob' class</Button>
            <Button Class="gauge">button with 'gauge' class</Button>
            <Button Class="box">button with 'box' class</Button>
            <Button Class="scrollbar-knob">button with 'scrollbar-knob' class</Button>
        </Group>
    </Window>
</Application>

Properties defined with the Style attribute have the final word over the cascading stylesheet and the style-class properties, overriding them all without any mercy.

As with CSS, you can also provide multiple classes, separated by a space character :

Example

element-multiclass
/* element-multiclass.css */
warn { color: white; palette: red 0%; }
<?xml version="1.0" ?>
<?xml-stylesheet type="text/css" href="element-multiclass.css" ?>
<Application> <Window Id="win" Title="Multi Class" Open="true"> <Group Orientation="vertical"> <Button>button</Button> <Button Class="button warn">warn button</Button> </Group> </Window> </Application>

Id -- (01.00) [I.G], STRPTR

A unique identifier so that you can identify the element with. You can use this for several purposes : save some of its attributes between sessions, retreive it from XML files, use it within XML Applications, give it a unique style...

You have to use differents Ids for each of your elements !

Parent -- (01.00) [..G], FObject

The parent object of an element.

Persist -- (01.00) [I..], STRPTR

Use this attribute to select which attributes should be loaded and saved during the LoadPersistentAttributes and SavePersistentAttributes methods.

The attributes are separated by a space character. Don't forget to provide an unique Id to your object, otherwise nothing will happen.

Example

The following example shows how to save the position and dimension of a window :

<Window Id="main-window" Persists="left top width height" />

You might also save only the dimension ("width height") of a window, in order to open it always centered.

PublicData -- (01.00) [..G], FElementPublic

The FElementPublic of an Element object.

Please, use the F_GET_ELEMENT_PUBLIC() macro to get the FElementPublic of an Element object.

Example

FElementPublic *element_public = F_GET_ELEMENT_PUBLIC(Obj);

Style -- (01.00) [I..], STRPTR

This attribute specifies style information for the current element.

Example

In a C source.

F_MakeObj
(
    FV_MakeObj_Button,
    "Styled button",
    FA_Element_Style, "background: red; padding: 2px 6px;",
    TAG_DONE
);

In a XML source.

<Button Style="background: red; padding: 2px 6px;">A button with style</Button>

Note that, in the XML source, the attribute is recognized even if all its letters are lowercased.

Properties defined with the Style attribute have the final word over the cascading stylesheet and the style-class properties, overriding them all without any mercy.

Cleanup -- (01.00)

[For use within classes only]
IFEELIN F_Do(Obj, FM_Element_Cleanup);

Function

This method is sent to your object when e.g. the window containing your object is closed, or when your object is removed from a setuped tree. Override it to free the resources you previous allocated during the Setup method.

When the method reaches the Element class, the FPreferenceStyle obtained during the Setup method is released.

Example

F_METHOD(uint32, Gauge_Cleanup)
{
    struct LocalObjectData *LOD = F_LOD(Class, Obj);
if (LOD->image != NULL) { IFEELIN F_Do(LOD->image, FM_ImageDisplay_Cleanup); IFEELIN F_DisposeObj(LOD->image);
LOD->image = NULL; }
return F_SUPERDO(); }

CreateDecodedStyle -- (01.00)

IFEELIN F_DoA(Obj, FM_Element_CreateDecodedStyle, FS_Element_CreateDecodedStyle);

Function

This method is invoked once the style is created by the Preference object, to allow the caller to parse and decode the style in easier things. Because styles are shared among objects, once a style is decoded, the result is accessible to everyone. As an example, if 1000 buttons are displayed in a window, their style is created and decoded once, then shared among them.

Inputs

DecodedSpace (APTR)

Enough memory was allocated for the true class' properties data, plus enough memory for the local properties data of each of the true class' superclasses.

Style (FPreferenceStyle *)

A shared FPreferenceStyle, which should be used to read style properties.

Pool (APTR)

If you need to allocate extra memory, you should use the memory pool provided here.

Result

Not defined yet, you should return TRUE.

Example

F_METHODM(bool32, Frame_CreateDecodedStyle, FS_Element_CreateDecodedStyle)
{
    struct LocalPropertiesData *local = F_LPD(Class, Msg->DecodedSpace);
FPreferenceStyle *style;
for (style = Msg->Style ; style ; style = style->Next) { struct in_Frame *state;
uint32 i;
FPreferenceProperty **properties_a;
/*** select state ***/
if (style->Atom == NULL) { i = FV_Area_State_Neutral; } else if (style->Atom == F_ATOM(TOUCH)) { i = FV_Area_State_Touch; } else if (style->Atom == F_ATOM(FOCUS)) { i = FV_Area_State_Focus; } else if (style->Atom == F_ATOM(GHOST)) { i = FV_Area_State_Ghost; } else continue;
state = &local->frames[i];
/*** parse properties ***/
for (properties_a = style->Properties ; *properties_a ; properties_a++) { FPreferenceProperty *prop = *properties_a;
if (prop->Atom == F_PROPERTY_ATOM(FRAME)) { if (IFEELIN F_StrCmp("none", prop->Value, ALL) == 0) { state->id = 0;
state->border.l = state->border.r = state->border.t = state->border.b = 0; } else { IFEELIN F_Log(FV_LOG_DEV, "frame shorthand not yet implemented (%s)", prop->Value); } } else if (prop->Atom == F_PROPERTY_ATOM(FRAME_ID)) { state->id = prop->NumericValue;
frame_get_borders(state->id, &state->border); } else if (style->Atom == NULL) { if (prop->Atom == F_PROPERTY_ATOM(FRAME_PREPARSE)) { local->caption_preparse = prop->Value; } else if (prop->Atom == F_PROPERTY_ATOM(FRAME_POSITION)) { f_parse_values(prop->Value, frame_parse_position, local); } else if (prop->Atom == F_PROPERTY_ATOM(FRAME_FONT)) { local->caption_font = prop->Value; } } }
/*** clone neutral ***/
if (i == FV_Area_State_Neutral) { IEXEC CopyMem(state, &local->frames[FV_Area_State_Touch], sizeof (struct in_Frame)); IEXEC CopyMem(state, &local->frames[FV_Area_State_Focus], sizeof (struct in_Frame)); IEXEC CopyMem(state, &local->frames[FV_Area_State_Ghost], sizeof (struct in_Frame)); } }
return F_SUPERDO(); }

DeleteDecodedStyle -- (01.00)

IFEELIN F_Do(Obj, FM_Element_DeleteDecodedStyle, APTR DecodedSpace);

Function

This method is invoked by the Preference object when it's deleting the style used by your object. You should free any additionnal resources that you might have allocated during the CreateDecodedStyle method. Abviously, you don't have to implement this method if you don't allocate extra resources.

Inputs

The memory space passed during the CreateDecodedStyle method.

Result

Not defined yet, you should return TRUE.

GetProperty -- (01.00)

IFEELIN F_DoA(Obj, FM_Element_GetProperty, FS_Element_GetProperty);

Function

Once the object has been setuped by the Setup method, you can use the GetProperty method to get the values (lexical and numerical) of properties.

You are strongly encouraged to implement the CreateDecodedStyle method instead of using this one. Because a style is decoded once and is shared a lot, each class doesn't have to get the properties and decoded them over and over.

Inputs

PseudoAtom (FAtom *)

A pointer to the atom of a pseudo class name. This member must be used if you want to get the value of a pseudo class' value e.g. button:hover { background: highlight fill; }, otherwise set it to NULL.

Atom (FAtom *)

A pointer to the atom of the property's name you want to get the values.

ValuePtr (STRPTR *)

Pointer to the variable in which you want to save the pointer to the lexical value of the property.

NumericValuePtr (uint32 *)

Pointer to the variable in which you want to save the numeric value of the property.

Result

The method returns the type of the property value, or 0 is the property wasn't found. Note that variables are not touched if the property is not found. Thus, you can easily set default values before getting properties.

Example

STRPTR value_image = DEF_IMAGE_SPEC;
uint32 value_image_width = DEF_IMAGE_WIDTH;
IFEELIN F_Do ( Obj, FM_Element_GetProperty, NULL, F_PROPERTY_ATOM(IMAGE), &value_image, NULL );
IFEELIN F_Do ( Obj, FM_Element_GetProperty, NULL, F_PROPERTY_ATOM(IMAGE_WIDTH), NULL, &value_image_width );

GlobalConnect -- (02.00)

IFEELIN F_DoA(Obj, FM_Element_GlobalConnect, FS_Element_GlobalConnect)

Function

Notify an element about the application and window it belongs to.

If the element has an Id, it will be publicized using the AddElementById method of the Application object. The element will then be retrievable using the application's GetElementById method.

Once connected, you can use the _element_application and _element_window macros to get the Application and Window objects of your element.

Note that Window is NULL if the element is the window.

Inputs

Application (FObject *)

The application the element belongs to.

Window (FObject *)

The window the element belongs to.

Result

Returns TRUE if the connection succeed.

GlobalDisconnect -- (02.00)

IFEELIN F_Do(Obj, FM_Element_GlobalDisconnect)

Function

Reset the application and the window of an element to NULL. This usualy happens when the element is removed from the application tree.

If the element has an Id, it will be privatized using the RemElementById method of the Application object.

Result

Returns TRUE if the disconnection succeed.

LoadPersistentAttributes -- (01.00)

[virtual method]
IFEELIN F_Do(Obj, FM_Element_LoadPersistentAttributes, FObject Storage);

Function

This method is invoked for each object in the application tree during execution of the Application's Load method. It's purpose is to load objects contents. What is actually loaded is selected by the attributes list defined with the Persist attribute.

If you override this method to load some of your object's attribute, you are supposed to use the handle obtained when the method returns from your super-class. The handle is not created if the Persist attribute is not defined or your object has no Id.

Result

The method returns a pointer to a FPDRHandle which must be used to load your attributes. You must return this same pointer in order to allow your sub-classes to load their own attributes.

Example

F_METHOD(FPDRHandle *, Window_LoadPersistentAttributes)
{
    struct LocalObjectData *LOD = F_LOD(Class, Obj);
FPDRHandle *handle = (FPDRHandle *) F_SUPERDO();
if (handle != NULL) { FPDRAttribute *attr;
for (attr = handle->Attributes ; attr ; attr = attr->Next) { if (attr->Atom == F_ATOM(LEFT)) { LOD->user_box_flags &= ~FF_WINDOW_BOX_XDEFINED;
_win_x = F_PDRDOCUMENT_GET_NUMERIC(attr); } else if (attr->Atom == F_ATOM(TOP)) { LOD->user_box_flags &= ~FF_WINDOW_BOX_YDEFINED;
_win_y = F_PDRDOCUMENT_GET_NUMERIC(attr); } else if (attr->Atom == F_ATOM(WIDTH)) { LOD->user_box_flags &= ~FF_WINDOW_BOX_WDEFINED;
_area_w = F_PDRDOCUMENT_GET_NUMERIC(attr); } else if (attr->Atom == F_ATOM(HEIGHT)) { LOD->user_box_flags &= ~FF_WINDOW_BOX_HDEFINED;
_area_h = F_PDRDOCUMENT_GET_NUMERIC(attr); } } }
F_OBJDO(LOD->root);
return handle; }

It's always a good idea to set your attributes, instead of modifying them in the shadow, because a developer might have set a notification upon some of them. The above example is somehow a bad example (yes, you naughty example!) because attributes are set directly to the local object data. The fact is that currently, the modification of the position and dimension of windows are not acheived through attributes, and thus no notification can be set.

SavePersistentAttributes -- (01.00)

[virtual method]
IFEELIN F_Do(Obj, FM_Element_SavePersistentAttributes, FObject Storage);

Function

This method is called for each object in the application tree during execution of the Application's Save method. Its purpose is to save objects contents. What is actually saved is selected by the attributes list defined with the Persist attribute.

If you override this method to save some of your object's attribute, you are supposed to use the handle obtained when the method returns from your super-class. The handle is not created if the Persist attribute is not defined or your object has no Id.

Result

The method returns a pointer to a FPDRHandle which must be used to save your attributes. You must return this same pointer in order to allow your sub-classes to save their own attributes.

Example

The following example comes from the Window class :

F_METHOD(FPDRHandle *, Window_SavePersistentAttributes)
{
    struct LocalObjectData *LOD = F_LOD(Class, Obj);
FPDRHandle *handle = (FPDRHandle *) F_SUPERDO();
if (handle) { FPDRAttribute *attr;
for (F_PDRDOCUMENT_EACH(handle->Attributes, attr)) { if (attr->Atom == F_ATOM(LEFT)) { F_PDRDOCUMENT_SET_TYPED(attr, _win_x, FV_TYPE_PIXEL); } else if (attr->Atom == F_ATOM(TOP)) { F_PDRDOCUMENT_SET_TYPED(attr, _win_y, FV_TYPE_PIXEL); } else if (attr->Atom == F_ATOM(WIDTH)) { F_PDRDOCUMENT_SET_TYPED(attr, _area_w, FV_TYPE_PIXEL); } else if (attr->Atom == F_ATOM(HEIGHT)) { F_PDRDOCUMENT_SET_TYPED(attr, _area_h, FV_TYPE_PIXEL); } } }
F_OBJDO(LOD->root);
return handle; }

Setup -- (01.00)

[for use within classes only]
IFEELIN F_Do(Obj, FM_Element_Setup, FRender *Render);

Function

This method is used to make objects aware of their environment : the display, the application and the window they belong to. The method is usually called for each object in the application tree when a window is opened.

When this method reaches the Element class, a FPreferenceStyle is obtained from the Preference object used by the application.

If you override this method to get properties or to allocate graphic resources, the first thing you have to do is pass the method to your super-class an return FALSE on failure. Afterward, you can get style properties, allocate colors as well as various resources related to the graphical setup of your environment. Return TRUE only if everything went ok. If you return FALSE, all objects in the window tree will be invoked with the Cleanup method to release any resources they might have previously allocated.

Inputs

A Render object, created by a Window object and shared by all the objects of the window. This object remains valid between the Setup and Cleanup methods.

Result

The method returns a bool32, which indicates if the setup of the object was a succes or not. You must pass this method to your super-class to be able to get properties, and abord setup process if your super-class returns FALSE or if you fail to allocate resources.

Example

F_METHODM(bool32, Gauge_Setup, FS_Element_Setup)
{
    struct LocalObjectData *LOD = F_LOD(Class,Obj);
STRPTR value;
if (F_SUPERDO() == FALSE) { return FALSE; }
value = NULL;
IFEELIN F_Do(Obj, FM_Element_GetProperty, NULL, F_PROPERTY_ATOM(IMAGE), &value, NULL);
if (value != NULL) { LOD->image = ImageDisplayObject,
FA_ImageDisplay_Spec, value, FA_ImageDisplay_Origin, &_area_content, FA_ImageDisplay_Owner, Obj,
End;
if (LOD->image != NULL) { if (IFEELIN F_Do(LOD->image, FM_ImageDisplay_Setup, Msg->Render) == FALSE) { IFEELIN F_DisposeObj(LOD->image);
LOD->image = NULL; } } }
return TRUE; }

Development