GeekTrack/2.Firmware/components/GeekOS/System/PageManager/PM_Drag.cpp

231 lines
6.5 KiB
C++
Raw Normal View History

2022-09-18 18:40:49 +08:00
/*
* MIT License
* Copyright (c) 2021 _VIFEXTech
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "PageManager.h"
#include "PM_Log.h"
#include <stdlib.h>
#define CONSTRAIN(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
/* The distance threshold to trigger the drag */
#define PM_INDEV_DEF_DRAG_THROW 20
/**
* @brief Page drag event callback
* @param event: Pointer to event structure
* @retval None
*/
void PageManager::onRootDragEvent(lv_event_t* event)
{
lv_event_code_t eventCode = lv_event_get_code(event);
if (!(eventCode == LV_EVENT_PRESSED || eventCode == LV_EVENT_PRESSING || eventCode == LV_EVENT_RELEASED))
{
return;
}
lv_obj_t* root = lv_event_get_current_target(event);
PageBase* base = (PageBase*)lv_event_get_user_data(event);
if (base == nullptr)
{
PM_LOG_ERROR("Page base is NULL");
return;
}
PageManager* manager = base->_Manager;
LoadAnimAttr_t animAttr;
if (!manager->GetCurrentLoadAnimAttr(&animAttr))
{
PM_LOG_ERROR("Can't get current anim attr");
return;
}
if (eventCode == LV_EVENT_PRESSED)
{
if (manager->_AnimState.IsSwitchReq)
{
return;
}
if (!manager->_AnimState.IsBusy)
{
return;
}
PM_LOG_INFO("Root anim interrupted");
lv_anim_del(root, animAttr.setter);
manager->_AnimState.IsBusy = false;
/* Temporary showing the bottom page */
PageBase* bottomPage = manager->GetStackTopAfter();
lv_obj_clear_flag(bottomPage->_root, LV_OBJ_FLAG_HIDDEN);
}
else if (eventCode == LV_EVENT_PRESSING)
{
lv_coord_t cur = animAttr.getter(root);
lv_coord_t max = std::max(animAttr.pop.exit.start, animAttr.pop.exit.end);
lv_coord_t min = std::min(animAttr.pop.exit.start, animAttr.pop.exit.end);
lv_point_t offset;
lv_indev_get_vect(lv_indev_get_act(), &offset);
if (animAttr.dragDir == ROOT_DRAG_DIR_HOR)
{
cur += offset.x;
}
else if (animAttr.dragDir == ROOT_DRAG_DIR_VER)
{
cur += offset.y;
}
animAttr.setter(root, CONSTRAIN(cur, min, max));
}
else if (eventCode == LV_EVENT_RELEASED)
{
if (manager->_AnimState.IsSwitchReq)
{
return;
}
lv_coord_t offset_sum = animAttr.push.enter.end - animAttr.push.enter.start;
lv_coord_t x_predict = 0;
lv_coord_t y_predict = 0;
RootGetDragPredict(&x_predict, &y_predict);
lv_coord_t start = animAttr.getter(root);
lv_coord_t end = start;
if (animAttr.dragDir == ROOT_DRAG_DIR_HOR)
{
end += x_predict;
PM_LOG_INFO("Root drag x_predict = %d", end);
}
else if (animAttr.dragDir == ROOT_DRAG_DIR_VER)
{
end += y_predict;
PM_LOG_INFO("Root drag y_predict = %d", end);
}
if (std::abs(end) > std::abs((int)offset_sum) / 2)
{
lv_async_call(onRootAsyncLeave, base);
}
else if(end != animAttr.push.enter.end)
{
manager->_AnimState.IsBusy = true;
lv_anim_t a;
manager->AnimDefaultInit(&a);
lv_anim_set_user_data(&a, manager);
lv_anim_set_var(&a, root);
lv_anim_set_values(&a, start, animAttr.push.enter.end);
lv_anim_set_exec_cb(&a, animAttr.setter);
lv_anim_set_ready_cb(&a, onRootDragAnimFinish);
lv_anim_start(&a);
PM_LOG_INFO("Root drag anim start");
}
}
}
/**
* @brief Drag animation end event callback
* @param a: Pointer to animation
* @retval None
*/
void PageManager::onRootDragAnimFinish(lv_anim_t* a)
{
PageManager* manager = (PageManager*)lv_anim_get_user_data(a);
PM_LOG_INFO("Root drag anim finish");
manager->_AnimState.IsBusy = false;
/* Hide the bottom page */
PageBase* bottomPage = manager->GetStackTopAfter();
if (bottomPage)
{
lv_obj_add_flag(bottomPage->_root, LV_OBJ_FLAG_HIDDEN);
}
}
/**
* @brief Enable root's drag function
* @param root: Pointer to the root object
* @retval None
*/
void PageManager::RootEnableDrag(lv_obj_t* root)
{
PageBase* base = (PageBase*)lv_obj_get_user_data(root);
lv_obj_add_event_cb(
root,
onRootDragEvent,
LV_EVENT_ALL,
base
);
PM_LOG_INFO("Page(%s) Root drag enabled", base->_Name);
}
/**
* @brief Asynchronous callback when dragging ends
* @param data: Pointer to the base class of the page
* @retval None
*/
void PageManager::onRootAsyncLeave(void* data)
{
PageBase* base = (PageBase*)data;
PM_LOG_INFO("Page(%s) send event: LV_EVENT_LEAVE, need to handle...", base->_Name);
lv_event_send(base->_root, LV_EVENT_LEAVE, base);
}
/**
* @brief Get drag inertia prediction stop point
* @param x: x stop point
* @param y: y stop point
* @retval None
*/
void PageManager::RootGetDragPredict(lv_coord_t* x, lv_coord_t* y)
{
lv_indev_t* indev = lv_indev_get_act();
lv_point_t vect;
lv_indev_get_vect(indev, &vect);
lv_coord_t y_predict = 0;
lv_coord_t x_predict = 0;
while (vect.y != 0)
{
y_predict += vect.y;
vect.y = vect.y * (100 - PM_INDEV_DEF_DRAG_THROW) / 100;
}
while (vect.x != 0)
{
x_predict += vect.x;
vect.x = vect.x * (100 - PM_INDEV_DEF_DRAG_THROW) / 100;
}
*x = x_predict;
*y = y_predict;
}