Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v6.0] General discussion #785

Open
kisvegabor opened this issue Feb 1, 2019 · 136 comments

Comments

Projects
None yet
@kisvegabor
Copy link
Member

commented Feb 1, 2019

This post will be updated as v6.0 is being developed.

Schedule 2019 summer

Development branch dev-6.0

Merge bugfixes directly into master

Main new features

  • Generic action handling #316
  • Multi-display support with run time display parameter settings #329 #109
  • Better GPU handling #87
  • Image rotation
  • Context to every callback comment
  • more come soon

Migrating from v5.3 to v6.0
v6.0 won't be fully compatible with v5.3 because some API changes will happen:

  • update lv_conf.h from lv_conf_templ.h
  • lv_obj_set_event_cb(obj, callback) instead of lv_btn_set_action(btn, LV_BTN_ACTION_..., callback). Event callbacks are used to handle all the former actions (i.e. long pressed, released are handled by a single function).
  • Objects now automatically detect if they've been deleted, no need for returning LV_RES_OK/LV_RES_INV in your lv_event_cb_t. For this reason, lv_event_cb_t functions return void.
  • Dynamically changeable display config. Instead of hardcoded in lv_conf.h.
  • Need to explicitly initialize your display buffer and add it to your display driver.
  • LV_HOR_RES and LV_VER_RES are replaced with LV_HOR_RES_MAX and LV_VER_RES_MAX, which define the maximum horizontal and vertical resolution of your display, respectively.
  • lv_obj_get_free_ptr and lv_obj_get_free_num are replaced lv_obj_get_user_data. The type of the user data can be changed in lv_conf.h
  • User data is now available for some other structures as well, like driver objects.
  • Driver function signatures now take an initial first parameter, the driver object itself. This allows your driver functions to work with more than one physical device without requiring two separate drivers to be written.
    • (i.e. indev callbacks now take an initial first parameter of lv_indev_t *)
  • disp_flush is now flush_cb. Instead of directly taking x/y coordinates, it takes in an lv_area_t which has fields x1, y1, x2, y2
  • Callbacks of lv_task now receive a pointer to the task itself instead of the user data. The user data can be accessed as task->user_data
  • lv_anim_set_...(&a) function are added to replace manual initialization of ```lv_anim_t`
  • Renames in lv_anim_t. The ready_cb get's lv_anim_t * as argument.
  • lv_style_anim_t is removed. Use lv_anim_t a; and lv_style_anim_set_...(&a, ...) intstead.
  • All padding and fits are left, right, top, bottom instead of ver and hor.
  • All the macros like USE_LV_BTN now are like LV_USE_BTN.
  • Rename symbols: SYMBOL_HOME --> LV_SYMBOL_HOME
  • Rename LV_GROUP_KEY_... to LV_KEY_...
  • minor function API changes...
  • more come soon

@kisvegabor kisvegabor added the pinned label Feb 1, 2019

@BrianPugh

This comment has been minimized.

Copy link
Contributor

commented Feb 1, 2019

what incompatibilities will there be between 6.x and 5.x ?

For bug fixes, what branch should we open PR's to?

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Feb 2, 2019

@BrianPugh
I updated the post above to answer your questions.
The biggest API change will be the introduction of generic actions lv_obj_set_action.

@puzrin

This comment has been minimized.

Copy link

commented Feb 2, 2019

Suggestion:

  • Directories structure change ( -> src, remove lv_ prefix, add test etc)
  • Advanced i18n, #791

Let's break everything :)

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Feb 2, 2019

@puzrin Please open a new issue for the structure change and tell why do think it would be better.

@kisvegabor kisvegabor changed the title v6.0 general discussion [v6.0] General discussion Feb 3, 2019

@amirgon

This comment has been minimized.

Copy link
Contributor

commented Feb 9, 2019

@kisvegabor I would like to bring up again the need for a context parameter in all callback functions, as discussed here.

What I think is missing is a parameter (void *user_data) that is received by every callback registration function, saved by lvgl, and passed over every time lvgl calls the callback function. This is common practice when defining a callback mechanism to pass such a variable.

