Open AlixANNERAUD opened 1 year ago
I am also interested in doing a C++ binding. After a quick review of this project, I believe it could be done in a more "Standard" compliant manner than this.
Hi guys,
Thank you for writing. Sorry @AlixANNERAUD somehow I haven't noticed your comment earlier. :slightly_frowning_face:
This project is really stale now, but it would be really great to have a C++ binding!
My 400 USD offering in the README is still also active.
However there is one more thing: LVGL v9 will be released by end of this year so we should target the v9 API with the C++ binding too. There will be some refactoring later on on the API but no conceptual changes.
Hello, OK, well I'm working on it. However, could you tell me what a typical widget class should look like? Because at the moment I'm using an approach where the class just contains a pointer to the widget which is then used/modified by the various methods. I'm not sure this is exactly what you're thinking...
How can it be used? E.g. how the set the size and position of a button and how to add an event to it?
Alix, I have been reviewing this code. To answer your question: A class containing a pointer to a widget and using that to invoke the C functions is exactly what you want. Basically. What you really want is a class that encapsulates an 'lv_obj_t*' and the widget classes derive from that, as it is in this code base. The basic design of this code base is correct. The issues I have are with the implementation. Chief among them being it is designed to be fluent (i.e. methods return a reference to the object). While fluent design is cool, but it makes the code difficult to in-line without adding bytes. The ideal C++ binding should not add any amount of code storage above what a C implementation would. While that may not be completely possible, placing function return value on what is effectively a void method is difficult to optimize away. Also the coding style used, while not uncommon, is not the same has the C code base, nor current C++ standard library, style. Using the same naming convention has the C library would make it easier for developers to move from C to C++. It should that they use the library basically the same way did before, but do not have to worry about object life time management has much.
Hello,
I've started generating the binding from scratch again using PyGCCXML. Here is the wrapper class for lv_obj_t
as an example (don't pay attention to the casing ^^ ) :
namespace LVGL
{
typedef class Object_Class
{
public:
virtual ~Object_Class();
void Clean();
void Del_Delayed(uint32_t delay_ms);
void Del_Anim_Ready_Cb(lv_anim_t * a);
void Del_Async();
void Set_Parent(Object_Class parent);
/* ... */
void Move_Background();
uint32_t Get_Child_Id();
inline Object_Class(lv_obj_t* LVGL_Pointer) : LVGL_Pointer(LVGL_Pointer) { };
inline Object_Class() : LVGL_Pointer(NULL) { };
inline lv_obj_t* Get_LVGL_Pointer() const { return LVGL_Pointer; };_lv_obj_t* Object_Class::Get_Child(int32_t id)
{
return lv_obj_get_child(LVGL_Pointer, id);
}
inline void Clear_Pointer() { LVGL_Pointer = NULL; };
static const lv_obj_class_t& Class;
protected:
lv_obj_t* LVGL_Pointer;
} Object_Type;
}
Some function here are not part of LVGL, it's only for shorter implementation.
And here the definition of one function as an example :
Object_Type Object_Class::Get_Child(int32_t id)
{
return Object_Type(lv_obj_get_child(LVGL_Pointer, id));
}
Does this look right to you ? I'd like to use a more RAII-oriented model (object creation / deletion) within the constructor, move semantic ...), but I don't think it's the most suitable for this context.
Hello, I have a first working version that generates a binding for almost all the wigets (the rest will come later). It is RAII oriented (all the objects are deleted out of the scope):
LVGL::Object_Type Screen(lv_scr_act());
LVGL::Button_Type B(Screen);
B.Set_Align(LV_ALIGN_CENTER);
LVGL::Label_Type Label(B);
LVGL::Switch_Type S(Screen);
S.Set_Align(LV_ALIGN_BOTTOM_LEFT);
LVGL::Colorwheel_Type C(Screen, true);
C.Set_Align(LV_ALIGN_BOTTOM_RIGHT);
C.Set_Size(200, 200);
Label.Set_Text("Hello World!");
Would it be possible to have your opinion on it? If you want to test it, I suggest you use my development environment available here: https://github.com/AlixANNERAUD/LVGL-Cpp-Binding-Environment (a fork of the native LVGL platform io). Just run Main.my inside the Tool folder, it's will generate the binding inside the LVGL_Cpp folder. Juste include from it the LVGL_Cpp.hpp file and you are done. Bye.
Thank you for the update. Does this code just creates a an obj
on the current screen, right? So I wonder why the variable is called "Screen"?
Shouldn't it be LVGL::Object_Type Screen(NULL);
?
Hello,
Sorry for my late reply, I've just come back from vacation.
The first object instantiated Screen
is instantiated from a pointer : there is a normal constructor that actually create an object and a constructor from a LVGL pointer which juste copy the LVGL pointer (no object creation). I know this can be confusing, but it simplifies the generation of binding code greatly.
Here's what the two constructors code looks like, roughly speaking :
Object_Class::Object_Class(lv_obj_t* LVGL_Pointer) : LVGL_Pointer(LVGL_Pointer)
{
}
Object_Class::Object_Class(Object_Class& Parent_Object) : LVGL_Pointer(NULL) // ! : This is not a copy constructor !!
{
this->LVGL_Pointer = lv_obj_create(Parent_Object.LVGL_Pointer)
}
I don't think LVGL::Object_Type Screen(NULL)
is right, because then only the child object of Screen
would be a screen actually, which isn't the point here. Rest assured, this isn't the final design at all, just some quick code for testing purposes.
In LVGL v9 I'm thinking about having an lv_obj_t * lv_screen_create(void)
function and remove the "create screen with NULL
parent". Would it help for the binding?
Well, it's could help, and would make more sense, but it's not required.
Hello, Is this project still on? I would be interested in doing the binding.