1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-21 06:53:01 +08:00
lvgl/lv_core/lv_indev.c

1087 lines
41 KiB
C
Raw Normal View History

2017-10-09 15:21:26 +02:00
/**
* @file lv_indev_proc.c
2018-06-19 09:49:58 +02:00
*
2017-10-09 15:21:26 +02:00
*/
/*********************
* INCLUDES
********************/
2017-11-26 23:57:39 +01:00
#include "lv_indev.h"
#include "lv_disp.h"
#include "lv_obj.h"
2017-10-09 15:21:26 +02:00
#include "../lv_hal/lv_hal_tick.h"
2017-11-30 11:35:33 +01:00
#include "../lv_core/lv_group.h"
#include "../lv_core/lv_refr.h"
2017-11-23 20:42:14 +01:00
#include "../lv_misc/lv_task.h"
2017-11-24 17:48:47 +01:00
#include "../lv_misc/lv_math.h"
2017-10-09 15:21:26 +02:00
/*********************
* DEFINES
*********************/
2019-02-10 06:53:11 -05:00
#if LV_INDEV_DRAG_THROW <= 0
#warning "LV_INDEV_DRAG_THROW must be greater than 0"
#endif
2017-10-09 15:21:26 +02:00
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
2018-01-10 09:42:52 +01:00
#if LV_INDEV_READ_PERIOD != 0
2017-10-09 15:21:26 +02:00
static void indev_proc_task(void * param);
2018-02-24 13:17:39 +01:00
static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data);
static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data);
2018-09-24 22:59:48 +02:00
static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data);
2018-02-24 13:17:39 +01:00
static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data);
static void indev_proc_press(lv_indev_proc_t * proc);
static void indev_proc_release(lv_indev_proc_t * proc);
2018-02-06 11:42:50 -08:00
static void indev_proc_reset_query_handler(lv_indev_t * indev);
static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj);
2017-11-29 13:08:03 +01:00
static void indev_drag(lv_indev_proc_t * state);
static void indev_drag_throw(lv_indev_proc_t * proc);
2018-01-10 09:42:52 +01:00
#endif
2017-10-09 15:21:26 +02:00
/**********************
* STATIC VARIABLES
**********************/
2018-06-19 09:49:58 +02:00
static lv_indev_t * indev_act;
2017-10-09 15:21:26 +02:00
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the display input device subsystem
*/
2017-10-10 16:17:23 +02:00
void lv_indev_init(void)
2017-10-09 15:21:26 +02:00
{
2017-10-10 16:17:23 +02:00
#if LV_INDEV_READ_PERIOD != 0
2018-01-10 09:42:52 +01:00
lv_task_create(indev_proc_task, LV_INDEV_READ_PERIOD, LV_TASK_PRIO_MID, NULL);
2017-10-09 15:21:26 +02:00
#endif
lv_indev_reset(NULL); /*Reset all input devices*/
}
/**
* Get the currently processed input device. Can be used in action functions too.
* @return pointer to the currently processed input device or NULL if no input device processing right now
*/
lv_indev_t * lv_indev_get_act(void)
{
return indev_act;
}
2018-07-13 00:37:28 +02:00
/**
* Get the type of an input device
* @param indev pointer to an input device
* @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`)
*/
lv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev)
2018-07-13 00:37:28 +02:00
{
2018-10-05 17:22:49 +02:00
if(indev == NULL) return LV_INDEV_TYPE_NONE;
2018-07-13 00:37:28 +02:00
2018-10-05 17:22:49 +02:00
return indev->driver.type;
2018-07-13 00:37:28 +02:00
}
2017-10-09 15:21:26 +02:00
/**
* Reset one or all input devices
2017-12-17 01:54:09 +01:00
* @param indev pointer to an input device to reset or NULL to reset all of them
2017-10-09 15:21:26 +02:00
*/
void lv_indev_reset(lv_indev_t * indev)
{
2017-11-29 13:08:03 +01:00
if(indev) indev->proc.reset_query = 1;
2017-10-09 15:21:26 +02:00
else {
lv_indev_t * i = lv_indev_next(NULL);
while(i) {
2017-11-29 13:08:03 +01:00
i->proc.reset_query = 1;
2017-10-09 15:21:26 +02:00
i = lv_indev_next(i);
}
}
}
/**
* Reset the long press state of an input device
2017-12-17 01:54:09 +01:00
* @param indev pointer to an input device
2017-10-09 15:21:26 +02:00
*/
2017-12-17 01:54:09 +01:00
void lv_indev_reset_lpr(lv_indev_t * indev)
2017-10-09 15:21:26 +02:00
{
2017-12-17 01:54:09 +01:00
indev->proc.long_pr_sent = 0;
indev->proc.longpr_rep_timestamp = lv_tick_get();
indev->proc.pr_timestamp = lv_tick_get();
2017-10-09 15:21:26 +02:00
}
2017-10-10 16:17:23 +02:00
/**
* Enable input devices device by type
* @param type Input device type
* @param enable true: enable this type; false: disable this type
*/
void lv_indev_enable(lv_hal_indev_type_t type, bool enable)
{
2019-02-20 23:58:13 +01:00
lv_indev_t * i = lv_indev_next(NULL);
while(i) {
if(i->driver.type == type) i->proc.disabled = enable == false ? 1 : 0;
i = lv_indev_next(i);
}
2017-10-10 16:17:23 +02:00
}
/**
2018-02-24 13:17:39 +01:00
* Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON)
* @param indev pointer to an input device
2017-10-10 16:17:23 +02:00
* @param cur_obj pointer to an object to be used as cursor
*/
2018-06-19 09:49:58 +02:00
void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj)
2017-10-10 16:17:23 +02:00
{
if(indev->driver.type != LV_INDEV_TYPE_POINTER) return;
2017-11-19 19:28:45 +01:00
indev->cursor = cur_obj;
lv_obj_set_parent(indev->cursor, lv_disp_get_layer_sys(indev->driver.disp));
lv_obj_set_pos(indev->cursor, indev->proc.types.pointer.act_point.x, indev->proc.types.pointer.act_point.y);
2017-10-10 16:17:23 +02:00
}
#if LV_USE_GROUP
2017-11-19 19:28:45 +01:00
/**
2018-02-24 13:17:39 +01:00
* Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD)
* @param indev pointer to an input device
2017-11-19 19:28:45 +01:00
* @param group point to a group
*/
2018-06-19 09:49:58 +02:00
void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group)
2017-11-19 19:28:45 +01:00
{
if(indev->driver.type == LV_INDEV_TYPE_KEYPAD || indev->driver.type == LV_INDEV_TYPE_ENCODER) {
indev->group = group;
}
2017-11-19 19:28:45 +01:00
}
2017-11-21 14:52:23 +01:00
#endif
2017-10-10 16:17:23 +02:00
2017-10-09 15:21:26 +02:00
/**
2018-02-24 13:17:39 +01:00
* Set the an array of points for LV_INDEV_TYPE_BUTTON.
* These points will be assigned to the buttons to press a specific point on the screen
* @param indev pointer to an input device
* @param group point to a group
*/
void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t * points)
2018-02-24 13:17:39 +01:00
{
if(indev->driver.type == LV_INDEV_TYPE_BUTTON) {
indev->btn_points = points;
}
2018-02-24 13:17:39 +01:00
}
2018-12-16 20:16:48 -05:00
/**
* Set feedback callback for indev.
* @param indev pointer to an input device
* @param feedback feedback callback
*/
void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback)
{
indev->feedback = feedback;
}
2018-02-24 13:17:39 +01:00
/**
* Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
2017-10-09 15:21:26 +02:00
* @param indev pointer to an input device
* @param point pointer to a point to store the result
*/
void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point)
2017-10-09 15:21:26 +02:00
{
2018-02-24 13:17:39 +01:00
if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) {
2018-07-13 00:37:28 +02:00
point->x = -1;
point->y = -1;
2018-02-24 13:17:39 +01:00
} else {
point->x = indev->proc.types.pointer.act_point.x;
point->y = indev->proc.types.pointer.act_point.y;
2018-02-24 13:17:39 +01:00
}
2017-10-09 15:21:26 +02:00
}
2018-08-09 07:30:10 +02:00
/**
* Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD)
* @param indev pointer to an input device
* @return the last pressed key (0 on error)
*/
uint32_t lv_indev_get_key(const lv_indev_t * indev)
{
if(indev->driver.type != LV_INDEV_TYPE_KEYPAD) return 0;
else return indev->proc.types.keypad.last_key;
2018-08-09 07:30:10 +02:00
}
2017-10-09 15:21:26 +02:00
/**
2018-02-24 13:17:39 +01:00
* Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
2017-10-09 15:21:26 +02:00
* @param indev pointer to an input device
* @return true: drag is in progress
*/
bool lv_indev_is_dragging(const lv_indev_t * indev)
2017-10-09 15:21:26 +02:00
{
if(indev == NULL) return false;
2018-02-24 13:17:39 +01:00
if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) return false;
return indev->proc.types.pointer.drag_in_prog == 0 ? false : true;
2017-10-09 15:21:26 +02:00
}
/**
* Get the types.pointer.vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
2017-10-09 15:21:26 +02:00
* @param indev pointer to an input device
* @param point pointer to a point to store the types.pointer.vector
2017-10-09 15:21:26 +02:00
*/
void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point)
2017-10-09 15:21:26 +02:00
{
2018-11-11 19:56:30 +01:00
if(indev == NULL) {
point->x = 0;
point->y = 0;
return;
}
2018-02-24 13:17:39 +01:00
if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) {
point->x = 0;
point->y = 0;
} else {
point->x = indev->proc.types.pointer.vect.x;
point->y = indev->proc.types.pointer.vect.y;
2018-02-24 13:17:39 +01:00
}
2017-10-09 15:21:26 +02:00
}
2017-12-11 10:59:33 +01:00
/**
* Get elapsed time since last press
2017-12-11 12:53:58 +01:00
* @param indev pointer to an input device (NULL to get the overall smallest inactivity)
2017-12-11 10:59:33 +01:00
* @return Elapsed ticks (milliseconds) since last press
*/
uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev)
2017-12-11 10:59:33 +01:00
{
2017-12-11 12:53:58 +01:00
2019-02-20 23:58:13 +01:00
uint32_t t;
if(indev) return t = lv_tick_elaps(indev->last_activity_time);
lv_indev_t * i;
t = UINT16_MAX;
i = lv_indev_next(NULL);
while(i) {
t = LV_MATH_MIN(t, lv_tick_elaps(i->last_activity_time));
i = lv_indev_next(i);
}
return t;
2017-12-11 10:59:33 +01:00
}
2018-12-16 20:16:48 -05:00
/**
* Get feedback callback for indev.
* @param indev pointer to an input device
* @return feedback callback
*/
lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev)
{
return indev->feedback;
}
2017-10-09 15:21:26 +02:00
/**
* Do nothing until the next release
* @param indev pointer to an input device
*/
void lv_indev_wait_release(lv_indev_t * indev)
{
2019-03-08 14:11:13 +01:00
indev->proc.types.pointer.wait_until_release = 1;
2017-10-09 15:21:26 +02:00
}
/**********************
* STATIC FUNCTIONS
**********************/
2018-01-10 09:42:52 +01:00
#if LV_INDEV_READ_PERIOD != 0
2017-10-09 15:21:26 +02:00
/**
* Called periodically to handle the input devices
* @param param unused
*/
static void indev_proc_task(void * param)
{
2017-12-02 20:43:50 +01:00
(void)param;
2018-07-25 17:57:08 +02:00
2018-10-05 17:22:49 +02:00
LV_LOG_TRACE("indev task started");
2018-07-25 17:57:08 +02:00
lv_indev_data_t data;
2017-10-09 15:21:26 +02:00
lv_indev_t * i;
i = lv_indev_next(NULL);
2017-10-12 16:59:09 +02:00
/*Read and process all indevs*/
2017-10-09 15:21:26 +02:00
while(i) {
2019-03-08 06:57:16 +01:00
if(i->driver.disp == NULL) continue; /*Not assigned to any displays*/
2017-10-09 15:21:26 +02:00
indev_act = i;
2017-10-12 16:59:09 +02:00
/*Handle reset query before processing the point*/
2018-02-06 11:42:50 -08:00
indev_proc_reset_query_handler(i);
2017-10-09 15:21:26 +02:00
2017-11-29 13:08:03 +01:00
if(i->proc.disabled == 0) {
2018-02-06 11:42:50 -08:00
bool more_to_read;
2018-03-07 13:07:00 +01:00
do {
2018-02-06 11:42:50 -08:00
/*Read the data*/
more_to_read = lv_indev_read(i, &data);
2018-10-05 17:22:49 +02:00
indev_proc_reset_query_handler(i); /*The active object might deleted even in the read function*/
2018-02-06 11:42:50 -08:00
i->proc.state = data.state;
if(i->proc.state == LV_INDEV_STATE_PR) {
i->last_activity_time = lv_tick_get();
}
2018-03-07 13:07:00 +01:00
if(i->driver.type == LV_INDEV_TYPE_POINTER) {
2018-06-19 09:49:58 +02:00
indev_pointer_proc(i, &data);
} else if(i->driver.type == LV_INDEV_TYPE_KEYPAD) {
2018-03-07 13:07:00 +01:00
indev_keypad_proc(i, &data);
2018-09-24 22:59:48 +02:00
} else if(i->driver.type == LV_INDEV_TYPE_ENCODER) {
indev_encoder_proc(i, &data);
2018-06-19 09:49:58 +02:00
} else if(i->driver.type == LV_INDEV_TYPE_BUTTON) {
2018-03-07 13:07:00 +01:00
indev_button_proc(i, &data);
2018-02-06 11:42:50 -08:00
}
/*Handle reset query if it happened in during processing*/
indev_proc_reset_query_handler(i);
} while(more_to_read);
2017-10-12 16:59:09 +02:00
}
i = lv_indev_next(i); /*Go to the next indev*/
2017-10-09 15:21:26 +02:00
}
2017-10-12 16:59:09 +02:00
indev_act = NULL; /*End of indev processing, so no act indev*/
2018-07-25 17:57:08 +02:00
2018-10-05 17:22:49 +02:00
LV_LOG_TRACE("indev task finished");
2017-10-09 15:21:26 +02:00
}
2018-02-24 13:17:39 +01:00
2017-10-09 15:21:26 +02:00
/**
2018-02-24 13:17:39 +01:00
* Process a new point from LV_INDEV_TYPE_POINTER input device
* @param i pointer to an input device
* @param data pointer to the data read from the input device
2017-10-09 15:21:26 +02:00
*/
2018-02-24 13:17:39 +01:00
static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data)
2017-10-09 15:21:26 +02:00
{
2018-02-24 13:17:39 +01:00
/*Move the cursor if set and moved*/
if(i->cursor != NULL &&
(i->proc.types.pointer.last_point.x != data->point.x ||
i->proc.types.pointer.last_point.y != data->point.y)) {
lv_obj_set_pos(i->cursor, data->point.x, data->point.y);
2018-02-24 13:17:39 +01:00
}
i->proc.types.pointer.act_point.x = data->point.x;
i->proc.types.pointer.act_point.y = data->point.y;
2018-02-24 13:17:39 +01:00
2018-06-19 09:49:58 +02:00
if(i->proc.state == LV_INDEV_STATE_PR) {
2018-02-24 13:17:39 +01:00
indev_proc_press(&i->proc);
} else {
indev_proc_release(&i->proc);
}
i->proc.types.pointer.last_point.x = i->proc.types.pointer.act_point.x;
i->proc.types.pointer.last_point.y = i->proc.types.pointer.act_point.y;
2018-02-24 13:17:39 +01:00
}
/**
* Process a new point from LV_INDEV_TYPE_KEYPAD input device
* @param i pointer to an input device
* @param data pointer to the data read from the input device
*/
static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
{
#if LV_USE_GROUP
lv_group_t * g = i->group;
if(g == NULL) return;
lv_obj_t * focused = lv_group_get_focused(g);
2019-03-01 06:26:03 +01:00
if(focused == NULL) return;
/*Key press happened*/
if(data->state == LV_INDEV_STATE_PR &&
2019-03-01 06:26:03 +01:00
i->proc.types.keypad.last_state == LV_INDEV_STATE_REL)
{
i->proc.pr_timestamp = lv_tick_get();
2019-03-01 06:26:03 +01:00
/*Simulate a press on the object if ENTER was pressed*/
if(data->key == LV_GROUP_KEY_ENTER) {
lv_obj_send_event(focused, LV_EVENT_PRESSED);
2019-03-01 06:26:03 +01:00
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_group_send_data(g, LV_GROUP_KEY_ENTER);
2019-03-01 06:26:03 +01:00
}
/*Move the focus on NEXT*/
else if(data->key == LV_GROUP_KEY_NEXT) {
lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
lv_group_focus_next(g);
if(i->proc.reset_query) return; /*The object might be deleted*/
}
/*Move the focus on PREV*/
else if(data->key == LV_GROUP_KEY_PREV) {
lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
lv_group_focus_prev(g);
if(i->proc.reset_query) return; /*The object might be deleted*/
}
/*Just send other keys to the object (e.g. 'A' or `LV_GORUP_KEY_RIGHT)*/
else {
lv_group_send_data(g, data->key);
}
}
/*Pressing*/
2019-03-01 06:26:03 +01:00
else if(data->state == LV_INDEV_STATE_PR && i->proc.types.keypad.last_state == LV_INDEV_STATE_PR)
{
/*Long press time has elapsed?*/
if(i->proc.long_pr_sent == 0 && lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {
i->proc.long_pr_sent = 1;
if(data->key == LV_GROUP_KEY_ENTER) {
i->proc.longpr_rep_timestamp = lv_tick_get();
lv_obj_send_event(focused, LV_EVENT_LONG_PRESSED);
2019-03-01 06:26:03 +01:00
if(i->proc.reset_query) return; /*The object might be deleted*/
}
}
/*Long press repeated time has elapsed?*/
else if(i->proc.long_pr_sent != 0 && lv_tick_elaps(i->proc.longpr_rep_timestamp) > LV_INDEV_LONG_PRESS_REP_TIME) {
i->proc.longpr_rep_timestamp = lv_tick_get();
/*Send LONG_PRESS_REP on ENTER*/
if(data->key == LV_GROUP_KEY_ENTER) {
lv_obj_send_event(focused, LV_EVENT_LONG_PRESSED_REPEAT);
if(i->proc.reset_query) return; /*The object might be deleted*/
}
/*Move the focus on NEXT again*/
else if(data->key == LV_GROUP_KEY_NEXT) {
lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
lv_group_focus_next(g);
if(i->proc.reset_query) return; /*The object might be deleted*/
}
/*Move the focus on PREV again*/
else if(data->key == LV_GROUP_KEY_PREV) {
lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
lv_group_focus_prev(g);
if(i->proc.reset_query) return; /*The object might be deleted*/
}
/*Just send other keys again to the object (e.g. 'A' or `LV_GORUP_KEY_RIGHT)*/
else {
lv_group_send_data(g, data->key);
if(i->proc.reset_query) return; /*The object might be deleted*/
2018-10-05 17:22:49 +02:00
}
}
}
/*Release happened*/
2019-03-01 06:26:03 +01:00
else if(data->state == LV_INDEV_STATE_REL && i->proc.types.keypad.last_state == LV_INDEV_STATE_PR)
{
2018-09-03 15:45:12 +02:00
/*The user might clear the key when it was released. Always release the pressed key*/
data->key = i->proc.types.keypad.last_key;
2019-03-01 06:26:03 +01:00
if(data->key == LV_GROUP_KEY_ENTER) {
if(i->proc.long_pr_sent == 0) {
2019-03-07 00:42:08 +01:00
lv_obj_send_event(focused, LV_EVENT_SHORT_CLICKED);
2018-10-05 17:22:49 +02:00
}
2019-03-07 00:42:08 +01:00
lv_obj_send_event(focused, LV_EVENT_CLICKED);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_obj_send_event(focused, LV_EVENT_RELEASED);
2019-03-01 06:26:03 +01:00
if(i->proc.reset_query) return; /*The object might be deleted*/
2018-09-24 22:59:48 +02:00
}
i->proc.pr_timestamp = 0;
i->proc.long_pr_sent = 0;
}
2018-09-24 00:35:19 +02:00
i->proc.types.keypad.last_state = data->state;
i->proc.types.keypad.last_key = data->key;
2018-10-09 15:03:46 +02:00
#else
(void)data; /*Unused*/
(void)i; /*Unused*/
2018-09-24 22:59:48 +02:00
#endif
}
2018-09-24 00:35:19 +02:00
2018-09-24 22:59:48 +02:00
/**
* Process a new point from LV_INDEV_TYPE_ENCODER input device
* @param i pointer to an input device
* @param data pointer to the data read from the input device
*/
static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
{
#if LV_USE_GROUP
lv_group_t * g = i->group;
if(g == NULL) return;
2018-09-24 00:35:19 +02:00
2019-03-01 22:23:59 +01:00
lv_obj_t * focused = lv_group_get_focused(g);
if(focused == NULL) return;
2018-09-24 22:59:48 +02:00
/*Process the steps first. They are valid only with released button*/
if(data->state == LV_INDEV_STATE_REL) {
/*In edit mode send LEFT/RIGHT keys*/
if(lv_group_get_editing(g)) {
int32_t s;
2018-09-24 22:59:48 +02:00
if(data->enc_diff < 0) {
for(s = 0; s < -data->enc_diff; s++) lv_group_send_data(g, LV_GROUP_KEY_LEFT);
2018-09-24 22:59:48 +02:00
} else if(data->enc_diff > 0) {
for(s = 0; s < data->enc_diff; s++) lv_group_send_data(g, LV_GROUP_KEY_RIGHT);
2018-09-24 22:59:48 +02:00
}
}
/*In navigate mode focus on the next/prev objects*/
else {
int32_t s;
2018-09-24 22:59:48 +02:00
if(data->enc_diff < 0) {
for(s = 0; s < -data->enc_diff; s++) lv_group_focus_prev(g);
2018-09-24 22:59:48 +02:00
} else if(data->enc_diff > 0) {
for(s = 0; s < data->enc_diff; s++) lv_group_focus_next(g);
2018-09-24 22:59:48 +02:00
}
}
}
2019-03-01 22:23:59 +01:00
/*Refresh the focused object. It might change due to lv_group_focus_prev/next*/
focused = lv_group_get_focused(g);
if(focused == NULL) return;
bool editable = false;
focused->signal_cb(focused, LV_SIGNAL_GET_EDITABLE, &editable);
/*Button press happened*/
2018-09-24 22:59:48 +02:00
if(data->state == LV_INDEV_STATE_PR &&
2019-03-01 22:23:59 +01:00
i->proc.types.keypad.last_state == LV_INDEV_STATE_REL)
{
2018-09-24 22:59:48 +02:00
i->proc.pr_timestamp = lv_tick_get();
if(lv_group_get_editing(g) == true || editable == false) {
lv_obj_send_event(focused, LV_EVENT_PRESSED);
if(i->proc.reset_query) return; /*The object might be deleted*/
}
2018-09-24 22:59:48 +02:00
}
/*Pressing*/
else if(data->state == LV_INDEV_STATE_PR && i->proc.types.keypad.last_state == LV_INDEV_STATE_PR) {
2018-09-24 22:59:48 +02:00
if(i->proc.long_pr_sent == 0 &&
2018-10-05 17:22:49 +02:00
lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {
2019-03-01 22:23:59 +01:00
/*On enter long press toggle edit mode.*/
2018-10-05 17:22:49 +02:00
if(editable) {
2019-03-01 22:23:59 +01:00
if(lv_ll_is_empty(&g->obj_ll) == false)
lv_group_set_editing(g, lv_group_get_editing(g) ? false : true); /*Toggle edit mode on long press*/
2019-03-01 22:23:59 +01:00
else {
/*Don't leave edit mode if there is only one object (nowhere to navigate)*/
lv_obj_send_event(focused, LV_EVENT_LONG_PRESSED);
if(i->proc.reset_query) return; /*The object might be deleted*/
2019-03-01 22:23:59 +01:00
}
2018-09-24 22:59:48 +02:00
}
/*If not editable then just send a long press signal*/
else {
2019-03-01 22:23:59 +01:00
lv_obj_send_event(focused, LV_EVENT_LONG_PRESSED);
if(i->proc.reset_query) return; /*The object might be deleted*/
2018-09-24 22:59:48 +02:00
}
i->proc.long_pr_sent = 1;
}
}
/*Release happened*/
else if(data->state == LV_INDEV_STATE_REL && i->proc.types.keypad.last_state == LV_INDEV_STATE_PR) {
2018-09-24 22:59:48 +02:00
/*The button was released on a non-editable object. Just send enter*/
2019-03-01 22:23:59 +01:00
if(editable == false) {
lv_group_send_data(g, LV_GROUP_KEY_ENTER);
2019-03-07 00:42:08 +01:00
if(i->proc.long_pr_sent == 0) lv_obj_send_event(focused, LV_EVENT_SHORT_CLICKED);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_obj_send_event(focused, LV_EVENT_CLICKED);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_obj_send_event(focused, LV_EVENT_RELEASED);
if(i->proc.reset_query) return; /*The object might be deleted*/
2019-03-01 22:23:59 +01:00
if(i->proc.reset_query) return; /*The object might be deleted*/
2018-09-24 22:59:48 +02:00
}
/*An object is being edited and the button is releases. Just send enter */
else if(g->editing) {
2019-03-01 22:23:59 +01:00
if(!i->proc.long_pr_sent || lv_ll_is_empty(&g->obj_ll)) {
lv_group_send_data(g, LV_GROUP_KEY_ENTER); /*Ignore long pressed enter release because it comes from mode switch*/
2019-03-07 00:42:08 +01:00
lv_obj_send_event(focused, LV_EVENT_SHORT_CLICKED);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_obj_send_event(focused, LV_EVENT_SHORT_CLICKED);
2019-03-01 22:23:59 +01:00
if(i->proc.reset_query) return; /*The object might be deleted*/
}
2018-09-24 22:59:48 +02:00
}
2019-03-01 22:23:59 +01:00
/*If the focused object is editable and now in navigate mode then on enter switch edit mode*/
else if(editable && !g->editing && !i->proc.long_pr_sent) {
2019-03-01 22:23:59 +01:00
lv_group_set_editing(g, true); /*Set edit mode*/
2018-02-24 13:17:39 +01:00
}
i->proc.pr_timestamp = 0;
i->proc.long_pr_sent = 0;
2018-02-24 13:17:39 +01:00
}
i->proc.types.keypad.last_state = data->state;
i->proc.types.keypad.last_key = data->key;
2018-10-09 15:03:46 +02:00
#else
(void)data; /*Unused*/
(void)i; /*Unused*/
2018-02-24 13:17:39 +01:00
#endif
}
/**
2017-10-09 15:21:26 +02:00
* Process new points from a input device. indev->state.pressed has to be set
* @param indev pointer to an input device state
* @param x x coordinate of the next point
* @param y y coordinate of the next point
2018-02-24 13:17:39 +01:00
*/
static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data)
{
i->proc.types.pointer.act_point.x = i->btn_points[data->btn_id].x;
i->proc.types.pointer.act_point.y = i->btn_points[data->btn_id].y;
2018-02-24 13:17:39 +01:00
/*Still the same point is pressed*/
if(i->proc.types.pointer.last_point.x == i->proc.types.pointer.act_point.x &&
i->proc.types.pointer.last_point.y == i->proc.types.pointer.act_point.y &&
2019-02-25 06:50:20 +01:00
data->state == LV_INDEV_STATE_PR)
{
2018-02-24 13:17:39 +01:00
indev_proc_press(&i->proc);
2017-10-09 15:21:26 +02:00
} else {
2018-02-24 13:17:39 +01:00
/*If a new point comes always make a release*/
indev_proc_release(&i->proc);
2017-10-09 15:21:26 +02:00
}
2018-02-24 13:17:39 +01:00
i->proc.types.pointer.last_point.x = i->proc.types.pointer.act_point.x;
i->proc.types.pointer.last_point.y = i->proc.types.pointer.act_point.y;
2018-02-24 13:17:39 +01:00
}
2017-10-09 15:21:26 +02:00
/**
2018-02-24 13:17:39 +01:00
* Process the pressed state of LV_INDEV_TYPE_POINER input devices
* @param indev pointer to an input device 'proc'
* @return LV_RES_OK: no indev reset required; LV_RES_INV: indev reset is required
2017-10-09 15:21:26 +02:00
*/
2018-02-24 13:17:39 +01:00
static void indev_proc_press(lv_indev_proc_t * proc)
2017-10-09 15:21:26 +02:00
{
lv_obj_t * pr_obj = proc->types.pointer.act_obj;
2018-06-19 09:49:58 +02:00
2019-03-08 14:11:13 +01:00
if(proc->types.pointer.wait_until_release != 0) return;
2017-10-09 15:21:26 +02:00
2019-02-20 10:16:33 +01:00
lv_disp_t * disp = indev_act->driver.disp;
2017-10-09 15:21:26 +02:00
/*If there is no last object then search*/
if(proc->types.pointer.act_obj == NULL) {
2019-02-20 23:58:13 +01:00
pr_obj = indev_search_obj(proc, lv_disp_get_layer_sys(disp));
if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_layer_top(disp));
if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_scr_act(disp));
2017-10-09 15:21:26 +02:00
}
2018-02-24 11:26:06 +01:00
/*If there is last object but it is not dragged and not protected also search*/
else if(proc->types.pointer.drag_in_prog == 0 &&
lv_obj_is_protected(proc->types.pointer.act_obj, LV_PROTECT_PRESS_LOST) == false) {/*Now types.pointer.act_obj != NULL*/
2019-02-20 23:58:13 +01:00
pr_obj = indev_search_obj(proc, lv_disp_get_layer_sys(disp));
if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_layer_top(disp));
if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_scr_act(disp));
2017-10-09 15:21:26 +02:00
}
2018-02-24 11:26:06 +01:00
/*If a dragable or a protected object was the last then keep it*/
2017-10-09 15:21:26 +02:00
else {
2018-06-19 09:49:58 +02:00
2017-10-09 15:21:26 +02:00
}
2018-06-19 09:49:58 +02:00
2017-10-09 15:21:26 +02:00
/*If a new object was found reset some variables and send a pressed signal*/
if(pr_obj != proc->types.pointer.act_obj) {
2017-10-09 15:21:26 +02:00
proc->types.pointer.last_point.x = proc->types.pointer.act_point.x;
proc->types.pointer.last_point.y = proc->types.pointer.act_point.y;
2018-06-19 09:49:58 +02:00
2017-10-09 15:21:26 +02:00
/*If a new object found the previous was lost, so send a signal*/
if(proc->types.pointer.act_obj != NULL) {
2019-02-27 06:04:30 +01:00
proc->types.pointer.act_obj->signal_cb(proc->types.pointer.act_obj, LV_SIGNAL_PRESS_LOST, indev_act);
lv_obj_send_event(proc->types.pointer.act_obj, LV_EVENT_PRESS_LOST);
if(proc->reset_query) return; /*The object might be deleted*/
2017-10-09 15:21:26 +02:00
}
2018-06-19 09:49:58 +02:00
proc->types.pointer.act_obj = pr_obj; /*Save the pressed object*/
proc->types.pointer.last_obj = proc->types.pointer.act_obj; /*Refresh the types.pointer.last_obj*/
2018-11-11 19:56:30 +01:00
if(proc->types.pointer.act_obj != NULL) {
2018-06-19 09:49:58 +02:00
/* Save the time when the obj pressed.
2017-10-09 15:21:26 +02:00
* It is necessary to count the long press time.*/
2018-02-24 13:17:39 +01:00
proc->pr_timestamp = lv_tick_get();
proc->long_pr_sent = 0;
2019-02-27 06:04:30 +01:00
proc->types.pointer.drag_limit_out = 0;
proc->types.pointer.drag_in_prog = 0;
proc->types.pointer.drag_sum.x = 0;
proc->types.pointer.drag_sum.y = 0;
proc->types.pointer.vect.x = 0;
proc->types.pointer.vect.y = 0;
2017-10-09 15:21:26 +02:00
/*Search for 'top' attribute*/
lv_obj_t * i = proc->types.pointer.act_obj;
2017-10-09 15:21:26 +02:00
lv_obj_t * last_top = NULL;
2018-06-19 09:49:58 +02:00
while(i != NULL) {
if(i->top != 0) last_top = i;
i = lv_obj_get_parent(i);
2017-10-09 15:21:26 +02:00
}
if(last_top != NULL) {
2018-06-19 09:49:58 +02:00
/*Move the last_top object to the foreground*/
lv_obj_t * par = lv_obj_get_parent(last_top);
/*After list change it will be the new head*/
2017-11-24 17:48:47 +01:00
lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top);
lv_obj_invalidate(last_top);
2017-10-09 15:21:26 +02:00
}
/*Send a signal about the press*/
2019-02-27 06:04:30 +01:00
proc->types.pointer.act_obj->signal_cb(proc->types.pointer.act_obj, LV_SIGNAL_PRESSED, indev_act);
lv_obj_send_event(proc->types.pointer.act_obj, LV_EVENT_PRESSED);
if(proc->reset_query) return; /*The object might be deleted*/
2017-10-09 15:21:26 +02:00
}
}
2018-06-19 09:49:58 +02:00
/*Calculate the types.pointer.vector*/
proc->types.pointer.vect.x = proc->types.pointer.act_point.x - proc->types.pointer.last_point.x;
proc->types.pointer.vect.y = proc->types.pointer.act_point.y - proc->types.pointer.last_point.y;
2017-10-09 15:21:26 +02:00
2019-02-27 06:04:30 +01:00
proc->types.pointer.drag_throw_vect.x = (proc->types.pointer.drag_throw_vect.x * 5) >> 3;
proc->types.pointer.drag_throw_vect.y = (proc->types.pointer.drag_throw_vect.y * 5) >> 3;
2019-02-27 06:04:30 +01:00
if(proc->types.pointer.drag_throw_vect.x < 0) proc->types.pointer.drag_throw_vect.x++;
else if(proc->types.pointer.drag_throw_vect.x > 0) proc->types.pointer.drag_throw_vect.x--;
2019-02-27 06:04:30 +01:00
if(proc->types.pointer.drag_throw_vect.y < 0) proc->types.pointer.drag_throw_vect.y++;
else if(proc->types.pointer.drag_throw_vect.y > 0) proc->types.pointer.drag_throw_vect.y--;
2019-02-27 06:04:30 +01:00
proc->types.pointer.drag_throw_vect.x += (proc->types.pointer.vect.x * 4) >> 3;
proc->types.pointer.drag_throw_vect.y += (proc->types.pointer.vect.y * 4) >> 3;
2017-10-12 16:59:09 +02:00
/*If there is active object and it can be dragged run the drag*/
if(proc->types.pointer.act_obj != NULL) {
2019-02-27 06:04:30 +01:00
proc->types.pointer.act_obj->signal_cb(proc->types.pointer.act_obj, LV_SIGNAL_PRESSING, indev_act);
lv_obj_send_event(proc->types.pointer.act_obj, LV_EVENT_PRESSING);
if(proc->reset_query) return; /*The object might be deleted*/
2017-10-09 15:21:26 +02:00
2018-02-24 13:17:39 +01:00
indev_drag(proc);
if(proc->reset_query != 0) return;
2017-10-09 15:21:26 +02:00
2017-10-12 16:59:09 +02:00
/*If there is no drag then check for long press time*/
if(proc->types.pointer.drag_in_prog == 0 && proc->long_pr_sent == 0) {
2017-10-12 16:59:09 +02:00
/*Send a signal about the long press if enough time elapsed*/
2018-02-24 13:17:39 +01:00
if(lv_tick_elaps(proc->pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {
pr_obj->signal_cb(pr_obj, LV_SIGNAL_LONG_PRESS, indev_act);
lv_obj_send_event(pr_obj, LV_EVENT_LONG_PRESSED);
if(proc->reset_query) return; /*The object might be deleted*/
2017-10-09 15:21:26 +02:00
2017-10-12 16:59:09 +02:00
/*Mark the signal sending to do not send it again*/
2018-02-24 13:17:39 +01:00
proc->long_pr_sent = 1;
2017-10-12 16:59:09 +02:00
/*Save the long press time stamp for the long press repeat handler*/
2018-02-24 13:17:39 +01:00
proc->longpr_rep_timestamp = lv_tick_get();
2017-10-09 15:21:26 +02:00
}
2017-10-12 16:59:09 +02:00
}
/*Send long press repeated signal*/
if(proc->types.pointer.drag_in_prog == 0 && proc->long_pr_sent == 1) {
2017-10-12 16:59:09 +02:00
/*Send a signal about the long press repeate if enough time elapsed*/
2018-02-24 13:17:39 +01:00
if(lv_tick_elaps(proc->longpr_rep_timestamp) > LV_INDEV_LONG_PRESS_REP_TIME) {
pr_obj->signal_cb(pr_obj, LV_SIGNAL_LONG_PRESS_REP, indev_act);
lv_obj_send_event(pr_obj, LV_EVENT_LONG_PRESSED_REPEAT);
if(proc->reset_query) return; /*The object might be deleted*/
2018-02-24 13:17:39 +01:00
proc->longpr_rep_timestamp = lv_tick_get();
2017-10-12 16:59:09 +02:00
2017-10-09 15:21:26 +02:00
}
}
}
}
/**
2018-02-24 13:17:39 +01:00
* Process the released state of LV_INDEV_TYPE_POINER input devices
* @param proc pointer to an input device 'proc'
2017-10-09 15:21:26 +02:00
*/
2018-02-24 13:17:39 +01:00
static void indev_proc_release(lv_indev_proc_t * proc)
2017-10-09 15:21:26 +02:00
{
2019-03-08 14:11:13 +01:00
if(proc->types.pointer.wait_until_release != 0) {
proc->types.pointer.act_obj = NULL;
proc->types.pointer.last_obj = NULL;
2018-02-24 13:17:39 +01:00
proc->pr_timestamp = 0;
proc->longpr_rep_timestamp = 0;
2019-03-08 14:11:13 +01:00
proc->types.pointer.wait_until_release = 0;
2017-10-09 15:21:26 +02:00
}
2019-03-03 11:20:49 +01:00
/*Forget the act obj and send a released signal */
if(proc->types.pointer.act_obj) {
/* If the object was protected against press lost then it possible that
2019-03-02 01:49:08 +01:00
* the object is already not pressed but still it is the `act_obj`.
* In this case send the `LV_SIGNAL_RELEASED/CLICKED` instead of `LV_SIGNAL_PRESS_LOST` if the indev is ON the `types.pointer.act_obj` */
if(lv_obj_is_protected(proc->types.pointer.act_obj, LV_PROTECT_PRESS_LOST)) {
2019-03-02 01:49:08 +01:00
proc->types.pointer.act_obj->signal_cb(proc->types.pointer.act_obj, LV_SIGNAL_RELEASED, indev_act);
if(proc->long_pr_sent == 0 && proc->types.pointer.drag_in_prog == 0) {
2019-03-07 00:42:08 +01:00
lv_obj_send_event(proc->types.pointer.act_obj, LV_EVENT_SHORT_CLICKED);
if(proc->reset_query) return; /*The object might be deleted*/
}
2019-03-07 00:42:08 +01:00
lv_obj_send_event(proc->types.pointer.act_obj, LV_EVENT_CLICKED);
if(proc->reset_query) return; /*The object might be deleted*/
lv_obj_send_event(proc->types.pointer.act_obj, LV_EVENT_RELEASED);
if(proc->reset_query) return; /*The object might be deleted*/
}
/* The simple case: `act_obj` was not protected against press lost.
2019-03-02 01:49:08 +01:00
* If it is already not pressed then was `indev_proc_press` would set `act_obj = NULL`*/
else {
2019-02-27 06:04:30 +01:00
proc->types.pointer.act_obj->signal_cb(proc->types.pointer.act_obj, LV_SIGNAL_RELEASED, indev_act);
2019-02-27 06:04:30 +01:00
if(proc->long_pr_sent == 0 && proc->types.pointer.drag_in_prog == 0) {
2019-03-07 00:42:08 +01:00
lv_obj_send_event(proc->types.pointer.act_obj, LV_EVENT_SHORT_CLICKED);
if(proc->reset_query) return; /*The object might be deleted*/
}
2019-03-07 00:42:08 +01:00
lv_obj_send_event(proc->types.pointer.act_obj, LV_EVENT_CLICKED);
if(proc->reset_query) return; /*The object might be deleted*/
2019-03-07 00:42:08 +01:00
lv_obj_send_event(proc->types.pointer.act_obj, LV_EVENT_RELEASED);
if(proc->reset_query) return; /*The object might be deleted*/
}
if(proc->reset_query != 0) return;
2018-07-12 23:38:27 +02:00
/*Handle click focus*/
#if LV_USE_GROUP
2018-09-26 14:21:39 +02:00
/*Edit mode is not used by POINTER devices. So leave edit mode if we are in it*/
2019-03-03 11:20:49 +01:00
lv_group_t * g = lv_obj_get_group(proc->types.pointer.act_obj);
if(lv_group_get_editing(g)) lv_group_set_editing(g, false);
2018-09-26 14:21:39 +02:00
2018-09-03 15:45:12 +02:00
/*Check, if the parent is in a group focus on it.*/
2019-03-03 11:20:49 +01:00
if(lv_obj_is_protected(proc->types.pointer.act_obj, LV_PROTECT_CLICK_FOCUS) == false) { /*Respect the click focus protection*/
lv_obj_t * parent = proc->types.pointer.act_obj;
2018-09-03 15:45:12 +02:00
while(g == NULL) {
parent = lv_obj_get_parent(parent);
if(parent == NULL) break;
if(lv_obj_is_protected(parent, LV_PROTECT_CLICK_FOCUS)) { /*Ignore is the protected against click focus*/
parent = NULL;
break;
}
g = lv_obj_get_group(parent);
}
2018-07-12 23:38:27 +02:00
2019-03-03 11:20:49 +01:00
/* If a pareit is in a group make it focused.
* `LV_EVENT_FOCUSED/DEFOCUSED` will be sent by `lv_group_focus_obj`*/
if(g && parent) {
2018-10-05 17:22:49 +02:00
if(lv_group_get_click_focus(g)) {
lv_group_focus_obj(parent);
}
2019-03-03 11:20:49 +01:00
}
2018-07-12 23:38:27 +02:00
}
#endif
2019-03-03 11:20:49 +01:00
/* Send defocus to the lastly "active" object and foucus to the new one.
* If the one of them is in group then it possible that `lv_group_focus_obj` alraedy sent
* a focus/defucus signal because of `click focus`*/
if(proc->types.pointer.last_pressed != proc->types.pointer.act_obj) {
lv_obj_send_event(proc->types.pointer.last_pressed, LV_EVENT_DEFOCUSED);
if(proc->reset_query) return; /*Not so strict as it's only the previous object and indev not uses it.*/
2019-03-03 11:20:49 +01:00
lv_obj_send_event(proc->types.pointer.act_obj, LV_EVENT_FOCUSED);
if(proc->reset_query) return; /*The object might be deleted*/
2019-03-03 11:20:49 +01:00
proc->types.pointer.last_pressed = proc->types.pointer.act_obj;
}
2018-02-24 13:17:39 +01:00
if(proc->reset_query != 0) return;
proc->types.pointer.act_obj = NULL;
2018-02-24 13:17:39 +01:00
proc->pr_timestamp = 0;
proc->longpr_rep_timestamp = 0;
2017-10-09 15:21:26 +02:00
}
2018-06-19 09:49:58 +02:00
/*The reset can be set in the signal function.
2017-10-09 15:21:26 +02:00
* In case of reset query ignore the remaining parts.*/
if(proc->types.pointer.last_obj != NULL && proc->reset_query == 0) {
2018-02-24 13:17:39 +01:00
indev_drag_throw(proc);
if(proc->reset_query != 0) return;
2017-10-09 15:21:26 +02:00
}
}
2018-03-07 13:07:00 +01:00
/**
* Process a new point from LV_INDEV_TYPE_BUTTON input device
* @param i pointer to an input device
* @param data pointer to the data read from the input device
* Reset input device if a reset query has been sent to it
* @param indev pointer to an input device
*/
static void indev_proc_reset_query_handler(lv_indev_t * indev)
{
if(indev->proc.reset_query) {
indev->proc.types.pointer.act_obj = NULL;
indev->proc.types.pointer.last_obj = NULL;
2019-03-03 11:20:49 +01:00
indev->proc.types.pointer.last_pressed = NULL;
2019-02-27 06:04:30 +01:00
indev->proc.types.pointer.drag_limit_out = 0;
indev->proc.types.pointer.drag_in_prog = 0;
2018-03-07 13:07:00 +01:00
indev->proc.long_pr_sent = 0;
indev->proc.pr_timestamp = 0;
indev->proc.longpr_rep_timestamp = 0;
indev->proc.types.pointer.drag_sum.x = 0;
indev->proc.types.pointer.drag_sum.y = 0;
2019-02-27 06:04:30 +01:00
indev->proc.types.pointer.drag_throw_vect.x = 0;
indev->proc.types.pointer.drag_throw_vect.y = 0;
2018-03-07 13:07:00 +01:00
indev->proc.reset_query = 0;
}
}
2017-10-09 15:21:26 +02:00
/**
* Search the most top, clickable object on the last point of an input device
* @param proc pointer to the `lv_indev_proc_t` part of the input device
2017-10-09 15:21:26 +02:00
* @param obj pointer to a start object, typically the screen
2018-06-19 09:49:58 +02:00
* @return pointer to the found object or NULL if there was no suitable object
2017-10-09 15:21:26 +02:00
*/
static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj)
2017-10-09 15:21:26 +02:00
{
lv_obj_t * found_p = NULL;
2018-06-19 09:49:58 +02:00
2017-10-09 15:21:26 +02:00
/*If the point is on this object*/
/*Check its children too*/
if(lv_area_is_point_on(&obj->coords, &proc->types.pointer.act_point)) {
2017-10-09 15:21:26 +02:00
lv_obj_t * i;
2018-06-19 09:49:58 +02:00
LV_LL_READ(obj->child_ll, i) {
found_p = indev_search_obj(proc, i);
2018-06-19 09:49:58 +02:00
2017-10-09 15:21:26 +02:00
/*If a child was found then break*/
if(found_p != NULL) {
break;
}
}
2018-06-19 09:49:58 +02:00
2017-11-30 14:46:16 +01:00
/*If then the children was not ok, and this obj is clickable
2017-10-09 15:21:26 +02:00
* and it or its parent is not hidden then save this object*/
if(found_p == NULL && lv_obj_get_click(obj) != false) {
2018-06-19 09:49:58 +02:00
lv_obj_t * hidden_i = obj;
while(hidden_i != NULL) {
if(lv_obj_get_hidden(hidden_i) == true) break;
hidden_i = lv_obj_get_parent(hidden_i);
}
/*No parent found with hidden == true*/
if(hidden_i == NULL) found_p = obj;
2017-10-09 15:21:26 +02:00
}
2018-06-19 09:49:58 +02:00
2017-10-09 15:21:26 +02:00
}
2018-06-19 09:49:58 +02:00
return found_p;
2017-10-09 15:21:26 +02:00
}
/**
* Handle the dragging of indev_proc_p->types.pointer.act_obj
2017-10-09 15:21:26 +02:00
* @param indev pointer to a input device state
*/
2017-11-29 13:08:03 +01:00
static void indev_drag(lv_indev_proc_t * state)
2017-10-09 15:21:26 +02:00
{
lv_obj_t * drag_obj = state->types.pointer.act_obj;
2018-06-19 09:49:58 +02:00
2017-10-09 15:21:26 +02:00
/*If drag parent is active check recursively the drag_parent attribute*/
2018-06-19 09:49:58 +02:00
while(lv_obj_get_drag_parent(drag_obj) != false &&
drag_obj != NULL) {
drag_obj = lv_obj_get_parent(drag_obj);
}
if(drag_obj == NULL) return;
2017-10-09 15:21:26 +02:00
if(lv_obj_get_drag(drag_obj) == false) return;
2018-11-25 12:02:16 +01:00
/*Count the movement by drag*/
state->types.pointer.drag_sum.x += state->types.pointer.vect.x;
state->types.pointer.drag_sum.y += state->types.pointer.vect.y;
2018-06-19 09:49:58 +02:00
2018-11-25 12:02:16 +01:00
/*Enough move?*/
2019-02-27 06:04:30 +01:00
if(state->types.pointer.drag_limit_out == 0) {
2017-10-09 15:21:26 +02:00
/*If a move is greater then LV_DRAG_LIMIT then begin the drag*/
if(LV_MATH_ABS(state->types.pointer.drag_sum.x) >= LV_INDEV_DRAG_LIMIT ||
LV_MATH_ABS(state->types.pointer.drag_sum.y) >= LV_INDEV_DRAG_LIMIT) {
2019-02-27 06:04:30 +01:00
state->types.pointer.drag_limit_out = 1;
2018-06-19 09:49:58 +02:00
}
2017-10-09 15:21:26 +02:00
}
2018-06-19 09:49:58 +02:00
/*If the drag limit is exceeded handle the dragging*/
2019-02-27 06:04:30 +01:00
if(state->types.pointer.drag_limit_out != 0) {
2017-10-09 15:21:26 +02:00
/*Set new position if the vector is not zero*/
if(state->types.pointer.vect.x != 0 ||
2019-02-27 06:04:30 +01:00
state->types.pointer.vect.y != 0)
{
2019-02-27 06:04:30 +01:00
/*Get the coordinates of the object and modify them*/
2017-11-23 21:28:36 +01:00
lv_coord_t act_x = lv_obj_get_x(drag_obj);
lv_coord_t act_y = lv_obj_get_y(drag_obj);
uint16_t inv_buf_size = lv_disp_get_inv_buf_size(indev_act->driver.disp); /*Get the number of currently invalidated areas*/
2017-10-09 15:21:26 +02:00
lv_coord_t prev_x = drag_obj->coords.x1;
lv_coord_t prev_y = drag_obj->coords.y1;
2019-01-31 03:17:15 +01:00
lv_coord_t prev_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj));
lv_coord_t prev_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj));
lv_obj_set_pos(drag_obj, act_x + state->types.pointer.vect.x, act_y + state->types.pointer.vect.y);
2017-10-09 15:21:26 +02:00
/*Set the drag in progress flag if the object is really moved*/
if(drag_obj->coords.x1 != prev_x || drag_obj->coords.y1 != prev_y) {
2019-02-27 06:04:30 +01:00
if(state->types.pointer.drag_in_prog != 0) { /*Send the drag begin signal on first move*/
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_BEGIN, indev_act);
2019-02-27 06:04:30 +01:00
if(state->reset_query != 0) return;
2017-10-09 15:21:26 +02:00
}
state->types.pointer.drag_in_prog = 1;
2017-10-09 15:21:26 +02:00
}
/*If the object didn't moved then clear the invalidated areas*/
else {
2019-01-31 03:17:15 +01:00
/*In a special case if the object is moved on a page and
* the scrollable has fit == true and the object is dragged of the page then
* while its coordinate is not changing only the parent's size is reduced */
lv_coord_t act_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj));
lv_coord_t act_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj));
if(act_par_w == prev_par_w && act_par_h == prev_par_h) {
uint16_t new_inv_buf_size = lv_disp_get_inv_buf_size(indev_act->driver.disp);
lv_disp_pop_from_inv_buf(indev_act->driver.disp, new_inv_buf_size - inv_buf_size);
2019-01-31 03:17:15 +01:00
}
}
2017-10-09 15:21:26 +02:00
}
}
}
/**
* Handle throwing by drag if the drag is ended
* @param indev pointer to an input device state
*/
static void indev_drag_throw(lv_indev_proc_t * proc)
2017-10-09 15:21:26 +02:00
{
2019-02-27 06:04:30 +01:00
if(proc->types.pointer.drag_in_prog == 0) return;
2017-10-09 15:21:26 +02:00
/*Set new position if the vector is not zero*/
2019-02-27 06:04:30 +01:00
lv_obj_t * drag_obj = proc->types.pointer.last_obj;
2018-06-19 09:49:58 +02:00
2017-10-09 15:21:26 +02:00
/*If drag parent is active check recursively the drag_parent attribute*/
2018-06-19 09:49:58 +02:00
while(lv_obj_get_drag_parent(drag_obj) != false &&
drag_obj != NULL) {
drag_obj = lv_obj_get_parent(drag_obj);
}
if(drag_obj == NULL) {
return;
}
2017-10-09 15:21:26 +02:00
/*Return if the drag throw is not enabled*/
2018-06-19 09:49:58 +02:00
if(lv_obj_get_drag_throw(drag_obj) == false) {
2019-02-27 06:04:30 +01:00
proc->types.pointer.drag_in_prog = 0;
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_END, indev_act);
2017-10-09 15:21:26 +02:00
return;
}
2018-06-19 09:49:58 +02:00
2017-10-09 15:21:26 +02:00
/*Reduce the vectors*/
2019-02-27 06:04:30 +01:00
proc->types.pointer.drag_throw_vect.x = proc->types.pointer.drag_throw_vect.x * (100 - LV_INDEV_DRAG_THROW) / 100;
proc->types.pointer.drag_throw_vect.y = proc->types.pointer.drag_throw_vect.y * (100 - LV_INDEV_DRAG_THROW) / 100;
2018-06-19 09:49:58 +02:00
2019-02-27 06:04:30 +01:00
if(proc->types.pointer.drag_throw_vect.x != 0 ||
proc->types.pointer.drag_throw_vect.y != 0) {
2018-11-11 19:56:30 +01:00
/*Get the coordinates and modify them*/
lv_area_t coords_ori;
lv_obj_get_coords(drag_obj, &coords_ori);
2019-02-27 06:04:30 +01:00
lv_coord_t act_x = lv_obj_get_x(drag_obj) + proc->types.pointer.drag_throw_vect.x;
lv_coord_t act_y = lv_obj_get_y(drag_obj) + proc->types.pointer.drag_throw_vect.y;
2017-10-09 15:21:26 +02:00
lv_obj_set_pos(drag_obj, act_x, act_y);
2018-11-11 19:56:30 +01:00
lv_area_t coord_new;
lv_obj_get_coords(drag_obj, &coord_new);
/*If non of the coordinates are changed then do not continue throwing*/
2019-02-27 06:04:30 +01:00
if((coords_ori.x1 == coord_new.x1 || proc->types.pointer.drag_throw_vect.x == 0) &&
(coords_ori.y1 == coord_new.y1 || proc->types.pointer.drag_throw_vect.y == 0)) {
proc->types.pointer.drag_in_prog = 0;
proc->types.pointer.vect.x = 0;
proc->types.pointer.vect.y = 0;
proc->types.pointer.drag_throw_vect.x = 0;
proc->types.pointer.drag_throw_vect.y = 0;
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_END, indev_act);
}
2017-10-09 15:21:26 +02:00
}
/*If the types.pointer.vectors become 0 -> types.pointer.drag_in_prog = 0 and send a drag end signal*/
2017-10-09 15:21:26 +02:00
else {
2019-02-27 06:04:30 +01:00
proc->types.pointer.drag_in_prog = 0;
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_END, indev_act);
2017-10-09 15:21:26 +02:00
}
2017-10-09 15:21:26 +02:00
}
2018-01-10 09:42:52 +01:00
#endif