/* * Copyright (c) 2019 Actions Semi Co., Inc. * * SPDX-License-Identifier: Apache-2.0 */ /** * @file */ #include #ifdef __ZEPHYR__ # include #else # define __ramfunc #endif /** * @brief Get the size of an region * * @param area_p pointer to an region * * @retval size of the region */ int32_t ui_region_get_size(const ui_region_t * region) { return (int32_t)(region->x2 - region->x1 + 1) * (region->y2 - region->y1 + 1); } /** * @brief Set the x coordinate of an region * * @param region pointer to an region * @param x new x coordinate * * @retval N/A */ void ui_region_set_x(ui_region_t * region, int16_t x) { region->x2 += x - region->x1; region->x1 = x; } /** * @brief Set the y coordinate of an region * * @param region pointer to an region * @param y new y coordinate * * @retval N/A */ void ui_region_set_y(ui_region_t * region, int16_t y) { region->y2 += y - region->y1; region->y1 = y; } /** * @brief Set the position of an region (width and height will be kept) * * @param region pointer to an region * @param x new x coordinate * @param y new y coordinate * * @retval N/A */ void ui_region_set_pos(ui_region_t * region, int16_t x, int16_t y) { ui_region_set_x(region, x); ui_region_set_y(region, y); } /** * @brief Set the width of an region * * @param region pointer to an region * @param w the new width of region (w == 1 makes x1 == x2) * * @retval N/A */ void ui_region_set_width(ui_region_t * region, int16_t w) { region->x2 = region->x1 + w - 1; } /** * @brief Set the height of an region * * @param region pointer to an region * @param w the new height of region (h == 1 makes y1 == y2) * * @retval N/A */ void ui_region_set_height(ui_region_t * region, int16_t h) { region->y2 = region->y1 + h - 1; } /** * @brief Move an region * * @param region pointer to an region * @param dx delta X to move * @param dy delta Y to move * * @retval N/A */ void ui_region_move(ui_region_t * region, int16_t dx, int16_t dy) { region->x1 += dx; region->y1 += dy; region->x2 += dx; region->y2 += dy; } /** * @brief Get the common parts of two regions * * @param result pointer to an region, the result will be stored here * @param region1 pointer to the first region * @param region2 pointer to the second region * * @return false: the two area has NO common parts, res_p is invalid */ bool __ramfunc ui_region_intersect(ui_region_t * result, const ui_region_t * region1, const ui_region_t * region2) { bool union_ok = true; /* Get the smaller region */ result->x1 = UI_MAX(region1->x1, region2->x1); result->y1 = UI_MAX(region1->y1, region2->y1); result->x2 = UI_MIN(region1->x2, region2->x2); result->y2 = UI_MIN(region1->y2, region2->y2); /*If x1 or y1 greater then x2 or y2 then the areas union is empty*/ if ((result->x1 > result->x2) || (result->y1 > result->y2)) { union_ok = false; } return union_ok; } /** * @brief merge two regions into a third which involves the other two * * @param result pointer to an region, the result will be stored here * @param region1 pointer to the first region * @param region2 pointer to the second region * * @retval N/A */ void ui_region_merge(ui_region_t * result, const ui_region_t * region1, const ui_region_t * region2) { result->x1 = UI_MIN(region1->x1, region2->x1); result->y1 = UI_MIN(region1->y1, region2->y1); result->x2 = UI_MAX(region1->x2, region2->x2); result->y2 = UI_MAX(region1->y2, region2->y2); } /** * @brief Subtract the common parts of two regions * * @param result pointer to a region array (4 at maximum), the result will be stored here * @param region pointer to a region * @param exclude pointer to the region to be subtracted from 'region' * * @retval the number of result regions */ int ui_region_subtract(ui_region_t * result, const ui_region_t * region, const ui_region_t * exclude) { int16_t cur_y = region->y1; int cnt = 0; if (region->x1 >= exclude->x1 && region->y1 >= exclude->y1 && region->x2 <= exclude->x1 && region->y2 <= exclude->y1) { return 0; } if (ui_region_is_on(region, exclude) == false) { ui_region_copy(result, region); return 1; } /* the top part */ if (region->y1 < exclude->y1) { result[cnt].x1 = region->x1; result[cnt].y1 = region->y1; result[cnt].x2 = region->x2; result[cnt++].y2 = exclude->y1 - 1; cur_y = exclude->y1; } /* the left part */ if (region->x1 < exclude->x1) { result[cnt].x1 = region->x1; result[cnt].y1 = cur_y; result[cnt].x2 = exclude->x1 - 1; result[cnt++].y2 = UI_MIN(region->y2, exclude->y2); } /* the right part */ if (region->x2 > exclude->x2) { result[cnt].x1 = exclude->x2 + 1; result[cnt].y1 = cur_y; result[cnt].x2 = region->x2; result[cnt++].y2 = UI_MIN(region->y2, exclude->y2); } /* the bottom part */ if (region->y2 > exclude->y2) { result[cnt].x1 = region->x1; result[cnt].y1 = exclude->y2 + 1; result[cnt].x2 = region->x2; result[cnt++].y2 = region->y2; } return cnt; } /** * @brief Try smallest adjustment of region position to make it totally fall in the holder region * * @param region pointer to an region which should fall in 'holder' * @param holder pointer to an region which involves 'region' * * @retval N/A */ void ui_region_fit_in(ui_region_t * region, const ui_region_t * holder) { int16_t dx = 0; int16_t dy = 0; if (region->x1 < holder->x1 && region->x2 < holder->x2) { dx = UI_MIN(holder->x1 - region->x1, holder->x2 - region->x2); } else if (region->x1 > holder->x1 && region->x2 > holder->x2) { dx = UI_MAX(holder->x1 - region->x1, holder->x2 - region->x2); } if (region->y1 < holder->y1 && region->y2 < holder->y2) { dy = UI_MIN(holder->y1 - region->y1, holder->y2 - region->y2); } else if (region->y1 > holder->y1 && region->y2 > holder->y2) { dy = UI_MAX(holder->y1 - region->y1, holder->y2 - region->y2); } ui_region_set_pos(region, region->x1 + dx, region->y1 + dy); } /** * @brief Check if a point is on an region * * @param region pointer to an region * @param point pointer to a point * * @return false: the point is out of the area */ bool ui_region_is_point_on(const ui_region_t * region, const ui_point_t * point) { if ((point->x >= region->x1 && point->x <= region->x2) && ((point->y >= region->y1 && point->y <= region->y2))) { return true; } else { return false; } } /** * @brief Check if two region has common parts * * @param region1 pointer to an region. * @param region2 pointer to an other region * * @return false: region1 and region2 has no common parts */ bool ui_region_is_on(const ui_region_t * region1, const ui_region_t * region2) { if ((region1->x1 <= region2->x2) && (region1->x2 >= region2->x1) && (region1->y1 <= region2->y2) && (region1->y2 >= region2->y1)) { return true; } else { return false; } } /** * @brief Check if a region is fully on an other * * @param region pointer to an region which could be in 'holder' * @param holder pointer to an region which could involve 'region' * * @return true: `region` is fully inside `holder` */ bool ui_region_is_in(const ui_region_t * region, const ui_region_t * holder) { if (region->x1 >= holder->x1 && region->y1 >= holder->y1 && region->x2 <= holder->x2 && region->y2 <= holder->y2) { return true; } else { return false; } } /** * @brief Check if an region is valid A valid region has a non negative width and height. * @param region pointer to an region. * * @return true if region is valid */ bool ui_region_is_valid(const ui_region_t * region) { return ui_region_get_width(region) >= 0 && ui_region_get_height(region) >= 0; } /** * @brief Check if an region is empty * * An empty region has a zero width or height, or is invalid * * @param region pointer to an region. * * @return true if region is empty */ bool ui_region_is_empty(const ui_region_t *region) { return ui_region_get_width(region) <= 0 || ui_region_get_height(region) <= 0; }