Without user_data parameter we have a problem which is not limited to Micropython.
To illustrate the problem think of the following example:


A user has two displays of the same type he wants to use (either simultaneously, or select one on runtime). The user can create a driver instance for each display driver, but the driver callback function is the same function for both driver instances. What makes the driver instances different from each other is some instance specific data such as which pins they are connected to etc.
Today when the user registers the driver he only passes a callback function, and when the callback function is called he cannot know for which driver-instance it was called.


In Micropython the problem is harder.
While in C the user could create two C callback functions one for each driver instance (not so pretty, but possible), on Micropython every callback should be attached to a Micropython object, and a C function pointer alone is not enough for this since we generate the Micropython objects on runtime.
Today, when creating the Micropython module from lvgl headers, we only have limited callback support (Only for objects, one action handler per object, and no support for callbacks unrelated to objects).
I think it would be better to provide a generic way to convert C callbacks to Micropython callbacks on other cases, such as display/input drivers and others.

Today, you register only the callback function:lv_disp_drv_register(&disp_drv) where disp_drv is a struct of C callbacks.
What I suggest is something like lv_disp_drv_register(void *user_data, &disp_drv).
Later on when the callback should be called, lvgl will call it with the user_data parameter: void disp_flush(void *user_data, int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p). The driver-instance specific parameters could now be accessed through user_data.

I think every callback should adhere to a coding convention that includes a user_data parameter (received when registering the callback and passed over when lvgl calls the callback).
More Examples where we miss this today: get_bitmap on lv_font_t and lv_log_register_print.

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Feb 11, 2019

@amirgon

I see the problem.

Display driver
It's possible to add a user_data element to the driver which can be set along with the flush function. In v6.0 lv_disp_drv_register will return a lv_disp_t variable similarly to lv_indev_drv_register. I suggest passing this lv_disp_t pointer to the flush callback because it contains other useful data too (e.g. resolution or other settings). I'm planning to change the x1, y1, x2, y2 parameters to one lv_area_t, so will have only 3 parameters.

Action callbacks
A pointer to the object is passed to the callback which means the contexts. As discussed earlier, in v6.0 you can define a custom free_data (or user_data) struct in lv_conf.h. In the action function you can get it with lv_obj_get_free_data(obj). Is it working well with Micropython?

Current state/Plans
I'm currently working on the multi-display and runtime display config support. I hope it will be merged to dev-6.0 in a few weeks . Once it's ready I'll add the generic action handling. With these, the two most important and most API breaking changes will be added.

@amirgon

This comment has been minimized.

Copy link
Contributor

commented Feb 11, 2019

@kisvegabor My hope was for a simple convention that would allow generic and automatic conversion of every callback function in lvgl to Micropython.

Your suggestion gives a specific (non generic) solution only for disp-driver and action-callbacks, but not to a future callback that you might add, and not even for some existing callbacks (such as get_bitmap on lv_font_t and lv_log_register_print).
With your suggestion we'd need ad-hoc handling of every callback type, and we are not Forward Compatible (we cannot support callbacks added to lvgl in the future without fixing the script).

My suggestion is to define a convention to any callback, no matter what it is:

  • typedef void (*callback_t)(void* user_data, ...);
  • register_callback(callback_t callback, void* user_data, ...)

With such convention, the script will identify the user_data parameter and use it to pass along the Micropython object when registering the callback. When the callback is called it will invoke the callback as a Micropython function using user_data parameter passed to the callback.
This would work for any callback, no matter what "type" of callback it is, even callbacks you might add in the future.

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Feb 11, 2019

@amirgon You are right, it'd be inconsistent. So I'm open add a context as the first parameter to every callback but this context shouldn't be the user_data but its "parent" data structure because you can get the user_data from a lv_obj_t, lv_indev_t, lv_font_t but it does not work in the opposite way. So having the "parent" structure you have a lot of additional data including the user_data.

@puzrin

This comment has been minimized.

