diff --git a/src/common/Gdc2/Alpha.cpp b/src/common/Gdc2/Alpha.cpp --- a/src/common/Gdc2/Alpha.cpp +++ b/src/common/Gdc2/Alpha.cpp @@ -1,1820 +1,1822 @@ /** \file \author Matthew Allen \date 4/3/1998 \brief Draw mode effects */ #include #include #include #include #include "lgi/common/Gdc2.h" #include "lgi/common/Path.h" #include "lgi/common/PixelRops.h" #include "lgi/common/Palette.h" // #define Div255(a) DivLut[a] #define Div255(a) ((a)/255) template void CreatePaletteLut(T *c, LPalette *Pal, int Scale = 255) { if (Scale < 255) { uchar *DivLut = Div255Lut; for (int i=0; i<256; i++) { GdcRGB *p = (Pal) ? (*Pal)[i] : 0; if (p) { c[i].r = DivLut[p->r * Scale]; c[i].g = DivLut[p->g * Scale]; c[i].b = DivLut[p->b * Scale]; } else { c[i].r = DivLut[i * Scale]; c[i].g = c[i].r; c[i].b = c[i].r; } } } else if (Scale) { for (int i=0; i<256; i++) { GdcRGB *p = (Pal) ? (*Pal)[i] : 0; if (p) { c[i].r = p->r; c[i].g = p->g; c[i].b = p->b; } else { c[i].r = i; c[i].g = i; c[i].b = i; } } } else { memset(c, 0, sizeof(*c) * 256); } } /// Alpha blending applicators class LAlphaApp : public LApplicator { protected: uchar alpha, oma; int Bits, Bytes; uchar *Ptr; uchar *APtr; const char *GetClass() { return "LAlphaApp"; } public: LAlphaApp() { Op = GDC_ALPHA; alpha = 0xFF; oma = 0; Bits = 8; Bytes = 1; Ptr = 0; APtr = 0; } int GetVar(int Var) { switch (Var) { case GAPP_ALPHA_A: return alpha; } return 0; } int SetVar(int Var, NativeInt Value) { switch (Var) { case GAPP_ALPHA_A: { int Old = alpha; alpha = (uchar)Value; oma = 0xFF - alpha; + + printf("GAPP_ALPHA_A=%i\n", alpha); return Old; } case GAPP_ALPHA_PAL: { } } return 0; } bool SetSurface(LBmpMem *d, LPalette *p, LBmpMem *a) { if (d && d->GetBits() == Bits) { Dest = d; Pal = p; Ptr = d->Base; Alpha = a; APtr = Alpha ? Alpha->Base : 0; return true; } return false; } void SetPtr(int x, int y) { LAssert(Dest && Dest->Base); Ptr = Dest->Base + ((y * Dest->Line) + (x * Bytes)); if (APtr) APtr = Alpha->Base + ((y * Alpha->Line) + x); } void IncX() { Ptr += Bytes; if (APtr) APtr++; } void IncY() { Ptr += Dest->Line; if (APtr) APtr += Alpha->Line; } void IncPtr(int X, int Y) { Ptr += (Y * Dest->Line) + (X * Bytes); if (APtr) APtr += (Y * Dest->Line) + X; } COLOUR Get() { switch (Bytes) { case 1: return *((uint8_t*)Ptr); case 2: return *((uint16*)Ptr); case 3: return Rgb24(Ptr[2], Ptr[1], Ptr[0]); case 4: return *((uint32_t*)Ptr); } return 0; } }; class GdcApp8Alpha : public LAlphaApp { char Remap[256]; uchar *DivLut; public: GdcApp8Alpha(); int SetVar(int Var, NativeInt Value); void Set(); void VLine(int height); void Rectangle(int x, int y); bool Blt(LBmpMem *Src, LPalette *SPal, LBmpMem *SrcAlpha); template void AlphaBlt15(LBmpMem *Src, LPalette *DPal, uchar *Lut) { System24BitPixel dc[256]; CreatePaletteLut(dc, DPal, oma); if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { Pixel *s = (Pixel*) (Src->Base + (y * Src->Line)); uchar *d = Ptr; uchar *e = d + Src->x; while (d < e) { System24BitPixel *dst = dc + *d; int r = dst->r + DivLut[G5bitTo8bit(s->r) * alpha]; int g = dst->g + DivLut[G5bitTo8bit(s->g) * alpha]; int b = dst->b + DivLut[G5bitTo8bit(s->b) * alpha]; *d++ = Lut[Rgb15(r, g, b)]; s++; } Ptr += Dest->Line; } } template void AlphaBlt16(LBmpMem *Src, LPalette *DPal, uchar *Lut) { System24BitPixel dc[256]; CreatePaletteLut(dc, DPal, oma); if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { Pixel *s = (Pixel*) (Src->Base + (y * Src->Line)); uchar *d = Ptr; uchar *e = d + Src->x; while (d < e) { System24BitPixel *dst = dc + *d; int r = dst->r + DivLut[G5bitTo8bit(s->r) * alpha]; int g = dst->g + DivLut[G6bitTo8bit(s->g) * alpha]; int b = dst->b + DivLut[G5bitTo8bit(s->b) * alpha]; *d++ = Lut[Rgb15(r, g, b)]; s++; } Ptr += Dest->Line; } } template void AlphaBlt24(LBmpMem *Src, LPalette *DPal, uchar *Lut) { System24BitPixel dc[256]; CreatePaletteLut(dc, DPal, oma); if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { Pixel *s = (Pixel*) (Src->Base + (y * Src->Line)); uchar *d = Ptr; uchar *e = d + Src->x; while (d < e) { System24BitPixel *dst = dc + *d; int r = dst->r + DivLut[s->r * alpha]; int g = dst->g + DivLut[s->g * alpha]; int b = dst->b + DivLut[s->b * alpha]; *d++ = Lut[Rgb15(r, g, b)]; s++; } Ptr += Dest->Line; } } template void AlphaBlt32(LBmpMem *Src, LPalette *DPal, uchar *Lut) { GdcRGB *dc = (*DPal)[0]; if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { Pixel *s = (Pixel*) (Src->Base + (y * Src->Line)); uchar *d = Ptr; uchar *e = d + Src->x; while (d < e) { GdcRGB dst = dc[*d]; OverNpm32toNpm24(s, &dst); *d++ = Lut[Rgb15(dst.r, dst.g, dst.b)]; s++; } Ptr += Dest->Line; } } template void AlphaBlt48(LBmpMem *Src, LPalette *DPal, uchar *Lut) { System24BitPixel dc[256]; CreatePaletteLut(dc, DPal, oma); if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { Pixel *s = (Pixel*) (Src->Base + (y * Src->Line)); uchar *d = Ptr; uchar *e = d + Src->x; while (d < e) { System24BitPixel dst = dc[*d]; LRgba32 src = { (uint8_t)(s->r >> 8), (uint8_t)(s->g >> 8), (uint8_t)(s->b >> 8), alpha }; OverNpm32toNpm24(&src, &dst); *d++ = Lut[Rgb15(dst.r, dst.g, dst.b)]; s++; } Ptr += Dest->Line; } } template void AlphaBlt64(LBmpMem *Src, LPalette *DPal, uchar *Lut) { System24BitPixel dc[256]; CreatePaletteLut(dc, DPal, 0xff); if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { Pixel *s = (Pixel*) (Src->Base + (y * Src->Line)); uchar *d = Ptr; uchar *e = d + Src->x; while (d < e) { System24BitPixel dst = dc[*d]; OverNpm64toNpm24(s, &dst); *d++ = Lut[Rgb15(dst.r, dst.g, dst.b)]; s++; } Ptr += Dest->Line; } } }; template class GdcAlpha : public LApplicator { protected: union { uint8_t *u8; uint16 *u16; uint32_t *u32; Pixel *p; }; uint8_t alpha, one_minus_alpha; public: GdcAlpha() { p = NULL; alpha = 0xff; one_minus_alpha = 0; } const char *GetClass() { return "GdcAlpha"; } int GetVar(int Var) { switch (Var) { case GAPP_ALPHA_A: return alpha; } return 0; } int SetVar(int Var, NativeInt Value) { switch (Var) { case GAPP_ALPHA_A: { int Old = alpha; alpha = (uchar)Value; one_minus_alpha = 0xFF - alpha; return Old; } } return 0; } bool SetSurface(LBmpMem *d, LPalette *p = 0, LBmpMem *a = 0) { if (d && d->Cs == ColourSpace) { Dest = d; Pal = p; u8 = d->Base; Alpha = a; return true; } else LAssert(0); return false; } void SetPtr(int x, int y) { u8 = Dest->Base + (Dest->Line * y); p += x; } void IncX() { p++; } void IncY() { u8 += Dest->Line; } void IncPtr(int X, int Y) { p += X; u8 += Dest->Line * Y; } COLOUR Get() { return Rgb24(p->r, p->g, p->b); } }; template class GdcAlpha15 : public GdcAlpha { public: const char *GetClass() { return "GdcAlpha15"; } #define Div2040(c) ((c) / 2040) #define Setup15() \ REG uint8_t r = Rc15(this->c); \ REG uint8_t g = Gc15(this->c); \ REG uint8_t b = Bc15(this->c); \ REG uint8_t a = this->alpha; \ REG uint8_t oma = 255 - a; \ REG Pixel *d = this->p #define Comp15() \ d->r = Div2040((G5bitTo8bit(d->r) * oma) + (r * a)); \ d->g = Div2040((G5bitTo8bit(d->g) * oma) + (g * a)); \ d->b = Div2040((G5bitTo8bit(d->b) * oma) + (b * a)) void Set() { Setup15(); Comp15(); } void VLine(int height) { Setup15(); REG ssize_t line = this->Dest->Line; while (height--) { Comp15(); d = (Pixel*)(((uint8_t*)d) + line); } this->p = d; } void Rectangle(int x, int y) { Setup15(); REG ssize_t line = this->Dest->Line; while (y--) { d = this->p; REG Pixel *e = d + x; while (d < e) { Comp15(); d++; } this->u8 += line; } } bool Blt(LBmpMem *Src, LPalette *SPal, LBmpMem *SrcAlpha) { if (!Src) return false; if (Src->Cs == CsIndex8) { Pixel map[256]; if (SPal) { GdcRGB *p = (*SPal)[0]; for (int i=0; i<256; i++, p++) { map[i].r = G8bitTo5bit(p->r); map[i].g = G8bitTo5bit(p->g); map[i].b = G8bitTo5bit(p->b); } } else { for (int i=0; i<256; i++) { map[i].r = G8bitTo5bit(i); map[i].g = G8bitTo5bit(i); map[i].b = G8bitTo5bit(i); } } for (int y=0; yy; y++) { uchar *s = ((uchar*)Src->Base) + (y * Src->Line); Pixel *d = this->p; for (int x=0; xx; x++) { *d++ = map[*s++]; } this->u8 += this->Dest->Line; } return true; } else { LBmpMem Dst; Dst.Base = this->u8; Dst.x = Src->x; Dst.y = Src->y; Dst.Cs = this->Dest->Cs; Dst.Line = this->Dest->Line; return LRopUniversal(&Dst, Src, true); } } }; template class GdcAlpha16 : public GdcAlpha { public: const char *GetClass() { return "GdcAlpha16"; } #define Div2040(c) ((c) / 2040) #define Div1020(c) ((c) / 1020) #define Setup16() \ REG uint8_t r = Rc16(this->c); \ REG uint8_t g = Gc16(this->c); \ REG uint8_t b = Bc16(this->c); \ REG uint8_t a = this->alpha; \ REG uint8_t oma = 255 - a; \ REG Pixel *d = this->p #define Comp16() \ d->r = Div2040((G5bitTo8bit(d->r) * oma) + (r * a)); \ d->g = Div1020((G6bitTo8bit(d->g) * oma) + (g * a)); \ d->b = Div2040((G5bitTo8bit(d->b) * oma) + (b * a)) void Set() { Setup16(); Comp16(); } void VLine(int height) { Setup16(); REG ssize_t line = this->Dest->Line; while (height--) { Comp16(); d = (Pixel*)(((uint8_t*)d) + line); } this->p = d; } void Rectangle(int x, int y) { Setup16(); REG ssize_t line = this->Dest->Line; while (y--) { d = this->p; REG Pixel *e = d + x; while (d < e) { Comp16(); d++; } this->u8 += line; } } bool Blt(LBmpMem *Src, LPalette *SPal, LBmpMem *SrcAlpha) { if (!Src) return false; if (Src->Cs == CsIndex8) { Pixel map[256]; if (SPal) { GdcRGB *p = (*SPal)[0]; for (int i=0; i<256; i++, p++) { map[i].r = G8bitTo5bit(p->r); map[i].g = G8bitTo6bit(p->g); map[i].b = G8bitTo5bit(p->b); } } else { for (int i=0; i<256; i++) { map[i].r = G8bitTo5bit(i); map[i].g = G8bitTo6bit(i); map[i].b = G8bitTo5bit(i); } } for (int y=0; yy; y++) { uchar *s = ((uchar*)Src->Base) + (y * Src->Line); Pixel *d = this->p; for (int x=0; xx; x++) { *d++ = map[*s++]; } this->u8 += this->Dest->Line; } return true; } else { LBmpMem Dst; Dst.Base = this->u8; Dst.x = Src->x; Dst.y = Src->y; Dst.Cs = this->Dest->Cs; Dst.Line = this->Dest->Line; return LRopUniversal(&Dst, Src, true); } } }; template class GdcAlpha24 : public GdcAlpha { public: const char *GetClass() { return "GdcAlpha24"; } #define InitComposite24() \ uchar *DivLut = Div255Lut; \ REG uint8_t a = this->alpha; \ REG uint8_t oma = this->one_minus_alpha; \ REG int r = this->p24.r * a; \ REG int g = this->p24.g * a; \ REG int b = this->p24.b * a #define InitFlat24() \ Pixel px; \ px.r = this->p24.r; \ px.g = this->p24.g; \ px.b = this->p24.b #define Composite24(ptr) \ ptr->r = DivLut[(oma * ptr->r) + r]; \ ptr->g = DivLut[(oma * ptr->g) + g]; \ ptr->b = DivLut[(oma * ptr->b) + b] void Set() { InitComposite24(); Composite24(this->p); } void VLine(int height) { if (this->alpha == 255) { InitFlat24(); while (height-- > 0) { *this->p = px; this->u8 += this->Dest->Line; } } else if (this->alpha > 0) { InitComposite24(); while (height-- > 0) { Composite24(this->p); this->u8 += this->Dest->Line; } } } void Rectangle(int x, int y) { if (this->alpha == 0xff) { InitFlat24(); while (y-- > 0) { REG Pixel *s = this->p; REG Pixel *e = s + x; while (s < e) { *s++ = px; } this->u8 += this->Dest->Line; } } else if (this->alpha > 0) { InitComposite24(); while (y-- > 0) { REG Pixel *s = this->p; REG Pixel *e = s + x; while (s < e) { Composite24(s); s++; } this->u8 += this->Dest->Line; } } } template void CompositeBlt24(LBmpMem *Src) { uchar *Lut = Div255Lut; REG uint8_t a = this->alpha; REG uint8_t oma = this->one_minus_alpha; for (int y=0; yy; y++) { Pixel *dst = this->p; Pixel *dst_end = dst + Src->x; SrcPx *src = (SrcPx*)(Src->Base + (y * Src->Line)); if (a == 0xff) { while (dst < dst_end) { // No source alpha, just copy blt dst->r = src->r; dst->g = src->g; dst->b = src->b; dst++; src++; } } else if (a > 0) { while (dst < dst_end) { // No source alpha, but apply our local alpha dst->r = Lut[(dst->r * oma) + (src->r * a)]; dst->g = Lut[(dst->g * oma) + (src->g * a)]; dst->b = Lut[(dst->b * oma) + (src->b * a)]; dst++; src++; } } this->u8 += this->Dest->Line; } } template void CompositeBlt32(LBmpMem *Src) { uchar *Lut = Div255Lut; REG uint8_t a = this->alpha; if (a == 0xff) { // Apply the source alpha only for (int y=0; yy; y++) { Pixel *dst = this->p; Pixel *dst_end = dst + Src->x; SrcPx *src = (SrcPx*)(Src->Base + (y * Src->Line)); while (dst < dst_end) { REG uint8_t sa = src->a; REG uint8_t soma = 0xff - sa; dst->r = Lut[(dst->r * soma) + (src->r * sa)]; dst->g = Lut[(dst->g * soma) + (src->g * sa)]; dst->b = Lut[(dst->b * soma) + (src->b * sa)]; dst++; src++; } this->u8 += this->Dest->Line; } } else if (a > 0) { // Apply source alpha AND our local alpha for (int y=0; yy; y++) { Pixel *dst = this->p; Pixel *dst_end = dst + Src->x; SrcPx *src = (SrcPx*)(Src->Base + (y * Src->Line)); while (dst < dst_end) { REG uint8_t sa = Lut[a * src->a]; REG uint8_t soma = 0xff - sa; dst->r = Lut[(dst->r * soma) + (src->r * sa)]; dst->g = Lut[(dst->g * soma) + (src->g * sa)]; dst->b = Lut[(dst->b * soma) + (src->b * sa)]; dst++; src++; } this->u8 += this->Dest->Line; } } } bool Blt(LBmpMem *Src, LPalette *SPal, LBmpMem *SrcAlpha = 0) { if (!Src) return false; if (SrcAlpha) { LAssert(!"Impl me."); } else { switch (Src->Cs) { case CsIndex8: { Pixel map[256]; for (int i=0; i<256; i++) { GdcRGB *p = (SPal) ? (*SPal)[i] : NULL; if (p) { map[i].r = p->r; map[i].g = p->g; map[i].b = p->b; } else { map[i].r = i; map[i].g = i; map[i].b = i; } } for (int y=0; yy; y++) { uchar *s = ((uchar*)Src->Base) + (y * Src->Line); Pixel *d = this->p; for (int x=0; xx; x++) { *d++ = map[*s++]; } this->u8 += this->Dest->Line; } return true; } #define Blt24Case(name, size) \ case Cs##name: \ CompositeBlt##size(Src); \ break Blt24Case(Rgb24, 24); Blt24Case(Bgr24, 24); Blt24Case(Rgbx32, 24); Blt24Case(Bgrx32, 24); Blt24Case(Xrgb32, 24); Blt24Case(Xbgr32, 24); Blt24Case(Rgba32, 32); Blt24Case(Bgra32, 32); Blt24Case(Argb32, 32); Blt24Case(Abgr32, 32); #undef Blt24Case default: { LBmpMem Dst; Dst.Base = this->u8; Dst.x = Src->x; Dst.y = Src->y; Dst.Cs = this->Dest->Cs; Dst.Line = this->Dest->Line; return LRopUniversal(&Dst, Src, true); break; } } } return false; } }; template class GdcAlpha32 : public GdcAlpha { public: #define InitComposite32() \ uchar *DivLut = Div255Lut; \ REG int a = DivLut[this->alpha * this->p32.a]; \ REG int r = this->p32.r * a; \ REG int g = this->p32.g * a; \ REG int b = this->p32.b * a; \ REG uint8_t oma = 0xff - a #define InitFlat32() \ Pixel px; \ px.r = this->p32.r; \ px.g = this->p32.g; \ px.b = this->p32.b; \ px.a = this->p32.a #define Composite32(ptr) \ ptr->r = DivLut[(oma * ptr->r) + r]; \ ptr->g = DivLut[(oma * ptr->g) + g]; \ ptr->b = DivLut[(oma * ptr->b) + b]; \ ptr->a = (a + ptr->a) - DivLut[a * ptr->a] const char *GetClass() { return "GdcAlpha32"; } void Set() { InitComposite32(); Composite32(this->p); } void VLine(int height) { int sa = Div255Lut[this->alpha * this->p32.a]; if (sa == 0xff) { InitFlat32(); while (height-- > 0) { *this->p = px; this->u8 += this->Dest->Line; } } else if (sa > 0) { InitComposite32(); while (height-- > 0) { Composite32(this->p); this->u8 += this->Dest->Line; } } } void Rectangle(int x, int y) { int sa = Div255Lut[this->alpha * this->p32.a]; if (sa == 0xff) { // Fully opaque InitFlat32(); while (y--) { Pixel *d = this->p; Pixel *e = d + x; while (d < e) { *d++ = px; } this->u8 += this->Dest->Line; } } else if (sa > 0) { // Translucent InitComposite32(); while (y--) { Pixel *d = this->p; Pixel *e = d + x; while (d < e) { Composite32(d); d++; } this->u8 += this->Dest->Line; } } } template void PmBlt32(LBmpMem *Src) { REG uchar *DivLut = Div255Lut; for (int y=0; yy; y++) { REG Pixel *d = this->p, *e = d + Src->x; REG SrcPx *s = (SrcPx*)(Src->Base + (Src->Line * y)); while (d < e) { OverPm32toPm32(s, d); d++; s++; } this->u8 += this->Dest->Line; } } bool Blt(LBmpMem *Src, LPalette *SPal, LBmpMem *SrcAlpha = 0) { if (!Src) return 0; REG uchar *DivLut = Div255Lut; uchar lookup[256]; REG uint8_t a = this->alpha; REG uint8_t oma = this->one_minus_alpha; for (int i=0; i<256; i++) { lookup[i] = DivLut[i * this->alpha]; } if (SrcAlpha) { switch (Src->Cs) { case CsIndex8: case CsAlpha8: { System24BitPixel c[256]; CreatePaletteLut(c, SPal); for (int y=0; yy; y++) { uchar *s = (uchar*) (Src->Base + (y * Src->Line)); uchar *sa = (uchar*) (SrcAlpha->Base + (y * SrcAlpha->Line)); System24BitPixel *sc; Pixel *d = this->p; uchar a, o; for (int x=0; xx; x++) { a = lookup[*sa++]; if (a == 255) { sc = c + *s; d->r = sc->r; d->g = sc->g; d->b = sc->b; d->a = 255; } else if (a) { sc = c + *s; o = 0xff - a; d->r = DivLut[(d->r * o) + (sc->r * a)]; d->g = DivLut[(d->g * o) + (sc->g * a)]; d->b = DivLut[(d->b * o) + (sc->b * a)]; d->a = (a + d->a) - DivLut[a * d->a]; } s++; d++; } this->u8 += this->Dest->Line; } break; } case System15BitColourSpace: { for (int y=0; yy; y++) { ushort *s = (ushort*) (Src->Base + (y * Src->Line)); uchar *sa = SrcAlpha->Base + (y * SrcAlpha->Line); Pixel *d = this->p; for (int x=0; xx; x++) { uchar a = lookup[*sa++]; if (a == 255) { d->r = Rc15(*s); d->g = Gc15(*s); d->b = Bc15(*s); } else if (a) { uchar o = 255 - a; d->r = DivLut[(a * Rc15(*s)) + (o * d->r)]; d->g = DivLut[(a * Gc15(*s)) + (o * d->g)]; d->b = DivLut[(a * Bc15(*s)) + (o * d->b)]; } s++; d++; } this->u8 += this->Dest->Line; } break; } case System16BitColourSpace: { for (int y=0; yy; y++) { ushort *s = (ushort*) (Src->Base + (y * Src->Line)); uchar *sa = SrcAlpha->Base + (y * SrcAlpha->Line); Pixel *d = this->p; for (int x=0; xx; x++) { uchar a = lookup[*sa++]; if (a == 255) { d->r = Rc16(*s); d->g = Gc16(*s); d->b = Bc16(*s); } else if (a) { uchar o = 255 - a; d->r = DivLut[(a * Rc16(*s)) + (o * d->r)]; d->g = DivLut[(a * Gc16(*s)) + (o * d->g)]; d->b = DivLut[(a * Bc16(*s)) + (o * d->b)]; } s++; d++; } this->u8 += this->Dest->Line; } break; } case System24BitColourSpace: { for (int y=0; yy; y++) { uchar *sa = SrcAlpha->Base + (y * SrcAlpha->Line); Pixel *d = this->p; System24BitPixel *s = (System24BitPixel*) (Src->Base + (y * Src->Line)); for (int x=0; xx; x++) { uchar a = lookup[*sa++]; if (a == 255) { d->r = s->r; d->g = s->g; d->b = s->b; } else if (a) { uchar o = 255 - a; d->r = DivLut[(a * s->r) + (o * d->r)]; d->g = DivLut[(a * s->g) + (o * d->g)]; d->b = DivLut[(a * s->b) + (o * d->b)]; } d++; s++; } this->u8 += this->Dest->Line; } break; } case System32BitColourSpace: { for (int y=0; yy; y++) { Pixel *d = this->p; Pixel *s = (Pixel*) (Src->Base + (y * Src->Line)); uchar *sa = SrcAlpha->Base + (y * SrcAlpha->Line); for (int x=0; xx; x++) { uchar a = lookup[*sa++]; if (a == 255) { d->r = s->r; d->g = s->g; d->b = s->b; d->a = 255; } else if (a) { uchar o = 255 - a; d->r = DivLut[(a * s->r) + (o * d->r)]; d->g = DivLut[(a * s->g) + (o * d->g)]; d->b = DivLut[(a * s->b) + (o * d->b)]; d->a = (s->a + d->a) - DivLut[s->a * d->a]; } d++; s++; } this->u8 += this->Dest->Line; } break; } default: return false; } return true; } if (this->Dest->PreMul() || Src->PreMul()) { switch (Src->Cs) { case CsRgba32: PmBlt32(Src); return true; case CsBgra32: PmBlt32(Src); return true; case CsArgb32: PmBlt32(Src); return true; case CsAbgr32: PmBlt32(Src); return true; default: break; } } switch (Src->Cs) { default: { LBmpMem Dst; Dst.Base = this->u8; Dst.x = Src->x; Dst.y = Src->y; Dst.Cs = this->Dest->Cs; Dst.Line = this->Dest->Line; if (!LRopUniversal(&Dst, Src, true)) { return false; } break; } case CsIndex8: { System24BitPixel c[256]; if (SPal && SPal->GetSize() == 0) return false; CreatePaletteLut(c, SPal, this->alpha); for (int y=0; yy; y++) { uchar *s = (uchar*) (Src->Base + (y * Src->Line)); System24BitPixel *sc; Pixel *d = this->p; if (this->alpha == 255) { for (int x=0; xx; x++) { sc = c + *s++; d->r = sc->r; d->g = sc->g; d->b = sc->b; d->a = 255; d++; } } else if (this->alpha) { for (int x=0; xx; x++) { sc = c + *s++; d->r = sc->r + DivLut[d->r * oma]; d->g = sc->g + DivLut[d->g * oma]; d->b = sc->b + DivLut[d->b * oma]; d->a = (a + d->a) - DivLut[a * d->a]; d++; } } this->u8 += this->Dest->Line; } break; } } return true; } }; LApplicator *LAlphaFactory::Create(LColourSpace Cs, int Op) { if (Op != GDC_ALPHA) return NULL; switch (Cs) { #define Case(name, px) \ case Cs##name: \ return new GdcAlpha##px() Case(Rgb15, 15); Case(Bgr15, 15); Case(Rgb16, 16); Case(Bgr16, 16); Case(Rgb24, 24); Case(Bgr24, 24); Case(Rgbx32, 24); Case(Bgrx32, 24); Case(Xrgb32, 24); Case(Xbgr32, 24); Case(Rgba32, 32); Case(Bgra32, 32); Case(Argb32, 32); Case(Abgr32, 32); #undef Case case CsIndex8: return new GdcApp8Alpha; default: LgiTrace("%s:%i - Unknown colour space: 0x%x %s\n", _FL, Cs, LColourSpaceToString(Cs)); // LAssert(0); break; } return 0; } GdcApp8Alpha::GdcApp8Alpha() { Bits = 8; Bytes = 1; Op = GDC_ALPHA; ZeroObj(Remap); DivLut = Div255Lut; } int GdcApp8Alpha::SetVar(int Var, NativeInt Value) { int Status = LAlphaApp::SetVar(Var, Value); switch (Var) { case GAPP_ALPHA_PAL: { LPalette *Pal = (LPalette*)Value; if (Pal && alpha < 255) { GdcRGB *p = (*Pal)[0]; GdcRGB *Col = (*Pal)[c&0xFF]; for (int i=0; iGetSize(); i++) { COLOUR Rgb = Rgb24( Div255((oma * p[i].r) + (alpha * Col->r)), Div255((oma * p[i].g) + (alpha * Col->g)), Div255((oma * p[i].b) + (alpha * Col->b))); Remap[i] = Pal->MatchRgb(Rgb); } } else { for (int i=0; i<256; i++) { Remap[i] = c; } } break; } } return Status; } void GdcApp8Alpha::Set() { *Ptr = Remap[*Ptr]; if (APtr) { *APtr += DivLut[(255 - *APtr) * alpha]; } } void GdcApp8Alpha::VLine(int y) { while (y--) { *Ptr = Remap[*Ptr]; Ptr += Dest->Line; if (APtr) { *APtr += DivLut[(255 - *APtr) * alpha]; APtr += Alpha->Line; } } } void GdcApp8Alpha::Rectangle(int x, int y) { while (y--) { uchar *p = Ptr; uchar *e = Ptr + x; while (p < e) { *p = Remap[*p]; p++; } Ptr += Dest->Line; if (APtr) { uchar *a = APtr; e = a + x; while (a < e) { *a += DivLut[(255 - *a) * alpha]; a++; } APtr += Alpha->Line; } } } bool GdcApp8Alpha::Blt(LBmpMem *Src, LPalette *SPal, LBmpMem *SrcAlpha) { if (!Src) return false; if (!SPal) SPal = Pal; LPalette Grey; LPalette *DPal; if (Pal) { DPal = Pal; } else { Grey.CreateGreyScale(); DPal = &Grey; } uchar *DivLut = Div255Lut; uchar *Lut = 0; uchar lookup[256]; for (int i=0; i<256; i++) { lookup[i] = (i * (int)alpha) / 255; } if (SrcAlpha) { // Per pixel source alpha GdcRGB *SRgb = (*SPal)[0]; GdcRGB *DRgb = (*DPal)[0]; if (!SRgb || !DRgb) return false; switch (Src->Cs) { default: { LAssert(!"Not impl."); break; } case CsIndex8: { System24BitPixel sc[256]; CreatePaletteLut(sc, SPal); System24BitPixel dc[256]; CreatePaletteLut(dc, DPal); for (int y=0; yy; y++) { uchar *s = Src->Base + (y * Src->Line); uchar *sa = SrcAlpha->Base + (y * SrcAlpha->Line); uchar *d = Ptr; int r = 0, g = 0, b = 0; Lut = DPal->MakeLut(15); for (int x=0; xx; x++) { uchar a = lookup[*sa]; System24BitPixel *src = sc + *s; if (a == 255) { r = src->r; g = src->g; b = src->b; } else if (a) { uchar o = 0xff - a; System24BitPixel *dst = dc + *d; r = DivLut[(dst->r * o) + (src->r * a)]; g = DivLut[(dst->g * o) + (src->g * a)]; b = DivLut[(dst->b * o) + (src->b * a)]; } *d++ = Lut[Rgb15(r, g, b)]; sa++; s++; } Ptr += Dest->Line; } break; } case System15BitColourSpace: { System24BitPixel dc[256]; CreatePaletteLut(dc, DPal); if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { ushort *s = (ushort*) (Src->Base + (y * Src->Line)); uchar *sa = SrcAlpha->Base + (y * SrcAlpha->Line); uchar *d = Ptr; uchar *end = d + Src->x; while (d < end) { uchar a = lookup[*sa++]; if (a == 255) { *d = Lut[*s]; } else if (a) { uchar o = 255 - a; System24BitPixel *dst = dc + *d; int r = DivLut[(dst->r * o) + (Rc15(*s) * a)]; int g = DivLut[(dst->g * o) + (Gc15(*s) * a)]; int b = DivLut[(dst->b * o) + (Bc15(*s) * a)]; *d = Lut[Rgb15(r, g, b)]; } d++; s++; } Ptr += Dest->Line; } break; } case System16BitColourSpace: { System24BitPixel dc[256]; CreatePaletteLut(dc, DPal); if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { ushort *s = (ushort*) (Src->Base + (y * Src->Line)); uchar *sa = SrcAlpha->Base + (y * SrcAlpha->Line); uchar *d = Ptr; uchar *end = d + Src->x; while (d < end) { uchar a = lookup[*sa++]; if (a == 255) { *d = Lut[Rgb16To15(*s)]; } else if (a) { uchar o = 255 - a; System24BitPixel *dst = dc + *d; int r = DivLut[(dst->r * o) + (Rc16(*s) * a)]; int g = DivLut[(dst->g * o) + (Gc16(*s) * a)]; int b = DivLut[(dst->b * o) + (Bc16(*s) * a)]; *d = Lut[Rgb15(r, g, b)]; } d++; s++; } Ptr += Dest->Line; } break; } case CsBgr24: { LBgr24 dc[256]; CreatePaletteLut(dc, DPal, 255); if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { LBgr24 *s = (LBgr24*) (Src->Base + (y * Src->Line)); uchar *sa = SrcAlpha->Base + (y * SrcAlpha->Line); uchar *d = Ptr; for (int x=0; xx; x++) { uchar a = lookup[*sa++]; if (a == 255) { *d = Lut[Rgb15(s->r, s->g, s->b)]; } else if (a) { uchar o = 255 - a; LBgr24 *dst = dc + *d; int r = DivLut[(dst->r * o) + (s->r * a)]; int g = DivLut[(dst->g * o) + (s->g * a)]; int b = DivLut[(dst->b * o) + (s->b * a)]; *d = Lut[Rgb15(r, g, b)]; } d++; s++; } Ptr += Dest->Line; } break; } case System32BitColourSpace: { System24BitPixel dc[256]; CreatePaletteLut(dc, DPal, 255); if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { System32BitPixel *s = (System32BitPixel*) (Src->Base + (y * Src->Line)); uchar *sa = SrcAlpha->Base + (y * SrcAlpha->Line); uchar *d = Ptr; for (int x=0; xx; x++) { uchar a = lookup[*sa++]; if (a == 255) { *d = Lut[Rgb15(s->r, s->g, s->b)]; } else if (a) { uchar o = 255 - a; System24BitPixel *dst = dc + *d; int r = DivLut[(dst->r * o) + (s->r * a)]; int g = DivLut[(dst->g * o) + (s->g * a)]; int b = DivLut[(dst->b * o) + (s->b * a)]; *d = Lut[Rgb15(r, g, b)]; } d++; s++; } Ptr += Dest->Line; } break; } } } else { // Global alpha level GdcRGB *SRgb = (*SPal)[0]; GdcRGB *DRgb = (*DPal)[0]; if (!SRgb || !DRgb) return false; switch (Src->Cs) { default: { LgiTrace("%s:%i - Not impl.\n", _FL); break; } case CsIndex8: { if (alpha == 255) { // do a straight blt for (int y=0; yy; y++) { uchar *s = Src->Base + (y * Src->Line); uchar *d = Ptr; memcpy(d, s, Src->x); Ptr += Dest->Line; } } else if (alpha) { System24BitPixel sc[256]; CreatePaletteLut(sc, SPal, alpha); System24BitPixel dc[256]; CreatePaletteLut(dc, DPal, oma); if (!Lut) Lut = DPal->MakeLut(15); for (int y=0; yy; y++) { uchar *s = Src->Base + (y * Src->Line); uchar *d = Ptr; for (int x=0; xx; x++, s++, d++) { System24BitPixel *src = sc + *s; System24BitPixel *dst = dc + *d; int r = src->r + dst->r; int g = src->g + dst->g; int b = src->b + dst->b; *d = Lut[Rgb15(r, g, b)]; } Ptr += Dest->Line; } } break; } #define Case(Px, Sz) \ case Cs##Px: \ AlphaBlt##Sz(Src, DPal, Lut); \ break Case(Rgb15, 15); Case(Bgr15, 15); Case(Rgb16, 16); Case(Bgr16, 16); Case(Rgb24, 24); Case(Bgr24, 24); Case(Rgbx32, 24); Case(Bgrx32, 24); Case(Xrgb32, 24); Case(Xbgr32, 24); Case(Rgba32, 32); Case(Bgra32, 32); Case(Argb32, 32); Case(Abgr32, 32); Case(Rgb48, 48); Case(Bgr48, 48); Case(Rgba64, 64); Case(Bgra64, 64); Case(Argb64, 64); Case(Abgr64, 64); #undef Case } } return false; } diff --git a/src/common/Widgets/ToolBar.cpp b/src/common/Widgets/ToolBar.cpp --- a/src/common/Widgets/ToolBar.cpp +++ b/src/common/Widgets/ToolBar.cpp @@ -1,1756 +1,1759 @@ /* ** FILE: GToolbar.cpp ** AUTHOR: Matthew Allen ** DATE: 18/10/2001 ** DESCRIPTION: Toolbar classes ** ** Copyright (C) 2001, Matthew Allen ** fret@memecode.com */ #include #include #include "lgi/common/Lgi.h" #include "lgi/common/Variant.h" #include "lgi/common/DisplayString.h" #include "lgi/common/Palette.h" #include "lgi/common/Notifications.h" #include "lgi/common/LgiRes.h" #include "lgi/common/CssTools.h" #include "lgi/common/ToolBar.h" #include "lgi/common/ToolTip.h" #include "lgi/common/Menu.h" #define ToolBarHilightColour LC_HIGH #ifdef WIN32 -HPALETTE GetSystemPalette(); -bool BltBmpToBmp(HBITMAP hDest, int xDst, int yDst, int cx, int cy, HBITMAP hSrc, int xSrc, int ySrc, DWORD dwRop); -bool BltBmpToDc(HDC DestDC, int xDst, int yDst, int cx, int cy, HBITMAP hSrc, int xSrc, int ySrc, DWORD dwRop); -bool BltDcToBmp(HBITMAP hDest, int xDst, int yDst, int cx, int cy, HDC SrcDC, int xSrc, int ySrc, DWORD dwRop); + HPALETTE GetSystemPalette(); + bool BltBmpToBmp(HBITMAP hDest, int xDst, int yDst, int cx, int cy, HBITMAP hSrc, int xSrc, int ySrc, DWORD dwRop); + bool BltBmpToDc(HDC DestDC, int xDst, int yDst, int cx, int cy, HBITMAP hSrc, int xSrc, int ySrc, DWORD dwRop); + bool BltDcToBmp(HBITMAP hDest, int xDst, int yDst, int cx, int cy, HDC SrcDC, int xSrc, int ySrc, DWORD dwRop); -#define AttachButton(b) AddView(b); + #define AttachButton(b) AddView(b); #else -#define AttachButton(b) b->Attach(this); + #define AttachButton(b) b->Attach(this); #endif enum IconCacheType { IconNormal, IconHilight, IconDisabled }; COLOUR Map(LSurface *pDC, COLOUR c); //////////////////////////////////////////////////////////////////////// LImageList *LLoadImageList(const char *File, int x, int y) { if (!File) return NULL; if (x < 0 || y < 0) { // Detect dimensions in the filename. auto leaf = LString(File).Split(DIR_STR).Last(); auto parts = leaf.RSplit(".", 1); auto last = parts[0].Split("-").Last(); auto dim = last.Split("x"); if (dim.Length() == 1) { auto i = dim[0].Strip().Int(); if (i > 0) x = y = (int)i; } else if (dim.Length() == 2) { auto X = dim[0].Strip().Int(), Y = dim[1].Strip().Int(); if (X > 0 && Y > 0) { x = (int)X; y = (int)Y; } } } auto Path = LFileExists(File) ? LString(File) : LFindFile(File); if (!Path) { LgiTrace("%s:%i - Couldn't find '%s'\n", _FL, File); return NULL; } LAutoPtr pDC(GdcD->Load(Path)); if (!pDC) { LgiTrace("%s:%i - Couldn't load '%s'\n", _FL, Path.Get()); return NULL; } return new LImageList(x, y, pDC); } LToolBar *LgiLoadToolbar(LViewI *Parent, const char *File, int x, int y) { LToolBar *Toolbar = new LToolBar; if (!Toolbar) return NULL; LString FileName = LFindFile(File); if (FileName) { bool Success = FileName && Toolbar->SetBitmap(FileName, x, y); if (!Success) { LgiMsg(Parent, "Can't load '%s' for the toolbar.\n" "This is probably because libpng/libjpeg is missing.", "LgiLoadToolbar", MB_OK, File); } } else { LgiMsg(Parent, "Can't find the graphic '%s' for the toolbar.\n" "You can find it in this program's archive.", "LgiLoadToolbar", MB_OK, File); } return Toolbar; } ///////////////////////////////////////////////////////////////////////////////////////////////////////// #define ImgLst_Empty 0x40000000 #define IgmLst_Add 0x80000000 class LImageListPriv { public: LImageList *ImgLst; int Sx, Sy; uint8_t DisabledAlpha; struct CacheDC : public LMemDC { bool Disabled; LColour Back; }; LArray Cache; LArray Bounds; CacheDC *GetCache(LColour Back, bool Disabled) { if (Back.IsTransparent()) return NULL; for (int i=0; iBack == Back && dc->Disabled == Disabled) return dc; } CacheDC *dc = new CacheDC; if (dc) { dc->Disabled = Disabled; dc->Back = Back; bool Status = dc->Create(ImgLst->X(), ImgLst->Y(), GdcD->GetColourSpace()); if (Status) { dc->Colour(dc->Back); dc->Rectangle(); dc->Op(GDC_ALPHA); if (Disabled) { LMemDC tmp(ImgLst->X(), ImgLst->Y(), System32BitColourSpace, LSurface::SurfaceRequireExactCs); tmp.Colour(0, 32); tmp.Rectangle(); tmp.Op(GDC_ALPHA); tmp.Blt(0, 0, ImgLst); tmp.SetConstantAlpha(DisabledAlpha); dc->Blt(0, 0, &tmp); } else { dc->Blt(0, 0, ImgLst); } Cache.Add(dc); } else { delete dc; LAssert(!"Create memdc failed."); } } return dc; } LImageListPriv(LImageList *imglst, int x, int y) { ImgLst = imglst; Sx = x; Sy = y; DisabledAlpha = 40; } ~LImageListPriv() { Cache.DeleteObjects(); } }; static bool HasPad(LColourSpace cs) { if (cs == CsRgbx32 || cs == CsBgrx32 || cs == CsXrgb32 || cs == CsXbgr32) return true; return false; } LImageList::LImageList(int x, int y, LSurface *pDC) { d = new LImageListPriv(this, x, y); uint32_t Transparent = 0; if (pDC && Create(pDC->X(), pDC->Y(), System32BitColourSpace, LSurface::SurfaceRequireExactCs)) { Colour(Transparent, 32); Rectangle(); int Old = Op(GDC_ALPHA); Blt(0, 0, pDC); Op(Old); #if 0 printf("Toolbar input image is %s, has_alpha=%i, has_pad=%i\n", LColourSpaceToString(pDC->GetColourSpace()), pDC->HasAlpha(), HasPad(pDC->GetColourSpace())); #endif #if 0 static int Idx = 0; char s[256]; sprintf_s(s, sizeof(s), "imglst_%i.bmp", Idx++); GdcD->Save(s, this); // sprintf_s(s, sizeof(s), "src_%i.bmp", Idx++); // GdcD->Save(s, pDC); #endif if (pDC->GetBits() < 32 || HasPad(pDC->GetColourSpace())) { if (!pDC->HasAlpha()) { // No source alpha, do colour keying to create the alpha channel REG uint32_t *p = (uint32_t*)(*this)[0]; if (p) { uint32_t key = *p; for (int y=0; ya == 0) { p->r = 0; p->g = 0; p->b = 0; } p++; } } } } } LImageList::~LImageList() { DeleteObj(d); } void LImageList::Draw(LSurface *pDC, int Dx, int Dy, int Image, LColour Background, bool Disabled) { if (!pDC) return; LRect rSrc; rSrc.ZOff(d->Sx-1, d->Sy-1); rSrc.Offset(Image * d->Sx, 0); LImageListPriv::CacheDC *Cache = d->GetCache(Background, Disabled); if (!Cache && Background.IsValid()) { LRect rDst; rDst.ZOff(d->Sx-1, d->Sy-1); rDst.Offset(Dx, Dy); pDC->Colour(Background); pDC->Rectangle(&rDst); pDC->Colour(LColour(255, 0, 0)); pDC->Line(rDst.x1, rDst.y1, rDst.x2, rDst.y2); pDC->Line(rDst.x2, rDst.y1, rDst.x1, rDst.y2); return; } - if (pDC->SupportsAlphaCompositing()) + if (pDC->SupportsAlphaCompositing() + #if HAIKU + && !Disabled // Constant alpha blt not supported (yet??!) + #endif + ) { int Old = pDC->Op(GDC_ALPHA, Disabled ? d->DisabledAlpha : -1); pDC->Blt(Dx, Dy, this, &rSrc); pDC->Op(Old); } else if (Cache) { pDC->Blt(Dx, Dy, Cache, &rSrc); } else LAssert(!"Impl me."); } int LImageList::TileX() { return d->Sx; } int LImageList::TileY() { return d->Sy; } int LImageList::GetItems() { return X() / d->Sx; } void LImageList::Update(int Flags) { } uint8_t LImageList::GetDisabledAlpha() { return d->DisabledAlpha; } void LImageList::SetDisabledAlpha(uint8_t alpha) { d->DisabledAlpha = alpha; } LRect LImageList::GetIconRect(int Idx) { LRect r(0, 0, -1, -1); if (Idx >= 0 && Idx < GetItems()) { r.ZOff(d->Sx-1, d->Sy-1); r.Offset(Idx * d->Sx, 0); } return r; } LRect *LImageList::GetBounds() { if (!d->Bounds.Length() && (*this)[0]) { int Items = GetItems(); if (d->Bounds.Length(Items)) { for (int i=0; iBounds[i].ZOff(d->Sx - 1, d->Sy - 1); d->Bounds[i].Offset(i * d->Sx, 0); LFindBounds(this, &d->Bounds[i]); d->Bounds[i].Offset(-i * d->Sx, 0); } } } return &d->Bounds[0]; } ///////////////////////////////////////////////////////////////////////////////////////////////////////// class LToolBarPrivate { public: int Bx, By; int Sx, Sy; bool Vertical; bool Text; int LastIndex; bool OwnImgList; LImageList *ImgList; LFont *Font; LToolTip *Tip; // Customization menu LDom *CustomDom; const char *CustomProp; // bitmap cache LAutoPtr IconCache; LToolBarPrivate() { Bx = By = 16; Sx = Sy = 10; Vertical = false; Text = false; Font = 0; Tip = 0; CustomProp = 0; CustomDom = 0; } bool ShowTextLabels() { return (Text || !ImgList) && Font; } void FixSeparators(LToolBar *Tb) { // Fix up separators so that no 2 separators are next to each other. I.e. // all the buttons between them are switched off. LToolButton *Last = 0; bool HasVis = false; for (LViewI *v: Tb->IterateViews()) { LToolButton *Btn = dynamic_cast(v); if (Btn) { if (Btn->Separator()) { Btn->Visible(HasVis); if (HasVis) { Last = Btn; } HasVis = false; } else { HasVis |= Btn->Visible(); } } } if (Last) { Last->Visible(HasVis); } } void Customizable(LToolBar *Tb) { LVariant v; if (CustomDom) { CustomDom->GetValue(CustomProp, v); } char *o; if ((o = v.Str())) { auto t = LString(o).SplitDelimit(","); if (t.Length() >= 1) { Text = stricmp(t[0], "text") == 0; // Make all controls not visible. for (auto v: Tb->IterateViews()) { LToolButton *Btn = dynamic_cast(v); if (Btn) v->Visible(false); } // Set sub-set of ctrls visible according to saved ID list for (int i=1; i 0) Tb->SetCtrlVisible(Id, true); } FixSeparators(Tb); } } } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////// struct LToolButtonPriv { LArray Text; }; LToolButton::LToolButton(int Bx, int By) { d = new LToolButtonPriv; Type = TBT_PUSH; SetId(IDM_NONE); Down = false; Clicked = false; Over = false; ImgIndex = -1; NeedsRightClick = false; LRect r(0, 0, Bx+1, By+1); SetPos(r); SetParent(0); TipId = -1; _BorderSize = 0; LResources::StyleElement(this); } LToolButton::~LToolButton() { d->Text.DeleteObjects(); delete d; } bool LToolButton::Name(const char *n) { bool s = LView::Name(n); d->Text.DeleteObjects(); return s; } void LToolButton::Layout() { auto Parent = GetParent(); LToolBar *ToolBar = dynamic_cast(Parent); if (!ToolBar) return; // Text auto s = Name(); if (!ToolBar->d->ShowTextLabels() || !s) return; // Write each word centered on a different line char Buf[256]; strcpy_s(Buf, sizeof(Buf), s); auto t = LString(Buf).SplitDelimit(" "); if (t.Length() < 3) { if (t.Length() > 0) d->Text.Add(new LDisplayString(ToolBar->d->Font, t[0])); if (t.Length() > 1) d->Text.Add(new LDisplayString(ToolBar->d->Font, t[1])); } else if (t.Length() == 3) { sprintf_s(Buf, sizeof(Buf), "%s %s", t[0].Get(), t[1].Get()); LDisplayString *d1 = new LDisplayString(ToolBar->d->Font, Buf); sprintf_s(Buf, sizeof(Buf), "%s %s", t[1].Get(), t[2].Get()); LDisplayString *d2 = new LDisplayString(ToolBar->d->Font, Buf); if (d1 && d2) { if (d1->X() < d2->X()) { DeleteObj(d2); d->Text.Add(d1); d->Text.Add(new LDisplayString(ToolBar->d->Font, t[2])); } else { DeleteObj(d1); d->Text.Add(new LDisplayString(ToolBar->d->Font, t[0])); d->Text.Add(d2); } } } } void LToolButton::OnPaint(LSurface *pDC) { LToolBar *Par = dynamic_cast(GetParent()); bool e = Enabled(); - if (Par) + if (!Par) { - LRect p = GetClient(); - - #if 0 // def _DEBUG pDC->Colour(LColour(255, 0, 255)); - pDC->Rectangle(); - #endif + pDC->Box(); + return; + } + + LRect p = GetClient(); + + #if 0 // def _DEBUG + pDC->Colour(LColour(255, 0, 255)); + pDC->Rectangle(); + #endif - LCssTools Tools(this); - LColour cBack = Tools.GetBack(); - auto BackImg = Tools.GetBackImage(); - bool Hilight = e && Over; - if (Hilight) - cBack = cBack.Mix(LColour::White); + LCssTools Tools(this); + LColour cBack = Tools.GetBack(); + auto BackImg = Tools.GetBackImage(); + bool Hilight = e && Over; + if (Hilight) + cBack = cBack.Mix(LColour::White); + + // Draw Background + if (GetId() >= 0) + { + // Draw border + LColour Background; + if (Down) // Sunken if the button is pressed + LThinBorder(pDC, p, DefaultSunkenEdge); - // Draw Background - if (GetId() >= 0) + if (BackImg) { - // Draw border - LColour Background; - if (Down) // Sunken if the button is pressed - LThinBorder(pDC, p, DefaultSunkenEdge); + LDoubleBuffer Buf(pDC); + Tools.PaintContent(pDC, p); + if (Hilight) + { + // Draw translucent white over image... + pDC->Op(GDC_ALPHA); + pDC->Colour(LColour(255, 255, 255, 128)); + pDC->Rectangle(&p); + } + } + else + { + Background = cBack; + pDC->Colour(Background); + pDC->Box(&p); + p.Inset(1, 1); + } - if (BackImg) + LRect IconPos; + if (Par->d->ImgList) + IconPos.Set(0, 0, Par->d->ImgList->TileX()-1, Par->d->ImgList->TileY()-1); + else + IconPos.ZOff(Par->d->Bx-1, Par->d->By-1); + LRegion Unpainted(p); + + // Center the icon + if (IconPos.X() < p.X() - 1) + IconPos.Offset((p.X() - IconPos.X()) >> 1, 0); + // Offset it if the button is pressed + if (Down) + IconPos.Offset(2, 2); + + // Draw any icon. + if (ImgIndex >= 0) + { + if (Par->d->ImgList) { - LDoubleBuffer Buf(pDC); - Tools.PaintContent(pDC, p); - if (Hilight) + // Draw cached + if (BackImg) + { + Par->d->ImgList->SetDisabledAlpha(0x60); + } + else if (pDC->SupportsAlphaCompositing()) { - // Draw translucent white over image... - pDC->Op(GDC_ALPHA); - pDC->Colour(LColour(255, 255, 255, 128)); - pDC->Rectangle(&p); + pDC->Colour(Background); + pDC->Rectangle(&IconPos); + } + + Par->d->ImgList->Draw(pDC, IconPos.x1, IconPos.y1, ImgIndex, Background, !e); + + Unpainted.Subtract(&IconPos); + + if (!BackImg) + { + // Fill in the rest of the area + pDC->Colour(Background); + for (LRect *r = Unpainted.First(); r; r = Unpainted.Next()) + pDC->Rectangle(r); } } else { - Background = cBack; + // Draw a red cross indicating no icons. pDC->Colour(Background); - pDC->Box(&p); - p.Inset(1, 1); + pDC->Rectangle(&p); + pDC->Colour(LColour::Red); + pDC->Line(IconPos.x1, IconPos.y1, IconPos.x2, IconPos.y2); + pDC->Line(IconPos.x2, IconPos.y1, IconPos.x1, IconPos.y2); + } + } + else if (!BackImg) + { + Tools.PaintContent(pDC, p); + } + + // Text + if (Par->d->ShowTextLabels()) + { + if (Name() && !d->Text.Length()) + { + Layout(); } - LRect IconPos; - if (Par->d->ImgList) - IconPos.Set(0, 0, Par->d->ImgList->TileX()-1, Par->d->ImgList->TileY()-1); - else - IconPos.ZOff(Par->d->Bx-1, Par->d->By-1); - LRegion Unpainted(p); - - // Center the icon - if (IconPos.X() < p.X() - 1) - IconPos.Offset((p.X() - IconPos.X()) >> 1, 0); - // Offset it if the button is pressed - if (Down) - IconPos.Offset(2, 2); - - // Draw any icon. - if (ImgIndex >= 0) + if (d->Text.Length()) { - if (Par->d->ImgList) - { - // Draw cached - if (BackImg) - { - Par->d->ImgList->SetDisabledAlpha(0x60); - } - else if (pDC->SupportsAlphaCompositing()) - { - pDC->Colour(Background); - pDC->Rectangle(&IconPos); - } - - Par->d->ImgList->Draw(pDC, IconPos.x1, IconPos.y1, ImgIndex, Background, !e); - - Unpainted.Subtract(&IconPos); + // Write each word centered on a different line + int Ty = Down + Par->d->By + 2; + LColour a = Tools.GetFore(); + LColour b = Tools.GetBack(); + if (!e) + a = b.Mix(a); - if (!BackImg) - { - // Fill in the rest of the area - pDC->Colour(Background); - for (LRect *r = Unpainted.First(); r; r = Unpainted.Next()) - pDC->Rectangle(r); - } - } - else + Par->d->Font->Colour(a, b); + for (int i=0; iText.Length(); i++) { - // Draw a red cross indicating no icons. - pDC->Colour(Background); - pDC->Rectangle(&p); - pDC->Colour(LColour::Red); - pDC->Line(IconPos.x1, IconPos.y1, IconPos.x2, IconPos.y2); - pDC->Line(IconPos.x2, IconPos.y1, IconPos.x1, IconPos.y2); - } - } - else if (!BackImg) - { - Tools.PaintContent(pDC, p); - } - - // Text - if (Par->d->ShowTextLabels()) - { - if (Name() && !d->Text.Length()) - { - Layout(); - } - - if (d->Text.Length()) - { - // Write each word centered on a different line - int Ty = Down + Par->d->By + 2; - LColour a = Tools.GetFore(); - LColour b = Tools.GetBack(); - if (!e) - a = b.Mix(a); - - Par->d->Font->Colour(a, b); - for (int i=0; iText.Length(); i++) - { - LDisplayString *Ds = d->Text[i]; - Ds->Draw(pDC, Down + ((X()-Ds->X())/2), Ty); - Ty += Ds->Y(); - } + LDisplayString *Ds = d->Text[i]; + Ds->Draw(pDC, Down + ((X()-Ds->X())/2), Ty); + Ty += Ds->Y(); } } } + } + else + { + // Separator + int Px = X()-1; + int Py = Y()-1; + + if (BackImg) + Tools.PaintContent(pDC, p); else { - // Separator - int Px = X()-1; - int Py = Y()-1; + pDC->Colour(cBack); + pDC->Rectangle(); + } - if (BackImg) - Tools.PaintContent(pDC, p); - else - { - pDC->Colour(cBack); - pDC->Rectangle(); - } - - LColour cLow = cBack.Mix(LColour::Black); - LColour cHigh = cBack.Mix(LColour::White, 0.8f); + LColour cLow = cBack.Mix(LColour::Black); + LColour cHigh = cBack.Mix(LColour::White, 0.8f); - if (X() > Y()) - { - int c = Y()/2-1; - pDC->Colour(cLow); - pDC->Line(2, c, Px-2, c); - pDC->Colour(cHigh); - pDC->Line(2, c+1, Px-2, c+1); - } - else - { - int c = X()/2-1; - pDC->Colour(cLow); - pDC->Line(c, 2, c, Py-2); - pDC->Colour(cHigh); - pDC->Line(c+1, 2, c+1, Py-2); - } + if (X() > Y()) + { + int c = Y()/2-1; + pDC->Colour(cLow); + pDC->Line(2, c, Px-2, c); + pDC->Colour(cHigh); + pDC->Line(2, c+1, Px-2, c+1); + } + else + { + int c = X()/2-1; + pDC->Colour(cLow); + pDC->Line(c, 2, c, Py-2); + pDC->Colour(cHigh); + pDC->Line(c+1, 2, c+1, Py-2); } } - - #if 0 // def _DEBUG - pDC->Colour(LColour(255, 0, 255)); - pDC->Box(); - #endif } void LToolButton::Image(int i) { if (ImgIndex != i) { ImgIndex = i; Invalidate(); } } void LToolButton::Value(int64 b) { switch (Type) { case TBT_PUSH: { // do nothing... can't set value break; } case TBT_TOGGLE: { if (Value() != b) { Down = b != 0; Invalidate(); SendNotify(LNotifyValueChanged); } break; } case TBT_RADIO: { if (GetParent() && b) { // Clear any other radio buttons that are down auto it = GetParent()->IterateViews(); ssize_t CurIdx = it.IndexOf(this); if (CurIdx >= 0) { for (ssize_t i=CurIdx-1; i>=0; i--) { LToolButton *But = dynamic_cast(it[i]); if (But->Separator()) break; if (But->Type == TBT_RADIO && But->Down) But->Value(false); } for (size_t i=CurIdx+1; i(it[i]); if (But->Separator()) break; if (But->Type == TBT_RADIO && But->Down) But->Value(false); } } } Down = b != 0; if (GetParent()) { GetParent()->Invalidate(); SendNotify(LNotifyValueChanged); } break; } } } void LToolButton::SendCommand() { LToolBar *t = dynamic_cast(GetParent()); if (t) t->OnButtonClick(this); else printf("%s:%i - Error: parent not toolbar.\n", _FL); } void LToolButton::OnMouseClick(LMouse &m) { LToolBar *ToolBar = dynamic_cast(GetParent()); #if 0 printf("tool button click %i,%i down=%i, left=%i right=%i middle=%i, ctrl=%i alt=%i shift=%i Double=%i\n", m.x, m.y, m.Down(), m.Left(), m.Right(), m.Middle(), m.Ctrl(), m.Alt(), m.Shift(), m.Double()); #endif if (m.IsContextMenu()) { if (!NeedsRightClick && ToolBar && ToolBar->IsCustomizable()) { m.ToScreen(); ToolBar->ContextMenu(m); } else { SendNotify(LNotification(m)); } } else if (m.Left()) { // left click action... if (GetId() >= 0 && Enabled()) { switch (Type) { case TBT_PUSH: { bool Old = Down; Clicked = m.Down(); Capture(m.Down()); if (Old && IsOver(m)) { SendCommand(); SendNotify(LNotifyActivate); } Down = m.Down(); if (Old != Down) { Invalidate(); } break; } case TBT_TOGGLE: { if (m.Down()) { if (m.Left()) { Value(!Down); SendCommand(); } SendNotify(LNotifyActivate); } break; } case TBT_RADIO: { if (m.Down()) { if (!Down && m.Left()) { Value(true); SendCommand(); } SendNotify(LNotifyActivate); } break; } } } } } void LToolButton::OnMouseEnter(LMouse &m) { if (!Separator() && Enabled()) { Over = true; Invalidate(); } if (Clicked) { Value(true); Invalidate(); } else { LToolBar *Bar = dynamic_cast(GetParent()); if (Bar) { Bar->OnMouseEnter(m); if (!Bar->TextLabels() && Bar->d->Tip && TipId < 0) { TipId = Bar->d->Tip->NewTip(Name(), GetPos()); } } if (GetParent()) { LToolBar *ToolBar = dynamic_cast(GetParent()); if (ToolBar) ToolBar->PostDescription(this, Name()); } } } void LToolButton::OnMouseMove(LMouse &m) { } void LToolButton::OnMouseExit(LMouse &m) { if (Over) { Over = false; Invalidate(); } if (Clicked) { Value(false); Invalidate(); } else if (GetParent()) { LToolBar *ToolBar = dynamic_cast(GetParent()); if (ToolBar) ToolBar->PostDescription(this, ""); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// LToolBar::LToolBar() { d = new LToolBarPrivate; Name("LGI_Toolbar"); _BorderSize = 1; _IsToolBar = 1; // Setup tool button font LFontType SysFontType; if (SysFontType.GetSystemFont("Small")) { d->Font = SysFontType.Create(); if (d->Font) { d->Font->PointSize(MIN(d->Font->PointSize(), LSysFont->PointSize())); d->Font->Colour(L_TEXT); d->Font->Bold(false); d->Font->Transparent(true); } } d->LastIndex = 0; d->OwnImgList = false; d->ImgList = 0; GetCss(true)->BackgroundColor(LColour(L_MED).Mix(LColour::Black, 0.05f)); LResources::StyleElement(this); } LToolBar::~LToolBar() { DeleteObj(d->Tip); if (d->OwnImgList) DeleteObj(d->ImgList); DeleteObj(d->Font); DeleteObj(d); } void LToolBar::OnCreate() { #ifndef WIN32 AttachChildren(); #endif } int LToolBar::GetBx() { return d->Bx; } int LToolBar::GetBy() { return d->By; } void LToolBar::ContextMenu(LMouse &m) { if (IsCustomizable()) { LSubMenu *Sub = new LSubMenu; if (Sub) { int n = 1; for (auto it = Children.begin(); it != Children.end(); it++, n++) { LViewI *v = *it; LToolButton *Btn = dynamic_cast(v); if (Btn && Btn->Separator()) { Sub->AppendSeparator(); } else { auto Item = Sub->AppendItem(v->Name(), n, true); if (Item) { Item->Checked(v->Visible()); } } } Sub->AppendSeparator(); auto Txt = Sub->AppendItem(LLoadString(L_TOOLBAR_SHOW_TEXT, "Show Text Labels"), 1000, true); Txt->Checked(d->Text); bool Save = false; int Pick = Sub->Float(this, m); switch (Pick) { case 1000: { d->Text = !d->Text; Save = true; SendNotify(LNotifyTableLayoutRefresh); break; } default: { LViewI *Ctrl = Children[Pick - 1]; if (Ctrl) { Ctrl->Visible(!Ctrl->Visible()); Save = true; } break; } } DeleteObj(Sub); if (Save) { LStringPipe p(256); p.Push((char*) (d->Text ? "text" : "no")); for (auto v: Children) { if (v->Visible()) { p.Print(",%i", v->GetId()); } } char *o = p.NewStr(); if (o) { if (d->CustomDom) { LVariant v(o); d->CustomDom->SetValue(d->CustomProp, v); } DeleteArray(o); } d->FixSeparators(this); for (auto v: Children) { LToolButton *b = dynamic_cast(v); if (b && b->TipId >= 0) { d->Tip->DeleteTip(b->TipId); b->TipId = -1; } } GetWindow()->PourAll(); } } } } bool LToolBar::IsCustomizable() { return d->CustomDom != 0 && d->CustomProp; } void LToolBar::Customizable(LDom *Store, const char *Option) { d->CustomDom = Store; d->CustomProp = Option; d->Customizable(this); } bool LToolBar::IsVertical() { return d->Vertical; } void LToolBar::IsVertical(bool v) { d->Vertical = v; } bool LToolBar::TextLabels() { return d->Text; } void LToolBar::TextLabels(bool i) { d->Text = i; } LFont *LToolBar::GetFont() { return d->Font; } bool LToolBar::OnLayout(LViewLayoutInfo &Inf) { if (Inf.Width.Min == 0) { // Calc width LRegion r(0, 0, 10000, 10000); Pour(r); Inf.Width.Min = X(); Inf.Width.Max = X(); } else { // Calc height Inf.Height.Min = Y(); Inf.Height.Max = Y(); } return true; } #define GetBorderSpacing() GetCss() && GetCss()->BorderSpacing().IsValid() ? \ GetCss()->BorderSpacing().ToPx(X(), GetFont()) : \ 1 bool LToolBar::Pour(LRegion &r) { int BorderSpacing = GetBorderSpacing(); int EndX = 0; int EndY = 0; int MaxDim = 0; LCssTools Tools(this); LRect Border = Tools.GetBorder(r); LRect Padding = Tools.GetPadding(r); int PosX = BorderSpacing + Border.x1 + Padding.x1; int PosY = BorderSpacing + Border.y1 + Padding.y1; LRect ButPos; for (auto But: Children) { if (But->Visible()) { int Tx = 0, Ty = 0; LToolButton *Btn = dynamic_cast(But); if (d->ShowTextLabels()) { if (Btn) { if (Btn->d->Text.Length() == 0) { Btn->Layout(); } for (int i=0; id->Text.Length(); i++) { LDisplayString *Ds = Btn->d->Text[i]; Tx = MAX(Ds->X() + 4, Tx); Ty += Ds->Y(); } } } ButPos = But->GetPos(); if (Btn) { if (Btn->Separator()) { // This will be stretched out later by the code that makes // everything the same height. ButPos.ZOff(BORDER_SEPARATOR+1, BORDER_SEPARATOR+1); } else { if (Btn->Image() >= 0) { // Set initial size to the icon size ButPos.ZOff(d->Bx + 2, d->By + 2); } else { // Otherwise default to text size if (d->Vertical) ButPos.ZOff(0, 7); else ButPos.ZOff(7, 0); } Tx += 4; if (ButPos.X() < Tx) { // Make button wider for text label ButPos.x2 = Tx - 1; } ButPos.y2 += Ty; } } if (d->Vertical) MaxDim = MAX(MaxDim, ButPos.X()); else MaxDim = MAX(MaxDim, ButPos.Y()); ButPos.Offset(PosX - ButPos.x1, PosY - ButPos.y1); if (But->GetId() == IDM_BREAK) { ButPos.ZOff(0, 0); if (d->Vertical) { PosX = MaxDim; PosY = BORDER_SHADE + BorderSpacing; } else { PosX = BORDER_SHADE + BorderSpacing; PosY = MaxDim; } } else { if (d->Vertical) PosY = ButPos.y2 + BorderSpacing; else PosX = ButPos.x2 + BorderSpacing; } But->SetPos(ButPos); } else { LRect p(-100, -100, -90, -90); But->SetPos(p); } } for (auto w: Children) { LRect p = w->GetPos(); if (d->Vertical) { if (w->X() < MaxDim) { p.x2 = p.x1 + MaxDim - 1; w->SetPos(p); } } else { if (w->Y() < MaxDim) { p.y2 = p.y1 + MaxDim - 1; w->SetPos(p); } } EndX = MAX(EndX, p.x2); EndY = MAX(EndY, p.y2); } d->Sx = EndX + BorderSpacing; d->Sy = EndY + BorderSpacing; d->Sx += Border.x2 + Padding.x2; d->Sy += Border.y2 + Padding.y2; LRect n; n.ZOff(MAX(7, d->Sx), MAX(7, d->Sy)); LRect *Best = FindLargestEdge(r, GV_EDGE_TOP); if (Best) { n.Offset(Best->x1, Best->y1); n.Bound(Best); SetPos(n, true); // _Dump(); return true; } else LgiTrace("%s:%i - No best pos.\n", _FL); return false; } void LToolBar::OnButtonClick(LToolButton *Btn) { LViewI *v = GetNotify() ? GetNotify() : GetParent(); if (v && Btn) { int Id = Btn->GetId(); if (v->PostEvent(M_COMMAND, (LMessage::Param) Id #if LGI_VIEW_HANDLE , (LMessage::Param) Handle() #endif )) ; //printf("Send M_COMMAND(%i)\n", Id); else printf("%s:%i - Failed to send M_COMMAND.\n", _FL); } else printf("%s:%i - Ptr error: %p %p\n", _FL, v, Btn); } int LToolBar::PostDescription(LView *Ctrl, const char *Text) { if (GetParent()) { return GetParent()->PostEvent(M_DESCRIBE, (LMessage::Param) Ctrl, (LMessage::Param) Text); } return 0; } LMessage::Result LToolBar::OnEvent(LMessage *Msg) { switch (Msg->Msg()) { case M_CHANGE: { if (GetParent()) return GetParent()->OnEvent(Msg); LAutoPtr note((LNotification*)Msg->B()); break; } } return LView::OnEvent(Msg); } void LToolBar::OnPaint(LSurface *pDC) { LRect c = GetClient(); LCssTools Tools(this); Tools.PaintBorder(pDC, c); Tools.PaintPadding(pDC, c); Tools.PaintContent(pDC, c); } void LToolBar::OnMouseClick(LMouse &m) { } void LToolBar::OnMouseEnter(LMouse &m) { if (!d->Tip) { d->Tip = new LToolTip; if (d->Tip) { d->Tip->Attach(this); } } } void LToolBar::OnMouseExit(LMouse &m) { } void LToolBar::OnMouseMove(LMouse &m) { } bool LToolBar::SetBitmap(char *File, int bx, int by) { LAutoPtr pDC(GdcD->Load(File)); return pDC ? SetDC(pDC, bx, by) : false; } bool LToolBar::SetDC(LSurface *pNewDC, int bx, int by) { if (d->OwnImgList) { DeleteObj(d->ImgList); } d->Bx = bx; d->By = by; if (pNewDC) { d->ImgList = new LImageList(bx, by, pNewDC); if (d->ImgList) { d->OwnImgList = true; return true; } } return false; } LImageList *LToolBar::GetImageList() { return d->ImgList; } bool LToolBar::SetImageList(LImageList *l, int bx, int by, bool Own) { if (d->OwnImgList) DeleteObj(d->ImgList); d->OwnImgList = Own; d->Bx = bx; d->By = by; d->ImgList = l; return d->ImgList != 0; } LToolButton *LToolBar::AppendButton(const char *Tip, int Id, int Type, int Enabled, int IconId) { // bool HasIcon = IconId != TOOL_ICO_NONE; LToolButton *But = new LToolButton(d->Bx, d->By); if (But) { But->Name(Tip); But->SetId(Id); But->Type = Type; But->Enabled(Enabled != 0); if (IconId >= 0) { But->ImgIndex = IconId; } else if (IconId == TOOL_ICO_NEXT) { But->ImgIndex = d->LastIndex++; } else if (IconId == TOOL_ICO_NONE) { But->ImgIndex = -1; } AttachButton(But); } return But; } bool LToolBar::AppendSeparator() { LToolButton *But = new LToolButton(d->Bx, d->By); if (But) { But->SetId(IDM_SEPARATOR); AttachButton(But); return true; } return false; } bool LToolBar::AppendBreak() { LToolButton *But = new LToolButton(d->Bx, d->By); if (But) { But->SetId(IDM_BREAK); But->SetParent(this); AttachButton(But); return true; } return false; } bool LToolBar::AppendControl(LView *Ctrl) { bool Status = false; if (Ctrl) { Ctrl->SetParent(this); AttachButton(Ctrl); Status = true; } return Status; } void LToolBar::Empty() { for (auto But: Children) { DeleteObj(But); } } #ifdef MAC bool LToolBar::Attach(LViewI *parent) { return LLayout::Attach(parent); } #endif /////////////////////////////////////////////////////////////////////// COLOUR Map(LSurface *pDC, COLOUR c) { if (pDC && pDC->GetBits() <= 8) { if (pDC->IsScreen()) { c = CBit(24, c); } #ifdef WIN32 else { HPALETTE hPal = GetSystemPalette(); if (hPal) { c = GetNearestPaletteIndex(hPal, c); DeleteObject(hPal); } } #endif } return c; } #ifdef WIN32 HPALETTE GetSystemPalette() { HPALETTE hPal = 0; LOGPALETTE *Log = (LOGPALETTE*) new uchar[sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 255)]; if (Log) { Log->palVersion = 0x300; Log->palNumEntries = 256; HDC hDC = CreateCompatibleDC(0); GetSystemPaletteEntries(hDC, 0, 256, Log->palPalEntry); DeleteDC(hDC); hPal = CreatePalette(Log); } return hPal; } bool BltBmpToBmp(HBITMAP hDest, int xDst, int yDst, int cx, int cy, HBITMAP hSrc, int xSrc, int ySrc, DWORD dwRop) { bool Status = false; HDC DestDC = CreateCompatibleDC(0); HDC SrcDC = CreateCompatibleDC(0); if (DestDC && SrcDC) { hDest = (HBITMAP) SelectObject(DestDC, hDest); hSrc = (HBITMAP) SelectObject(SrcDC, hSrc); Status = BitBlt(DestDC, xDst, yDst, cx, cy, SrcDC, xSrc, ySrc, dwRop) != 0; hDest = (HBITMAP) SelectObject(DestDC, hDest); hSrc = (HBITMAP) SelectObject(SrcDC, hSrc); } if (DestDC) { DeleteDC(DestDC); } if (SrcDC) { DeleteDC(SrcDC); } return Status; } bool BltBmpToDc(HDC DestDC, int xDst, int yDst, int cx, int cy, HBITMAP hSrc, int xSrc, int ySrc, DWORD dwRop) { bool Status = false; HDC SrcDC = CreateCompatibleDC(0); if (DestDC && SrcDC) { hSrc = (HBITMAP) SelectObject(SrcDC, hSrc); Status = BitBlt(DestDC, xDst, yDst, cx, cy, SrcDC, xSrc, ySrc, dwRop) != 0; hSrc = (HBITMAP) SelectObject(SrcDC, hSrc); } if (SrcDC) { DeleteDC(SrcDC); } return Status; } bool BltDcToBmp(HBITMAP hDest, int xDst, int yDst, int cx, int cy, HDC SrcDC, int xSrc, int ySrc, DWORD dwRop) { bool Status = false; HDC DestDC = CreateCompatibleDC(0); if (DestDC && SrcDC) { hDest = (HBITMAP) SelectObject(DestDC, hDest); Status = BitBlt(DestDC, xDst, yDst, cx, cy, SrcDC, xSrc, ySrc, dwRop) != 0; hDest = (HBITMAP) SelectObject(DestDC, hDest); } if (DestDC) { DeleteDC(DestDC); } return Status; } #endif diff --git a/src/haiku/ScreenDC.cpp b/src/haiku/ScreenDC.cpp --- a/src/haiku/ScreenDC.cpp +++ b/src/haiku/ScreenDC.cpp @@ -1,481 +1,504 @@ /*hdr ** FILE: LScreenDC.cpp ** AUTHOR: Matthew Allen ** DATE: 29/11/2021 ** DESCRIPTION: Haiku screen DC ** ** Copyright (C) 2021, Matthew Allen ** fret@memecode.com */ #include #include #include "lgi/common/Lgi.h" #include #include #define LOGGING 0 #define VIEW_CHECK(...) if (!d->v) return __VA_ARGS__; class LScreenPrivate { public: int x = 0, y = 0, Bits = 32; bool Own = false; LColour Col; LRect Client; + int Rop = GDC_SET; + NativeInt Alpha = -1; LView *View = NULL; OsView v = NULL; LScreenPrivate() { Client.ZOff(-1, -1); } ~LScreenPrivate() { } }; // Translates are cumulative... so we undo the last one before resetting it. ///////////////////////////////////////////////////////////////////////////////////////////////////// LScreenDC::LScreenDC() { d = new LScreenPrivate; d->x = GdcD->X(); d->y = GdcD->Y(); d->Bits = GdcD->GetBits(); } LScreenDC::LScreenDC(LView *view, void *param) { d = new LScreenPrivate; if (d->View = view) d->v = view->Handle(); d->Bits = GdcD->GetBits(); /* if (d->v) d->Client = d->v->Frame(); else LgiTrace("%s:%i - LScreenDC::LScreenDC - No view?\n", _FL); */ } LScreenDC::~LScreenDC() { DeleteObj(d); } OsPainter LScreenDC::Handle() { return d->v; } ::LString LScreenDC::Dump() { ::LString s; s.Printf("LScreenDC size=%i,%i\n", d->x, d->y); return s; } bool LScreenDC::SupportsAlphaCompositing() { return true; } LPoint LScreenDC::GetDpi() { return LScreenDpi(); } bool LScreenDC::GetClient(LRect *c) { if (!c) return false; *c = d->Client; return true; } LString GetClip(BView *v) { BRegion r; v->GetClippingRegion(&r); LRect lr = r.Frame(); return lr.GetStr(); } void LScreenDC::GetOrigin(int &x, int &y) { x = OriginX; y = OriginY; #if LOGGING printf("%p.GetOrigin=%i+%i=%i, %i+%i=%i\n", this, OriginX, d->Client.x1, x, OriginY, d->Client.y1, y); #endif } void LScreenDC::SetOrigin(int x, int y) { VIEW_CHECK() if (d->Client.Valid()) { // The clipping region is relative to the offset. // Remove it here and reinstate it after setting the origin. d->v->ConstrainClippingRegion(NULL); } OriginX = x - d->Client.x1; OriginY = y - d->Client.y1; #if LOGGING printf("%p.SetOrigin=%i,%i (%i,%i) = %i,%i\n", this, x, y, d->Client.x1, d->Client.y1, d->Client.x1 - OriginX, d->Client.y1 - OriginY); #endif d->v->SetOrigin( d->Client.x1 - OriginX, d->Client.y1 - OriginY); if (d->Client.Valid()) { // Reset the clipping region related to the origin. auto clp = d->Client.ZeroTranslate(); clp.Offset(OriginX, OriginY); d->v->ClipToRect(clp); } } void LScreenDC::SetClient(LRect *c) { VIEW_CHECK() if (c) { d->Client = *c; OriginX += d->Client.x1; OriginY += d->Client.y1; #if LOGGING printf("SetClient(%s)\n", d->Client.GetStr()); #endif d->v->SetOrigin(OriginX, OriginY); auto clp = d->Client.ZeroTranslate(); // clp.Offset(OriginX, OriginY); d->v->ClipToRect(clp); /* BRegion r; d->v->GetClippingRegion(&r); LRect lr = r.Frame(); printf("SetClient %s = %s (%i,%i)\n", c->GetStr(), lr.GetStr(), OriginX, OriginY); */ } else { d->v->ConstrainClippingRegion(NULL); d->v->SetOrigin(OriginX = 0, OriginX = 0); d->Client.ZOff(-1, -1); #if LOGGING printf("SetClient()\n"); #endif } } LRect *LScreenDC::GetClient() { return &d->Client; } uint LScreenDC::LineStyle() { return LSurface::LineStyle(); } uint LScreenDC::LineStyle(uint32_t Bits, uint32_t Reset) { return LSurface::LineStyle(Bits); } int LScreenDC::GetFlags() { return 0; } LRect LScreenDC::ClipRgn() { return Clip; } LRect LScreenDC::ClipRgn(LRect *c) { LRect Prev = Clip; if (c) { Clip = *c; d->v->ClipToRect(Clip); } else { Clip.ZOff(-1, -1); d->v->ConstrainClippingRegion(NULL); } return Prev; } COLOUR LScreenDC::Colour() { return d->Col.Get(GetBits()); } COLOUR LScreenDC::Colour(COLOUR c, int Bits) { auto b = Bits ? Bits : GetBits(); d->Col.Set(c, b); return Colour(d->Col).Get(b); } LColour LScreenDC::Colour(LColour c) { LColour Prev = d->Col; d->Col = c; if (d->v) { d->v->SetLowColor(c); d->v->SetHighColor(c); } else LgiTrace("%s:%i - No view.\n", _FL); return Prev; } int LScreenDC::Op(int ROP, NativeInt Param) { - return GDC_SET; // not supported.. + auto prev = d->Rop; + d->Alpha = Param; + d->Rop = ROP; + return prev; } int LScreenDC::Op() { - return GDC_SET; // not supported.. + return d->Rop; } int LScreenDC::X() { return d->Client.Valid() ? d->Client.X() : d->x; } int LScreenDC::Y() { return d->Client.Valid() ? d->Client.Y() : d->y; } int LScreenDC::GetBits() { return d->Bits; } LPalette *LScreenDC::Palette() { return NULL; // not supported. } void LScreenDC::Palette(LPalette *pPal, bool bOwnIt) { } void LScreenDC::Set(int x, int y) { VIEW_CHECK() d->v->StrokeLine(BPoint(x, y), BPoint(x, y)); } COLOUR LScreenDC::Get(int x, int y) { return 0; } void LScreenDC::HLine(int x1, int x2, int y) { VIEW_CHECK() d->v->StrokeLine(BPoint(x1, y), BPoint(x2, y)); } void LScreenDC::VLine(int x, int y1, int y2) { VIEW_CHECK() d->v->StrokeLine(BPoint(x, y1), BPoint(x, y2)); } void LScreenDC::Line(int x1, int y1, int x2, int y2) { VIEW_CHECK() d->v->StrokeLine(BPoint(x1, y1), BPoint(x2, y2)); } void LScreenDC::Circle(double cx, double cy, double radius) { VIEW_CHECK() d->v->StrokeArc(BPoint(cx, cy), radius, radius, 0, 360); } void LScreenDC::FilledCircle(double cx, double cy, double radius) { VIEW_CHECK() d->v->FillArc(BPoint(cx, cy), radius, radius, 0, 360); } void LScreenDC::Arc(double cx, double cy, double radius, double start, double end) { VIEW_CHECK() d->v->StrokeArc(BPoint(cx, cy), radius, radius, start, end); } void LScreenDC::FilledArc(double cx, double cy, double radius, double start, double end) { VIEW_CHECK() d->v->FillArc(BPoint(cx, cy), radius, radius, start, end); } void LScreenDC::Ellipse(double cx, double cy, double x, double y) { VIEW_CHECK() d->v->StrokeArc(BPoint(cx, cy), x, y, 0, 360); } void LScreenDC::FilledEllipse(double cx, double cy, double x, double y) { VIEW_CHECK() d->v->FillArc(BPoint(cx, cy), x, y, 0, 360); } void LScreenDC::Box(int x1, int y1, int x2, int y2) { VIEW_CHECK() d->v->StrokeRect(LRect(x1, y1, x2, y2)); } void LScreenDC::Box(LRect *a) { VIEW_CHECK() if (a) d->v->StrokeRect(*a); else Box(0, 0, X()-1, Y()-1); } void LScreenDC::Rectangle(int x1, int y1, int x2, int y2) { VIEW_CHECK() if (x2 >= x1 && y2 >= y1) { // auto o = d->v->Origin(); // printf("Rect %i,%i,%i,%i %g,%g\n", x1, y1, x2, y2, o.x, o.y); d->v->FillRect(LRect(x1, y1, x2, y2)); } } void LScreenDC::Rectangle(LRect *a) { VIEW_CHECK() LRect r = a ? *a : Bounds(); BRect br(r.x1, r.y1, r.x2, r.y2); d->v->FillRect(br); } void LScreenDC::Polygon(int Points, LPoint *Data) { VIEW_CHECK() if (!Data || Points <= 0) return; } void LScreenDC::Blt(int x, int y, LSurface *Src, LRect *a) { VIEW_CHECK() if (!Src) { LgiTrace("%s:%i - No source.\n", _FL); return; } if (Src->IsScreen()) { LgiTrace("%s:%i - Can't do screen->screen blt.\n", _FL); return; } BBitmap *bmp = Src->GetBitmap(); if (!bmp) { LAssert(!"no bmp."); LgiTrace("%s:%i - No bitmap.\n", _FL); return; } - d->v->SetDrawingMode(B_OP_ALPHA); - d->v->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); + switch (d->Rop) + { + case GDC_SET: + d->v->SetDrawingMode(B_OP_COPY); + break; + case GDC_OR: + d->v->SetDrawingMode(B_OP_ADD); + break; + case GDC_XOR: + d->v->SetDrawingMode(B_OP_INVERT); + break; + default: + case GDC_ALPHA: + d->v->SetDrawingMode(B_OP_ALPHA); + d->v->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); + + if (d->Alpha >= 0) + LgiTrace("%s:%i - WARNING: Haiku doesn't support constant alpha Blt to screen!!!\n", _FL); + break; + } if (a) { BRect bitmapRect = *a; BRect viewRect(x, y, x + a->X() - 1, y + a->Y() - 1); d->v->DrawBitmap(bmp, bitmapRect, viewRect); #if 0 printf("ScreenDC::Blt %g,%g/%gx%g -> %g,%g/%gx%g %i,%i\n", bitmapRect.left, bitmapRect.top, bitmapRect.Width(), bitmapRect.Height(), viewRect.left, viewRect.top, viewRect.Width(), viewRect.Height(), a->X(), a->Y()); #endif } else { BRect bitmapRect = bmp->Bounds(); BRect viewRect(x, y, x + Src->X() - 1, y + Src->Y() - 1); d->v->DrawBitmap(bmp, bitmapRect, viewRect); #if 0 printf("ScreenDC::Blt %g,%g/%gx%g -> %g,%g/%gx%g %i,%i\n", bitmapRect.left, bitmapRect.top, bitmapRect.Width(), bitmapRect.Height(), viewRect.left, viewRect.top, viewRect.Width(), viewRect.Height(), x, y); #endif } d->v->SetDrawingMode(B_OP_COPY); } void LScreenDC::StretchBlt(LRect *Dest, LSurface *Src, LRect *s) { VIEW_CHECK() LAssert(0); } void LScreenDC::Bezier(int Threshold, LPoint *Pt) { VIEW_CHECK() LAssert(0); } void LScreenDC::FloodFill(int x, int y, int Mode, COLOUR Border, LRect *Bounds) { VIEW_CHECK() LAssert(0); }