* MIT License
* Copyright (c) 2023 _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 "TrackView.h"
#include "Utils/PointContainer/PointContainer.h"
#include "Utils/lv_poly_line/lv_poly_line.h"
TrackView::TrackView(lv_obj_t* parent)
: _cont(nullptr)
, _trackLine(nullptr)
, _activeLine(nullptr)
, _activePoint { 0 }
, _pointContainer(nullptr)
, _refLevel(0)
, _curLevel(0)
, _pointFilter(onPointFilterEvent, &_lineFilter)
, _lineFilter(onLineFilterEvent, this)
{
_cont = lv_obj_create(parent);
lv_obj_remove_style_all(_cont);
lv_obj_clear_flag(_cont, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_clear_flag(_cont, LV_OBJ_FLAG_CLICKABLE);
lv_obj_add_flag(_cont, LV_OBJ_FLAG_IGNORE_LAYOUT);
lv_obj_add_flag(_cont, LV_OBJ_FLAG_HIDDEN);
_trackLine = new lv_poly_line(_cont);
_activeLine = lv_line_create(_cont);
lv_obj_add_flag(_activeLine, LV_OBJ_FLAG_HIDDEN);
_pointFilter.setSecondFilterModeEnable(true);
}
TrackView::~TrackView()
{
delete _trackLine;
lv_obj_del(_cont);
}
void TrackView::setStyle(lv_style_t* style)
{
_trackLine->set_style(style);
lv_obj_add_style(_activeLine, style, 0);
}
void TrackView::setArea(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
{
lv_obj_set_size(_cont, x1 - x0 + 1, y1 - y0 + 1);
TrackLineFilter::Area_t area = { x0, y0, x1, y1 };
_lineFilter.setArea(&area);
}
void TrackView::setActivePoint(int32_t x, int32_t y)
{
if (!_pointContainer) {
return;
}
lv_point_precise_t end;
if (!_trackLine->get_end_point(&end)) {
lv_obj_add_flag(_activeLine, LV_OBJ_FLAG_HIDDEN);
return;
}
const TrackLineFilter::Area_t* area = _lineFilter.getArea();
TrackLineFilter::Point_t relEndPoint = { area->x0 + (int32_t)end.x, area->y0 + (int32_t)end.y };
auto relActivePoint = convertPoint(x, y, _refLevel, _curLevel);
if (!_lineFilter.getIsPointInArea(&relEndPoint)
&& !_lineFilter.getIsPointInArea((TrackLineFilter::Point_t*)&relActivePoint)) {
lv_obj_add_flag(_activeLine, LV_OBJ_FLAG_HIDDEN);
LV_LOG_INFO("Point out of area");
return;
}
auto offset = getOffset(relActivePoint.x, relActivePoint.y);
_activePoint[0].x = end.x;
_activePoint[0].y = end.y;
_activePoint[1].x = offset.x;
_activePoint[1].y = offset.y;
lv_line_set_points(_activeLine, _activePoint, 2);
lv_obj_clear_flag(_activeLine, LV_OBJ_FLAG_HIDDEN);
}
void TrackView::pushPoint(int32_t x, int32_t y)
{
if (!_pointContainer) {
return;
}
auto point = convertPoint(x, y, _refLevel, _curLevel);
_pointFilter.pushPoint(point.x, point.y);
}
void TrackView::setLevel(int level)
{
if (level == _curLevel) {
return;
}
_curLevel = level;
}
void TrackView::setPointContainer(PointContainer* pointCont, int refLevel)
{
_pointContainer = pointCont;
_refLevel = refLevel;
}
bool TrackView::reload()
{
if (!_pointContainer) {
lv_obj_add_flag(_cont, LV_OBJ_FLAG_HIDDEN);
return false;
}
_pointFilter.reset();
_lineFilter.reset();
_trackLine->reset();
int32_t x, y;
_pointContainer->popStart();
while (_pointContainer->popPoint(&x, &y)) {
pushPoint(x, y);
}
lv_obj_add_flag(_activeLine, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(_cont, LV_OBJ_FLAG_HIDDEN);
return true;
}
TrackView::Point_t TrackView::convertPoint(int32_t srcX, int32_t srcY, int srcLevel, int destLevel)
{
Point_t point;
int diff = srcLevel - destLevel;
if (diff == 0) {
return { srcX, srcY };
}
if (diff > 0) {
point.x = srcX >> diff;
point.y = srcY >> diff;
} else {
point.x = srcX << -diff;
point.y = srcY << -diff;
}
return point;
}
TrackView::Point_t TrackView::getOffset(int32_t x, int32_t y)
{
const TrackLineFilter::Area_t* area = _lineFilter.getArea();
return { x - area->x0, y - area->y0 };
}
void TrackView::onPointFilterEvent(TrackPointFilter* filter, const TrackPointFilter::Point_t* point)
{
auto lineFilter = (TrackLineFilter*)filter->getUserData();
lineFilter->pushPoint(point->x, point->y);
}
void TrackView::onLineFilterEvent(TrackLineFilter* filter, const TrackLineFilter::Event_t* event)
{
auto self = (TrackView*)filter->getUserData();
switch (event->eventID) {
case TrackLineFilter::EVENT_ID::START_LINE:
self->_trackLine->start();
break;
case TrackLineFilter::EVENT_ID::APPEND_POINT: {
Point_t offset = self->getOffset(event->point->x, event->point->y);
self->_trackLine->append(offset.x, offset.y);
} break;
default:
break;
}
}