Igor Kromin |   Consultant. Coder. Blogger. Tinkerer. Gamer.

Not too long ago I announced that jPhotoFrame 0.4 has been released. The biggest feature of this release has got to be the all new layout engine. I didn't go into too much depth in the release article about how this layout engine can be configured, and that's what I intend to cover now.

The layout engine uses a JSON configuration file that requires a basic structure like this:
 layout.json
{
"widgets": []
}


The 'widgets' property is an array that holds all of the widgets for the layout engine to render. The available widgets types are: anchor, text, weather. You're free to use any of these but the most likely widget you will start with is the anchor.

Each of the widgets is a JSON object, it's type is specified by the 'type' property. For example adding an anchor widget would look like this...
 layout.json
{
"widgets": [
{
"type": "anchor",
"anchor": [0, 0],
"children: []
}
]
}


Screen Coordinate System

All coordinates are defined as standard 2D Cartesian values with the top-left being treated as (0,0) and bottom-right as (width, height).
jphotoframe_coords.png




Anchor/Origin Coordinates

There are a number of widgets that make use of an origin or anchor property. This property is specified as a 2D Cartesian coordinate that is clamped to 2x2 pixels in size. This means it has values of either 0 or 1 for each of its axes. These properties define a corner of the widget/screen. The diagram below shows this...
jphotoframe_anchors2.png


Even though the value for each axis is either a 0 or a 1, the value of 1 actually means the width (for the x-axis) and the height (for the y-axis). From that, a value of (1,1) would define the bottom-right corner.

Widget Transformation

A number of widgets define the 'transform' property. This allows a widget to be transformed in 2D space. There are the following properties defined for a transform:
  • origin : two-integer array specifying the transformation origin (x,y), similar to Anchor 'anchor'
  • offset : two-integer array specifying the offset in pixels relative to the origin (x, y)
  • rotate : degrees rotation around the origin point
  • showBounds : whether to show the drawing boundary box or not


The origin is very important as that is the point around which both the translation and rotation are done. The translation is performed first, then the rotation is performed around the origin at the new (x,y) location. The translation value will not affect how a rotation is performed i.e. they do not stack.

Anchor Widget

By itself this widget does not display anything, but it is used to affect how its child widgets are displayed. The purpose of this widget is to anchor its children to one of the screen corners.

Properties:
  • anchor : two-integer array specifying which side to anchor along an axis (x,y)
  • children : list of child widgets


The 'children' property is an array of widgets that the anchor is to display relative to its position. This should only contain the text and weather widgets.

Examples

I will not go into specifics of the text or weather widgets as this article is about how to use the layout system, so for the examples below I'll be using a very simple text widget that displays the text "Hello World!". It's going to be configured as follows:
 layout.json
{
"type": "text",
"text" : {
"data": "Hello World!",
"colour": [255,0,0],
"size": 20
}
}


If you want to learn more about the text and weather widgets, see the README.md.

Lets start with an example showing the text in the top-left corner...
 layout.json
{
"widgets": [
{
"type": "anchor",
"anchor": [0, 0],
"children": [
{
"type": "text",
"transform": {
"origin": [0, 0],
"offset": [0, 0],
"showBounds": "true"
},
"text" : {
"data": "Hello World",
"colour": [255,0,0],
"size": 20
}
}
]
}
]
}


The above will render the following (showing just the relevant part of the screen)...
jphotoframe_ex1.png


To move the text to (40,40) the offset is changed to:
 layout.json
"offset": [40, 40]


Note the bounding box shows the origin location as a circle.
jphotoframe_ex2.png


Now if we change the origin to [1,0] the result becomes...
jphotoframe_ex3.png


The widget's rightmost corner is the part that is used to translate relative to, so only the last 40 pixels of the text are visible on screen now.

Now we can add a rotation of -90 degrees like so:
 layout.json
"rotate": -90


This swivels the text back on screen, in a vertical position.
jphotoframe_ex4.png


If we now change the anchor to [0,1] i.e. bottom-left corner and reset the rest of the widget properties i.e. the offset to [0,0] and rotation to 0, and the origin back to [0,0] the widget completely disappears...
jphotoframe_ex5.png


There is a hint of the widget anchor in the bottom-left corner however. Why is the text widget not visible though? That's because its origin is placing its top-left corner in the bottom-left part of the screen via the anchor. This renders the text 'below' the screen. To get the text back on screen, its origin must be changed to the match the anchor ie. we change the origin to [0,1]...
jphotoframe_ex6.png


So by manipulating the anchor and the origin of the widget, text can be snapped to any corner on screen. The offset and rotation then further influence how the text is moved or spun around relative to that snapped-to location. The possibilities are endless!

Hopefully that explains how the layout engine works in more detail.

-i

A quick disclaimer...

Although I put in a great effort into researching all the topics I cover, mistakes can happen. Use of any information from my blog posts should be at own risk and I do not hold any liability towards any information misuse or damages caused by following any of my posts.

All content and opinions expressed on this Blog are my own and do not represent the opinions of my employer (Oracle). Use of any information contained in this blog post/article is subject to this disclaimer.
Hi! You can search my blog here ⤵
NOTE: (2022) This Blog is no longer maintained and I will not be answering any emails or comments.

I am now focusing on Atari Gamer.