Here's my take regarding the layout engine:
-
Separate the content from the layout engine. Content should be coded where it makes sense (e.g. ISO in lens.c, HDR bracketing info in shoot.c, histobar in histogram.c, raw video info in raw_rec.c and so on),
not in the library. I still don't understand why moving all the strings to flexinfo.c was considered an improvement over leaving them in the source files where the info was generated (no offence, just technical discussion).
-
User code should only care about content => a handler routine should simply fill some string buffer. Overriding colors is allowed. Custom drawing is supported, but plain strings should be preferred.
-
Exact placement should be handled by the layout engine. User code is allowed to specify some hints (e.g. I prefer this to be on the top bar on the left, if not, it's OK to be on the bottom bar too, or maybe not, and so on). The layout engine should be allowed to re-arrange items if some things get very big, or are no longer displayed, and so on.
- For LiveView bars I think a centered layout works best (each item is aligned at center, and free space is distributed uniformly between items). Rationale: when an item changes its size a little, the overall layout is not disrupted.
- I want the font to be choosen by the layout engine too (if there are too many things, the layout engine should be allowed to try a smaller font for large items, for example).
- The layout engine should be allowed to discard some items if you add too much stuff. User code may specify a priority, so the layout engine should know what to discard first.
- I want the API to be similar to the menu one (because I'm used to it).
With this in mind,
I wrote a pretty basic layout engine, separate from flexinfo, that does pretty much what stevefal suggested: modular design (no hardcoded content), automatic layout and fairly simple API. Of course, with a much smaller degree of generality, and also lighter-weight.
APISee
lvinfo.h.
Example of user code:
static LVINFO_UPDATE_FUNC(temp_update)
{
LVINFO_BUFFER(8);
int t = EFIC_CELSIUS;
snprintf(buffer, sizeof(buffer), "%d"SYM_DEGREE"C", t);
if (t >= 60)
{
item->color_bg = COLOR_RED;
}
}
where the user function does these things:
- reserve space for the string buffer
- fill the string buffer with the content (temperature)
- override the background color if the temperature gets too high (and do nothing in normal situations).
That's it. Can it get any simpler? Maybe only with some macros like the ones used in menu code (like MENU_SET_VALUE).
How this item is described?
static struct lvinfo_item info_items[] = {
...
{
.name = "Temperature",
.which_bar = LV_TOP_BAR_ONLY,
.update = temp_update,
.priority = 1,
},
...
};
From this, it's pretty obvious where this item will be placed (in a fuzzy way, not the exact position) and what it does.
After describing the items, you register them with something like this, just like menu items:
lvinfo_add_items(info_items, COUNT(info_items));
Special fields (all optional):
-
.preferred_position: this works pretty much like Z-order. Within one bar, all fields will get sorted according to this field. For example, I want the clock to be on the far left, so I specify a large negative value:
{
.name = "Clock",
.which_bar = LV_TOP_BAR_ONLY,
.update = clock_update,
.preferred_position = -128,
},
-
.priority: if the layout gets really tight, the backend is allowed to discard items with a lower priority. For example, I don't really care about displaying picture style name (which is quite long anyway).
{
.name = "Pic.Style",
.which_bar = LV_TOP_BAR_ONLY,
.update = picstyle_update,
.priority = -1,
},
Algorithm for squeezing space (what happens if you throw too much stuff at it):
1) discard some items with negative priority (items with lowest priority get discarded first)
2) try a smaller font for some items (bigger items get squeezed first)
3) discard some more items (again, items with lowest priority get discarded first)
Custom drawingstatic LVINFO_UPDATE_FUNC(my_custom_drawing_item)
{
item->width = <whatever you need>;
/* request custom drawing */
item->custom_drawing = 1;
if (can_draw)
{
/* you got permission to draw */
/* just don't forget that item->x is the center of the item */
int x_left = item->x - item->width/2;
/* now go ahead and draw it */
/* tip: use item->fontspec or its metrics so you know how big your drawing should be */
}
}
Menu: I didn't implement one, but it's straightforward. Saving user config is a little harder, and it's not a priority, because I prefer to have something that just works without too much tinkering, rather than having infinite customizability that may get very hard to use.
There are still some functionality not yet ported from the old implementation (e.g. precise ISO/shutter, FPS, free space), but I think it works well enough so you can already try it in the current nightly builds.
Please post screenshots. I'd like to see how the layout handles different configurations. In particular, I'd like you to try a fairly long lens (long focal length string), IS enabled, focal length reported, dual ISO 1600/12800, 10000 kelvins... you get the idea (just try hard to make the info strings as long as you can).
Histobar kinda works too.