Copy link

commented Feb 11, 2019

Can metadata join be implemented via proxy layer? It's not very clear, does it need deep integration with lvgl core.

@amirgon

This comment has been minimized.

Copy link
Contributor

commented Feb 11, 2019

So I'm open add a context as the first parameter to every callback but this context shouldn't be the user_data but its "parent" data structure

@kisvegabor, ok, it makes sense.

  • Do we always have a "parent" structure? For example, what is the parent structure of lv_log_register_print?
  • Is there a generic way to identify the parent structure and access the user_data there? We can define such convention. For example - parent structure will alway be the first parameter to both the callback function and the callback registration function, and the parent structure will always have a member called void *user_data.
@embeddedt

This comment has been minimized.

Copy link
Member

commented Feb 11, 2019

@amirgon @kisvegabor

  • For example - parent structure will always be the first parameter to both the callback function and the callback registration function, and the parent structure will always have a member called void *user_data.

For simplicity, it would also be handy to have user_data as the first member of that parent structure.

@embeddedt embeddedt closed this Feb 11, 2019

@embeddedt embeddedt reopened this Feb 11, 2019

@embeddedt

This comment has been minimized.

Copy link
Member

commented Feb 11, 2019

Sorry, somehow I keep closing issues when I comment. Reopened.

@puzrin

This comment has been minimized.

Copy link

commented Feb 11, 2019

Ah, seems i understood initial idea. If that's about equivalent of this in OOP, that's a certainly useful pattern. In plain C this looks like method(context, params...). Where context = current object.

@amirgon

This comment has been minimized.

Copy link
Contributor

commented Feb 11, 2019

@puzrin Yes. More generally, a function pointer is defined per type while context is defined per instance. Without context we would not have access to instance data.

@puzrin

This comment has been minimized.

Copy link

commented Feb 11, 2019

I have not enougth C experience, to say exactly "right implementation must be like this", but such feature is really mandatory. With high probability *ctx (equivalent of pointer to current object's instance) should be first param, but i'm not 100% sure about right programming patterns for C.

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Feb 12, 2019

@embeddedt "Close and comment" button instead of "Comment"? :)

For simplicity, it would also be handy to have user_data as the first member of that parent structure.

Why not, I agree. It might be useful once.

I updated the TODO list in the first post.

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Feb 12, 2019

@amirgon

Do we always have a "parent" structure? For example, what is the parent structure of lv_log_register_print?

I didn't see the purpose of context in case of lv_log_register_print. It should just register a printf-like function. Can you explain it?

Is there a generic way to identify the parent structure and access the user_data there? We can define such convention. For example - parent structure will alway be the first parameter to both the callback function and the callback registration function, and the parent structure will always have a member called void *user_data.

Parent structure can be the first parameter of the callback but the callback are not always registered with API functions. For example, in the display driver, you just assign the flush function to structure. However, if it's registered with API function then the parent structure can be the first element.

@puzrin

This comment has been minimized.

Copy link

commented Feb 12, 2019

Parent structure can be the first parameter of the callback but the callback are not always registered with API functions. For example, in the display driver, you just assign the flush function to structure. However, if it's registered with API function then the parent structure can be the first element.

We speak about convention like "we need emulate classes somehow", because it can be suddenly required anywhere. If you don't need context - just ignore first param of function, that's not a problem.

@embeddedt

This comment has been minimized.

Copy link
Member

commented Feb 12, 2019

@kisvegabor

@embeddedt "Close and comment" button instead of "Comment"? :)

Yes, I wasn't trying to click it but somehow I managed to.

@puzrin

If you don't need context - just ignore first param of function, that's not a problem.

I agree.

@puzrin

This comment has been minimized.

Copy link

commented Feb 12, 2019

Let me add some buzz. Design of API, stable for long time ahead is not trivial thing. Sometime it's impossible to describe all factors via direct statements like "we should avoid floats". In this case it's common to do "one step back" and impress requirements via "probabilities":

  • "probability of this is high enougth"
  • "probability of this is about zero"

