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

Still on ? #8

Open
AlixANNERAUD opened this issue Jun 8, 2023 · 11 comments
Open

Still on ? #8

AlixANNERAUD opened this issue Jun 8, 2023 · 11 comments

Comments

@AlixANNERAUD
Copy link

Hello,
Is this project still on?
I would be interested in doing the binding.

@RobinPurtee
Copy link

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.

@kisvegabor
Copy link
Member

Hi guys,

Thank you for writing. Sorry @AlixANNERAUD somehow I haven't noticed your comment earlier. 🙁

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.

@AlixANNERAUD
Copy link
Author

AlixANNERAUD commented Jul 16, 2023

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...

@kisvegabor
Copy link
Member

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?

@RobinPurtee
Copy link

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.

@AlixANNERAUD
Copy link
Author

AlixANNERAUD commented Aug 12, 2023

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.

@AlixANNERAUD
Copy link
Author

AlixANNERAUD commented Aug 23, 2023

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.

@kisvegabor
Copy link
Member

kisvegabor commented Aug 25, 2023

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);?

@AlixANNERAUD
Copy link
Author

AlixANNERAUD commented Aug 31, 2023

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.

@kisvegabor
Copy link
Member

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?

@AlixANNERAUD
Copy link
Author

Well, it's could help, and would make more sense, but it's not required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants