/* Based up Neutrino-GUI - Tuxbox-Project Copyright (C) 2001 by Steffen Hehn 'McClean' Classes for generic GUI-related components. Copyright (C) 2012-2017, Thilo Graf 'dbt' Copyright (C) 2012, Michael Liebmann 'micha-bbg' License: GPL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cc_draw.h" #include "cc_timer.h" #include #include #include extern CPictureViewer * g_PicViewer; /* export CCDRAW_DEBUG to paint red lines around all elements */ static bool CCDraw_debug = !!(getenv("CCDRAW_DEBUG")); CCDraw::CCDraw() : COSDFader(g_settings.theme.menu_Content_alpha) { frameBuffer = CFrameBuffer::getInstance(); x = cc_xr = cc_xr_old = x_old = 0; y = cc_yr = cc_yr_old = y_old = 0; height = height_old = CC_HEIGHT_MIN; width = width_old = CC_WIDTH_MIN; col_body_std = COL_MENUCONTENT_PLUS_0; col_body_sel = COL_MENUCONTENTSELECTED_PLUS_0; col_body_sec = COL_MENUCONTENTINACTIVE_PLUS_0; col_shadow = col_shadow_old = COL_SHADOW_PLUS_0; col_frame = col_frame_old = COL_FRAME_PLUS_0; col_shadow_clean = 0; cc_bg_image = cc_bg_image_old = cc_bg_sel_image = cc_bg_sec_image = ""; fr_thickness = fr_thickness_old = 0; corner_type = corner_type_old = CORNER_NONE; corner_rad = corner_rad_old = 0; shadow = CC_SHADOW_OFF; shadow_w = shadow_w_old = OFFSET_SHADOW; shadow_force = false; cc_paint_cache = false; cc_scrdata.pixbuf = NULL; cc_save_bg = false; firstPaint = true; is_painted = false; force_paint_bg = false; paint_bg = true; cc_allow_paint = true; cc_enable_frame = true; cc_body_gradient_enable = cc_body_gradient_enable_old = CC_COLGRAD_OFF; cc_body_gradient_2nd_col = cc_body_gradient_2nd_col_old = COL_MENUCONTENT_PLUS_0; cc_body_gradient_mode = CColorGradient::gradientLight2Dark; cc_body_gradient_intensity = CColorGradient::light; cc_body_gradient_intensity_v_min = 0x40; cc_body_gradient_intensity_v_max = 0xE0; cc_body_gradient_saturation = 0xC0; cc_body_gradient_direction = cc_body_gradient_direction_old = CFrameBuffer::gradientVertical; cc_draw_timer = NULL; cc_draw_trigger_slot = sigc::mem_fun0(*this, &CCDraw::paintTrigger); cc_gradient_bg_cleanup = true; v_fbdata.clear(); } CCDraw::~CCDraw() { if(cc_draw_timer){ delete cc_draw_timer; cc_draw_timer = NULL; } clearFbData(); } bool CCDraw::applyPosChanges() { bool ret = false; if (x != x_old || cc_xr != cc_xr_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], Pos changes x %d != x_old %d... [cc_xr = %d cc_xr_old = %d]\033[0m\n", __func__, __LINE__, x, x_old, cc_xr, cc_xr_old); x_old = x; cc_xr_old = cc_xr; ret = true; } if (y != y_old || cc_yr != cc_yr_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], Pos changes y %d != y_old %d... [cc_yr = %d cc_yr_old = %d]\033[0m\n", __func__, __LINE__, y, y_old, cc_yr, cc_yr_old); y_old = y; cc_yr_old = cc_yr; ret = true; } return ret; } bool CCDraw::applyDimChanges() { bool ret = false; if (height != height_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], dim changes height %d != height_old %d...\033[0m\n", __func__, __LINE__, height, height_old); height_old = height; ret = true; } if (width != width_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], dim changes width %d != width_old %d...\033[0m\n", __func__, __LINE__, width, width_old); width_old = width; ret = true; } if (fr_thickness != fr_thickness_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], dim changes fr_thickness %d != fr_thickness_old %d...\033[0m\n", __func__, __LINE__, fr_thickness, fr_thickness_old); fr_thickness_old = fr_thickness; ret = true; } if (shadow_w != shadow_w_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], dim changes shadow_w_sel %d != shadow_w_old %d...\033[0m\n", __func__, __LINE__, shadow_w, shadow_w_old); shadow_w_old = shadow_w; ret = true; } if (corner_rad != corner_rad_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], dim changes corner_rad %d != corner_rad_old %d...\033[0m\n", __func__, __LINE__, corner_rad, corner_rad_old); corner_rad_old = corner_rad; ret = true; } if (corner_type != corner_type_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], dim changes corner_type %d != corner_type_old %d...\033[0m\n", __func__, __LINE__, corner_type, corner_type_old); corner_type_old = corner_type; ret = true; } return ret; } bool CCDraw::applyColChanges() { bool ret = false; if (col_body != col_body_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], col changes col_body %d != col_body_old %d...\033[0m\n", __func__, __LINE__, col_body, col_body_old); col_body_old = col_body; ret = true; } if (col_shadow != col_shadow_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], col changes col_shadow %d != col_shadow_old %d...\033[0m\n", __func__, __LINE__, col_shadow, col_shadow_old); col_shadow_old = col_shadow; ret = true; } if (col_frame != col_frame_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], col changes col_frame %d != col_frame_old %d...\033[0m\n", __func__, __LINE__, col_frame, col_frame_old); col_frame_old = col_frame; ret = true; } if (cc_body_gradient_enable != cc_body_gradient_enable_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], col changes cc_body_gradient_enable %d != cc_body_gradient_enable_old %d...\033[0m\n", __func__, __LINE__, cc_body_gradient_enable, cc_body_gradient_enable_old); cc_body_gradient_enable_old = cc_body_gradient_enable; ret = true; } if (cc_body_gradient_2nd_col != cc_body_gradient_2nd_col_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], col changes cc_body_gradient_2nd_col %d != cc_body_gradient_2nd_col_old %d...\033[0m\n", __func__, __LINE__, cc_body_gradient_2nd_col, cc_body_gradient_2nd_col_old); cc_body_gradient_2nd_col_old = cc_body_gradient_2nd_col; ret = true; } if (cc_body_gradient_direction != cc_body_gradient_direction_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], col changes cc_body_gradient_direction %d != cc_body_gradient_direction_old %d...\033[0m\n", __func__, __LINE__, cc_body_gradient_direction, cc_body_gradient_direction_old); cc_body_gradient_direction_old = cc_body_gradient_direction; ret = true; } if (cc_bg_image != cc_bg_image_old){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], col changes cc_bg_image %s != cc_bg_image_old %s...\033[0m\n", __func__, __LINE__, cc_bg_image.c_str(), cc_bg_image_old.c_str()); cc_bg_image_old = cc_bg_image; ret = true; } return ret; } bool CCDraw::hasChanges() { if (applyPosChanges() || applyDimChanges() || applyColChanges()) return true; return false; } void CCDraw::setXPos(const int& xpos) { if (x == xpos) return; x = xpos; } void CCDraw::setYPos(const int& ypos) { if (y == ypos) return; y = ypos; } void CCDraw::setHeight(const int& h) { if (height == h) return; height = h; } void CCDraw::setWidth(const int& w) { if (width == w) return; width = w; } void CCDraw::setFrameThickness(const int& thickness) { fr_thickness = thickness; //ensure enabled frame if frame width > 0 cc_enable_frame = false; if (fr_thickness) cc_enable_frame = true; } bool CCDraw::enableColBodyGradient(const int& enable_mode, const fb_pixel_t& sec_color, const int& direction) { if (cc_body_gradient_enable == enable_mode && cc_body_gradient_direction == direction) return false; dprintf(DEBUG_DEBUG, "\033[33m[CCDraw]\t[%s - %d], change gradient mode: current=[%d] new=[%d] direction=[%d]\033[0m\n", __func__, __LINE__, cc_body_gradient_enable, enable_mode, direction); bool ret = false; if ((cc_body_gradient_enable != enable_mode) || (cc_body_gradient_enable == CC_COLGRAD_OFF)){ clearScreenBuffer(); cc_body_gradient_enable = enable_mode; ret = true; } if (cc_body_gradient_enable == CC_COLGRAD_COL_A_2_COL_B || cc_body_gradient_enable == CC_COLGRAD_COL_B_2_COL_A) set2ndColor(sec_color); //handle direction if (cc_body_gradient_direction != direction){ cc_body_gradient_direction = direction; ret = true; } return ret; } void CCDraw::setCornerType(const int& type) { if (corner_type == type) return; corner_type = type; } void CCDraw::setCorner(const int& radius, const int& type) { setCornerType(type); if (corner_rad == radius) return; corner_rad = radius; } gradientData_t* CCDraw::getGradientData() { if (cc_body_gradient_enable == CC_COLGRAD_OFF) return NULL; gradientData_t* gdata = new gradientData_t; gdata->gradientBuf = NULL; gdata->boxBuf = NULL; gdata->direction = cc_body_gradient_direction; gdata->mode = CFrameBuffer::pbrg_noFree; CColorGradient ccGradient; int gsize = cc_body_gradient_direction == CFrameBuffer::gradientVertical ? height : width; //TODO: add modes for direction and intensity switch (cc_body_gradient_enable){ case CC_COLGRAD_LIGHT_2_DARK: cc_body_gradient_mode = CColorGradient::gradientLight2Dark; break; case CC_COLGRAD_DARK_2_LIGHT: cc_body_gradient_mode = CColorGradient::gradientDark2Light; break; case CC_COLGRAD_COL_A_2_COL_B: cc_body_gradient_mode = CColorGradient::gradientLight2Dark; break; case CC_COLGRAD_COL_B_2_COL_A: cc_body_gradient_mode = CColorGradient::gradientDark2Light; break; case CC_COLGRAD_COL_LIGHT_DARK_LIGHT: cc_body_gradient_mode = CColorGradient::gradientLight2Dark2Light; break; case CC_COLGRAD_COL_DARK_LIGHT_DARK: cc_body_gradient_mode = CColorGradient::gradientDark2Light2Dark; break; } if (cc_body_gradient_enable == CC_COLGRAD_COL_A_2_COL_B || cc_body_gradient_enable == CC_COLGRAD_COL_B_2_COL_A){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], init gradient c2c)...\033[0m\n", __func__, __LINE__); gdata->gradientBuf = ccGradient.gradientColorToColor(col_body, cc_body_gradient_2nd_col, NULL, gsize, cc_body_gradient_mode, cc_body_gradient_intensity); }else{ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], init gradient single color)...\033[0m\n", __func__, __LINE__); gdata->gradientBuf = ccGradient.gradientOneColor(col_body, NULL, gsize, cc_body_gradient_mode, cc_body_gradient_intensity, cc_body_gradient_intensity_v_min, cc_body_gradient_intensity_v_max, cc_body_gradient_saturation); } return gdata; } bool CCDraw::clearSavedScreen() { /* Here we clean only screen buffers from background layers. * Paint cache and gradient are not touched. */ bool ret = false; for(size_t i =0; i< v_fbdata.size() ;i++) { if (v_fbdata.at(i).fbdata_type == CC_FBDATA_TYPE_BGSCREEN){ if (v_fbdata.at(i).pixbuf){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], cleanup bg...\033[0m\n", __func__, __LINE__); delete[] v_fbdata.at(i).pixbuf; v_fbdata.at(i).pixbuf = NULL; ret = true; } } } return ret; } bool CCDraw::clearPaintCache() { /* Here we clean only the paint cache from foreground layers. * BG layer is not touched. */ bool ret = false; for(size_t i =0; i< v_fbdata.size() ;i++) { if (v_fbdata.at(i).fbdata_type != CC_FBDATA_TYPE_BGSCREEN){ if (v_fbdata.at(i).pixbuf){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], cleanup paint cache layer...\033[0m\n", __func__, __LINE__); delete[] v_fbdata.at(i).pixbuf; v_fbdata.at(i).pixbuf = NULL; ret = true; } } } return ret; } //clean old gradient buffer bool CCDraw::clearFbGradientData() { bool ret = false; for(size_t i =0; i< v_fbdata.size() ;i++) { if (v_fbdata.at(i).gradient_data){ if (v_fbdata.at(i).gradient_data->gradientBuf){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], clean up gradientBuf \t %p...\033[0m\n", __func__, __LINE__, v_fbdata.at(i).gradient_data->gradientBuf); free(v_fbdata.at(i).gradient_data->gradientBuf); v_fbdata.at(i).gradient_data->gradientBuf = NULL; } if (v_fbdata.at(i).gradient_data->boxBuf){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], clean up boxBuf \t %p...\033[0m\n", __func__, __LINE__, v_fbdata.at(i).gradient_data->boxBuf); cs_free_uncached(v_fbdata.at(i).gradient_data->boxBuf); v_fbdata.at(i).gradient_data->boxBuf = NULL; } dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], clean up gradient data \t %p...\033[0m\n", __func__, __LINE__, v_fbdata.at(i).gradient_data); delete v_fbdata.at(i).gradient_data; v_fbdata.at(i).gradient_data = NULL; ret = true; } } return ret; } bool CCDraw::clearScreenBuffer() { bool ret = false; for(size_t i =0; i< v_fbdata.size() ;i++) { if (v_fbdata.at(i).pixbuf){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], cleanup pixbuf...\033[0m\n", __func__, __LINE__); delete[] v_fbdata.at(i).pixbuf; v_fbdata.at(i).pixbuf = NULL; ret = true; } } if (clearFbGradientData()) ret = true; firstPaint = true; return ret; } void CCDraw::clearFbData() { clearScreenBuffer(); v_fbdata.clear(); } bool CCDraw::CheckFbData(const cc_fbdata_t& fbdata, const char* func, const int& line) { if (fbdata.x < 0 || fbdata.y < 0 || fbdata.dx == 0 || fbdata.dy == 0) { dprintf(DEBUG_DEBUG,"[CCDraw]\t[%s - %d], INFO! Position < 0 or dx and/or dy = 0, x = %d, y = %d, dx = %d, dy = %d item: %s [type: %d]\n", func, line, fbdata.x, fbdata.y, fbdata.dx, fbdata.dy, cc_item_type.name.c_str(), cc_item_type.id ); return false; } int32_t rows = fbdata.dx / (int32_t)frameBuffer->getScreenWidth(true) - 1 + fbdata.y; int32_t rest = fbdata.dx % (int32_t)frameBuffer->getScreenWidth(true); int32_t end = rows * (int32_t)frameBuffer->getScreenWidth(true) + rest; if (end >= (int32_t)frameBuffer->getScreenWidth(true)*(int32_t)frameBuffer->getScreenHeight(true)) { dprintf(DEBUG_NORMAL, "[CCDraw] ERROR! Position > FB end [%s - %d]\n\tx = %d y = %d\n\tdx = %d dy = %d\n item: %s [type: %d]\n", func, line, fbdata.x, fbdata.y, fbdata.dx, fbdata.dy, cc_item_type.name.c_str(), cc_item_type.id ); return false; } return true; } //screen area save fb_pixel_t* CCDraw::getScreen(int ax, int ay, int dx, int dy) const { fb_pixel_t* pixbuf = NULL; if (dx < 1 || dy < 1 || dx * dy == 0) return NULL; else pixbuf = new fb_pixel_t[dx * dy]; frameBuffer->waitForIdle("CCDraw::getScreen()"); frameBuffer->SaveScreen(ax, ay, dx, dy, pixbuf); return pixbuf; } cc_screen_data_t CCDraw::getScreenData(const int& ax, const int& ay, const int& dx, const int& dy) { cc_screen_data_t res; res.x = res.y = res.dx = res.dy = 0; res.pixbuf = getScreen(ax, ay, dx, dy); if (res.pixbuf){ res.x = ax; res.y = ay; res.dx = dx; res.dy = dy; } else dprintf(DEBUG_NORMAL, "\033[33m[CCDraw]\[%s - %d], Warning: initialize of screen buffer failed!\033[0m\n", __func__, __LINE__); return res; } void CCDraw::enableSaveBg(const bool &save_bg) { if (!cc_save_bg || (cc_save_bg != save_bg)) clearSavedScreen(); cc_save_bg = save_bg; } void CCDraw::enablePaintCache(const bool &enable) { if (!cc_paint_cache || (cc_paint_cache != enable)) clearPaintCache(); cc_paint_cache = enable; } //paint framebuffer layers void CCDraw::paintFbItems(const bool &do_save_bg) { //Pick up signal if filled and execute slots. OnBeforePaintLayers(); //First we modify background handling. enableSaveBg(do_save_bg); //Save background before first paint, cc_save_bg must be true. if (firstPaint && cc_save_bg){ /* On first we must ensure that screen buffer is empty. * Here we clean possible screen buffers in bg layers, * without paint cache and gradient buffer. */ clearSavedScreen(); /* On second step we check for * usable item dimensions and exit here if found any problem. */ for(size_t i=0; i 0 && cc_allow_paint){ frameBuffer->paintBoxFrame(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, v_fbdata.at(i).frame_thickness, v_fbdata.at(i).color, v_fbdata.at(i).r, v_fbdata.at(i).rtype); v_fbdata.at(i).is_painted = true; } continue; } } if (paint_bg){ if (fbtype == CC_FBDATA_TYPE_BACKGROUND){ frameBuffer->paintBackgroundBoxRel(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy); v_fbdata.at(i).is_painted = true; if (CCDraw_debug) frameBuffer->paintBoxFrame(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, 1, COL_RANDOM); } } if (fbtype == CC_FBDATA_TYPE_SHADOW_BOX && ((!is_painted || !v_fbdata.at(i).is_painted)|| shadow_force || force_paint_bg)) { if (v_fbdata.at(i).enabled) { /* Here we paint the shadow around the body. * On 1st step we check for already cached screen buffer, if true * then restore this instead to call the paint methode. * This could be usally, if we use an existant instances of "this" object */ if (cc_allow_paint){ if (v_fbdata.at(i).pixbuf){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], paint shadow from cache...\033[0m\n", __func__, __LINE__); frameBuffer->RestoreScreen(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, v_fbdata.at(i).pixbuf); }else{ frameBuffer->paintBoxRel(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, v_fbdata.at(i).color, v_fbdata.at(i).r, v_fbdata.at(i).rtype); } //If is paint cache enabled, catch screen into cache if (cc_paint_cache && v_fbdata.at(i).pixbuf == NULL) v_fbdata.at(i).pixbuf = getScreen(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy); v_fbdata.at(i).is_painted = true; } continue; } } if (paint_bg){ if (fbtype == CC_FBDATA_TYPE_BOX){ if(cc_allow_paint) { /* Here we paint the main body of box. * On 1st step we check for already cached background buffer, if true * then restore this instead to call the paint methodes and gradient creation. * Paint cache can be enable/disable with enablePaintCache() */ if (v_fbdata.at(i).pixbuf){ /* If is paint cache enabled and cache is filled, it's prefered to paint * from cache. Cache is also filled if body background images are used */ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], paint body from cache...\033[0m\n", __func__, __LINE__); frameBuffer->RestoreScreen(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, v_fbdata.at(i).pixbuf); }else{ //Ensure clean gradient data on disabled gradient. if (v_fbdata.at(i).gradient_data){ if(cc_body_gradient_enable == CC_COLGRAD_OFF){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], gradient mode is disabled but filled\033[0m\n", __func__, __LINE__); clearFbGradientData(); } } /* If background image is defined, * we try to render an image instead to render default box. * Paint of background image is prefered, next steps will be ignored! */ if (!cc_bg_image.empty()){ if (g_PicViewer->DisplayImage(cc_bg_image, v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, CFrameBuffer::TM_NONE)){ // catch screen and store into paint cache v_fbdata.at(i).pixbuf = getScreen(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy); v_fbdata.at(i).is_painted = true; }else{ if (v_fbdata.at(i).pixbuf){ delete[] v_fbdata.at(i).pixbuf; v_fbdata.at(i).pixbuf = NULL; } v_fbdata.at(i).is_painted = false; } // On failed image paint, write this into log and reset image name. if (!v_fbdata.at(i).is_painted){ dprintf(DEBUG_NORMAL, "\033[33m\[CCDraw]\t[%s - %d], WARNING: bg image %s defined, but paint failed,\nfallback to default rendering...\033[0m\n", __func__, __LINE__, cc_bg_image.c_str()); cc_bg_image = ""; } } /* If no background image is defined, we paint default box or box with gradient * This is also possible if any background image is defined but image paint ist failed */ if (cc_bg_image.empty()){ if (cc_body_gradient_enable != CC_COLGRAD_OFF ){ /* If color gradient enabled we create a gradient_data * instance and add it to the fbdata object * On disabled color gradient or image paint was failed, we do paint only a default box */ if (v_fbdata.at(i).gradient_data == NULL){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], create new gradient data)...\033[0m\n", __func__, __LINE__); v_fbdata.at(i).gradient_data = getGradientData(); } if (v_fbdata.at(i).gradient_data->boxBuf == NULL){ if (v_fbdata.at(i).pixbuf == NULL){ /* Before we paint any gradient box with hw acceleration, we must cleanup first. * FIXME: This is only a workaround for this framebuffer behavior on enabled hw acceleration. * Without this, ugly ghost letters or ghost images inside gradient boxes are possible. */ if (cc_gradient_bg_cleanup) frameBuffer->paintBoxRel(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, 0, v_fbdata.at(i).r, v_fbdata.at(i).rtype); // create gradient buffer and paint gradient box v_fbdata.at(i).gradient_data->boxBuf = frameBuffer->paintBoxRel(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, 0, v_fbdata.at(i).gradient_data, v_fbdata.at(i).r, v_fbdata.at(i).rtype); dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], paint and cache new gradient into gradient cache...\033[0m\n", __func__, __LINE__); } /* On enabled paint cache or clean up, catch the screen into paint cache and clean up unused gradient buffer. * If we don't do this explicit, gradient cache is used. */ if (cc_paint_cache || cc_gradient_bg_cleanup){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], cache new created gradient into external cache...\033[0m\n", __func__, __LINE__); v_fbdata.at(i).pixbuf = getScreen(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy); if (clearFbGradientData()) dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], remove unused gradient data...\033[0m\n", __func__, __LINE__); } }else{ // If found gradient buffer, paint box from gradient cache. if (frameBuffer->checkFbArea(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, true)){ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], paint cached gradient)...\033[0m\n", __func__, __LINE__); frameBuffer->blitBox2FB(v_fbdata.at(i).gradient_data->boxBuf, v_fbdata.at(i).gradient_data->dx, v_fbdata.at(i).dy, v_fbdata.at(i).gradient_data->x, v_fbdata.at(i).y); frameBuffer->checkFbArea(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, false); } } }else{ /* If is nothing cached or no background image was defined or image paint was failed, * render a default box. */ dprintf(DEBUG_INFO, "\033[33m[CCDraw]\t[%s - %d], paint default box)...\033[0m\n", __func__, __LINE__); frameBuffer->paintBoxRel(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, v_fbdata.at(i).color, v_fbdata.at(i).r, v_fbdata.at(i).rtype); //If is paint cache enabled, catch screen into cache. if (cc_paint_cache) v_fbdata.at(i).pixbuf = getScreen(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy); } } } v_fbdata.at(i).is_painted = true; OnAfterPaintBg(); } } } if (CCDraw_debug) frameBuffer->paintBoxFrame(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, 1, getRandomColor({255, 255}, {1,255}, {1, 255})); } //set is_painted attribut. if any layer was painted set it to true; if (force_paint_bg){ is_painted = false; }else{ for(size_t i=0; i< v_fbdata.size(); i++){ if (v_fbdata.at(i).is_painted){ is_painted = true; break; } } } //reset is painted ignore flag to default value force_paint_bg = false; OnAfterPaintLayers(); } bool CCDraw::isPainted() { return is_painted; } void CCDraw::hide() { OnBeforeHide(); //restore saved screen background of item if available for(size_t i =0; i< v_fbdata.size() ;i++) { if (v_fbdata.at(i).fbdata_type == CC_FBDATA_TYPE_BGSCREEN){ if (v_fbdata.at(i).pixbuf) { //restore screen from backround layer frameBuffer->waitForIdle("CCDraw::hide()"); frameBuffer->RestoreScreen(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, v_fbdata.at(i).pixbuf); v_fbdata.at(i).is_painted = false; } } } firstPaint = true; is_painted = false; OnAfterHide(); } //erase or paint over rendered objects void CCDraw::kill(const fb_pixel_t& bg_color, const int& corner_radius, const int& fblayer_type /*fbdata_type*/) { int layers = fblayer_type; if (fblayer_type & ~CC_FBDATA_TYPES) layers = CC_FBDATA_TYPES; for(size_t i =0; i< v_fbdata.size() ;i++){ if (v_fbdata.at(i).fbdata_type & layers){ int r = 0; if (corner_radius > -1){ r = v_fbdata.at(i).r; if (corner_radius != v_fbdata.at(i).r) r = corner_radius; } if (v_fbdata.at(i).dx > 0 && v_fbdata.at(i).dy > 0){ if (v_fbdata.at(i).fbdata_type & (CC_FBDATA_TYPE_BOX | CC_FBDATA_TYPE_SHADOW_BOX) && v_fbdata.at(i).enabled){ frameBuffer->paintBoxRel(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, bg_color, r, v_fbdata.at(i).rtype); } if (v_fbdata.at(i).fbdata_type & CC_FBDATA_TYPE_FRAME){ if (v_fbdata.at(i).frame_thickness) frameBuffer->paintBoxFrame(v_fbdata.at(i).x, v_fbdata.at(i).y, v_fbdata.at(i).dx, v_fbdata.at(i).dy, v_fbdata.at(i).frame_thickness, bg_color, v_fbdata.at(i).r, v_fbdata.at(i).rtype); } }else dprintf(DEBUG_DEBUG, "\033[33m[CCDraw]\t[%s - %d] WARNING! render with bad dimensions [dx = %d dy = %d]\033[0m\n", __func__, __LINE__, v_fbdata.at(i).dx, v_fbdata.at(i).dy ); v_fbdata.at(i).is_painted = false; } } firstPaint = true; is_painted = false; } void CCDraw::killShadow(const fb_pixel_t& bg_color, const int& corner_radius) { kill(bg_color, corner_radius, CC_FBDATA_TYPE_SHADOW_BOX); } bool CCDraw::doPaintBg(const bool &do_paint) { if (paint_bg == do_paint) return false; paint_bg = do_paint; //clearSavedScreen(); return true; } void CCDraw::enableShadow(int mode, const int& shadow_width, bool force_paint) { if (shadow != mode){ killShadow(); shadow = mode; } if (shadow != CC_SHADOW_OFF) if (shadow_width != -1) setShadowWidth(shadow_width); shadow_force = force_paint; } void CCDraw::paintTrigger() { if (is_painted) hide(); else paint(); } bool CCDraw::paintBlink(CComponentsTimer* Timer) { if (Timer){ Timer->OnTimer.connect(cc_draw_trigger_slot); return Timer->isRun(); } return false; } bool CCDraw::paintBlink(const int64_t& interval) { if (cc_draw_timer == NULL){ cc_draw_timer = new CComponentsTimer(interval); cc_draw_timer->setThreadName(__func__); cc_draw_timer->startTimer(); } return paintBlink(cc_draw_timer); } bool CCDraw::cancelBlink(bool keep_on_screen) { if (cc_draw_timer){ cc_draw_timer->stopTimer(); delete cc_draw_timer; cc_draw_timer = NULL; } if(keep_on_screen) paint1(); else hide(); if (!cc_draw_timer) return true; return false; } bool CCDraw::setBodyBGImage(const std::string& image_path, const std::string& sel_image_path, const std::string& sec_image_path) { if (cc_bg_std_image == image_path && cc_bg_image == image_path && cc_bg_sel_image == sel_image_path && cc_bg_sec_image == sec_image_path) return false; cc_bg_std_image = cc_bg_image = image_path; cc_bg_sel_image = sel_image_path; cc_bg_sec_image = sec_image_path; if (clearPaintCache()) dprintf(DEBUG_NORMAL, "\033[33m\[CCDraw]\t[%s - %d], body background image defined standard: [%s] selected: [%s], secondary: [%s]\033[0m\n", __func__, __LINE__, cc_bg_image.c_str(), cc_bg_sel_image.c_str(), cc_bg_sec_image.c_str()); return true; } bool CCDraw::setBodyBGImageName(const std::string& image_name, const std::string& sel_image_name, const std::string& sec_image_name) { return setBodyBGImage(frameBuffer->getIconPath(image_name), frameBuffer->getIconPath(sel_image_name), frameBuffer->getIconPath(sec_image_name)); } int CCDraw::getXPos() const { return x; } int CCDraw::getYPos() const { return y; } int CCDraw::getHeight() const { return height; } int CCDraw::getWidth() const { return width; } void CCDraw::setDimensionsAll(const int& xpos, const int& ypos, const int& w, const int& h) { setPos(xpos, ypos); setWidth(w); setHeight(h); } void CCDraw::setPos(const int& xpos, const int& ypos) { setXPos(xpos); setYPos(ypos); } void CCDraw::allowPaint(const bool& allow) { if (allow != cc_allow_paint) cc_allow_paint = allow; if (cc_allow_paint) is_painted = false; } bool CCDraw::paintAllowed() { return cc_allow_paint; } void CCDraw::setColorBody(const fb_pixel_t &color_std, const fb_pixel_t &color_sel, const fb_pixel_t &color_sec) { if (col_body_std != color_std) col_body_std = color_std; if (color_sel != col_body_sel) col_body_sel = color_sel; if (color_sec != col_body_sec) col_body_sec = color_sec; } void CCDraw::setColorAll(const fb_pixel_t &color_frame, const fb_pixel_t &color_body, const fb_pixel_t &color_shadow, const fb_pixel_t &color_body_sel, const fb_pixel_t &color_body_sec) { setColorBody(color_body, color_body_sel, color_body_sec); setColorFrame(color_frame); setColorShadow(color_shadow); }