diff --git a/lib/gdi/Makefile.inc b/lib/gdi/Makefile.inc index fc07be7342c..aa7cfb9708e 100644 --- a/lib/gdi/Makefile.inc +++ b/lib/gdi/Makefile.inc @@ -5,6 +5,7 @@ gdi_libenigma_gdi_CXXFLAGS = $(LIBSDL_CFLAGS) gdi_libenigma_gdi_a_SOURCES = \ gdi/accel.cpp \ gdi/bcm.cpp \ + gdi/color.cpp \ gdi/compositing.cpp \ gdi/epng.cpp \ gdi/erect.cpp \ @@ -25,6 +26,7 @@ gdi_libenigma_gdi_a_SOURCES = \ gdiincludedir = $(pkgincludedir)/lib/gdi gdiinclude_HEADERS = \ gdi/accel.h \ + gdi/color.h \ gdi/compositing.h \ gdi/epng.h \ gdi/epoint.h \ diff --git a/lib/gdi/color.cpp b/lib/gdi/color.cpp new file mode 100644 index 00000000000..3912a5b0513 --- /dev/null +++ b/lib/gdi/color.cpp @@ -0,0 +1,420 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +#include + +#ifndef FLT_EPSILON +#define FLT_EPSILON 1E-5 +#endif + +int convertSetupColor2RGB(const unsigned char r, const unsigned char g, const unsigned char b) +{ + unsigned char red = (int)r * 255 / 100; + unsigned char green = (int)g * 255 / 100; + unsigned char blue = (int)b * 255 / 100; + + return (red << 16) | (green << 8) | blue; +} + +int convertSetupAlpha2Alpha(unsigned char alpha) +{ + if(alpha == 0) + return 0xFF; + else if(alpha >= 100) + return 0; + + int a = 100 - alpha; + int ret = a * 0xFF / 100; + + return ret; +} + +uint8_t limitChar(int c) +{ + uint8_t ret; + + if (c < 0) + ret = 0; + else if (c > 0xFF) + ret = 0xFF; + else + ret = (uint8_t)c; + + return ret; +} + +uint8_t getBrightnessRGB(uint32_t color) +{ + RgbColor rgb; + rgb.r = (uint8_t)((color & 0x00FF0000) >> 16); + rgb.g = (uint8_t)((color & 0x0000FF00) >> 8); + rgb.b = (uint8_t) (color & 0x000000FF); + + return rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b); +} + +uint32_t changeBrightnessRGBRel(uint32_t color, int br, bool transp) +{ + int br_ = (int)getBrightnessRGB(color); + br_ += br; + if (br_ < 0) br_ = 0; + if (br_ > 255) br_ = 255; + return changeBrightnessRGB(color, (uint8_t)br_, transp); +} + +uint32_t changeBrightnessRGB(uint32_t color, uint8_t br, bool transp) +{ + HsvColor hsv; + uint8_t tr = SysColor2Hsv(color, &hsv); + hsv.v = (float)br / (float)255; + if (!transp) + tr = 0xFF; + return Hsv2SysColor(&hsv, tr); +} + +uint32_t Hsv2SysColor(HsvColor *hsv, uint8_t tr) +{ + RgbColor rgb; + Hsv2Rgb(hsv, &rgb); + return (((tr << 24) & 0xFF000000) | + ((rgb.r << 16) & 0x00FF0000) | + ((rgb.g << 8) & 0x0000FF00) | + ((rgb.b ) & 0x000000FF)); +} + +uint8_t SysColor2Hsv(uint32_t color, HsvColor *hsv) +{ + uint8_t tr; + RgbColor rgb; + tr = (uint8_t)((color & 0xFF000000) >> 24); + rgb.r = (uint8_t)((color & 0x00FF0000) >> 16); + rgb.g = (uint8_t)((color & 0x0000FF00) >> 8); + rgb.b = (uint8_t) (color & 0x000000FF); + Rgb2Hsv(&rgb, hsv); + return tr; +} + +void Hsv2Rgb(HsvColor *hsv, RgbColor *rgb) +{ + float f_H = hsv->h; + float f_S = hsv->s; + float f_V = hsv->v; + if (fabsf(f_S) < FLT_EPSILON) { + rgb->r = (uint8_t)(f_V * 255); + rgb->g = (uint8_t)(f_V * 255); + rgb->b = (uint8_t)(f_V * 255); + + } else { + float f_R; + float f_G; + float f_B; + float hh = f_H; + if (hh >= 360) hh = 0; + hh /= 60; + int i = (int)hh; + float ff = hh - (float)i; + float p = f_V * (1 - f_S); + float q = f_V * (1 - (f_S * ff)); + float t = f_V * (1 - (f_S * (1 - ff))); + + switch (i) { + case 0: + f_R = f_V; f_G = t; f_B = p; + break; + case 1: + f_R = q; f_G = f_V; f_B = p; + break; + case 2: + f_R = p; f_G = f_V; f_B = t; + break; + case 3: + f_R = p; f_G = q; f_B = f_V; + break; + case 4: + f_R = t; f_G = p; f_B = f_V; + break; + case 5: + default: + f_R = f_V; f_G = p; f_B = q; + break; + } + rgb->r = (uint8_t)(f_R * 255); + rgb->g = (uint8_t)(f_G * 255); + rgb->b = (uint8_t)(f_B * 255); + } +} + +void Rgb2Hsv(RgbColor *rgb, HsvColor *hsv) +{ + float f_R = (float)rgb->r / (float)255; + float f_G = (float)rgb->g / (float)255; + float f_B = (float)rgb->b / (float)255; + + float min = f_R < f_G ? (f_R < f_B ? f_R : f_B) : (f_G < f_B ? f_G : f_B); + float max = f_R > f_G ? (f_R > f_B ? f_R : f_B) : (f_G > f_B ? f_G : f_B); + float delta = max - min; + + float f_V = max; + float f_H = 0; + float f_S = 0; + + if (fabsf(delta) < FLT_EPSILON) + { + //gray + f_S = 0; + f_H = 0; + } + else + { + f_S = (delta / max); + if (f_R >= max) + f_H = (f_G - f_B) / delta; + else if (f_G >= max) + f_H = 2 + (f_B - f_R) / delta; + else + f_H = 4 + (f_R - f_G) / delta; + + f_H *= 60; + if (f_H < 0) + f_H += 360; + } + hsv->h = f_H; + hsv->s = f_S; + hsv->v = f_V; +} + +uint32_t* gradientColorToTransparent(const gRGB &grad_col, uint32_t *gradientBuf, int bSize, int /*mode*/, int /*intensity*/) +{ + if (gradientBuf == NULL) + { + gradientBuf = (uint32_t*) malloc(bSize * sizeof(uint32_t)); + + if (gradientBuf == NULL) + { + return NULL; + } + } + + uint32_t col = grad_col.argb(); + col^=0xFF000000; + + memset((void*)gradientBuf, '\0', bSize * sizeof(uint32_t)); + + int start_box = 0; + int end_box = bSize; + uint8_t tr_min = 0xFF; + uint8_t tr_max = 0x20; + float factor = (float)(tr_min - tr_max) / (float)(end_box - start_box); + + for (int i = start_box; i < end_box; i++) + { + + uint8_t tr = limitChar((int)(factor * (float)i + tr_max) + 1); + uint8_t r = (uint8_t)((col & 0x00FF0000) >> 16); + uint8_t g = (uint8_t)((col & 0x0000FF00) >> 8); + uint8_t b = (uint8_t) (col & 0x000000FF); + + gradientBuf[i] = ((tr << 24) & 0xFF000000) | + ((r << 16) & 0x00FF0000) | + ((g << 8) & 0x0000FF00) | + ( b & 0x000000FF); + } + + return gradientBuf; +} + +uint32_t* gradientOneColor(const gRGB &grad_col, uint32_t *gradientBuf, int bSize, int mode, int intensity, uint8_t v_min, uint8_t v_max, uint8_t s) +{ + if (gradientBuf == NULL) + { + gradientBuf = (uint32_t*) malloc(bSize * sizeof(uint32_t)); + + if (gradientBuf == NULL) + { + return NULL; + } + } + + uint32_t col = grad_col.argb(); + col^=0xFF000000; + + memset((void*)gradientBuf, '\0', bSize * sizeof(uint32_t)); + + HsvColor hsv; + uint8_t min_v = 0, max_v = 0, col_s = 0; + uint8_t start_v = 0 , end_v = 0; + + uint8_t tr = SysColor2Hsv(col, &hsv); + bool noSaturation = (hsv.s <= (float)0.05); + + if (intensity == INT_EXTENDED) + { + min_v = v_min; + max_v = v_max; + col_s = s; + } + else + { + switch (intensity) + { + case INT_LIGHT: + min_v = 0x40; + max_v = 0xE0; + col_s = (noSaturation) ? 0 : 0xC0; + break; + case INT_NORMAL: + min_v = 0x00; + max_v = 0xFF; + col_s = (noSaturation) ? 0 : 0xC0; + break; + } + } + + switch (mode) + { + case DARK2LIGHT: + case DARK2LIGHT2DARK: + start_v = min_v; + end_v = max_v; + break; + case LIGHT2DARK: + case LIGHT2DARK2LIGHT: + start_v = max_v; + end_v = min_v; + break; + default: + return 0; + } + + int bSize1 = ((mode == DARK2LIGHT2DARK) || (mode == LIGHT2DARK2LIGHT)) ? bSize/2 : bSize; + + int v = start_v; int v_ = v; + float factor_v = ((float)end_v - (float)v) / (float)bSize1; + + for (int i = 0; i < bSize1; i++) + { + v = v_ + (int)(factor_v * (float)i); + hsv.v = (float)limitChar(v) / (float)255; + hsv.s = (float)col_s / (float)255; + gradientBuf[i] = Hsv2SysColor(&hsv, tr); + } + + if ((mode == DARK2LIGHT2DARK) || (mode == LIGHT2DARK2LIGHT)) + { + bSize1 = bSize - bSize1; + for (int i = 0; i < bSize1; i++) + { + v = v_ + (int)(factor_v * (float)i); + hsv.v = (float)limitChar(v) / (float)255; + hsv.s = (float)col_s / (float)255; + gradientBuf[bSize - i - 1] = Hsv2SysColor(&hsv, tr); + } + } + + return gradientBuf; +} + +uint32_t* gradientColorToColor(const gRGB &start_grad_col,const gRGB &end_grad_col, uint32_t *gradientBuf, int bSize, int mode, int /*intensity*/) +{ + if (gradientBuf == NULL) + { + gradientBuf = (uint32_t*) malloc(bSize * sizeof(uint32_t)); + + if (gradientBuf == NULL) + { + return NULL; + } + } + + uint32_t start_col = start_grad_col.argb(); + start_col^=0xFF000000; + + uint32_t end_col = end_grad_col.argb(); + end_col^=0xFF000000; + + memset((void*)gradientBuf, '\0', bSize * sizeof(uint32_t)); + + int start_box = 0; + int end_box = bSize; + + uint32_t temp_col = end_col; + end_col = start_col; + start_col = temp_col; + + if (mode == DARK2LIGHT) + { + temp_col = start_col; + start_col = end_col; + end_col = temp_col; + } + + uint8_t start_tr = (uint8_t)((start_col & 0xFF000000) >> 24); + uint8_t start_r = (uint8_t)((start_col & 0x00FF0000) >> 16); + uint8_t start_g = (uint8_t)((start_col & 0x0000FF00) >> 8); + uint8_t start_b = (uint8_t) (start_col & 0x000000FF); + + uint8_t end_tr = (uint8_t)((end_col & 0xFF000000) >> 24); + uint8_t end_r = (uint8_t)((end_col & 0x00FF0000) >> 16); + uint8_t end_g = (uint8_t)((end_col & 0x0000FF00) >> 8); + uint8_t end_b = (uint8_t) (end_col & 0x000000FF); + + float steps = (float) bSize; + + float trStep = (float)(end_tr - start_tr) / steps; + float rStep = (float)(end_r - start_r) / steps; + float gStep = (float)(end_g - start_g) / steps; + float bStep = (float)(end_b - start_b) / steps; + + for (int i = start_box; i < end_box; i++) + { + + uint8_t tr = limitChar((int)((float)start_tr + trStep*(float)i)); + uint8_t r = limitChar((int)((float)start_r + rStep*(float)i)); + uint8_t g = limitChar((int)((float)start_g + gStep*(float)i)); + uint8_t b = limitChar((int)((float)start_b + bStep*(float)i)); + + gradientBuf[i] = ((tr << 24) & 0xFF000000) | + ((r << 16) & 0x00FF0000) | + ((g << 8) & 0x0000FF00) | + ( b & 0x000000FF); + } + + return gradientBuf; +} + + + + + + diff --git a/lib/gdi/color.h b/lib/gdi/color.h new file mode 100644 index 00000000000..662216b30a6 --- /dev/null +++ b/lib/gdi/color.h @@ -0,0 +1,125 @@ +/* + Neutrino-GUI - DBoxII-Project + + $Id: color.h 2013/10/12 mohousch Exp $ + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __color__ +#define __color__ + +#include +#include "gpixmap.h" + +// gradient mode +enum { + DARK2LIGHT, + LIGHT2DARK, + DARK2LIGHT2DARK, + LIGHT2DARK2LIGHT +}; + +// gradient intensity +enum { + INT_LIGHT, + INT_NORMAL, + INT_EXTENDED +}; + +// gradient type +enum { + GRADIENT_COLOR2TRANSPARENT, + GRADIENT_ONECOLOR, + GRADIENT_COLOR2COLOR +}; + + +// +int convertSetupColor2RGB(unsigned char r, unsigned char g, unsigned char b); +int convertSetupAlpha2Alpha(unsigned char alpha); + +// +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; +} RgbColor; + +typedef struct { + float h; + float s; + float v; +} HsvColor; + +uint8_t limitChar(int c); +uint8_t getBrightnessRGB(uint32_t color); +uint32_t changeBrightnessRGBRel(uint32_t color, int br, bool transp=true); +uint32_t changeBrightnessRGB(uint32_t color, uint8_t br, bool transp=true); +uint32_t Hsv2SysColor(HsvColor *hsv, uint8_t tr=0xFF); +uint8_t SysColor2Hsv(uint32_t color, HsvColor *hsv); +void Hsv2Rgb(HsvColor *hsv, RgbColor *rgb); +void Rgb2Hsv(RgbColor *rgb, HsvColor *hsv); + +uint32_t* gradientColorToTransparent(const gRGB &grad_col, uint32_t *gradientBuf, int bSize, int mode, int intensity = INT_LIGHT); + +uint32_t* gradientOneColor(const gRGB &grad_col, uint32_t *gradientBuf, int bSize, int mode, int intensity = INT_LIGHT, uint8_t v_min = 0x40, uint8_t v_max = 0xE0, uint8_t s = 0xC0); + +uint32_t* gradientColorToColor(const gRGB &start_grad_col, const gRGB &end_grad_col, uint32_t *gradientBuf, int bSize, int mode = DARK2LIGHT, int intensity = INT_LIGHT); + +// +inline uint32_t make16color(__u32 rgb) +{ + return 0xFF000000 | rgb; +} + +// for lua until +inline uint32_t make16Color(unsigned int rgb) +{ + uint32_t col = 0xFF000000 | rgb; + + return col; +} + +inline uint32_t convertSetupColor2Color(unsigned char r, unsigned char g, unsigned char b, unsigned char alpha) +{ + int color = convertSetupColor2RGB(r, g, b); + int tAlpha = (alpha ? (convertSetupAlpha2Alpha(alpha)) : 0); + + if(!alpha) + tAlpha = 0xFF; + + uint32_t col = ((tAlpha << 24) & 0xFF000000) | color; + + return col; +} + +#endif + + diff --git a/lib/gdi/gpixmap.cpp b/lib/gdi/gpixmap.cpp index 467d88e1b9d..797674d1a12 100644 --- a/lib/gdi/gpixmap.cpp +++ b/lib/gdi/gpixmap.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #ifndef BYTE_ORDER @@ -451,6 +452,115 @@ static void convert_palette(uint32_t* pal, const gPalette& clut) #define FIX 0x10000 +uint32_t* gPixmap::allocBoxBuf(const int dx, const int dy, uint32_t* buf) +{ + uint32_t* pixBuf = buf; + if (pixBuf == NULL) + { + pixBuf = (uint32_t*)malloc(dx*dy*sizeof(uint32_t)); + if (pixBuf == NULL) + { + return NULL; + } + } + memset((void*)pixBuf, '\0', dx*dy*sizeof(uint32_t)); + + return pixBuf; +} + +void gPixmap::drawGradient(const gRegion ®ion, const eRect &area, const gRGB &startcolor, const gRGB &endcolor, int direction, int flag) +{ + uint32_t* gradientBuf = NULL; + uint32_t* boxBuf = allocBoxBuf(area.width(), area.height(), NULL); + + gradientBuf = gradientColorToColor(startcolor, endcolor, NULL, (direction == 0) ? area.height() : area.width()); + + uint32_t *bp = boxBuf; + uint32_t *gra = gradientBuf; + + if (direction == 0) + { + for (int pos = 0; pos < area.width(); pos++) + { + for(int count = 0; count < area.height(); count++) + { + *(bp + pos) = (uint32_t)(*(gra + count)); + bp += area.width(); + } + bp = boxBuf; + } + } + else + { + for (int line = 0; line < area.height(); line++) + { + int gra_pos = 0; + for (int pos = 0; pos < area.width(); pos++) + { + if ( (pos >= 0) && (gra_pos < area.width())) + { + *(bp + pos) = (uint32_t)(*(gra + gra_pos)); + gra_pos++; + } + } + bp += area.width(); + } + } + + //blit + for (unsigned int i=0; ibypp; + const uint8_t* srcptr = (const uint8_t*)boxBuf + srcarea.left()*surface->bypp + srcarea.top()*src_stride; + uint8_t* dstptr = (uint8_t*)surface->data + reg.left()*surface->bypp + reg.top()*surface->stride; + const int width = reg.width(); + const int height = reg.height(); + const int src_height = srcarea.height(); + const int src_width = srcarea.width(); + if (flag & blitAlphaBlend) + { + for (int y = 0; y < height; ++y) + { + const gRGB *src_row_ptr = (gRGB *)(srcptr + (((y * src_height) / height) * src_stride)); + gRGB *dst = (gRGB*)dstptr; + for (int x = 0; x < width; ++x) + { + dst->alpha_blend(src_row_ptr[(x * src_width) / width]); + ++dst; + } + dstptr += surface->stride; + } + } + else + { + for (int y = 0; y < height; ++y) + { + const uint32_t *src_row_ptr = (uint32_t*)(srcptr + (((y * src_height) / height) * src_stride)); + uint32_t *dst = (uint32_t*)dstptr; + for (int x = 0; x < width; ++x) + { + *dst = src_row_ptr[(x * src_width) / width]; + ++dst; + } + dstptr += surface->stride; + } + } + + } + if (boxBuf) + free(boxBuf); +} + void gPixmap::blit(const gPixmap &src, const eRect &_pos, const gRegion &clip, int flag) { bool accel = (surface->data_phys && src.surface->data_phys); diff --git a/lib/gdi/gpixmap.h b/lib/gdi/gpixmap.h index 7b73f8f164f..ad27be9ca89 100644 --- a/lib/gdi/gpixmap.h +++ b/lib/gdi/gpixmap.h @@ -235,6 +235,9 @@ class gPixmap: public iObject void line(const gRegion &clip, ePoint start, ePoint end, gColor color); void line(const gRegion &clip, ePoint start, ePoint end, gRGB color); void line(const gRegion &clip, ePoint start, ePoint end, unsigned int color); + + uint32_t* allocBoxBuf(const int dx, const int dy, uint32_t* buf = NULL); + void drawGradient(const gRegion ®ion, const eRect &area, const gRGB &startcolor, const gRGB &endcolor, int direction = 0, int flag = 0); }; SWIG_TEMPLATE_TYPEDEF(ePtr, gPixmapPtr); diff --git a/lib/gdi/grc.cpp b/lib/gdi/grc.cpp index 1b234cd0755..58ed0854817 100644 --- a/lib/gdi/grc.cpp +++ b/lib/gdi/grc.cpp @@ -471,6 +471,23 @@ void gPainter::blit(gPixmap *pixmap, const eRect &pos, const eRect &clip, int fl m_rc->submit(o); } +void gPainter::drawGradient(const eRect &area, const gRGB &startcolor, const gRGB &endcolor, int orientation, int flag) +{ + if ( m_dc->islocked() ) + return; + gOpcode o; + o.opcode=gOpcode::gradient; + o.dc = m_dc.grabRef(); + o.parm.gradient = new gOpcode::para::pgradient; + o.parm.gradient->area = area; + o.parm.gradient->gradientStartColor = startcolor; + o.parm.gradient->gradientEndColor = endcolor; + o.parm.gradient->orientation = orientation; + o.parm.gradient->flag = flag; + m_rc->submit(o); +} + + void gPainter::setPalette(gRGB *colors, int start, int len) { if (m_dc->islocked()) @@ -969,6 +986,14 @@ void gDC::exec(const gOpcode *o) delete o->parm.blit; break; } + case gOpcode::gradient: + { + o->parm.gradient->area.moveBy(m_current_offset); + gRegion clip = m_current_clip & o->parm.gradient->area; + m_pixmap->drawGradient(clip, o->parm.gradient->area, o->parm.gradient->gradientStartColor, o->parm.gradient->gradientEndColor, o->parm.gradient->orientation, o->parm.gradient->flag); + delete o->parm.gradient; + break; + } case gOpcode::setPalette: if (o->parm.setPalette->palette->start > m_pixmap->surface->clut.colors) o->parm.setPalette->palette->start = m_pixmap->surface->clut.colors; diff --git a/lib/gdi/grc.h b/lib/gdi/grc.h index 376fa86a7c5..71943b504bd 100644 --- a/lib/gdi/grc.h +++ b/lib/gdi/grc.h @@ -39,6 +39,7 @@ struct gOpcode fillRegion, clear, blit, + gradient, setPalette, mergePalette, @@ -128,6 +129,15 @@ struct gOpcode eRect clip; } *blit; + struct pgradient + { + eRect area; + gRGB gradientStartColor; + gRGB gradientEndColor; + int orientation; + int flag; + } *gradient; + struct pmergePalette { gPixmap *target; @@ -302,9 +312,17 @@ class gPainter BT_VALIGN_BOTTOM = 128 }; - void blitScale(gPixmap *pixmap, const eRect &pos, const eRect &clip = eRect(), int flags = 0, int aflags = BT_SCALE); - void blit(gPixmap *pixmap, ePoint pos, const eRect &clip = eRect(), int flags = 0); - void blit(gPixmap *pixmap, const eRect &pos, const eRect &clip = eRect(), int flags = 0); + enum + { + GRADIENT_VERTICAL = 0, + GRADIENT_HORIZONTAL = 1 + }; + + void blitScale(gPixmap *pixmap, const eRect &pos, const eRect &clip=eRect(), int flags=0, int aflags = BT_SCALE); + void blit(gPixmap *pixmap, ePoint pos, const eRect &clip=eRect(), int flags=0); + void blit(gPixmap *pixmap, const eRect &pos, const eRect &clip=eRect(), int flags=0); + + void drawGradient(const eRect &area, const gRGB &startcolor, const gRGB &endcolor, int orientation, int flag=0); void setPalette(gRGB *colors, int start = 0, int len = 256); void setPalette(gPixmap *source); diff --git a/lib/gui/Makefile.inc b/lib/gui/Makefile.inc index 263afbb727d..b24b7572637 100644 --- a/lib/gui/Makefile.inc +++ b/lib/gui/Makefile.inc @@ -8,6 +8,7 @@ gui_libenigma_gui_a_SOURCES = \ gui/elistbox.cpp \ gui/elistboxcontent.cpp \ gui/epixmap.cpp \ + gui/erectangle.cpp \ gui/epositiongauge.cpp \ gui/eslider.cpp \ gui/esubtitle.cpp \ @@ -28,6 +29,7 @@ guiinclude_HEADERS = \ gui/elistbox.h \ gui/elistboxcontent.h \ gui/epixmap.h \ + gui/erectangle.h \ gui/epositiongauge.h \ gui/eslider.h \ gui/esubtitle.h \ diff --git a/lib/gui/elistbox.cpp b/lib/gui/elistbox.cpp index 1b7f34842c0..32196bb64da 100644 --- a/lib/gui/elistbox.cpp +++ b/lib/gui/elistbox.cpp @@ -17,9 +17,9 @@ bool eListbox::defaultWrapAround = eListbox::DefaultWrapAround; eRect eListbox::defaultPadding = eRect(1, 1, 1, 1); eListbox::eListbox(eWidget *parent) : eWidget(parent), m_scrollbar_mode(showNever), m_prev_scrollbar_page(-1), - m_scrollbar_scroll(byPage), m_content_changed(false), m_enabled_wrap_around(false), m_scrollbar_width(10), - m_scrollbar_height(10), m_top(0), m_left(0), m_selected(0), m_itemheight(25), m_itemwidth(25), - m_orientation(orVertical), m_max_columns(0), m_max_rows(0), m_selection_enabled(1), m_page_size(0), m_item_alignment(0), + m_scrollbar_scroll(byPage), m_content_changed(false), m_enabled_wrap_around(false), m_itemwidth_set(false), m_itemheight_set(false), m_scrollbar_width(10), + m_scrollbar_height(10), m_scrollbar_length(0), m_top(0), m_left(0), m_selected(0), m_itemheight(25), m_itemwidth(25), + m_orientation(orVertical), m_max_columns(0), m_max_rows(0), m_selection_enabled(1), m_page_size(0), m_item_alignment(0), xOffset(0), yOffset(0), m_native_keys_bound(false), m_first_selectable_item(-1), m_last_selectable_item(-1), m_scrollbar(nullptr) { m_scrollbar_width = eListbox::defaultScrollBarWidth; @@ -33,6 +33,7 @@ eListbox::eListbox(eWidget *parent) : eWidget(parent), m_scrollbar_mode(showNeve memset(static_cast(&m_style), 0, sizeof(m_style)); m_style.m_text_padding = eListbox::defaultPadding; + m_style.m_selection_zoom = 1.0; // setContent(new eListboxStringContent()); allowNativeKeys(true); @@ -72,11 +73,11 @@ void eListbox::setScrollbarMode(int mode) m_scrollbar->setBackgroundPixmap(m_scrollbarbackgroundpixmap); if (m_scrollbarpixmap) m_scrollbar->setPixmap(m_scrollbarpixmap); - if (m_style.m_scollbarborder_color_set) + if (m_style.is_set.scollbarborder_color) m_scrollbar->setBorderColor(m_style.m_scollbarborder_color); - if (m_style.m_scrollbarforeground_color_set) + if (m_style.is_set.scrollbarforeground_color) m_scrollbar->setForegroundColor(m_style.m_scrollbarforeground_color); - if (m_style.m_scrollbarbackground_color_set) + if (m_style.is_set.scrollbarbackground_color) m_scrollbar->setBackgroundColor(m_style.m_scrollbarbackground_color); } } @@ -195,12 +196,80 @@ int eListbox::getCurrentIndex() return 0; } +int eListbox::setScrollbarPosition() +{ + + int width = size().width(); + int height = size().height(); + int x = xOffset; + int y = yOffset; + + if (m_scrollbar_length == -1) + { + if (m_orientation == orHorizontal) + { + if (xOffset > 0) + width -= (xOffset * 2); + } + else { + if (yOffset > 0) + height -= (yOffset * 2); + } + } + else if (m_scrollbar_length != 0) + { + x = 0; + y = 0; + if (m_orientation == orHorizontal) + { + width = m_scrollbar_length; + } + else + { + height = m_scrollbar_length; + } + } + else + { + x = 0; + y = 0; + } + + if (m_scrollbar_mode == showTopAlways || m_scrollbar_mode == showTopOnDemand) + { + m_scrollbar->move(ePoint(x, y)); + m_scrollbar->resize(eSize(width, m_scrollbar_height)); + } + else if (m_scrollbar_mode == showLeftOnDemand || m_scrollbar_mode == showLeftAlways) + { + m_scrollbar->move(ePoint(x, y)); + m_scrollbar->resize(eSize(m_scrollbar_width, height)); + } + else if (m_orientation == orHorizontal) + { + m_scrollbar->move(ePoint(x, height - m_scrollbar_height)); + m_scrollbar->resize(eSize(width, m_scrollbar_height)); + } + else + { + m_scrollbar->move(ePoint(width - m_scrollbar_width, y)); + m_scrollbar->resize(eSize(m_scrollbar_width, height)); + } + + if (m_orientation == orHorizontal) + return width; + else + return height; + +} + void eListbox::updateScrollBar() { if (!m_scrollbar || !m_content || m_scrollbar_mode == showNever) return; int entries = (m_orientation == orGrid) ? (m_content->size() + m_max_columns - 1) / m_max_columns : m_content->size(); bool scrollbarvisible = m_scrollbar->isVisible(); + bool scrollbarvisibleOld = m_scrollbar->isVisible(); int maxItems = (m_orientation == orHorizontal) ? m_max_columns : m_max_rows; if (m_content_changed) @@ -208,20 +277,11 @@ void eListbox::updateScrollBar() int width = size().width(); int height = size().height(); - if (m_scrollbar_scroll == byLine) - { - if (m_orientation == orHorizontal) - m_scrollbar->setRange(0, width - (m_scrollbar_border_width * 2)); - else - m_scrollbar->setRange(0, height - (m_scrollbar_border_width * 2)); - } - m_content_changed = false; if (m_scrollbar_mode == showTopAlways || m_scrollbar_mode == showTopOnDemand) { m_content->setSize(eSize(m_itemwidth, height - m_scrollbar_height - m_scrollbar_offset)); - m_scrollbar->move(ePoint(0, 0)); - m_scrollbar->resize(eSize(width, m_scrollbar_height)); + m_scrollbar_calcsize = setScrollbarPosition(); if (entries > m_max_columns || m_scrollbar_mode == showLeftAlways) { m_scrollbar->show(); @@ -239,8 +299,9 @@ void eListbox::updateScrollBar() m_content->setSize(eSize(width - m_scrollbar_width - m_scrollbar_offset, m_itemheight)); else m_content->setSize(eSize(m_itemwidth, m_itemheight)); - m_scrollbar->move(ePoint(0, 0)); - m_scrollbar->resize(eSize(m_scrollbar_width, height)); + + m_scrollbar_calcsize = setScrollbarPosition(); + if (entries > m_max_rows || m_scrollbar_mode == showLeftAlways) { m_scrollbar->show(); @@ -256,22 +317,17 @@ void eListbox::updateScrollBar() { if (m_orientation == orHorizontal) { - m_scrollbar->move(ePoint(0, height - m_scrollbar_height)); - m_scrollbar->resize(eSize(width, m_scrollbar_height)); m_content->setSize(eSize(m_itemwidth, height - m_scrollbar_height - m_scrollbar_offset)); } else if (m_orientation == orVertical) { - m_scrollbar->move(ePoint(width - m_scrollbar_width, 0)); - m_scrollbar->resize(eSize(m_scrollbar_width, height)); m_content->setSize(eSize(width - m_scrollbar_width - m_scrollbar_offset, m_itemheight)); } else { - m_scrollbar->move(ePoint(width - m_scrollbar_width, 0)); - m_scrollbar->resize(eSize(m_scrollbar_width, height)); m_content->setSize(eSize(m_itemwidth, m_itemheight)); } + m_scrollbar_calcsize = setScrollbarPosition(); m_scrollbar->show(); scrollbarvisible = true; } @@ -286,6 +342,12 @@ void eListbox::updateScrollBar() m_scrollbar->hide(); scrollbarvisible = false; } + + if (m_scrollbar_scroll == byLine) + { + m_scrollbar->setRange(0, m_scrollbar_calcsize - (m_scrollbar_border_width * 2)); + } + } // Don't set Start/End if scollbar not visible or entries/maxItems = 0 @@ -301,9 +363,7 @@ void eListbox::updateScrollBar() int start = 0; int selected = (m_orientation == orGrid) ? m_selected / m_max_columns : m_selected; - int range = size().height() - (m_scrollbar_border_width * 2); - if (m_orientation == orHorizontal) - range = size().width() - (m_scrollbar_border_width * 2); + int range = m_scrollbar_calcsize - (m_scrollbar_border_width * 2); int end = range; // calculate thumb only if needed if (entries > 1 && entries > maxItems) @@ -343,6 +403,8 @@ void eListbox::updateScrollBar() m_scrollbar->setStartEnd(start, start + vis); } } + if (scrollbarvisible != scrollbarvisibleOld) + recalcSizeAlignment(scrollbarvisible); } int eListbox::getEntryTop() @@ -377,165 +439,102 @@ int eListbox::event(int event, void *data, void *data2) return 0; gPainter &painter = *(gPainter *)data2; + gRegion entryRect; m_content->cursorSave(); - gRegion entryRect = m_orientation == orVertical ? eRect(0, 0, size().width(), m_itemheight) : eRect(0, 0, m_itemwidth, size().height()); if (m_orientation == orVertical) m_content->cursorMove(m_top - m_selected); else if (m_orientation == orHorizontal) m_content->cursorMove(m_left - m_selected); else - { m_content->cursorMove((m_max_columns * m_top) - m_selected); - entryRect = eRect(0, 0, m_itemwidth, m_itemheight); - } const gRegion &paint_region = *(gRegion *)data; - int xOffset = 0; - int yOffset = 0; - if (m_scrollbar) + if (!isTransparent()) { - if (m_scrollbar_mode == showLeftOnDemand || m_scrollbar_mode == showLeftAlways) - { - xOffset = m_scrollbar->size().width() + m_scrollbar_offset; - } - - if (m_scrollbar_mode == showTopOnDemand || m_scrollbar_mode == showTopAlways) + painter.clip(paint_region); + style->setStyle(painter, eWindowStyle::styleListboxNormal); + if (m_style.is_set.spacer_color) + painter.setBackgroundColor(m_style.m_spacer_color); + else { - yOffset = m_scrollbar->size().height() + m_scrollbar_offset; + if (m_style.is_set.background_color) + painter.setBackgroundColor(m_style.m_background_color); } + painter.clear(); + painter.clippop(); } - int itemOffset = 0; - if (m_orientation == orGrid) - { - style->setStyle(painter, eWindowStyle::styleListboxNormal); - painter.clear(); - if (m_item_alignment != itemAlignDefault) + int line = 0; + int m_max_items = m_orientation == orGrid ? m_max_columns * m_max_rows : m_orientation == orHorizontal ? m_max_columns + : m_max_rows; + + + + for (int posx = 0, posy = 0, i = 0; (m_orientation == orVertical) ? i <= m_max_items : i < m_max_items; posx += m_itemwidth + m_spacing.x(), ++i) + { + if (m_orientation == orGrid && i > 0) { - int fullSpace = size().width() - ((m_scrollbar) ? m_scrollbar->size().width() + m_scrollbar_offset : 0); - int itemSpace = m_max_columns * m_itemwidth; - if (fullSpace > itemSpace) + if (i % m_max_columns == 0) { - if (m_item_alignment == itemAlignCenter) - { - xOffset = (fullSpace - itemSpace) / 2; - } - else if (m_item_alignment == itemAlignJustify && m_max_columns > 1) - { - itemOffset = (fullSpace - itemSpace) / (m_max_columns - 1); - } + posy += m_itemheight + m_spacing.y(); + posx = 0; } } - } - - int line = 0; + if (m_orientation == orVertical) + { + posx = 0; + if (i > 0) + posy += m_itemheight + m_spacing.y(); + } - if (m_orientation == orVertical) - { + bool sel = (m_selected == m_content->cursorGet() && m_content->size() && m_selection_enabled); - for (int y = 0, i = 0; i <= m_max_rows; y += m_itemheight, ++i) - { - gRegion entry_clip_rect = paint_region & entryRect; + if (sel) + line = m_orientation == orGrid ? (i / m_max_columns) : i; - bool sel = (m_selected == m_content->cursorGet() && m_content->size() && m_selection_enabled); + entryRect = eRect(posx + xOffset, posy + yOffset, m_itemwidth * m_style.m_selection_zoom, m_itemheight * m_style.m_selection_zoom); + gRegion entry_clip_rect = paint_region & entryRect; - if (sel) - line = i; + if (!entry_clip_rect.empty()) + { + if (m_orientation != orVertical && m_content->cursorValid()) + { + int t = m_orientation == orGrid ? (m_top * m_max_columns) : m_top; + if (i != (m_selected - t) || !m_selection_enabled) + m_content->paint(painter, *style, ePoint(posx + xOffset, posy + yOffset), 0); + } + else if (m_orientation == orVertical) + m_content->paint(painter, *style, ePoint(posx + xOffset, posy + yOffset), sel); - if (!entry_clip_rect.empty()) - m_content->paint(painter, *style, ePoint(xOffset, y), sel); #ifdef USE_LIBVUGLES2 - if (sel) + if (sel && m_orientation == orVertical) { ePoint pos = getAbsolutePosition(); - painter.sendShowItem(m_dir, ePoint(pos.x(), pos.y() + y), eSize(m_scrollbar && m_scrollbar->isVisible() ? size().width() - m_scrollbar->size().width() : size().width(), m_itemheight)); - gles_set_animation_listbox_current(pos.x(), pos.y() + y, m_scrollbar && m_scrollbar->isVisible() ? size().width() - m_scrollbar->size().width() : size().width(), m_itemheight); + painter.sendShowItem(m_dir, ePoint(pos.x() + xOffset, pos.y() + posy + yOffset), eSize(m_scrollbar && m_scrollbar->isVisible() ? size().width() - m_scrollbar->size().width() : size().width(), m_itemheight)); + gles_set_animation_listbox_current(pos.x() + xOffset, pos.y() + posy + yOffset, m_scrollbar && m_scrollbar->isVisible() ? size().width() - m_scrollbar->size().width() : size().width(), m_itemheight); m_dir = justCheck; } #endif - /* (we could clip with entry_clip_rect, but - this shouldn't change the behavior of any - well behaving content, so it would just - degrade performance without any gain.) */ - - m_content->cursorMove(+1); - entryRect.moveBy(ePoint(0, m_itemheight)); } - } - - if (m_orientation == orHorizontal) - { - - for (int x = 0, i = 0; i <= m_max_columns; x += m_itemwidth, ++i) - { - gRegion entry_clip_rect = paint_region & entryRect; - - bool sel = (m_selected == m_content->cursorGet() && m_content->size() && m_selection_enabled); - if (sel) - line = i; - - if (!entry_clip_rect.empty()) - m_content->paint(painter, *style, ePoint(x, yOffset), sel); - - /* (we could clip with entry_clip_rect, but - this shouldn't change the behavior of any - well behaving content, so it would just - degrade performance without any gain.) */ - - m_content->cursorMove(+1); - entryRect.moveBy(ePoint(m_itemwidth, 0)); - } + m_content->cursorMove(+1); } - if (m_orientation == orGrid) - { - int i = 0; - int l = 0; - int m_max_items = m_max_columns * m_max_rows; - for (int y = 0; y < m_max_rows; y++) - { - for (int x = 0; x < m_max_columns; x++) - { - - int leftOffset = (itemOffset > 0) ? (itemOffset * x) : xOffset; - - gRegion entry_clip_rect = paint_region & entryRect; - - // This is a workaround because there is a bug in gRegion intersect - bool paint = !entry_clip_rect.empty(); - if (!paint) - { - paint = (paint_region.extends.height() >= (entryRect.extends.y() + entryRect.extends.height())); - } - - bool sel = (m_selected == m_content->cursorGet() && m_content->size() && m_selection_enabled); - - if (sel) - line = l; - - if (paint) - m_content->paint(painter, *style, ePoint(leftOffset + (x * m_itemwidth), y * m_itemheight), sel); - - m_content->cursorMove(+1); - entryRect.moveBy(ePoint(m_itemwidth, 0)); - ++i; - if (i > m_max_items) - break; - } - l++; + m_content->cursorSaveLine(line); + m_content->cursorRestore(); - entryRect.moveBy(ePoint(0, m_itemheight)); - entryRect.extends.setX(0); - entryRect.extends.setWidth(m_itemwidth); - } + // draw selected item last for horizontal/grid orientations + if (m_selected == m_content->cursorGet() && m_content->size() && m_selection_enabled && m_orientation != orVertical) + { + if (m_content) + m_content->paint(painter, *style, getItemPostion(m_selected), 1); } // clear/repaint empty/unused space between scrollbar and listbox entries - if (m_scrollbar) + if (m_scrollbar && !isTransparent()) { if (m_scrollbar_mode == showLeftOnDemand || m_scrollbar_mode == showLeftAlways) { @@ -548,6 +547,14 @@ int eListbox::event(int event, void *data, void *data2) { painter.clip(eRect(m_scrollbar->position(), eSize(m_scrollbar->size().width() + m_scrollbar_offset, m_scrollbar->size().height()))); } + + if (m_style.is_set.spacer_color) + painter.setBackgroundColor(m_style.m_spacer_color); + else + { + if (m_style.is_set.background_color) + painter.setBackgroundColor(m_style.m_background_color); + } painter.clear(); painter.clippop(); } @@ -562,6 +569,13 @@ int eListbox::event(int event, void *data, void *data2) { painter.clip(eRect(m_scrollbar->position(), eSize(m_scrollbar->size().width(), m_scrollbar->size().height() + m_scrollbar_offset))); } + if (m_style.is_set.spacer_color) + painter.setBackgroundColor(m_style.m_spacer_color); + else + { + if (m_style.is_set.background_color) + painter.setBackgroundColor(m_style.m_background_color); + } painter.clear(); painter.clippop(); } @@ -576,14 +590,18 @@ int eListbox::event(int event, void *data, void *data2) { painter.clip(eRect(m_scrollbar->position() - ePoint(m_scrollbar_offset, 0), eSize(m_scrollbar_offset, m_scrollbar->size().height()))); } + if (m_style.is_set.spacer_color) + painter.setBackgroundColor(m_style.m_spacer_color); + else + { + if (m_style.is_set.background_color) + painter.setBackgroundColor(m_style.m_background_color); + } painter.clear(); painter.clippop(); } } - m_content->cursorSaveLine(line); - m_content->cursorRestore(); - return 0; } @@ -609,23 +627,62 @@ void eListbox::recalcSize() m_prev_scrollbar_page = -1; if (m_orientation == orVertical) { + m_itemwidth_set = false; // reset m_itemwidth + if (size().width() > -1) + m_itemwidth = size().width(); if (m_content) - m_content->setSize(eSize(size().width(), m_itemheight)); - m_max_rows = size().height() / m_itemheight; + m_content->setSize(eSize(m_itemwidth, m_itemheight)); + m_max_rows = (size().height() - m_spacing.y() * 2) / (m_itemheight + m_spacing.y() * 2); } else if (m_orientation == orHorizontal) { + if (size().height() > -1 && !m_itemheight_set) + { + m_style.m_selection_zoom = 1.0; + m_itemheight = size().height(); + } if (m_content) - m_content->setSize(eSize(m_itemwidth, size().height())); - m_max_columns = size().width() / m_itemwidth; + m_content->setSize(eSize(m_itemwidth, m_itemheight)); + int w = size().width() - m_spacing.x(); + m_max_columns = w / (m_itemwidth + m_spacing.x()); + if(m_style.m_selection_zoom > 1.0) + { + int item_w_zoom = (m_itemwidth * m_style.m_selection_zoom) + m_spacing.x(); + if (m_max_columns > 1) { + if(w < (item_w_zoom + (m_max_columns - 1) * (m_itemwidth + m_spacing.x()))) + m_max_columns --; + } + } } else { if (m_content) m_content->setSize(eSize(m_itemwidth, m_itemheight)); - m_max_columns = size().width() / m_itemwidth; - m_max_rows = size().height() / m_itemheight; + int w = size().width() - m_spacing.x(); + int h = size().height() - m_spacing.y(); + + m_max_columns = w / (m_itemwidth + m_spacing.x()); + m_max_rows = h / (m_itemheight + m_spacing.y()); + + if (m_style.m_selection_zoom > 1.0) + { + + int item_w_zoom = (m_itemwidth * m_style.m_selection_zoom) + m_spacing.x(); + int item_h_zoom = (m_itemheight * m_style.m_selection_zoom) + m_spacing.y(); + + if (m_max_columns > 1) + { + if (w < (item_w_zoom + (m_max_columns - 1) * (m_itemwidth + m_spacing.x()))) + m_max_columns--; + } + + if (m_max_rows > 1) + { + if (h < (item_h_zoom + (m_max_rows - 1) * (m_itemheight + m_spacing.y()))) + m_max_rows--; + } + } } /* TODO: whyever - our size could be invalid, or itemheigh could be wrongly specified. */ @@ -634,25 +691,78 @@ void eListbox::recalcSize() if (m_max_rows < 0) m_max_rows = 0; + if (m_content) + { + bool scrollbarVisible = m_scrollbar && m_scrollbar->isVisible(); + recalcSizeAlignment(scrollbarVisible); + } + + moveSelection(justCheck); } +void eListbox::recalcSizeAlignment(bool scrollbarVisible) +{ + + if (m_orientation != orVertical && m_item_alignment != itemAlignDefault) + { + + int xscrollBar = (m_orientation == orGrid) ? ((scrollbarVisible) ? m_scrollbar->size().width() + m_scrollbar_offset : 0) : 0; + int yscrollBar = (m_orientation == orHorizontal) ? ((scrollbarVisible) ? m_scrollbar->size().height() + m_scrollbar_offset : 0) : 0; + int xfullSpace = size().width() - xscrollBar; + int yfullSpace = size().height() - yscrollBar; + int xitemSpace = (m_max_columns > 1) ? ((m_max_columns - 1) * (m_itemwidth + m_spacing.x()) + m_itemwidth * m_style.m_selection_zoom) : (m_itemwidth * m_style.m_selection_zoom) + m_spacing.x(); + int yitemSpace = (m_max_rows > 1) ? ((m_max_rows - 1) * (m_itemheight + m_spacing.y()) + m_itemheight * m_style.m_selection_zoom) : (m_itemheight * m_style.m_selection_zoom) + m_spacing.y(); + + + int scrollbarLeftSpace = (m_scrollbar_mode == showLeftOnDemand || m_scrollbar_mode == showLeftAlways) ? xscrollBar : 0; + int scrollbarTopSpace = (m_scrollbar_mode == showTopOnDemand || m_scrollbar_mode == showTopAlways) ? yscrollBar : 0; + + if (xfullSpace > xitemSpace) + { + if (m_item_alignment & itemHorizontalAlignCenter) + xOffset = ((xfullSpace - xitemSpace) / 2) + scrollbarLeftSpace; + } + if (yfullSpace > yitemSpace) + { + if (m_item_alignment & itemVertialAlignMiddle) + yOffset = ((yfullSpace - yitemSpace) / 2) + scrollbarTopSpace; + } + } + + if (m_scrollbar && m_orientation == orVertical) + { + if (m_scrollbar_mode == showLeftOnDemand || m_scrollbar_mode == showLeftAlways) + { + xOffset = m_scrollbar->size().width() + m_scrollbar_offset; + } + + if (m_scrollbar_mode == showTopOnDemand || m_scrollbar_mode == showTopAlways) + { + yOffset = m_scrollbar->size().height() + m_scrollbar_offset; + } + } +} + void eListbox::setItemHeight(int h) { - if (h) + if (h && m_itemheight != h) + { m_itemheight = h; - else - m_itemheight = 20; // TODO : why 20 - recalcSize(); + m_itemheight_set = true; + recalcSize(); + } } void eListbox::setItemWidth(int w) { - if (w) + if (w && m_itemwidth != w) + { + eDebug("[eListbox] DO setItemWidth %d", w); m_itemwidth = w; - else - m_itemwidth = 20; // TODO : why 20 - recalcSize(); + m_itemwidth_set = true; + recalcSize(); + } } void eListbox::setSelectionEnable(int en) @@ -775,29 +885,8 @@ void eListbox::entryRemoved(int index) void eListbox::entryChanged(int index) { - if (m_orientation == orVertical) - { - if ((m_top <= index) && (index < (m_top + m_max_rows))) - { - gRegion inv = eRect(0, m_itemheight * (index - m_top), size().width(), m_itemheight); - invalidate(inv); - } - } - else if (m_orientation == orHorizontal) - { - if ((m_left <= index) && (index < (m_left + m_max_columns))) - { - gRegion inv = eRect(m_itemwidth * (index - m_left), 0, m_itemwidth, size().height()); - invalidate(inv); - } - } - else - { - int col = index % m_max_columns; - int row = index / m_max_rows; - gRegion inv = eRect(col * m_itemwidth, row * m_itemheight, m_itemwidth, m_itemheight); - invalidate(inv); - } + gRegion inv = eRect(getItemPostion(index), eSize(m_itemwidth, m_itemheight)); + invalidate(inv); } void eListbox::entryReset(bool selectionHome) @@ -836,28 +925,34 @@ void eListbox::entryReset(bool selectionHome) invalidate(); } +void eListbox::setSpacerColor(gRGB &col) +{ + m_style.m_spacer_color = col; + m_style.is_set.spacer_color = 1; +} + void eListbox::setBackgroundColor(gRGB &col) { m_style.m_background_color = col; - m_style.m_background_color_set = 1; + m_style.is_set.background_color = 1; } void eListbox::setBackgroundColorSelected(gRGB &col) { m_style.m_background_color_selected = col; - m_style.m_background_color_selected_set = 1; + m_style.is_set.background_color_selected = 1; } void eListbox::setForegroundColor(gRGB &col) { m_style.m_foreground_color = col; - m_style.m_foreground_color_set = 1; + m_style.is_set.foreground_color = 1; } void eListbox::setForegroundColorSelected(gRGB &col) { m_style.m_foreground_color_selected = col; - m_style.m_foreground_color_selected_set = 1; + m_style.is_set.foreground_color_selected = 1; } void eListbox::setBorderWidth(int size) @@ -870,7 +965,7 @@ void eListbox::setBorderWidth(int size) void eListbox::setScrollbarBorderWidth(int width) { m_style.m_scrollbarborder_width = width; - m_style.m_scrollbarborder_width_set = 1; + m_style.is_set.scrollbarborder_width = 1; if (m_scrollbar) m_scrollbar->setBorderWidth(width); } @@ -885,7 +980,7 @@ void eListbox::setScrollbarForegroundPixmap(ePtr &pm) void eListbox::setScrollbarBackgroundColor(gRGB &col) { m_style.m_scrollbarbackground_color = col; - m_style.m_scrollbarbackground_color_set = 1; + m_style.is_set.scrollbarbackground_color = 1; if (m_scrollbar) m_scrollbar->setBackgroundColor(col); } @@ -893,7 +988,7 @@ void eListbox::setScrollbarBackgroundColor(gRGB &col) void eListbox::setScrollbarForegroundColor(gRGB &col) { m_style.m_scrollbarforeground_color = col; - m_style.m_scrollbarforeground_color_set = 1; + m_style.is_set.scrollbarforeground_color = 1; if (m_scrollbar) m_scrollbar->setForegroundColor(col); } @@ -901,7 +996,7 @@ void eListbox::setScrollbarForegroundColor(gRGB &col) void eListbox::setScrollbarBorderColor(const gRGB &col) { m_style.m_scollbarborder_color = col; - m_style.m_scollbarborder_color_set = 1; + m_style.is_set.scollbarborder_color = 1; if (m_scrollbar) m_scrollbar->setBorderColor(col); } @@ -933,27 +1028,76 @@ void eListbox::invalidate(const gRegion ®ion) struct eListboxStyle *eListbox::getLocalStyle(void) { /* transparency is set directly in the widget */ - m_style.m_transparent_background = isTransparent(); + m_style.is_set.transparent_background = isTransparent(); return &m_style; } void eListbox::setOrientation(int newOrentation) { - if (m_orientation != newOrentation && m_scrollbar) + if (m_orientation != newOrentation) { - if (newOrentation == orHorizontal) - { - m_scrollbar->setOrientation(eSlider::orHorizontal); - } - else + if (m_scrollbar) { - m_scrollbar->setOrientation(eSlider::orVertical); + if (newOrentation == orHorizontal) + { + m_scrollbar->setOrientation(eSlider::orHorizontal); + } + else + { + m_scrollbar->setOrientation(eSlider::orVertical); + } } + m_orientation = newOrentation; + recalcSize(); } - m_orientation = newOrentation; invalidate(); } +void eListbox::setItemSpacing(const ePoint &spacing, bool innerOnly) +{ + if ((spacing.x() >= 0 && spacing.y() >= 0)) + { + m_spacing = spacing; + m_spacing_innerOnly = innerOnly; + recalcSize(); + invalidate(); + } +} + +void eListbox::setFont(gFont *font) +{ + m_style.m_font = font; + if (m_style.m_selection_zoom > 1.0) + m_style.m_font_zoomed = new gFont(m_style.m_font->family, m_style.m_font->pointSize * m_style.m_selection_zoom); +} + +void eListbox::setSelectionZoom(float zoom) +{ + if (zoom > 1.0) + { + m_style.m_selection_zoom = zoom; + if (m_style.m_font) + m_style.m_font_zoomed = new gFont(m_style.m_font->family, m_style.m_font->pointSize * zoom); + recalcSize(); + invalidate(); + } +} + +ePoint eListbox::getItemPostion(int index) +{ + int posx = 0, posy = 0; + ePoint indexSpacing = (index > 0) ? m_spacing : ePoint(0, 0); + if (m_orientation == orGrid || m_orientation == orHorizontal) + { + posx = (m_orientation == orGrid) ? (m_itemwidth + indexSpacing.x()) * ((index - (m_top * m_max_columns)) % m_max_columns) : (m_itemwidth + indexSpacing.x()) * (index - m_left); + posy = (m_orientation == orGrid) ? (m_itemheight + indexSpacing.y()) * ((index - (m_top * m_max_columns)) / m_max_columns) : 0; + } + else + posy = (m_itemheight + indexSpacing.y()) * (index - m_top); + + return ePoint(posx + xOffset, posy + yOffset); +} + void eListbox::moveSelection(int dir) { /* refuse to do anything without a valid list. */ @@ -1050,18 +1194,19 @@ void eListbox::moveSelection(int dir) case moveUp: if (isGrid && dir != moveBottom) { + int newColumn = -1; do { if (oldRow == 0 && m_enabled_wrap_around) { m_content->cursorEnd(); - int newColumn = -1; do { m_content->cursorMove(-1); newSel = m_content->cursorGet(); newColumn = newSel % m_max_columns; } while (oldColumn != newColumn); + if (m_content->currentCursorSelectable()) break; } @@ -1134,7 +1279,7 @@ void eListbox::moveSelection(int dir) do { - bool wrap = (oldRow == (m_max_rows - 1)) || (oldSel + m_max_columns >= m_content->size()); + bool wrap = (oldSel + m_max_columns) >= m_content->size(); if (wrap && m_enabled_wrap_around) { m_content->cursorHome(); @@ -1305,8 +1450,8 @@ void eListbox::moveSelection(int dir) else if (m_selected != oldSel) { /* redraw the old and newly selected */ - gRegion inv = eRect(m_itemwidth * (m_selected - m_left), 0, m_itemwidth, size().height()); - inv |= eRect(m_itemwidth * (oldSel - m_left), 0, m_itemwidth, size().height()); + gRegion inv = eRect(getItemPostion(m_selected), eSize((m_itemwidth * m_style.m_selection_zoom), (m_itemheight * m_style.m_selection_zoom))); + inv |= eRect(getItemPostion(oldSel), eSize((m_itemwidth * m_style.m_selection_zoom), (m_itemheight * m_style.m_selection_zoom))); invalidate(inv); } } @@ -1318,21 +1463,9 @@ void eListbox::moveSelection(int dir) } else if (m_selected != oldSel) { - if (m_orientation == orGrid) - { - // TODO: - // gRegion inv = eRect(0, m_itemheight * m_top, m_itemwidth, m_itemheight); - // inv |= eRect(0, m_itemheight * (oldSel - m_top), m_itemwidth, m_itemheight); - // invalidate(inv); - invalidate(); - } - else - { - /* redraw the old and newly selected */ - gRegion inv = eRect(0, m_itemheight * (m_selected - m_top), size().width(), m_itemheight); - inv |= eRect(0, m_itemheight * (oldSel - m_top), size().width(), m_itemheight); - invalidate(inv); - } + gRegion inv = eRect(getItemPostion(m_selected), eSize((m_itemwidth * m_style.m_selection_zoom), (m_itemheight * m_style.m_selection_zoom))); + inv |= eRect(getItemPostion(oldSel), eSize((m_itemwidth * m_style.m_selection_zoom), (m_itemheight * m_style.m_selection_zoom))); + invalidate(inv); } } } @@ -1350,10 +1483,12 @@ int eListbox::moveSelectionLineMode(bool doUp, bool doDown, int dir, int oldSel, return 0; } int newlinecalc = (m_selected / m_max_columns) - oldTopLeft; - if (doUp && m_enabled_wrap_around && oldSel == 0) + + if (doUp && m_enabled_wrap_around && oldLine == 0) { - return newline - m_max_rows + 1; + return ((m_content->size() - 1) / m_max_columns) - m_max_rows + 1; } + if (doUp) { if ((oldLine > 0 && oldTopLeft > 0) || (newlinecalc > 0)) diff --git a/lib/gui/elistbox.h b/lib/gui/elistbox.h index 1d89f22e311..42903036cc7 100644 --- a/lib/gui/elistbox.h +++ b/lib/gui/elistbox.h @@ -61,16 +61,37 @@ class iListboxContent : public iObject }; #ifndef SWIG +struct eListboxStyleSetted +{ + bool transparent_background : 1; + bool border : 1; + bool background_color : 1; + bool foreground_color : 1; + bool background_color_selected : 1; + bool foreground_color_selected : 1; + bool scrollbarforeground_color : 1; + bool scrollbarbackground_color : 1; + bool scollbarborder_color : 1; + bool scrollbarborder_width : 1; + bool spacer_color : 1; + bool overlay : 1; + bool max_rows : 1; + bool max_columns : 1; + bool use_vti_workaround : 1; +}; + struct eListboxStyle { - ePtr m_background, m_selection; - int m_transparent_background; - int m_border_set; - gRGB m_background_color, m_background_color_selected, - m_foreground_color, m_foreground_color_selected, m_border_color, m_scollbarborder_color, m_scrollbarforeground_color, m_scrollbarbackground_color; - int m_background_color_set, m_foreground_color_set, m_background_color_selected_set, m_foreground_color_selected_set, m_scrollbarforeground_color_set, m_scrollbarbackground_color_set, m_scollbarborder_color_set, m_scrollbarborder_width_set; + ePtr m_background, m_selection, m_overlay; + gRGB m_background_color, m_background_color_selected, m_foreground_color, m_foreground_color_selected, m_border_color, m_scollbarborder_color, m_scrollbarforeground_color, m_scrollbarbackground_color, m_spacer_color; + int m_max_columns; + int m_max_rows; + float m_selection_zoom; + + eListboxStyleSetted is_set; + /* - {m_transparent_background m_background_color_set m_background} + {transparent_background background_color background} {0 0 0} use global background color {0 1 x} use background color {0 0 p} use background picture @@ -88,9 +109,8 @@ struct eListboxStyle alignBlock }; int m_valign, m_halign, m_border_size, m_scrollbarborder_width; - ePtr m_font, m_valuefont; + ePtr m_font, m_font_zoomed, m_valuefont; eRect m_text_padding; - bool m_use_vti_workaround; }; #endif @@ -137,11 +157,40 @@ class eListbox : public eWidget orHorizontal = 2, orGrid = 3 }; + + enum + { + itemVertialAlignTop = 1 << 0, + itemVertialAlignMiddle = 1 << 1, + itemVertialAlignBottom = 1 << 2, + itemVertialAlignJustify = 1 << 3, + itemHorizontalAlignLeft = 1 << 4, + itemHorizontalAlignCenter = 1 << 5, + itemHorizontalAlignRight = 1 << 6, + itemHorizontalAlignJustify = 1 << 7, + }; + enum { - itemAlignDefault, - itemAlignCenter, - itemAlignJustify + itemAlignLeftTop = itemVertialAlignTop + itemHorizontalAlignLeft, + itemAlignLeftMiddle = itemVertialAlignMiddle + itemHorizontalAlignLeft, + itemAlignLeftBottom = itemVertialAlignBottom + itemHorizontalAlignLeft, + itemAlignRightTop = itemVertialAlignTop + itemHorizontalAlignRight, + itemAlignRightMiddle = itemVertialAlignMiddle + itemHorizontalAlignRight, + itemAlignRightBottom = itemVertialAlignBottom + itemHorizontalAlignRight, + itemAlignCenterTop = itemVertialAlignTop + itemHorizontalAlignCenter, + itemAlignCenterMiddle = itemVertialAlignMiddle + itemHorizontalAlignCenter, + itemAlignCenterBottom = itemVertialAlignBottom + itemHorizontalAlignCenter, + itemAlignJustifyTop = itemVertialAlignTop + itemHorizontalAlignJustify, + itemAlignJustifyMiddle = itemVertialAlignMiddle + itemHorizontalAlignJustify, + itemAlignJustifyBottom = itemVertialAlignBottom + itemHorizontalAlignJustify, + itemAlignJustifyLeft = itemVertialAlignJustify + itemHorizontalAlignLeft, + itemAlignJustifyRight = itemVertialAlignJustify + itemHorizontalAlignRight, + itemAlignJustifyFull = itemVertialAlignJustify + itemHorizontalAlignJustify, + + itemAlignDefault = itemAlignLeftTop, + itemAlignCenter = itemAlignCenterMiddle, + itemAlignJustify = itemAlignJustifyFull }; void setItemAlignment(int align); @@ -207,17 +256,20 @@ class eListbox : public eWidget void setForegroundColor(gRGB &col); void setForegroundColorSelected(gRGB &col); - void clearBackgroundColor() { m_style.m_background_color_set = 0; } - void clearBackgroundColorSelected() { m_style.m_background_color_selected_set = 0; } - void clearForegroundColor() { m_style.m_foreground_color_set = 0; } - void clearForegroundColorSelected() { m_style.m_foreground_color_selected_set = 0; } + void setSpacerColor(gRGB &col); + void clearSpacerColor() { m_style.is_set.spacer_color = 0; } + + void clearBackgroundColor() { m_style.is_set.background_color = 0; } + void clearBackgroundColorSelected() { m_style.is_set.background_color_selected = 0; } + void clearForegroundColor() { m_style.is_set.foreground_color = 0; } + void clearForegroundColorSelected() { m_style.is_set.foreground_color_selected = 0; } void setBorderColor(const gRGB &col) { m_style.m_border_color = col; } void setBorderWidth(int size); void setBackgroundPixmap(ePtr &pm) { m_style.m_background = pm; } void setSelectionPixmap(ePtr &pm) { m_style.m_selection = pm; } - void setSelectionBorderHidden() { m_style.m_border_set = 1; } + void setSelectionBorderHidden() { m_style.is_set.border = 1; } void setScrollbarForegroundPixmap(ePtr &pm); void setScrollbarBackgroundPixmap(ePtr &pm); @@ -226,19 +278,27 @@ class eListbox : public eWidget void setScrollbarWidth(int size) { m_scrollbar_width = size; } void setScrollbarHeight(int size) { m_scrollbar_height = size; } void setScrollbarOffset(int size) { m_scrollbar_offset = size; } + void setScrollbarLength(int size) { m_scrollbar_length = size; } - void setFont(gFont *font) { m_style.m_font = font; } + void setFont(gFont *font); void setEntryFont(gFont *font) { m_style.m_font = font; } void setValueFont(gFont *font) { m_style.m_valuefont = font; } void setVAlign(int align) { m_style.m_valign = align; } void setHAlign(int align) { m_style.m_halign = align; } void setTextPadding(const eRect &padding) { m_style.m_text_padding = padding; } - void setUseVTIWorkaround(void) { m_style.m_use_vti_workaround = 1; } + void setUseVTIWorkaround(void) { m_style.is_set.use_vti_workaround = 1; } void setScrollbarBorderColor(const gRGB &col); void setScrollbarForegroundColor(gRGB &col); void setScrollbarBackgroundColor(gRGB &col); + void setMaxRows(int rows) {m_style.m_max_rows = rows; m_style.is_set.max_rows = 1;}; + void setMaxColumns(int columns) {m_style.m_max_columns = columns; m_style.is_set.max_columns = 1;}; + void setItemSpacing(const ePoint &spacing, bool innerOnly=false); + void setSelectionZoom(float zoom); + + void setOverlay(ePtr &pm) { m_style.m_overlay = pm; m_style.is_set.overlay = 1; } + void setPageSize(int size) { m_page_size = size; } static void setDefaultScrollbarStyle(int width, int offset, int borderwidth, int scroll, int mode, bool enablewraparound, int pageSize) @@ -294,7 +354,11 @@ class eListbox : public eWidget void recalcSize(); private: + ePoint getItemPostion(int index); int moveSelectionLineMode(bool doUp, bool doDown, int dir, int oldSel, int oldTopLeft, int maxItems, bool indexChanged, int pageOffset, int topLeft); + void recalcSizeAlignment(bool scrollbarVisible); + int setScrollbarPosition(); + static int defaultScrollBarWidth; static int defaultScrollBarOffset; static int defaultScrollBarBorderWidth; @@ -307,9 +371,12 @@ class eListbox : public eWidget int m_scrollbar_mode, m_prev_scrollbar_page, m_scrollbar_scroll; bool m_content_changed; bool m_enabled_wrap_around; + bool m_itemwidth_set; + bool m_itemheight_set; int m_scrollbar_width; int m_scrollbar_height; + int m_scrollbar_length; int m_scrollbar_offset; int m_scrollbar_border_width; int m_top, m_left, m_selected; @@ -321,11 +388,16 @@ class eListbox : public eWidget int m_selection_enabled; int m_page_size; int m_item_alignment; + int xOffset; + int yOffset; bool m_native_keys_bound; int m_first_selectable_item; int m_last_selectable_item; + int m_scrollbar_calcsize; + ePoint m_spacing; + bool m_spacing_innerOnly; ePtr m_content; eSlider *m_scrollbar; eListboxStyle m_style; diff --git a/lib/gui/elistboxcontent.cpp b/lib/gui/elistboxcontent.cpp index cd7bb573e0d..40731a8e2aa 100644 --- a/lib/gui/elistboxcontent.cpp +++ b/lib/gui/elistboxcontent.cpp @@ -43,9 +43,9 @@ iListboxContent::iListboxContent() : m_listbox(0) void iListboxContent::setListbox(eListbox *lb) { m_listbox = lb; + m_listbox->setOrientation(getOrientation()); m_listbox->setItemHeight(getItemHeight()); m_listbox->setItemWidth(getItemWidth()); - m_listbox->setOrientation(getOrientation()); } int iListboxContent::currentCursorSelectable() @@ -157,13 +157,14 @@ void eListboxPythonStringContent::setSize(const eSize &size) void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected) { ePtr fnt; - painter.clip(eRect(offset, m_itemsize)); - style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal); bool validitem = (m_list && cursorValid()); eListboxStyle *local_style = 0; bool cursorValid = this->cursorValid(); + bool itemZoomed; gRGB border_color; int border_size = 0; + ePoint offs = offset; + eRect itemRect(offset, m_itemsize); /* get local listbox style, if present */ if (m_listbox) @@ -173,45 +174,73 @@ void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, { border_size = local_style->m_border_size; border_color = local_style->m_border_color; - fnt = local_style->m_font; + itemZoomed = local_style->m_selection_zoom > 1.0; + + if (selected && itemZoomed) + fnt = local_style->m_font_zoomed; + else + fnt = local_style->m_font; + + if (selected && itemZoomed) + itemRect = eRect(offs, eSize(m_itemsize.width() * local_style->m_selection_zoom, m_itemsize.height() * local_style->m_selection_zoom)); + else if (!selected && itemZoomed) + { + offs = ePoint(offset.x() + (((m_itemsize.width() * local_style->m_selection_zoom) - m_itemsize.width()) / 2), offset.y() + (((m_itemsize.height() * local_style->m_selection_zoom) - m_itemsize.height()) / 2)); + itemRect = eRect(offs, m_itemsize); + } + painter.clip(itemRect); + style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal); + if (selected) { /* if we have a local background color set, use that. */ - if (local_style->m_background_color_selected_set) + if (local_style->is_set.background_color_selected) painter.setBackgroundColor(local_style->m_background_color_selected); /* same for foreground */ - if (local_style->m_foreground_color_selected_set) + if (local_style->is_set.foreground_color_selected) painter.setForegroundColor(local_style->m_foreground_color_selected); } else { /* if we have a local background color set, use that. */ - if (local_style->m_background_color_set) + if (local_style->is_set.background_color) painter.setBackgroundColor(local_style->m_background_color); /* same for foreground */ - if (local_style->m_foreground_color_set) + if (local_style->is_set.foreground_color) painter.setForegroundColor(local_style->m_foreground_color); } } + else + { + painter.clip(itemRect); + style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal); + } + if (!fnt) { style.getFont(eWindowStyle::fontListbox, fnt); + if (selected && local_style && local_style->m_selection_zoom > 1.0) + { + if(fnt) + m_font_zoomed = new gFont(fnt->family, fnt->pointSize * local_style->m_selection_zoom); + fnt = m_font_zoomed; + } } int orientation = (m_listbox) ? m_listbox->getOrientation() : 1; /* if we have no transparent background */ - if (!local_style || !local_style->m_transparent_background) + if (!local_style || !local_style->is_set.transparent_background) { /* blit background picture, if available (otherwise, clear only) */ if (local_style && local_style->m_background && cursorValid) { if (validitem) { - int x = offset.x(); - int y = offset.y(); - x += (orientation & 2) ? (m_itemsize.width() - local_style->m_background->size().width()) / 2 : 0; // vertical - y += (orientation & 1) ? (m_itemsize.height() - local_style->m_background->size().height()) / 2 : 0; // horizontal + int x = offs.x(); + int y = offs.y(); + x += (orientation & 2) ? (itemRect.width() - local_style->m_background->size().width()) / 2 : 0; // vertical + y += (orientation & 1) ? (itemRect.height() - local_style->m_background->size().height()) / 2 : 0; // horizontal painter.blit(local_style->m_background, ePoint(x, y), eRect(), 0); } } @@ -224,10 +253,10 @@ void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, { if (validitem) { - int x = offset.x(); - int y = offset.y(); - x += (orientation & 2) ? (m_itemsize.width() - local_style->m_background->size().width()) / 2 : 0; // vertical - y += (orientation & 1) ? (m_itemsize.height() - local_style->m_background->size().height()) / 2 : 0; // horizontal + int x = offs.x(); + int y = offs.y(); + x += (orientation & 2) ? (itemRect.width() - local_style->m_background->size().width()) / 2 : 0; // vertical + y += (orientation & 1) ? (itemRect.height() - local_style->m_background->size().height()) / 2 : 0; // horizontal painter.blit(local_style->m_background, ePoint(x, y), eRect(), gPainter::BT_ALPHATEST); } } @@ -235,8 +264,8 @@ void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, painter.clear(); } // Draw frame here so to be under the content - if (selected && (!local_style || !local_style->m_selection) && (!local_style || !local_style->m_border_set)) - style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry); + if (selected && (!local_style || !local_style->m_selection) && (!local_style || !local_style->is_set.border)) + style.drawFrame(painter, eRect(offs, itemRect.size()), eWindowStyle::frameListboxEntry); if (validitem) { @@ -254,10 +283,10 @@ void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, if (selected && local_style && local_style->m_selection) { - int x = offset.x(); - int y = offset.y(); - x += (orientation & 2) ? (m_itemsize.width() - local_style->m_selection->size().width()) / 2 : 0; // vertical - y += (orientation & 1) ? (m_itemsize.height() - local_style->m_selection->size().height()) / 2 : 0; // horizontal + int x = offs.x(); + int y = offs.y(); + x += (orientation & 2) ? (itemRect.width() - local_style->m_selection->size().width()) / 2 : 0; // vertical + y += (orientation & 1) ? (itemRect.height() - local_style->m_selection->size().height()) / 2 : 0; // horizontal painter.blit(local_style->m_selection, ePoint(x, y), eRect(), gPainter::BT_ALPHATEST); } @@ -265,17 +294,17 @@ void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, { /* Please Note .. this needs to fixed in the navigation code because this separator can be selected as an active element*/ /* seperator */ - int half_height = m_itemsize.height() / 2; - int half_width = m_itemsize.width() / 2; + int half_height = itemRect.height() / 2; + int half_width = itemRect.width() / 2; if (orientation == 1) - painter.fill(eRect(offset.x() + half_height, offset.y() + half_height - 2, m_itemsize.width() - m_itemsize.height(), 4)); + painter.fill(eRect(offs.x() + half_height, offs.y() + half_height - 2, itemRect.width() - itemRect.height(), 4)); if (orientation == 2) - painter.fill(eRect(offset.x() + half_width, offset.y() + half_width - 2, m_itemsize.width() - m_itemsize.height(), 4)); + painter.fill(eRect(offs.x() + half_width, offs.y() + half_width - 2, itemRect.width() - itemRect.height(), 4)); } else { const char *string = PyUnicode_Check(item) ? PyUnicode_AsUTF8(item) : ""; - ePoint text_offset = offset; + ePoint text_offset = offs; if (gray) painter.setForegroundColor(gRGB(0x808080)); @@ -284,7 +313,7 @@ void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, { text_offset += local_style->m_text_padding.topLeft(); // HACK VTI hat hier scheinbar einen Fehler und addiert den Textoffset zweimal auf, also machen wir das hier auch so - if (local_style->m_use_vti_workaround) + if (local_style->is_set.use_vti_workaround) text_offset += local_style->m_text_padding.topLeft(); if (local_style->m_valign == eListboxStyle::alignTop) @@ -308,13 +337,13 @@ void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, int paddingw = local_style->m_text_padding.width(); int paddingh = local_style->m_text_padding.height(); - auto position = eRect(text_offset.x(), text_offset.y(), m_itemsize.width() - (paddingx * 2) - paddingw, m_itemsize.height() - (paddingy * 2) - paddingh); + auto position = eRect(text_offset.x(), text_offset.y(), itemRect.width() - (paddingx * 2) - paddingw, itemRect.height() - (paddingy * 2) - paddingh); painter.renderText(position, string, flags, border_color, border_size); } else { - painter.renderText(eRect(text_offset, m_itemsize), string, flags, border_color, border_size); + painter.renderText(eRect(text_offset, itemRect.size()), string, flags, border_color, border_size); } } } @@ -420,19 +449,19 @@ void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, if (selected) { /* if we have a local background color set, use that. */ - if (local_style->m_background_color_selected_set) + if (local_style->is_set.background_color_selected) painter.setBackgroundColor(local_style->m_background_color_selected); /* same for foreground */ - if (local_style->m_foreground_color_selected_set) + if (local_style->is_set.foreground_color_selected) painter.setForegroundColor(local_style->m_foreground_color_selected); } else { /* if we have a local background color set, use that. */ - if (local_style->m_background_color_set) + if (local_style->is_set.background_color) painter.setBackgroundColor(local_style->m_background_color); /* same for foreground */ - if (local_style->m_foreground_color_set) + if (local_style->is_set.foreground_color) painter.setForegroundColor(local_style->m_foreground_color); } } @@ -445,7 +474,7 @@ void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, int orientation = (m_listbox) ? m_listbox->getOrientation() : 1; - if (!local_style || !local_style->m_transparent_background) + if (!local_style || !local_style->is_set.transparent_background) /* if we have no transparent background */ { /* blit background picture, if available (otherwise, clear only) */ @@ -475,7 +504,7 @@ void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, } // Draw frame here so to be drawn under icons - if (selected && (!local_style || !local_style->m_selection) && (!local_style || !local_style->m_border_set)) + if (selected && (!local_style || !local_style->m_selection) && (!local_style || !local_style->is_set.border)) style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry); if (m_list && cursorValid) { @@ -736,7 +765,7 @@ static void clearRegionHelper(gPainter &painter, eListboxStyle *local_style, con } else if (local_style) { - if (local_style->m_background_color_set) + if (local_style->is_set.background_color) painter.setBackgroundColor(local_style->m_background_color); if (local_style->m_background && cursorValid) { @@ -744,10 +773,10 @@ static void clearRegionHelper(gPainter &painter, eListboxStyle *local_style, con int y = offset.y(); x += (orientation & 2) ? (size.width() - local_style->m_background->size().width()) / 2 : 0; // vertical y += (orientation & 1) ? (size.height() - local_style->m_background->size().height()) / 2 : 0; // horizontal - painter.blit(local_style->m_background, ePoint(x, y), eRect(), local_style->m_transparent_background ? gPainter::BT_ALPHATEST : 0); + painter.blit(local_style->m_background, ePoint(x, y), eRect(), local_style->is_set.transparent_background ? gPainter::BT_ALPHATEST : 0); return; } - else if (local_style->m_transparent_background) + else if (local_style->is_set.transparent_background) return; } if (clear) @@ -763,7 +792,7 @@ static void clearRegionSelectedHelper(gPainter &painter, eListboxStyle *local_st } else if (local_style) { - if (local_style->m_background_color_selected_set) + if (local_style->is_set.background_color_selected) painter.setBackgroundColor(local_style->m_background_color_selected); if (local_style->m_background && cursorValid) { @@ -771,7 +800,7 @@ static void clearRegionSelectedHelper(gPainter &painter, eListboxStyle *local_st int y = offset.y(); x += (orientation & 2) ? (size.width() - local_style->m_background->size().width()) / 2 : 0; // vertical y += (orientation & 1) ? (size.height() - local_style->m_background->size().height()) / 2 : 0; // horizontal - painter.blit(local_style->m_background, ePoint(x, y), eRect(), local_style->m_transparent_background ? gPainter::BT_ALPHATEST : 0); + painter.blit(local_style->m_background, ePoint(x, y), eRect(), local_style->is_set.transparent_background ? gPainter::BT_ALPHATEST : 0); return; } } @@ -829,7 +858,7 @@ static void clearRegion(gPainter &painter, eWindowStyle &style, eListboxStyle *l painter.setForegroundColor(gRGB(color)); } /* if we have a local foreground color set, use that. */ - else if (local_style && local_style->m_foreground_color_selected_set) + else if (local_style && local_style->is_set.foreground_color_selected) painter.setForegroundColor(local_style->m_foreground_color_selected); } else @@ -840,7 +869,7 @@ static void clearRegion(gPainter &painter, eWindowStyle &style, eListboxStyle *l painter.setForegroundColor(gRGB(color)); } /* if we have a local foreground color set, use that. */ - else if (local_style && local_style->m_foreground_color_set) + else if (local_style && local_style->is_set.foreground_color) painter.setForegroundColor(local_style->m_foreground_color); } } @@ -872,13 +901,14 @@ static ePyObject lookupColor(ePyObject color, ePyObject data) void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected) { - gRegion itemregion(eRect(offset, m_itemsize)); + eListboxStyle *local_style = 0; eRect sel_clip(m_selection_clip); bool cursorValid = this->cursorValid(); gRGB border_color; int border_size = 0; int orientation = 0; + bool itemZoomed = false; if (sel_clip.valid()) sel_clip.moveBy(offset); @@ -890,13 +920,30 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c border_size = local_style->m_border_size; border_color = local_style->m_border_color; orientation = m_listbox->getOrientation(); + itemZoomed = local_style->m_selection_zoom > 1.0; + } + + ePoint offs = offset; + eRect itemRect = eRect(offset, m_itemsize); + gRegion itemregion(itemRect); + + if (selected && itemZoomed) + { + itemRect = eRect(offs, eSize(m_itemsize.width() * local_style->m_selection_zoom, m_itemsize.height() * local_style->m_selection_zoom)); + itemregion = itemRect; + } + else if (!selected && itemZoomed) + { + offs = ePoint(offset.x() + (((m_itemsize.width() * local_style->m_selection_zoom) - m_itemsize.width()) / 2), offset.y() + (((m_itemsize.height() * local_style->m_selection_zoom) - m_itemsize.height()) / 2)); + itemRect = eRect(offs, m_itemsize); + itemregion = itemRect; } painter.clip(itemregion); - clearRegion(painter, style, local_style, ePyObject(), ePyObject(), ePyObject(), ePyObject(), selected, itemregion, sel_clip, offset, m_itemsize, cursorValid, true, orientation); + clearRegion(painter, style, local_style, ePyObject(), ePyObject(), ePyObject(), ePyObject(), selected, itemregion, sel_clip, offs, itemRect.size(), cursorValid, true, orientation); // Draw frame here so to be under the content - if (selected && !sel_clip.valid() && (!local_style || !local_style->m_selection) && (!local_style || !local_style->m_border_set)) - style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry); + if (selected && !sel_clip.valid() && (!local_style || !local_style->m_selection) && (!local_style || !local_style->is_set.border)) + style.drawFrame(painter, eRect(offs, itemRect.size()), eWindowStyle::frameListboxEntry); ePyObject items, buildfunc_ret; @@ -988,6 +1035,100 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c switch (type) { + case TYPE_RECT: + { + ePyObject px = PyTuple_GET_ITEM(item, 1), + py = PyTuple_GET_ITEM(item, 2), + pwidth = PyTuple_GET_ITEM(item, 3), + pheight = PyTuple_GET_ITEM(item, 4), + pbackColor, + pbackColorSelected, + pforeColor, + pforeColorSelected, pborderWidth, pborderColor, pborderColorSelected; + + if (size > 5) + pbackColor = lookupColor(PyTuple_GET_ITEM(item, 5), data); + + if (size > 6) + pbackColorSelected = lookupColor(PyTuple_GET_ITEM(item, 6), data); + + if (size > 7) + { + pborderWidth = PyTuple_GET_ITEM(item, 7); + if (pborderWidth == Py_None) + pborderWidth = ePyObject(); + } + + if (size > 8) { + pborderColor = lookupColor(PyTuple_GET_ITEM(item, 8), data); + + if (size > 9) + pborderColorSelected = lookupColor(PyTuple_GET_ITEM(item, 9), data); + else + pborderColorSelected = pborderColor; + } + + if (!(px && py && pwidth && pheight)) + { + eDebug("[eListboxPythonMultiContent] tuple too small (must be (TYPE_RECT, x, y, width, height [, backgroundColor, backgroundColorSelected, borderWidth, borderColor, borderColorSelected])"); + goto error_out; + } + + int x = PyFloat_Check(px) ? (int)PyFloat_AsDouble(px) : PyLong_AsLong(px); + int y = PyFloat_Check(py) ? (int)PyFloat_AsDouble(py) : PyLong_AsLong(py); + int width = PyFloat_Check(pwidth) ? (int)PyFloat_AsDouble(pwidth) : PyLong_AsLong(pwidth); + int height = PyFloat_Check(pheight) ? (int)PyFloat_AsDouble(pheight) : PyLong_AsLong(pheight); + int bwidth = pborderWidth ? PyLong_AsLong(pborderWidth) : 0; + + if(selected && itemZoomed) + { + x = (x * local_style->m_selection_zoom) + offs.x(); + y = (y * local_style->m_selection_zoom) + offs.y(); + width *= local_style->m_selection_zoom; + height *= local_style->m_selection_zoom; + } + else + { + x += offs.x(); + y += offs.y(); + } + + eRect rect(x + bwidth, y + bwidth, width - bwidth * 2, height - bwidth * 2); + painter.clip(rect); + { + gRegion rc(rect); + bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor); + clearRegion(painter, style, local_style, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, selected, rc, sel_clip, offs, itemRect.size(), cursorValid, mustClear, orientation); + } + painter.clippop(); + + if (bwidth) + { + eRect rect(eRect(x, y, width, height)); + painter.clip(rect); + + if(pborderColor) { + unsigned int color = PyLong_AsUnsignedLongMask(selected ? pborderColorSelected : pborderColor); + painter.setForegroundColor(gRGB(color)); + } + + rect.setRect(x, y, width, bwidth); + painter.fill(rect); + + rect.setRect(x, y + bwidth, bwidth, height - bwidth); + painter.fill(rect); + + rect.setRect(x + bwidth, y + height - bwidth, width - bwidth, bwidth); + painter.fill(rect); + + rect.setRect(x + width - bwidth, y + bwidth, bwidth, height - bwidth); + painter.fill(rect); + + painter.clippop(); + } + + break; + } case TYPE_TEXT: // text { /* @@ -1039,10 +1180,8 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c const char *string = (PyUnicode_Check(pstring)) ? PyUnicode_AsUTF8(pstring) : ""; int x = PyFloat_Check(px) ? (int)PyFloat_AsDouble(px) : PyLong_AsLong(px); - x += offset.x(); int y = PyFloat_Check(py) ? (int)PyFloat_AsDouble(py) : PyLong_AsLong(py); - y += offset.y(); int width = PyFloat_Check(pwidth) ? (int)PyFloat_AsDouble(pwidth) : PyLong_AsLong(pwidth); int height = PyFloat_Check(pheight) ? (int)PyFloat_AsDouble(pheight) : PyLong_AsLong(pheight); @@ -1057,16 +1196,36 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c goto error_out; } + if(selected && itemZoomed) + { + x = (x * local_style->m_selection_zoom) + offs.x(); + y = (y * local_style->m_selection_zoom) + offs.y(); + width *= local_style->m_selection_zoom; + height *= local_style->m_selection_zoom; + } + else + { + x += offs.x(); + y += offs.y(); + } + eRect rect(x + bwidth, y + bwidth, width - bwidth * 2, height - bwidth * 2); painter.clip(rect); { gRegion rc(rect); bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor); - clearRegion(painter, style, local_style, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, selected, rc, sel_clip, offset, m_itemsize, cursorValid, mustClear, orientation); + clearRegion(painter, style, local_style, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, selected, rc, sel_clip, offs, itemRect.size(), cursorValid, mustClear, orientation); } - painter.setFont(m_fonts[fnt]); + if (selected && itemZoomed) { + // find and set zoomed font + if(m_fonts_zoomed.find(fnt) == m_fonts_zoomed.end()) + m_fonts_zoomed[fnt] = new gFont(m_fonts[fnt]->family, m_fonts[fnt]->pointSize * local_style->m_selection_zoom); + painter.setFont(m_fonts_zoomed[fnt]); + } + else + painter.setFont(m_fonts[fnt]); painter.renderText(rect, string, flags, border_color, border_size); painter.clippop(); @@ -1165,10 +1324,8 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c } int x = PyFloat_Check(px) ? (int)PyFloat_AsDouble(px) : PyLong_AsLong(px); - x += offset.x(); int y = PyFloat_Check(py) ? (int)PyFloat_AsDouble(py) : PyLong_AsLong(py); - y += offset.y(); int width = PyFloat_Check(pwidth) ? (int)PyFloat_AsDouble(pwidth) : PyLong_AsLong(pwidth); int height = PyFloat_Check(pheight) ? (int)PyFloat_AsDouble(pheight) : PyLong_AsLong(pheight); @@ -1183,13 +1340,26 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c int bwidth = pborderWidth ? PyLong_AsLong(pborderWidth) : 2; + if(selected && itemZoomed) + { + x = (x * local_style->m_selection_zoom) + offs.x(); + y = (y * local_style->m_selection_zoom) + offs.y(); + width *= local_style->m_selection_zoom; + height *= local_style->m_selection_zoom; + } + else + { + x += offs.x(); + y += offs.y(); + } + eRect rect(x, y, width, height); painter.clip(rect); { gRegion rc(rect); bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor); - clearRegion(painter, style, local_style, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, selected, rc, sel_clip, offset, m_itemsize, cursorValid, mustClear, orientation); + clearRegion(painter, style, local_style, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, selected, rc, sel_clip, offs, itemRect.size(), cursorValid, mustClear, orientation); } // border @@ -1223,7 +1393,10 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c painter.clippop(); continue; } - painter.blit(pixmap, rect.topLeft(), rect, 0); + if(pixmap->size().width() != width || pixmap->size().height() != height) + painter.blitScale(pixmap ,eRect(rect.left(), rect.top(), width, height) ,rect); + else + painter.blit(pixmap, rect.topLeft(), rect, 0); } else painter.fill(rect); @@ -1231,6 +1404,80 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c painter.clippop(); break; } + case TYPE_LINEAR_GRADIENT_ALPHABLEND: + case TYPE_LINEAR_GRADIENT: + { + ePyObject px = PyTuple_GET_ITEM(item, 1), + py = PyTuple_GET_ITEM(item, 2), + pwidth = PyTuple_GET_ITEM(item, 3), + pheight = PyTuple_GET_ITEM(item, 4), + ppdirection = PyTuple_GET_ITEM(item, 5), + pbackColor, pbackColorSelected, ppstartColor, pendColor, pstartColorSelected, pendColorSelected; + + if (!(px && py && pwidth && pheight && ppdirection)) + { + eDebug("[eListboxPythonMultiContent] tuple too small (must be (TYPE_LINEAR_GRADIENT, x, y, width, height, direction, [, startColor, endColor, startColorSelected, endColorSelected] ))"); + goto error_out; + } + + if (size > 6) + ppstartColor = lookupColor(PyTuple_GET_ITEM(item, 6), data); + + if (size > 7) + pendColor = lookupColor(PyTuple_GET_ITEM(item, 7), data); + + if (size > 8) + pstartColorSelected = lookupColor(PyTuple_GET_ITEM(item, 8), data); + + if (size > 9) + pendColorSelected = lookupColor(PyTuple_GET_ITEM(item, 9), data); + + int x = PyFloat_Check(px) ? (int)PyFloat_AsDouble(px) : PyLong_AsLong(px); + int y = PyFloat_Check(py) ? (int)PyFloat_AsDouble(py) : PyLong_AsLong(py); + int width = PyFloat_Check(pwidth) ? (int)PyFloat_AsDouble(pwidth) : PyLong_AsLong(pwidth); + int height = PyFloat_Check(pheight) ? (int)PyFloat_AsDouble(pheight) : PyLong_AsLong(pheight); + int direction = PyLong_AsLong(ppdirection); + + if(selected && itemZoomed) + { + x = (x * local_style->m_selection_zoom) + offs.x(); + y = (y * local_style->m_selection_zoom) + offs.y(); + width *= local_style->m_selection_zoom; + height *= local_style->m_selection_zoom; + } + else + { + x += offs.x(); + y += offs.y(); + } + + eRect rect(x, y, width, height); + painter.clip(rect); + { + gRegion rc(rect); + bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor); + clearRegion(painter, style, local_style, ePyObject(), ePyObject(), pbackColor, pbackColorSelected, selected, rc, sel_clip, offs, itemRect.size(), cursorValid, mustClear, orientation); + } + + int flag = type == TYPE_LINEAR_GRADIENT_ALPHABLEND ? gPainter::BT_ALPHABLEND : 0; + + if (!selected && ppstartColor && pendColor) + { + unsigned int color = PyLong_AsUnsignedLongMask(ppstartColor); + unsigned int color1 = PyLong_AsUnsignedLongMask(pendColor); + painter.drawGradient(rect, gRGB(color), gRGB(color1), direction, flag); + } + else if (selected && pstartColorSelected && pendColorSelected) + { + unsigned int color = PyLong_AsUnsignedLongMask(pstartColorSelected); + unsigned int color1 = PyLong_AsUnsignedLongMask(pendColorSelected); + painter.drawGradient(rect, gRGB(color), gRGB(color1), direction, flag); + } + + painter.clippop(); + + break; + } case TYPE_PIXMAP_ALPHABLEND: case TYPE_PIXMAP_ALPHATEST: case TYPE_PIXMAP: // pixmap @@ -1260,10 +1507,8 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c continue; int x = PyFloat_Check(px) ? (int)PyFloat_AsDouble(px) : PyLong_AsLong(px); - x += offset.x(); int y = PyFloat_Check(py) ? (int)PyFloat_AsDouble(py) : PyLong_AsLong(py); - y += offset.y(); int width = PyFloat_Check(pwidth) ? (int)PyFloat_AsDouble(pwidth) : PyLong_AsLong(pwidth); int height = PyFloat_Check(pheight) ? (int)PyFloat_AsDouble(pheight) : PyLong_AsLong(pheight); @@ -1285,13 +1530,25 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c if (size > 8) flags = PyLong_AsLong(PyTuple_GET_ITEM(item, 8)); + if(selected && itemZoomed) + { + x = (x * local_style->m_selection_zoom) + offs.x(); + y = (y * local_style->m_selection_zoom) + offs.y(); + width *= local_style->m_selection_zoom; + height *= local_style->m_selection_zoom; + } + else + { + x += offs.x(); + y += offs.y(); + } + eRect rect(x, y, width, height); painter.clip(rect); - { gRegion rc(rect); bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor); - clearRegion(painter, style, local_style, ePyObject(), ePyObject(), pbackColor, pbackColorSelected, selected, rc, sel_clip, offset, m_itemsize, cursorValid, mustClear, orientation); + clearRegion(painter, style, local_style, ePyObject(), ePyObject(), pbackColor, pbackColorSelected, selected, rc, sel_clip, offs, itemRect.size(), cursorValid, mustClear, orientation); } flags |= (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : (type == TYPE_PIXMAP_ALPHABLEND) ? gPainter::BT_ALPHABLEND @@ -1374,10 +1631,13 @@ int eListboxPythonMultiContent::currentCursorSelectable() void eListboxPythonMultiContent::setFont(int fnt, gFont *font) { - if (font) + if (font) { m_fonts[fnt] = font; - else + } + else { m_fonts.erase(fnt); + m_fonts_zoomed.erase(fnt); + } } void eListboxPythonMultiContent::setList(ePyObject list) diff --git a/lib/gui/elistboxcontent.h b/lib/gui/elistboxcontent.h index a051d1796ed..ff9ae57a6ea 100644 --- a/lib/gui/elistboxcontent.h +++ b/lib/gui/elistboxcontent.h @@ -53,6 +53,7 @@ class eListboxPythonStringContent : public virtual iListboxContent int m_cursor; int m_saved_cursor; int m_saved_cursor_line; + ePtr m_font_zoomed; protected: ePyObject m_list; @@ -93,8 +94,11 @@ class eListboxPythonMultiContent : public eListboxPythonStringContent ~eListboxPythonMultiContent(); enum { + TYPE_RECT, TYPE_TEXT, TYPE_PROGRESS, + TYPE_LINEAR_GRADIENT, + TYPE_LINEAR_GRADIENT_ALPHABLEND, TYPE_PIXMAP, TYPE_PIXMAP_ALPHATEST, TYPE_PIXMAP_ALPHABLEND, @@ -114,6 +118,7 @@ class eListboxPythonMultiContent : public eListboxPythonStringContent private: std::map> m_fonts; + std::map> m_fonts_zoomed; }; #ifdef SWIG @@ -140,6 +145,9 @@ class eListboxPythonMultiContent : public eListboxPythonStringContent #define BT_VALIGN_BOTTOM 128 #define BT_ALIGN_CENTER BT_HALIGN_CENTER | BT_VALIGN_CENTER +#define GRADIENT_VERTICAL 0 +#define GRADIENT_HORIZONTAL 1 + #endif // SWIG #endif diff --git a/lib/gui/epixmap.cpp b/lib/gui/epixmap.cpp index f3f7705dab7..dfe9a82c8cd 100644 --- a/lib/gui/epixmap.cpp +++ b/lib/gui/epixmap.cpp @@ -4,7 +4,7 @@ #include ePixmap::ePixmap(eWidget *parent) - : eWidget(parent), m_alphatest(0), m_scale(0), m_have_border_color(false), m_border_width(0) + : eWidget(parent), m_alphatest(0), m_scale(0), m_have_border_color(false), m_gradient_set(false), m_border_width(0), m_gradient_direction(0) { } @@ -75,6 +75,15 @@ void ePixmap::setBorderColor(const gRGB &color) invalidate(); } +void ePixmap::setGradient(const gRGB &startcolor, const gRGB &endcolor, int direction, int blend) +{ + m_gradient_startcolor = startcolor; + m_gradient_endcolor = endcolor; + m_gradient_direction = direction; + m_gradient_set = true; + invalidate(); +} + void ePixmap::checkSize() { /* when we have no pixmap, or a pixmap of different size, we need @@ -126,6 +135,9 @@ int ePixmap::event(int event, void *data, void *data2) painter.fill(eRect(s.width() - m_border_width, m_border_width, m_border_width, s.height() - m_border_width)); } + if (m_gradient_set) + painter.drawGradient(eRect(ePoint(0, 0), s), m_gradient_startcolor, m_gradient_endcolor, m_gradient_direction, m_alphatest == 2 ? gPainter::BT_ALPHABLEND : 0); + return 0; } case evtChangedPixmap: diff --git a/lib/gui/epixmap.h b/lib/gui/epixmap.h index 71c4cdb7fd0..2a87eaa135e 100644 --- a/lib/gui/epixmap.h +++ b/lib/gui/epixmap.h @@ -20,6 +20,13 @@ class ePixmap : public eWidget void setPixmapScaleFlags(int flags) { setPixmapScale(flags); } // DEPRECATED void setBorderWidth(int pixel); void setBorderColor(const gRGB &color); + void setGradient(const gRGB &startcolor, const gRGB &endcolor, int direction, int blend); + + enum + { + GRADIENT_VERTICAL = 0, + GRADIENT_HORIZONTAL = 1 + }; protected: ePtr m_pixmap; @@ -31,9 +38,9 @@ class ePixmap : public eWidget { evtChangedPixmap = evtUserWidget, }; - bool m_have_border_color; - int m_border_width; - gRGB m_border_color; + bool m_have_border_color, m_gradient_set; + int m_border_width, m_gradient_direction; + gRGB m_border_color, m_gradient_startcolor, m_gradient_endcolor; }; #endif diff --git a/lib/gui/erectangle.cpp b/lib/gui/erectangle.cpp new file mode 100644 index 00000000000..294aa1a9263 --- /dev/null +++ b/lib/gui/erectangle.cpp @@ -0,0 +1,67 @@ +#include +#include +#include + +eRectangle::eRectangle(eWidget *parent) + : eWidget(parent), m_have_border_color(false), m_gradient_set(false), m_border_width(0), m_gradient_direction(0) +{ +} + +void eRectangle::setBorderWidth(int pixel) +{ + m_border_width = pixel; + invalidate(); +} + +void eRectangle::setBorderColor(const gRGB &color) +{ + m_border_color = color; + m_have_border_color = true; + invalidate(); +} + +void eRectangle::setBackgroundGradient(const gRGB &startcolor, const gRGB &endcolor, int direction, int blend) +{ + m_gradient_startcolor = startcolor; + m_gradient_endcolor = endcolor; + m_gradient_direction = direction; + m_gradient_blend = blend; + m_gradient_set = true; + invalidate(); +} + +int eRectangle::event(int event, void *data, void *data2) +{ + switch (event) + { + case evtPaint: + { + ePtr style; + gPainter &painter = *(gPainter *)data2; + + eSize s(size()); + + getStyle(style); + + eWidget::event(event, data, data2); + + if (m_have_border_color) + painter.setForegroundColor(m_border_color); + + if (m_border_width) + { + painter.fill(eRect(0, 0, s.width(), m_border_width)); + painter.fill(eRect(0, m_border_width, m_border_width, s.height() - m_border_width)); + painter.fill(eRect(m_border_width, s.height() - m_border_width, s.width() - m_border_width, m_border_width)); + painter.fill(eRect(s.width() - m_border_width, m_border_width, m_border_width, s.height() - m_border_width)); + } + + if (m_gradient_set) + painter.drawGradient(eRect(ePoint(0, 0), s), m_gradient_startcolor, m_gradient_endcolor, m_gradient_direction, m_gradient_blend); + + return 0; + } + default: + return eWidget::event(event, data, data2); + } +} diff --git a/lib/gui/erectangle.h b/lib/gui/erectangle.h new file mode 100644 index 00000000000..e35006697e1 --- /dev/null +++ b/lib/gui/erectangle.h @@ -0,0 +1,30 @@ +#ifndef __lib_gui_erectangle_h +#define __lib_gui_erectangle_h + +#include + +class eRectangle : public eWidget +{ +public: + eRectangle(eWidget *parent); + + void setBorderWidth(int pixel); + void setBorderColor(const gRGB &color); + void setBackgroundGradient(const gRGB &startcolor, const gRGB &endcolor, int direction, int blend); + + enum + { + GRADIENT_VERTICAL = 0, + GRADIENT_HORIZONTAL = 1 + }; + +protected: + int event(int event, void *data = 0, void *data2 = 0); + +private: + bool m_have_border_color, m_gradient_set; + int m_border_width, m_gradient_direction, m_gradient_blend; + gRGB m_border_color, m_gradient_startcolor, m_gradient_endcolor; +}; + +#endif diff --git a/lib/gui/eslider.cpp b/lib/gui/eslider.cpp index b4065cb10f1..f3fbf3a4963 100644 --- a/lib/gui/eslider.cpp +++ b/lib/gui/eslider.cpp @@ -102,8 +102,12 @@ int eSlider::event(int event, void *data, void *data2) painter.setForegroundColor(m_foreground_color); painter.fill(m_currently_filled); } - else - painter.blit(m_pixmap, ePoint(0, 0), m_currently_filled.extends, isTransparent() ? gPainter::BT_ALPHATEST : 0); + else { + if(m_pixmap->size().width() != m_currently_filled.extends.width() || m_pixmap->size().height() != m_currently_filled.extends.height()) + painter.blitScale(m_pixmap, eRect(ePoint(0,0),s),m_currently_filled.extends, isTransparent() ? gPainter::BT_ALPHATEST : 0); + else + painter.blit(m_pixmap, ePoint(0, 0), m_currently_filled.extends, isTransparent() ? gPainter::BT_ALPHATEST : 0); + } // Border if(m_border_width>0) { diff --git a/lib/python/Components/Converter/TemplatedMultiContent.py b/lib/python/Components/Converter/TemplatedMultiContent.py index 2ea1dcf4f58..0191e1ee1ad 100644 --- a/lib/python/Components/Converter/TemplatedMultiContent.py +++ b/lib/python/Components/Converter/TemplatedMultiContent.py @@ -8,7 +8,7 @@ def __init__(self, args): StringList.__init__(self, args) from enigma import BT_HALIGN_CENTER, BT_HALIGN_LEFT, BT_HALIGN_RIGHT, BT_KEEP_ASPECT_RATIO, BT_SCALE, BT_VALIGN_BOTTOM, BT_VALIGN_CENTER, BT_VALIGN_TOP, RT_ELLIPSIS, RT_HALIGN_CENTER, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_VALIGN_BOTTOM, RT_VALIGN_CENTER, RT_VALIGN_TOP, RT_WRAP, gFont from skin import getSkinFactor, parseFont - from Components.MultiContent import MultiContentEntryPixmap, MultiContentEntryPixmapAlphaBlend, MultiContentEntryPixmapAlphaTest, MultiContentEntryProgress, MultiContentEntryProgressPixmap, MultiContentEntryText, MultiContentTemplateColor + from Components.MultiContent import MultiContentEntryPixmap, MultiContentEntryPixmapAlphaBlend, MultiContentEntryPixmapAlphaTest, MultiContentEntryProgress, MultiContentEntryProgressPixmap, MultiContentEntryText, MultiContentTemplateColor, MultiContentEntryRectangle, MultiContentEntryLinearGradient, MultiContentEntryLinearGradientAlphaBlend f = getSkinFactor() # This is needed for special OpenViX skins using f in the template. loc = locals() del loc["self"] # Cleanup locals a bit. diff --git a/lib/python/Components/MultiContent.py b/lib/python/Components/MultiContent.py index 2f6491eeb92..49ecb8160ae 100644 --- a/lib/python/Components/MultiContent.py +++ b/lib/python/Components/MultiContent.py @@ -1,5 +1,5 @@ from __future__ import print_function -from enigma import RT_HALIGN_LEFT, RT_VALIGN_TOP, eListboxPythonMultiContent +from enigma import GRADIENT_VERTICAL, RT_HALIGN_LEFT, RT_VALIGN_TOP, eListboxPythonMultiContent from skin import parseColor from Tools.Directories import SCOPE_GUISKIN, resolveFilename @@ -30,6 +30,10 @@ def MultiContentTemplateColor(n): return 0xff000000 | n +def MultiContentEntryRectangle(pos=(0, 0), size=(0, 0), backgroundColor=None, backgroundColorSelected=None, borderWidth=None, borderColor=None, borderColorSelected=None): + return eListboxPythonMultiContent.TYPE_RECT, int(pos[0]), int(pos[1]), int(size[0]), int(size[1]), __resolveColor(backgroundColor), __resolveColor(backgroundColorSelected), borderWidth, __resolveColor(borderColor), __resolveColor(borderColorSelected) + + def MultiContentEntryText(pos=(0, 0), size=(0, 0), font=0, flags=RT_HALIGN_LEFT | RT_VALIGN_TOP, text="", color=None, color_sel=None, backcolor=None, backcolor_sel=None, border_width=None, border_color=None): return eListboxPythonMultiContent.TYPE_TEXT, int(pos[0]), int(pos[1]), int(size[0]), int(size[1]), font, flags, text, __resolveColor(color), __resolveColor(color_sel), __resolveColor(backcolor), __resolveColor(backcolor_sel), border_width, __resolveColor(border_color) @@ -52,3 +56,11 @@ def MultiContentEntryProgress(pos=(0, 0), size=(0, 0), percent=None, borderWidth def MultiContentEntryProgressPixmap(pos=(0, 0), size=(0, 0), percent=None, pixmap=None, borderWidth=None, foreColor=None, foreColorSelected=None, backColor=None, backColorSelected=None): return eListboxPythonMultiContent.TYPE_PROGRESS_PIXMAP, int(pos[0]), int(pos[1]), int(size[0]), int(size[1]), percent, __resolvePixmap(pixmap), borderWidth, __resolveColor(foreColor), __resolveColor(foreColorSelected), __resolveColor(backColor), __resolveColor(backColorSelected) + + +def MultiContentEntryLinearGradient(pos=(0, 0), size=(0, 0), direction=GRADIENT_VERTICAL, startColor=None, endColor=None, startColorSelected=None, endColorSelected=None): + return eListboxPythonMultiContent.TYPE_LINEAR_GRADIENT, int(pos[0]), int(pos[1]), int(size[0]), int(size[1]), direction, __resolveColor(startColor), __resolveColor(endColor), __resolveColor(startColorSelected), __resolveColor(endColorSelected) + + +def MultiContentEntryLinearGradientAlphaBlend(pos=(0, 0), size=(0, 0), direction=GRADIENT_VERTICAL, startColor=None, endColor=None, startColorSelected=None, endColorSelected=None): + return eListboxPythonMultiContent.TYPE_LINEAR_GRADIENT_ALPHABLEND, int(pos[0]), int(pos[1]), int(size[0]), int(size[1]), direction, __resolveColor(startColor), __resolveColor(endColor), __resolveColor(startColorSelected), __resolveColor(endColorSelected) diff --git a/lib/python/enigma_python.i b/lib/python/enigma_python.i index 63af94cb4ae..62ab16a067b 100644 --- a/lib/python/enigma_python.i +++ b/lib/python/enigma_python.i @@ -61,6 +61,7 @@ is usually caused by not marking PSignals as immutable. #include #include #include +#include #include #include #include @@ -215,6 +216,7 @@ typedef long time_t; %include %include %include +%include %include %include %include diff --git a/lib/python/skin.py b/lib/python/skin.py index e1e360ff4bb..644a0172cac 100644 --- a/lib/python/skin.py +++ b/lib/python/skin.py @@ -3,7 +3,7 @@ from os import listdir, unlink from xml.etree.cElementTree import Element, ElementTree, fromstring -from enigma import BT_ALPHABLEND, BT_ALPHATEST, BT_HALIGN_CENTER, BT_HALIGN_LEFT, BT_HALIGN_RIGHT, BT_KEEP_ASPECT_RATIO, BT_SCALE, BT_VALIGN_BOTTOM, BT_VALIGN_CENTER, BT_VALIGN_TOP, addFont, eLabel, eListbox, ePixmap, ePoint, eRect, eSize, eSlider, eSubtitleWidget, eWindow, eWindowStyleManager, eWindowStyleSkinned, getDesktop, gFont, getFontFaces, gMainDC, gRGB +from enigma import BT_ALPHABLEND, BT_ALPHATEST, BT_HALIGN_CENTER, BT_HALIGN_LEFT, BT_HALIGN_RIGHT, BT_KEEP_ASPECT_RATIO, BT_SCALE, BT_VALIGN_BOTTOM, BT_VALIGN_CENTER, BT_VALIGN_TOP, addFont, eLabel, eListbox, ePixmap, ePoint, eRect, eRectangle, eSize, eSlider, eSubtitleWidget, eWindow, eWindowStyleManager, eWindowStyleSkinned, getDesktop, gFont, getFontFaces, gMainDC, gRGB from Components.config import ConfigSubsection, ConfigText, config from Components.SystemInfo import BoxInfo @@ -303,12 +303,12 @@ def parseColor(value, default=0x00FFFFFF): try: value = gRGB(int(value[1:], 0x10)) except ValueError: - skinError("The color code '%s' must be #aarrggbb, using #00ffffff (White)" % value) + skinError("The color code '%s' must be #aarrggbb, using #00FFFFFF (White)" % value) value = gRGB(default) elif value in colors: value = colors[value] else: - skinError("The color '%s' must be #aarrggbb or valid named color, using #00ffffff (White)" % value) + skinError("The color '%s' must be #aarrggbb or valid named color, using #00FFFFFF (White)" % value) value = gRGB(default) return value @@ -421,6 +421,22 @@ def parseFont(value, scale=((1, 1), (1, 1))): return gFont(name, int(size * scale[1][0] / scale[1][1])) +def parseGradient(value): + data = [x.strip() for x in value.split(",")] + if len(data) > 2: + options = { + "horizontal": ePixmap.GRADIENT_HORIZONTAL, + "vertical": ePixmap.GRADIENT_VERTICAL, + } + direction = parseOptions(options, "gradient", data[2], ePixmap.GRADIENT_VERTICAL) + if len(data) == 3: + alphaBend = BT_ALPHABLEND if data[3] == '1' else 0 + return (parseColor(data[0], default=0x00000000), parseColor(data[1], 0x00FFFFFF), direction, alphaBend) + else: + skinError("The gradient '%s' must be 'startColor,endColor,direction[,blend]', using '#00000000,#00FFFFFF,vertical' (Black,White,vertical)" % value) + return (0x000000, 0x00FFFFFF, ePixmap.GRADIENT_VERTICAL, 0) + + def parseHorizontalAlignment(value): options = { "left": 0, @@ -446,7 +462,7 @@ def parseItemAlignment(value): "center": eListbox.itemAlignCenter, "justify": eListbox.itemAlignJustify, } - return parseOptions(options, "scrollbarItemAlignment", value, eListbox.itemAlignDefault) + return parseOptions(options, "itemAlignment", value, eListbox.itemAlignDefault) def parseListOrientation(value): @@ -743,6 +759,12 @@ def backgroundColor(self, value): def backgroundColorSelected(self, value): self.guiObject.setBackgroundColorSelected(parseColor(value, 0x00000000)) + def setBackgroundGradient(self, value): + self.guiObject.setBackgroundGradient(*parseGradient(value)) + + def setBackgroundGradientSeleced(self, value): + self.guiObject.setBackgroundGradientSeleced(*parseGradient(value)) + def backgroundCrypted(self, value): self.guiObject.setBackgroundColor(parseColor(value, 0x00000000)) @@ -804,6 +826,9 @@ def foregroundEncrypted(self, value): def foregroundNotCrypted(self, value): self.guiObject.setForegroundColor(parseColor(value, 0x00FFFFFF)) + def gradient(self, value): + self.guiObject.setGradient(*parseGradient(value)) + def halign(self, value): # This legacy definition uses an inconsistent name, use 'horizontalAlignment' instead! self.horizontalAlignment(value) # attribDeprecationWarning("halign", "horizontalAlignment") @@ -818,10 +843,18 @@ def horizontalAlignment(self, value): def includes(self, value): # Same as conditional. Created to partner new "excludes" attribute. pass + def itemAlignment(self, value): + self.guiObject.setItemAlignment(parseItemAlignment(value)) + def itemHeight(self, value): # print("[Skin] DEBUG: Scale itemHeight %d -> %d." % (int(value), self.applyVerticalScale(value))) self.guiObject.setItemHeight(self.applyVerticalScale(value)) + def itemSpacing(self, value): + if len(value.split(",")) == 1: + value = "%s,%s" % (value, value) + self.guiObject.setItemSpacing(parsePosition(value, self.scaleTuple, self.guiObject, self.desktop)) + def itemWidth(self, value): # print("[Skin] DEBUG: Scale itemWidth %d -> %d." % (int(value), self.applyHorizontalScale(value))) self.guiObject.setItemWidth(self.applyHorizontalScale(value)) @@ -878,9 +911,6 @@ def scrollbarbackgroundPixmap(self, value): # This legacy definition uses an in self.scrollbarBackgroundPixmap(value) attribDeprecationWarning("scrollbarbackgroundPixmap", "scrollbarBackgroundPixmap") - def scrollbarItemAlignment(self, value): - self.guiObject.setItemAlignment(parseItemAlignment(value)) - def scrollbarMode(self, value): self.guiObject.setScrollbarMode(parseScrollbarMode(value)) @@ -953,6 +983,13 @@ def selectionDisabled(self, value): # This legacy definition is a redundant opt def selectionPixmap(self, value): self.guiObject.setSelectionPixmap(parsePixmap(value, self.desktop)) + def selectionZoom(self, value): + try: + value = float(value) + except ValueError: + value = 1.0 + self.guiObject.setSelectionZoom(value) + def shadowColor(self, value): self.guiObject.setShadowColor(parseColor(value, 0x00000000)) @@ -966,6 +1003,9 @@ def sliderPixmap(self, value): # For compatibility same as 'scrollbarSliderPixm self.scrollbarForegroundPixmap(value) attribDeprecationWarning("sliderPixmap", "scrollbarForegroundPixmap") + def spacerColor(self, value): + self.guiObject.setSpacerColor(parseColor(value, 0x00000000)) + def text(self, value): if value: value = _(value) @@ -1553,6 +1593,13 @@ def processPixmap(widget, context): collectAttributes(w.skinAttributes, widget, context, skinPath, ignore=("name",)) screen.additionalWidgets.append(w) + def processRectangle(widget, context): + w = additionalWidget() + w.widget = eRectangle + w.skinAttributes = [] + collectAttributes(w.skinAttributes, widget, context, skinPath, ignore=("name",)) + screen.additionalWidgets.append(w) + def processScreen(widget, context): widgets = widget for w in widgets.findall('constant-widget'): @@ -1600,6 +1647,7 @@ def processPanel(widget, context): "applet": processApplet, "eLabel": processLabel, "ePixmap": processPixmap, + "eRectangle": processRectangle, "panel": processPanel } diff --git a/lib/service/listboxservice.cpp b/lib/service/listboxservice.cpp index 2957ed0f0c3..38a3d649257 100644 --- a/lib/service/listboxservice.cpp +++ b/lib/service/listboxservice.cpp @@ -679,24 +679,24 @@ void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const if (selected) { /* if we have a local background color set, use that. */ - if (local_style->m_background_color_selected_set) + if (local_style->is_set.background_color_selected) painter.setBackgroundColor(local_style->m_background_color_selected); /* same for foreground */ - if (local_style->m_foreground_color_selected_set) + if (local_style->is_set.foreground_color_selected) painter.setForegroundColor(local_style->m_foreground_color_selected); } else { /* if we have a local background color set, use that. */ - if (local_style->m_background_color_set) + if (local_style->is_set.background_color) painter.setBackgroundColor(local_style->m_background_color); /* same for foreground */ - if (local_style->m_foreground_color_set) + if (local_style->is_set.foreground_color) painter.setForegroundColor(local_style->m_foreground_color); } } - if (!local_style || !local_style->m_transparent_background) + if (!local_style || !local_style->is_set.transparent_background) /* if we have no transparent background */ { /* blit background picture, if available (otherwise, clear only) */