Skip to content
linusrj edited this page Aug 4, 2022 · 5 revisions

Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".

If you would like to contribute but don't have a suggestion of your own, have a look at the issues and try to solve any of them.

Don't forget to give the project a star! Thanks again!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Adding components

This guide explains how new components can be added to MicroGUI-Embedded. New components may be added to this library even though they are not implemented in the MicroGUI web application. However it is probably much easier if the new component is implemented in the web application already, so that you know what props the web application will include for that specific component.

Step 1: Create the new object

The first step is to figure out how to create the new object with LVGL. LVGL has probably already made an implementation for the widget that you are trying to create, so have a look at their documentation on widgets and see if you can find the one that you are trying to implement into MicroGUI-Embedded.

Step 2: Make a rendering function for this object

Once you know how to use the LVGL object it is time to implement it into MicroGUI-Embedded. Inside the MicroGUI.cpp file, create a new function:

void mgui_render_<ComponentName>(JsonPair kv, JsonObject root){
  // Put the code for creating your new component object here
  // You may also have some code for styling your component, put that here
}

⚠️ Important: Remember to change <ComponentName> to the actual name of your component. This applies to everywhere you see <ComponentName> or ComponentName inside this guide.

Step 3: Create a new linked list

The reference for your newly created component has to be stored somewhere, right? Create a new linked list for storing references to all of your new components. Put this definition by the other linked list definitions towards the beginning of the cpp-file.

LinkedList<MGUI_object*> ComponentName;

Step 4: Add component to the list

Go back to your rendering function, now it is time to add your new component to the list you just created. Add the code below to your rendering function:

// Create MGUI_object for newly created component
MGUI_object * m_ComponentName = new MGUI_object;
m_ComponentName->setObject(ComponentName);
memcpy(m_ComponentName->getType(), (const char*)root[kv.key()]["type"]["resolvedName"], strlen((const char*)root[kv.key()]["type"]["resolvedName"]));
memcpy(m_ComponentName->getParent(), kv.key().c_str(), strlen(kv.key().c_str()));
memcpy(m_ComponentName->getEvent(), (const char*)root[kv.key()]["props"]["event"], strlen((const char*)root[kv.key()]["props"]["event"]));

// Store MGUI_object pointer in linked list
ComponentName.add(m_ComponentName);

// Store the MGUI_object as user data
lv_obj_set_user_data(button, m_button);

This code creates a new MGUI_object, which is just a MicroGUI class for storing custom data together with an LVGL object. Then it copies the properties "Type", "Parent" and "Event" from the JSON document. This is why we want the component to be implemented in the web application before we implement it in this library. If the component is not yet implemented in the web application, remove the memcpy lines temporarily.

Step 5: Add component event callback

(Skip this step if your component is not interactive, meaning you are not supposed to click or change it in any way)

Add the following to your rendering function:

// Add event callback
lv_obj_add_event_cb(ComponentName, widget_cb, LV_EVENT_CLICKED, NULL); 

For this step, you have to look at the documentation for your specific component and add this callback according to instructions mentioned there. You want to find out what the event code (third parameter) should be for your component.

Now go to the widget_cb() function which is in the same file that you should already be in, MicroGUI.cpp. This is where you have to add the "translation" of an LVGL to a MicroGUI event. The easiest thing to do here is to look at the components that are already in there, and try to add corresponding code for your component. Here is an example:

if(code == LV_EVENT_VALUE_CHANGED) {
  if(lv_obj_check_type(object, &lv_ComponentName_class)) {     // If object is of type ComponentName
    value = lv_slider_get_value(object);
    latest = new MGUI_event(((MGUI_object*)lv_obj_get_user_data(object))->getEvent(), 
                            ((MGUI_object*)lv_obj_get_user_data(object))->getParent(), 
                            value);
  }
} 

Step 6: Add component to more functions

There are a few more functions that you need to add some implementation for your specific component to. You will see in the comments of each function what they do.

Clear lists

Go to the mgui_clear_lists() function and add the following for your component:

for(int i = 0; i < ComponentName.size(); i++) {
  delete ComponentName.get(i);
}

ComponentName.clear();

Update document

Go to the mgui_update_doc() function and add the corresponding update of your component. For example:

for(int i = 0; i < ComponentName.size(); i++) {
  root[ComponentName.get(i)->getParent()]["props"]["value"] = lv_ComponentName_get_value(ComponentName.get(i)->getObject());
}

This function is going to depend on your specific component. Look at the other components in that function for inspiration and look up how to retrieve a value/state/text for your component if possible.

Get and set value/state/text

If it is applicable to your component to get or set a value/state/text, then head over to the functions mgui_get_value(), mgui_set_value(), mgui_get_text() and mgui_set_text() and add your components implementation for those.

Step 7: Add your rendering function to the main rendering function

Once you have completed all the steps above, your implementation should be complete and you can finally add your rendering function to mgui_render().

⚠️ As a good check for knowing that you have added all the necessary pieces of code for your component, search for "button" in your editor and look through all the search results. If you find your component in the near vicinity of all search results, you probably added your component correctly. If it does not work for some reason, take extra care looking at the API for your component. The LVGL documentation will have the answer to most of your questions!

Step 8: Contribute! 🙌

If you have come this far and your implementation works, it would be truly amazing if you want to contribute to the MicroGUI-Embedded library. Follow the "Contributing" guide to do this. Thanks!

Styling components

LVGL (the graphics library used by MicroGUI-Embedded) has extensive support for styling components. Currently, MicroGUI-Embedded does not make use of all features available but the most basic like setting color etc. What is missing (among other things) from this library is the ability to have different size buttons, checkboxes and switches which is a feature available in the web application.

Step 1: Find the component rendering function

Go to the rendering function for the component that you want to edit the styling of. They are named mgui_render_button() for example and are located in the MicroGUI.cpp file.

Step 2: Look up LVGL documentation

Since styling of components differ a bit depending on type, you need to look up your selected component's LVGL documentation.

Step 3: Style the component

Now it is time for you to style the component. Consider what properties are available in the web application and study the exported JSON to know how to extract certain styling properties. Have a look at the other rendering functions for inspiration on styling a component.

Step 4: Test, test and test...

Test your new styling by uploading your code to the display until you are completely satisfied with the results. Make sure that your styling works for all possible cases.

If you find testing by uploading too tedious of work you can try to set up a styling environment in the LVGL simulator for PC. It has not been used during early development of MicroGUI-Embedded, however you might find it useful.

Step 5: Contribute! 🙌

If you have come this far and your implementation works, it would be truly amazing if you want to contribute to the MicroGUI-Embedded library. Follow the "Contributing" guide to do this. Thanks!