In this scope "probability of context need in GUI lib is 100%". If accepted as base of API signatures principle (first param of methods), it can also help to not reinvent similar things in different parts of lvgl internals. Note, i use more wide term "method" instead of "callback", because issue is more generic.

@amirgon

This comment has been minimized.

Copy link
Contributor

commented Feb 12, 2019

@kisvegabor

I didn't see the purpose of context in case of lv_log_register_print. It should just register a printf-like function. Can you explain it?

If you assume there is a single global "logger" which is registered once, I guess there is no need for a "parent" struct, or a "context".
But if you ever want to allow multiple independent registrations of loggers (for example, one to a file and other to UART), or log to two files with different log levels, then I think a context could be useful.

If we decide on a canonical way to define callback functions, I think it would be a good practice to apply it to all callbacks, lv_log_register_print included (although I agree this is not a must)

Parent structure can be the first parameter of the callback but the callback are not always registered with API functions. For example, in the display driver, you just assign the flush function to structure. However, if it's registered with API function then the parent structure can be the first element.

I need a way to update user_data when a callback is registered and read user_data when callback is called. This is why I suggested user_data as a parameter to both the registration function and the callback function.

My problem with your suggestion is - how do I identify the registration function if it does not receive a callback? How do I find each callback function pointer and correlate it to its right user_data?
There may be some convoluted ways to do it. I could check if a function receives a struct, and this struct contains function pointers, and then assume this is a registration function. In that case I would need to update user_data in the struct and register the callbacks on that struct. Not a clean solution, and there are some problems:

  • I also need to assume every function pointer on the struct is a callback I need to register, but this doesn't have to be true! What if we have some function pointer on that struct which is not a callback, but something else?
  • What if the user doesn't want to update both callbacks? How do I know which callback functions to register when the registration function is called with the struct?
  • user_data would be common to all callbacks on the struct. This is not good since we need context for each callback independently, as every callback may be a member of a different object.

I think that the source of the problem is that we have one context (parent struct, user_data) for multiple callbacks. This makes life harder.
If we had 1-to-1 relation between user_data and callback we could correlate them much easier.

This brings me back to my original suggestion of passing user_data as a parameter to both the registration function and the callback function instead of making it a field on the parent struct. This also requires a separate registration function for every callback, and a separate user_data to every callback. You can still have a parent struct, of course, to hold some other data. You can even store the user_data (or multiple user_data fields for multiple callbacks) on the parent struct.

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Feb 13, 2019

If you assume there is a single global "logger" which is registered once, I guess there is no need for a "parent" struct, or a "context".
But if you ever want to allow multiple independent registrations of loggers (for example, one to a file and other to UART), or log to two files with different log levels, then I think a context could be useful.

Clear now, thank you for the explanation. lv_log don't have any data structure or user data to pass right now but it can be updated if we decide it's required.

I need a way to update user_data when a callback is registered and read user_data when callback is called. This is why I suggested user_data as a parameter to both the registration function and the callback function. ....

I think we are talking about the same thing. There are two cases:

  1. There are API functions to set/get data of something, e.g. lv_obj_t. Use case:
lv_obj_t  * btn = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_user_data(btn, pointer_to_something);
lv_obj_set_action(btn, my_btn_action);

lv_res_t my_btn_action(lv_obj_t * btn, lv_action_t action) 
{
   void * user_data = lv_obj_get_user_data(btn)
   ...
   return LV_RES_OK;
}
  1. You are initializing structures and assign callbacks there. E.g. lv_disp_drv_t will work this way:
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);       
    disp_drv.disp_flush = my_disp_flush;
    disp_drv.user_data = pointer_to_something;   
    lv_disp_drv_register(&disp_drv);

...
void my_disp_flush(lv_disp_t * disp, lv_area_t * area, lv_color_t * color_p)
{
  void * user_data = lv_disp_get_user_data(disp);
  ...
}
@amirgon

This comment has been minimized.

Copy link
Contributor

commented Feb 13, 2019

