lvgl / lv_binding_micropython

LVGL binding for MicroPython
MIT License
237 stars 157 forks source link

Provide access to C function pointers #110

Closed amirgon closed 3 years ago

amirgon commented 3 years ago

For example:

typedef lv_design_res_t (*lv_design_cb_t)(struct _lv_obj_t * obj, const lv_area_t * clip_area, lv_design_mode_t mode);
...
lv_design_cb_t lv_obj_get_design_cb(const lv_obj_t * obj);

Today obj.get_design_cb returns a generic pointer ("Blob") that cannot be used to call the original function. Alternatively, the binding could return a function object that could be called from Python.

Also relevant to struct members which are function pointers.

amirgon commented 3 years ago

Done.

In the example script below (custom widget), self.parent.get_signal_cb()(self.parent, sign, param) is a function pointer that is returned from get_signal_cb and gets called with arguments.

import display_driver
import lvgl as lv

class MyLine(lv.obj):

    def __init__(self, par):
        super().__init__(par) 
        self.ancestor_signal = self.get_signal_cb()        
        self.set_design_cb(self.design)
        self.set_signal_cb(self.signal)
        self.pressed = False        
        self.parent = par

    def signal(self, line, sign, param):
        prev_pressed = self.pressed
        if sign == lv.SIGNAL.PRESSED:
            self.pressed = True
        elif sign == lv.SIGNAL.RELEASED or sign == lv.SIGNAL.PRESS_LOST:
            self.pressed = False
        print("sign = %s, pressed = %s" % (sign, repr(self.pressed)))
        if (self.pressed != prev_pressed):
            self.invalidate()
        self.parent.get_signal_cb()(self.parent, sign, param)
        return lv.RES.OK

    def design(self, line, clip_area, mode):        
        print("mode = %d" % (mode))
        if mode == lv.DESIGN.COVER_CHK:
            return lv.DESIGN_RES.NOT_COVER
        if mode == lv.DESIGN.DRAW_MAIN:         
            area = lv.area_t()
            self.get_coords(area)
            h = self.get_height()
            x_ofs = area.x1
            y_ofs = area.y1
            if self.pressed:            
                p1 = lv.point_t({'x':x_ofs, 'y': y_ofs})
                p2 = lv.point_t({'x':x_ofs+h, 'y': y_ofs+h})
            else:
                p1 = lv.point_t({'x':x_ofs+h, 'y': y_ofs})
                p2 = lv.point_t({'x':x_ofs, 'y': y_ofs+h})
            dsc = lv.draw_line_dsc_t()
            dsc.init()
            lv.draw_line(p1, p2, clip_area, dsc)                        
        return lv.DESIGN_RES.OK

scr = lv.obj()

line = MyLine(scr)
line.align(None, lv.ALIGN.CENTER, 0, 0)
line.set_drag(True)

lv.scr_load(scr)