Hi, I’d like to use lvgl to implement a video chatting app for a smartwatch. In Whatsapp, you can see a picture-in-picture displaying yourself beside the remote side when you are doing a video call. But I’m not sure how to implement this feature with lvgl? I suppose we need a small video container layer be on top of a big video container? Any examples would be helpful. Thanks in advance!
Make you PIP container draggable similar to this example.
You can also add snap to corners with animations with some code and animations
#define PIP_EDGE_MARGIN 12
#define PIP_SNAP_DURATION_MS 250
static void snap_x_anim_cb(void *obj, int32_t value) {
lv_obj_set_x((lv_obj_t *)obj, value);
}
static void snap_y_anim_cb(void *obj, int32_t value) {
lv_obj_set_y((lv_obj_t *)obj, value);
}
static void animate_to_position(lv_obj_t *obj, int32_t x, int32_t y) {
lv_anim_delete(obj, snap_x_anim_cb);
lv_anim_delete(obj, snap_y_anim_cb);
lv_anim_t anim;
lv_anim_init(&anim);
lv_anim_set_var(&anim, obj);
lv_anim_set_values(&anim, lv_obj_get_x_aligned(obj), x);
lv_anim_set_duration(&anim, PIP_SNAP_DURATION_MS);
lv_anim_set_exec_cb(&anim, snap_x_anim_cb);
lv_anim_set_path_cb(&anim, lv_anim_path_ease_out);
lv_anim_start(&anim);
lv_anim_init(&anim);
lv_anim_set_var(&anim, obj);
lv_anim_set_values(&anim, lv_obj_get_y_aligned(obj), y);
lv_anim_set_duration(&anim, PIP_SNAP_DURATION_MS);
lv_anim_set_exec_cb(&anim, snap_y_anim_cb);
lv_anim_set_path_cb(&anim, lv_anim_path_ease_out);
lv_anim_start(&anim);
}
static int32_t clamp_value(int32_t value, int32_t min, int32_t max) {
if (value < min)
return min;
if (value > max)
return max;
return value;
}
static void drag_event_handler(lv_event_t *e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t *obj = lv_event_get_current_target_obj(e);
lv_obj_t *parent = lv_obj_get_parent(obj);
int32_t obj_w = lv_obj_get_width(obj);
int32_t obj_h = lv_obj_get_height(obj);
int32_t parent_w = lv_obj_get_content_width(parent);
int32_t parent_h = lv_obj_get_content_height(parent);
int32_t min_x = PIP_EDGE_MARGIN;
int32_t min_y = PIP_EDGE_MARGIN;
int32_t max_x = parent_w - obj_w - PIP_EDGE_MARGIN;
int32_t max_y = parent_h - obj_h - PIP_EDGE_MARGIN;
if (max_x < min_x)
max_x = min_x;
if (max_y < min_y)
max_y = min_y;
if (code == LV_EVENT_PRESSING) {
lv_indev_t *indev = lv_indev_active();
if (indev == NULL)
return;
/* Stop snapping if the object is grabbed again. */
lv_anim_delete(obj, snap_x_anim_cb);
lv_anim_delete(obj, snap_y_anim_cb);
lv_point_t vect;
lv_indev_get_vect(indev, &vect);
int32_t x = lv_obj_get_x_aligned(obj) + vect.x;
int32_t y = lv_obj_get_y_aligned(obj) + vect.y;
x = clamp_value(x, min_x, max_x);
y = clamp_value(y, min_y, max_y);
lv_obj_set_pos(obj, x, y);
} else if (code == LV_EVENT_RELEASED) {
int32_t center_x = lv_obj_get_x_aligned(obj) + obj_w / 2;
int32_t center_y = lv_obj_get_y_aligned(obj) + obj_h / 2;
int32_t target_x = center_x < parent_w / 2 ? min_x : max_x;
int32_t target_y = center_y < parent_h / 2 ? min_y : max_y;
animate_to_position(obj, target_x, target_y);
}
}
void lv_example_obj_draggable(void) {
lv_obj_t *obj = lv_obj_create(lv_screen_active());
lv_obj_set_size(obj, 100, 150);
lv_obj_set_pos(obj, PIP_EDGE_MARGIN, PIP_EDGE_MARGIN);
lv_obj_add_event_cb(obj, drag_event_handler, LV_EVENT_PRESSING, NULL);
lv_obj_add_event_cb(obj, drag_event_handler, LV_EVENT_RELEASED, NULL);
lv_obj_t *label = lv_label_create(obj);
lv_label_set_text(label, "Drag me");
lv_obj_center(label);
}
// make the parent non-scrollable
lv_obj_set_flag(lv_scr_act(), LV_OBJ_FLAG_SCROLLABLE, false);
lv_example_obj_draggable();