I think we are talking about the same thing

@kisvegabor, I'm not sure. There is an open issue here and no agreed solution yet.

In the previous post I presented a problem, please let me try to explain it again:

If I understand correctly, you suggested passing a "parent struct" to the callback, and register the parent struct instead of the callback function. You also assume the same parent struct could be used by more than one callback.
For example you suggest having these callback functions:

// callbacks
typedef void (*disp_flush)(lv_disp_t * disp, lv_area_t * area, lv_color_t * color_p);
typedef void (*disp_fill)(lv_disp_t * disp, lv_area_t * area, lv_color_t color);

// registration
void lv_disp_drv_register(lv_disp_t *disp)'

The problems I see with this are:

  • both callbacks (flush and fill) refer to the same parent structure (disp). This means we would have a single user_data for both. However, I need a separate user_data for each callback, since each could be a member of a different object.
  • An automatic script could have trouble identifying lv_disp_drv_register as a registration function. lv_disp_drv_register looks like a regular function that receives a struct, not as a callback registration function that needs to be handled in a special way.
    A registration function is special since it needs to automatically initialize user_data. As I said above there may be a way to handle this by looking into the struct that the function receives, but there are several problems with that (see my previous post)

My suggestion:

We could register each callback function separately, with a different registration function. Each would receive its own with user_data.
So instead of a single lv_disp_drv_register(&disp_drv) we could have:

// callbacks
typedef void (*disp_flush_t)(void *user_data, lv_disp_t * disp, lv_area_t * area, lv_color_t * color_p);
typedef void (*disp_fill_t)(void *user_data, lv_disp_t * disp, lv_area_t * area, lv_color_t color_p);

// registration
void lv_disp_drv_register_flush(disp_flush_t disp_flush, void *user_data, lv_disp_t *disp_drv);
void lv_disp_drv_register_fill(disp_fill_t disp_fill, void *user_data, lv_disp_t *disp_drv);

This is generic - When the binding script sees a function that receives a function pointer and user_data it will know it's a registration function, it will know which callback is registered and what to pass as user_data for this callback registration.
This ensures that we have 1-to-1 relation between each callback and its user_data.
To summarize, the following needs to be true:

  • Every callback function should have a separate registration function, and each registration function should register exactly one callback.
  • The registration function should receive both the function pointer and void *user_data (and can receive other parameters)
  • The callback function should receive user_data (and can receive other parameters)
@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Feb 15, 2019

@amirgon I got it. Let's continue here: #316

@puzrin

This comment has been minimized.

Copy link

commented Apr 19, 2019

The ability to use 8859-1 has effectively been removed, can someone tell me why?

It's a part of full font system rework (upcoming). Supporting multiple encoding does not give notable benefits and makes codebase more complicated "without need".

You can see details in other issues with word "font" in header, and in lv_font_conv repo.

@upbeat27

This comment has been minimized.

Copy link
Contributor

commented Apr 19, 2019

@embeddedt OK, if the intent is to call the default kb handler from your own, I get that - but you must prevent infinitely recursive custom->default->custom loop.

@embeddedt @puzrin I'm perfectly aware of the work going on with the font system. This issue is that a previously useful feature (LV_TXT_UTF8) has been removed. There was no need to 'support' multiple encodings, the support already existed and could be enabled/disabled at will with one define, which I hardly would consider complicated (and the ASCII handling, which allowed 8859-1 to work, can hardly be considered complicated either).

@puzrin

This comment has been minimized.

Copy link

commented Apr 19, 2019

@upbeat27 IMO there are no fun to spend time for porting old kludges to new font system. But if you have arguments why 8859-1 support is important, you can post those to font API issue, and we discuss it with care.

I think, problem is that 6.0rc is in intermediate state (some old feateres are broken, but new one not ready yet). May be @kisvegabor could consider temporary roll back, until we are ready to switch for new fonts, if regenerating font is not acceptable for you.

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Apr 20, 2019

It's independent of the font system rework because the font doesn't know anything about the character encoding. They use only Unicode codes.

