The Area class is superclass of almost any graphical objects in Feelin, such as windows, menus, or widgets. It holds various important information such as object's box values, object's parent, object's FRender... and it manages fonts, palettes and backgrounds.
typedef struct FeelinAreaPublic { bits16 Flags; uint8 State; uint8 _pad0;
FRender *Render;
FBox Box; FBox Content; FPadding Padding; FPadding Border; FPadding Margin;
FMinMax MinMax;
struct TextFont *Font; FPalette *Palette; FObject Background; } FAreaPublic;
One usualy uses attributes to get informations from objects, but sometimes you need faster ways to get these informations, more importantly if it's your own object. Unfortunately, since the Object class is opaque, you cannot peek and poke blindly. Fortunately, every Area 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_AREA_PUBLIC macro. Don't forget to add a AreaPublic member to your struct LocalObjectData using the F_MEMBER_AREA_PUBLIC macro.
FF_Area_Damaged is set when an object has been damaged and need to be redrawn. You can use the _area_is_damaged or _area_isnt_damaged macros to know if you are damaged or not.
FF_Area_Drawable is set when all conditions are met for an object to be drawn : successfully setuped, showable and located within a displayable region. You can use the _area_is_drawable or _area_isnt_drawable macros to know if you are drawable or not.
FF_Area_Fillable is set when the erasing of the content box is handled by the Area class. This flag can be modified at any time using the Fillable attribute. You can use the _area_is_fillable or _area_isnt_fillable macros to know if you are fillable or not.
FF_Area_Horizontal is set when an object orientation is horizontal, and cleared otherwise (the object has a vertical orientation). The flag can be modified at creation time, and gotten afterward, using the Orientation attribute. You can use the _area_is_horizontal or _area_isnt_horizontal macros to know if you have an horizontal or a vertical orientation.
The state is modified during the SetState method. You can use the _area_state macro to get yours.
The shared Render object, used by every objects belonging to a window, is set during the Setup method, and is valid until the Cleanup method. You can use the _area_render macro to access your FRender. You can also use the _area_app macro to get your application, the _area_win macro to get your window, the _area_display macro to get your display, and finaly the _area_rp macro to get to rastport you should draw in, provided you have checked that _area_render isn't NULL.
Coordinates of an object, which are only valid between the Show and Hide methods. The box is modified in mysterious way, followed by an invokation of the Layout method, the sign that your box has been modified. You can use the _area_x, _area_y, _area_x2, _area_y2, _area_w and _area_h macros to get the coordinates and dimensions of your box. You can also use the _area_box macro to access the box directly. The perimeter of each of the four areas (content, padding, border, and margin) is called an edge, so each box has four edges:
The content edge surrounds the element's rendered content. This is the only place where you are allowed to draw in. The content box coordinates are computed during the Layout method. You can use the _area_cx, _area_cy, _area_cx2, _area_cy2 and _area_cw and _area_ch macros to get the coordintaes and dimensions of your content box. You can also use the _area_cbox macro to access the box directly.
The padding edge surrounds the box padding. If the padding has 0 width, the padding edge is the same as the content edge. The padding edge of a box defines the edges of the containing block established by the box. The padding shorthand property set the padding for all sides while the other padding properties ony set their respective side. You can use the _area_padding macro to access your padding.
The border edge surrounds the box's border. If the border has 0 width, the border edge is the same as the padding edge. The border is currently handled the Border subclass. You can use the _area_border macro to access your border.
The margin edge surrounds the box margin. If the margin has 0 width, the margin edge is the same as the border edge. Margin properties specify the width of the margin area of a box. The margin shorthand property sets the margin for all four sides while the other margin properties only set their respective side. You can use the _area_margin macro to access your margin.
Minimum and maximum dimensions of the object are computed during the AskMinMax method and are only valid between the Show and Hide methods. The min-width and min-height properties set the minimum dimensions of the content box, while the max-width and max-height properties set its maximum ones. The width and height properties set both minimum and maximum dimensions of the content box, resulting in a box with fixed width and height. The _area_minw and _area_minh macros give your minimum dimensions, while the _area_maxw and _area_maxh macros give your maximum dimensions. The _area_minmax macro gives you access to your FMinMax.
If you render some text you should use this font. It's defined by the font property, but can be modified at any time using the Font attribute, updating the layout automatically. You can use the _area_font macro to get yours.
The palette to use to draw the object. It's defined by the palette property. You can use the _area_palette macro to acces yours, and use the _area_pens macro to acces the array of uint32 values representing the pens you should use to render your object. For example, "_area_pens[FV_Pen_Shine]" gives you the brigther color.
The ImageDisplay object used to erase the background. It's defined by the background property. You should never use the object yourself, but rather the Erase method. You can get your background using the _area_background macro, but don't do that :-)
struct LocalObjectData { F_MEMBER_AREA_PUBLIC; };
F_METHOD(uint32, mNew) { struct LocalObjectData *LOD = F_LOD(Class, Obj);
F_MEMBER_SAVE_PUBLIC; return F_SUPERDO(); }
F_METHOD(uint32,mAskMinMax) { struct LocalObjectData *LOD = F_LOD(Class, Obj);
_area_minw += 30; _area_minh += 30;
return F_SUPERDO(); }
F_METHOD(void,mDraw) { struct LocalObjectData *LOD = F_LOD(Class,Obj); struct RastPort *rp = _area_rp;
F_SUPERDO();
_APen(Rnd(1 << rp->BitMap->Depth)); _Boxf(_area_cx, _area_cy, _area_cx2, _area_cy2); }
typedef struct FeelinBox { int16 x,y; uint16 w,h; } FBox;
Coordinates and dimensions of a box.
Coordinates of the box.
Dimensions of the box.
typedef struct FeelinMinMax { uint16 MinW,MinH; uint16 MaxW,MaxH; } FMinMax;
This structure holds the minimum and maximum dimensions of an object.
Minimum width and height of an object.
Maximum width and height of an object.
typedef struct FeelinRect { int16 x1,y1; int16 x2,y2; } FRect;
This structure holds the coordinates of a region.
Region coordinates.
By default, areas erase their content box during the Draw method if the FF_Draw_Object flag is set. If you intent to handle the erasing of your content box yourself, you can set this attribute to FALSE.
By default objects are oriented horizontaly, which, for example, results in groups displaying their children on a row or gauges with an horizontal progress bar. You can modify this attribute at creation time if you'd rather like a vertical orientation.
Use the _area_is_horizontal and _area_isnt_horizontal macros to know if you have an horizontal or vertical orientation.
FV_Area_Orientation_Horizontal FV_Area_Orientation_Vertical
<?xml version="1.0" ?>
<Application> <Window Id="win" Title="Orientation" Open="true"> <Group Orientation="vertical"> <Group Class="box" Orientation="vertical" Caption="Vertical"> <Button>One</Button> <Button>Two</Button> </Group>
<Group Class="box" Orientation="horizontal" Caption="Horizontal"> <Button>One</Button> <Button>Two</Button> </Group> </Group> </Window> </Application>
The FAreaPublic of an Area object.
Please, use the F_GET_AREA_PUBLIC() macro to get the FAreaPublic of an Area object.
FAreaPublic *area_public = F_GET_AREA_PUBLIC(Obj);
This property describes the foreground color of an element's text content. There are different ways to specify red:
button { color: red } /* predefined color name */ button { color: rgb(255,0,0) } /* RGB range 0-255 */ button { color: rgb(100%,0,0) } /* RGB range in percentage */ button { color: #F00 } /* Hexadecimal triplet */ button { color: #FF0000 } /* Hexadecimal */
This property sets both min-height and max-height properties to the same value, resulting in a content box with a fixed height.
The value is in pixels, but you can also use the keyword auto, in which case the maximum dimensions are set to the value of the minimum dimensions, computed during the AskMinMax method.
Margin properties specify the width of the margin area of a box.
The margin property is a shorthand property for setting margin-top, margin-right, margin-bottom, and margin-left at the same place in the style sheet.
If there is only one value, it applies to all sides. If there are two values, the top and bottom margins are set to the first value and the right and left margins are set to the second. If there are three values, the top is set to the first value, the left and right are set to the second, and the bottom is set to the third. If there are four values, they apply to the top, right, bottom, and left, respectively.
This property sets the maximum height of the content box.
This property sets the maximum width of the content box.
This property sets the minimum height of the content box.
This property sets the minimum width of the content box.
Padding properties specify the width of the padding area of a box.
The padding property is a shorthand property for setting padding-top, padding-right, padding-bottom, and padding-left at the same place in the style sheet.
If there is only one value, it applies to all sides. If there are two values, the top and bottom paddings are set to the first value and the right and left paddings are set to the second. If there are three values, the top is set to the first value, the left and right are set to the second, and the bottom is set to the third. If there are four values, they apply to the top, right, bottom, and left, respectively.
This property sets both min-width and max-width properties to the same value, resulting in a content box with a fixed width.
The value is in pixels, but you can also use the keyword auto, in which case the maximum dimensions are set to the value of the minimum dimensions, computed during the AskMinMax method.
[For use within classes only]
This method is invoked on your object when Feelin wants to know its minimun and maximum sizes, which are needed to compute the layout.
When the method reaches the Area class, the minimum and maximum dimensions of the object are checked against restrictions defined by the following style-properties :
The min-width and min-height properties set the minimum width and height of an element, while the max-width and max-height properties set the maximum width and height of an element.
The width and height properties set both minimum and maximum dimensions for the width and the height of an element, resulting in an element with a fixed width and a fixed height.
<?xml version="1.0" ?>
<Application> <Window Id="win" Title="Box Model" Open="true"> <Group Style="background: yellow;" Orientation="vertical"> <Widget Style="height: 20px; margin: 10px; padding: 10px; min-width: 10px; max-width: 100px; background: red; border: 1px solid dark;" /> <Button Style="width: auto">auto-width</Button> <Widget Style="height: 20px; margin: 10px; padding: 10px; min-width: 10px; max-width: 30px; background: red; border: 1px solid dark;" /> </Group> </Window> </Application>
We add the values specific to our object before calling our superclass.
Note well that we indeed need to add these values, not just set them !
F_METHOD(uint32, mAskMinMax) { struct LocalObjectData *LOD = F_LOD(Class,Obj);
// x-size depending on objects font
_area_minw += _area_font->tf_XSize * 10; _area_maxw += _area_font->tf_XSize * 20;
// y-size
_area_minh += _area_font->tf_YSize; _area_maxh += _area_font->tf_YSize;
return F_SUPERDO(); }
[For use within classes only]
Whenever your object should render itself, the Draw method is invoked. This happens e.g. when a window is openend for the first time, after a window was resized or when your object has been damaged because its state has changed.
Together with the Draw method comes a Flags value that indicates which parts of the object are to be redrawn. The only interesting bits in this flag value are FF_Draw_Object and FF_Draw_Update. When FF_Draw_Object is set, Feelin wants you to do a complete redraw of your object. FF_Draw_Update is used by Feelin when the frame doesn't have to be redrawn, only the inner area of the object should be updated. You can use this flags for private requirement with the F_Draw() function call. You can also use one of the FF_Draw_Custom_? flags if you need something special.
The Draw method is the only place where you are allowed to render !
You should not invoke this method yourself, but rather use the F_Draw() function. The method can only be used to be passed to your superclass.
IFEELIN F_Do(Obj, FM_Area_Erase, FRect *Rect, bits32 Flags);
Use this method to fill a specific part of an object's background.
Pointer to a FRect describing the area to fill. You can provide a pointer to a struct Region instead, but remember to set the FF_Erase_Region flag together.
FF_Erase_Region - If this flag is set the FRect is used as a struct Region (holding multiple rectangles). This region is a standard graphics.library region, created with NewRegion() and setup with appropiate function e.g. OrRectRegion(). Using regions facilities you can fill multiple areas in a single step and also create rather complex rendering and refreshing. Such facilities are used by the Group class when clearing damaged zones in complex rendering mode.
FF_Erase_Fill - This method takes care of rendering context and possibilities e.g. the rectangle or region is not filled if the window is in refresh mode and a same background has already been used to clear the region, unless the flag FF_Erase_Fill is set. If this flag is set the background is always drawn (even if not necessary).
You don't have to worry about offsets or coordinates, ImageDisplay, which is used to draw things, is clever enough to adjust patterns, gradients and bitmaps by itself and render them nicely.
[For use within classes only]
An object receive this method right before it is hidden, which may happen when the page containing the object is no longer the active one, when the attribute Hidden is set to TRUE, or more commonly when the window that contains the object is closed.
[For use within classes only]
Objects usualy receives this method after their box has been modified.
When this method reaches the Area class, the coordinates of the contents box are computed, taking care of margins, borders and paddings.
[For use within classes only]
This method is invoked to change the display state of an object. You may not send this method yourself, it is invoked by Feelin usualy after a state attribute such as Disabled has been modified.
When the method reaches the Area class, the palette, background, margins and paddings are set to the values of the state.
Unless your class adds properties, you'll rarely have to implement this method.
F_METHODM(bool32, Area_SetState, FS_Area_SetState) { struct LocalObjectData *LOD = F_LOD(Class, Obj);
FPalette *palette; FObject background;
switch (Msg->State) { case FV_Area_State_Neutral: { palette = LOD->palette; background = LOD->background; } break;
case FV_Area_State_Touch: { palette = LOD->palette_touch; background = LOD->background_touch; } break;
case FV_Area_State_Ghost: { palette = LOD->palette_ghost; background = LOD->background_ghost; } break;
case FV_Area_State_Focus: { palette = LOD->palette_focus; background = LOD->background_focus; } break;
default: { IFEELIN F_Log(FV_LOG_DEV, "(%ld) is not a valid state", Msg->State);
return FALSE; } }
_area_flags |= FF_Area_Damaged;
_area_palette = palette; _area_background = background;
LOD->state = &LOD->properties[Msg->State];
_area_margin.l = LOD->state->margin.l; _area_margin.r = LOD->state->margin.r; _area_margin.t = LOD->state->margin.t; _area_margin.b = LOD->state->margin.b;
_area_padding.l = LOD->state->padding.l; _area_padding.r = LOD->state->padding.r; _area_padding.t = LOD->state->padding.t; _area_padding.b = LOD->state->padding.b;
return TRUE; }
[For use within classes only]
This method is sent to your object when it's allowed to show its face to the world. This happens when a window opens, or when the Hidden attribute is modified. If you have some window/rastport environment dependant things to do, this method is the right place.
When the method reaches the Area class, the FF_Area_Damaged and FF_Area_Drawable flags are both set.
You should not render during the Show method. Remeber that the only place your are allowed to is during the Draw method.