The advantage I see in 8859 is you can store some "special characters" in one byte.

@upbeat27

Being able to use a font like this is extremely useful, and necessary in my case.

Please describe why it is so important to better understand your case.

@puzrin

This comment has been minimized.

Copy link

commented Apr 20, 2019

The advantage I see in 8859 is you can store some "special characters" in one byte.

In my eyes that the same as "just for fun" :).

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Apr 20, 2019

In my eyes that the same as "just for fun" :).

I don't think so. Probably @upbeat27 has a good reason to say it's very important for him.

@upbeat27

This comment has been minimized.

Copy link
Contributor

commented Apr 22, 2019

@kisvegabor all of my source text is encoded in 8859-1 (doesn't matter where it comes from, just know that it is in this format, and can't be converted pre-compilation as the text is coming in "live" from another device), so putting any text on a label is as simple as just setting the text. No conversion required.
If only UTF-8 is supported, and ASCII is not, all text must be converted from 8859-1 to UTF-8.
This means:

  • more steps: 8859-1 to UTF-8 conversion
  • more RAM usage. All text must be converted into an intermediate buffer, which must be 4x the size of the original as it is possible that all existing chars convert to 4 byte UTF-8 chars.
  • more flash usage as all fonts are larger than they would be otherwise. See the font I've attached above.
  • most importantly: it works perfectly in 5.x
@puzrin

This comment has been minimized.

Copy link

commented Apr 22, 2019

  • more steps: 8859-1 to UTF-8 conversion

  • more RAM usage. All text must be converted into an intermediate buffer, which must be 4x the size of the original as it is possible that all existing chars convert to 4 byte UTF-8 chars.

  • more flash usage as all fonts are larger than they would be otherwise. See the font I've attached above.

  • most importantly: it works perfectly in 5.x

  • (2) & (3) - terms like "more" and "better" can not replace real metrics. Prior to talk about "more ram/flash", there should be exact estimate and explanation why is this a problem at all.
  • (4) does not tell us any additional info.

(1) with not quoted explanation above looks clear. Can it be enougth - i don't know.

@upbeat27

This comment has been minimized.

Copy link
Contributor

commented Apr 22, 2019

@puzrin more RAM = up to 4x the original length, per string, as explained.

(4) tells plenty. One expects improvements + added features over time, not the removal of existing features. It is so easy to support I don't even understand the pushback. The support was already there, a single #define between UTF-8 and any 1 byte per character encoding, 8859-1 included. The "new font system" doesn't have to do anything special to handle it. Just keep the ASCII functions, switched in with the #define... once again, as was already done before.

I don't have any interest in trying to explain it further. I will just use 5.x going forward.

@puzrin

This comment has been minimized.

Copy link

commented Apr 22, 2019

more RAM = up to 4x the original length, per string, as explained.

Such statement are difficult to use for decisions. Metrics should explain something like memory usage increase in % of previous one (total), + absolute values and hardware limits. In other words, how memory increase are related with real device.

For example: "i have 2K flash, with 1K code & 200 cyrilic strings with 700bytes total, utf8 2x size increase will not fit into existing memory". That's clear and constructive.

One expects improvements + added features over time, not the removal of existing features.

Iterative constant features add is possible in ideal world only. Sometime big reworks happen, breaking API and deprecating outdated things. 6.0 will have (i hope) reworked fonts with significant rendering quality improvements and (or?) fonts size reduce. 5.0 had a lot of decisions, specific for previous design, and it's not effective to do new one without dropping old kludges. It's more reasonable to make new things work, and then inspect if each old feature should be reworked.

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Apr 23, 2019

UTF8 on/off was dropped mainly because of symbols. In v5.3:

  • it was difficult to extend the built-in symbols.
  • it was messy to support symbols with and without UTF8 support too.

I agree with @upbeat27, the library should be backward compatible as much as it's possible. In this case, having ASCII support really makes sense and possible to implement by changing the decoder functions in lv_txt.c. A lot of UIs are English only where you don't need UTF-8 support. In addition, working with UTF8 strings in C is very inconvenient.

@puzrin
The new font converter tool will support remapping the character, right? So if somebody needs FontAwsome symbols with ISO8859 he can remap them as he wants.

@upbeat27
I added the ISO8859 decoder functions to see if it really solves the issue. Can you test it?
See abd081d

@upbeat27

This comment has been minimized.

Copy link
Contributor

commented Apr 23, 2019

@kisvegabor I will test it. Thanks for considering this as a worthy feature to keep.

Just a note: I don't think naming the encoding/functions 8859-1 is necessarily the most intuitive. It can really be used for any encoding where 1 character is always 1 byte (like before: you had it named ASCII, but 8859-1 also worked because 1 character is 1 byte in both - ASCII being a subset). I don't necessarily have a better name, just throwing it out there.

I see the problem about extending symbols without UTF-8 enabled... in fact, I was not using symbols at all so it wasn't an issue. If I wanted to use symbols, they would not render correctly at the 8 pixel height of the font I use (unscii). Things change a lot when you are using lvgl as a GUI for a small screen. In my case it is a 256x64 OLED, but the same would apply for many screen sizes in which the larger size (in pixels) fonts are not very usable. Anyway: I guess the takeaway is that not everyone will use symbols, either because they don't need them or they just won't render correctly.

If you look at the built in font lv_font_monospace_8, it is the same as the font I use except mine includes more characters (in the 127-255 range) and isn't set to be monospaced. You might consider adding multiple versions of the unscii font as built in, such as monospaced vs. not. You could also extend the included characters to make it 8859-1 instead of just ASCII.

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Apr 24, 2019

I don't think naming the encoding/functions 8859-1 is necessarily the most intuitive. It can really be used for any encoding where 1 character is always 1 byte (like before: you had it named ASCII, but 8859-1 also worked because 1 character is 1 byte in both - ASCII being a subset). I don't necessarily have a better name, just throwing it out there.

ASCII really was a better name. I updated accordingly.

If you look at the built in font lv_font_monospace_8, it is the same as the font I use except mine includes more characters (in the 127-255 range) and isn't set to be monospaced. You might consider adding multiple versions of the unscii font as built in, such as monospaced vs. not. You could also extend the included characters to make it 8859-1 instead of just ASCII.

Actually, I see no reason to use monospace built-in pixel-perfect fonts. So probably non-monospace, pixel perfect font will be added with more sizes.

@BrianPugh

This comment has been minimized.

Copy link
Contributor

commented Apr 29, 2019

@kisvegabor something in commit #5243d235 has some of my lv_task's no longer working. I'll investigate when i get a chance, but just a heads up incase you can debug faster

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented Apr 29, 2019

Sorry, still not announced it here but there are two important changes:

  • Callbacks of lv_task now receive a pointer to the task itself instead of the user data. The user data can be accessed as task->user_data
  • Renames in lv_anim_t. The ready_cb get's lv_anim_t * as argument.
@BrianPugh

This comment has been minimized.

Copy link
Contributor

commented Apr 29, 2019

Thanks! I'll change my code to reflect this, just saved me a whole lot of debugging!

@BrianPugh

This comment has been minimized.

Copy link
Contributor

commented May 8, 2019

@kisvegabor why was lv_obj_user_data_t *lv_obj_get_user_data(lv_obj_t * obj); changed to lv_obj_user_data_t lv_obj_get_user_data(lv_obj_t * obj);? This now assumes lv_obj_user_data_t is some sort of pointer. Previously it could be a struct (directly putting the struct inside the lv_obj_t).

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented May 9, 2019

@BrianPugh
We had a long discussion about it here: #1019

We concluded that as user data is usually small it can be simply passed and returned to/from a function directly. If it's a struct it might be passed via the stack instead of registers but it's not an issue if it's only a few bytes. However, an lv_obj_get_user_data_ptr() still might be reasonable to enable simple modification of the struct fields. For example:

d = lv_obj_get_user_data_ptr(obj);
d->x = 2;
d->y.z = 8;

What do you think?

@BrianPugh

This comment has been minimized.

Copy link
Contributor

commented May 9, 2019

I’d like that!

@BrianPugh

This comment has been minimized.

Copy link
Contributor

commented May 9, 2019

See #1058

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented May 9, 2019

@BrianPugh
Merged, thank you!

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented May 15, 2019

Animation
Updates related to the animation.

  1. lv_anim_t a; and manual initialization still works but functions are added to set its values. See lv_anim.h
  2. lv_style_anim_t is removed. Normal lv_anim_t can be used instead with lv_style_anim_...() functions. See lv_style.h

Image decoder
The image decoder interface is reworked. It works like this:

  1. Create a new decoder with lv_img_decoder_t * decoder = lv_img_decoder_create()
  2. Set callbacks with lv_img_decoder_set_info/open/read_line/close_cb(decoder, my_xxx_cb)

From now you can use the decoders externally (manully) too:

  1. To use the decoder declare lv_img_decoder_dsc_t dsc;
  2. Use the decoders as lv_img_decoder_open(&dsc, dsc, src, style), lv_img_decoder_close(&dsc)

See lv_img_decoder.h

@BrianPugh

This comment has been minimized.

Copy link
Contributor

commented May 18, 2019

@embeddedt Currently a lot of the LV_OBJX_DEF_ANIM_TIME (e.g. LV_DDLIST_DEF_ANIM_TIME) have incorrect guards in their files. What's the correct macro?

@embeddedt

This comment has been minimized.

Copy link
Member

commented May 18, 2019

@BrianPugh It should be whatever is in lv_conf_templ.h. That would be LV_DDLIST_DEF_ANIM_TIME.

@BrianPugh

This comment has been minimized.

Copy link
Contributor

commented May 18, 2019

@embeddedt alright I'll make a PR

EDIT: See #1067

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented May 19, 2019

Thank you @BrianPugh!

@BrianPugh

This comment has been minimized.

Copy link
Contributor

commented May 19, 2019

This is going to sound vague and not helpful, but I'm currently trying to tackle this bug I think is reduced to the following:

  1. I Create an lv_list in a keypad group
  2. In a button element's callback of the list, on event short_clicked I create another list and then delete the current list.
  3. If I delete the current list first, then create the new list, everything is fine. However, If I create the new list first, then delete the first list, I seg fault because on line 480 of lv_indev.c, I believe it's trying to send a signal to an object that has been deleted (the crash comes from trying to execute a deleted object's callback). From this, I think it's not detecting that the object has been deleted from the short_clicked

I'll still be investigating and report what i find.

EDIT:
Ok the bug is because in my short_clicked callback of ObjA, I create a new object ObjB in the same group and focus on it. I then delete ObjA (still within the CB). Because ObjA was no longer focused, the indev didn't detect that it should reset, so it continues sending signals (the next signal being CLICKED) to an object that has been deleted. Now that I know what the problem is, I'll try and come up with a solution.

EDIT2:
I think that the indev reset_query should be triggered any time a new object is focused.

EDIT3:
See #1072

@ShenRen

This comment has been minimized.

Copy link

commented May 23, 2019

Hello !
Can lvgl v6.0 support 3D rendering ? This will be a very cool feature .
I was looking for a way to draw 3D object , like stl , obj . Then I found uGFX has a 3D Widget which use tinygl to software rendering 3D.
uGFX https://ugfx.io/
TinyGL https://bellard.org/TinyGL/
TinyGL is a very small implementation of a subset of OpenGL * for embedded systems or games.

Now I'm trying to implementing 3D for my 3DPrinter project.

@kisvegabor

This comment has been minimized.

Copy link
Member Author

commented May 23, 2019

Hi @ShenRen,
It's not planned for v6.0. However, we have the lv_canvas object where you can draw anything, even the output of TinyGL.

I'd like to check TinyGL in more detail but haven't found any documentation. Can you link something where we can see how to port it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.