diff --git a/core/base/inc/TVirtualX.h b/core/base/inc/TVirtualX.h index ddbae75d26dbc..de2c1b3c5c99b 100644 --- a/core/base/inc/TVirtualX.h +++ b/core/base/inc/TVirtualX.h @@ -112,6 +112,8 @@ class TVirtualX : public TNamed, public TAttLine, public TAttFill, public TAttTe virtual EDrawMode GetDrawModeW(WinContext_t wctxt); virtual void ClearWindowW(WinContext_t wctxt); virtual void UpdateWindowW(WinContext_t wctxt, Int_t mode); + virtual void SetOpacityW(WinContext_t wctxt, Int_t percent); + virtual void CopyPixmapW(WinContext_t wctxt, Int_t wid, Int_t xpos, Int_t ypos); virtual void DrawBoxW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode); virtual void DrawFillAreaW(WinContext_t wctxt, Int_t n, TPoint *xy); diff --git a/core/base/src/TAttFill.cxx b/core/base/src/TAttFill.cxx index 257318a061268..4f418792202e2 100644 --- a/core/base/src/TAttFill.cxx +++ b/core/base/src/TAttFill.cxx @@ -116,16 +116,13 @@ method `GetFillStyle`. - 0 : hollow - 1001 : Solid - - 3000+pattern_number (see below) - - For TPad only: + - 3000 + pattern_number (see below) + - 4000..4100: 100% transparent .. 100% opaque - - 4000 :the window is transparent. - - 4000 to 4100 the window is 100% transparent to 100% opaque. - - The pad transparency is visible in binary outputs files like gif, jpg, png etc .. - but not in vector graphics output files like PS, PDF and SVG. This convention - (fill style > 4000) is kept for backward compatibility. It is better to use - the color transparency instead. +Historically the styles between 4000 and 4100 were introduced to implement pad +transparency on platforms like X11 which does not support alpha channel in color. +Since ROOT 6.40 any objects can use such fill styles. On supported platforms like +Cocoa or GL or PS/PDF/SVG output style will be automatically converted to transparent colors. pattern_number can have any value from 1 to 25 (see table), or any value from 100 to 999. For the latest the numbering convention is the following: @@ -268,6 +265,9 @@ void TAttFill::SetFillColorAlpha(Color_t fcolor, Float_t falpha) fFillColor = TColor::GetColorTransparent(fcolor, falpha); } +//////////////////////////////////////////////////////////////////////////////// +/// Set a fill color. + void TAttFill::SetFillColor(TColorNumber lcolor) { SetFillColor(lcolor.number()); diff --git a/core/base/src/TVirtualX.cxx b/core/base/src/TVirtualX.cxx index 3c0f39558e328..f4e05e3f07b5f 100644 --- a/core/base/src/TVirtualX.cxx +++ b/core/base/src/TVirtualX.cxx @@ -460,6 +460,22 @@ void TVirtualX::UpdateWindowW(WinContext_t /* wctxt */, Int_t mode) UpdateWindow(mode); } +//////////////////////////////////////////////////////////////////////////////// +/// Set opactity for specified window + +void TVirtualX::SetOpacityW(WinContext_t /* wctxt */, Int_t percent) +{ + SetOpacity(percent); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Copy pixmap to specified window + +void TVirtualX::CopyPixmapW(WinContext_t /* wctxt */, Int_t wid, Int_t xpos, Int_t ypos) +{ + CopyPixmap(wid, xpos, ypos); +} + //////////////////////////////////////////////////////////////////////////////// /// Draw box on specified window diff --git a/graf2d/cocoa/inc/TGCocoa.h b/graf2d/cocoa/inc/TGCocoa.h index 28f67306a3386..123a7135fd07b 100644 --- a/graf2d/cocoa/inc/TGCocoa.h +++ b/graf2d/cocoa/inc/TGCocoa.h @@ -110,6 +110,7 @@ class TGCocoa : public TVirtualX { EDrawMode GetDrawModeW(WinContext_t wctxt) override; void ClearWindowW(WinContext_t wctxt) override; void UpdateWindowW(WinContext_t wctxt, Int_t mode) override; + void CopyPixmapW(WinContext_t wctxt, Int_t wid, Int_t xpos, Int_t ypos) override; //-Functions used by GUI. Window_t CreateWindow(Window_t parent, Int_t x, Int_t y, diff --git a/graf2d/cocoa/inc/TGQuartz.h b/graf2d/cocoa/inc/TGQuartz.h index 8c9e8603c557c..b1bdaec556722 100644 --- a/graf2d/cocoa/inc/TGQuartz.h +++ b/graf2d/cocoa/inc/TGQuartz.h @@ -76,6 +76,7 @@ class TGQuartz : public TGCocoa { Float_t GetTextMagnitude() override; //---- Methods used for new graphics ----- + void SetOpacityW(WinContext_t wctxt, Int_t percent) override; void SetAttFill(WinContext_t wctxt, const TAttFill &att) override; void SetAttLine(WinContext_t wctxt, const TAttLine &att) override; void SetAttMarker(WinContext_t wctxt, const TAttMarker &att) override; diff --git a/graf2d/cocoa/src/TGCocoa.mm b/graf2d/cocoa/src/TGCocoa.mm index 004ea9586eabe..f63285d3b840b 100644 --- a/graf2d/cocoa/src/TGCocoa.mm +++ b/graf2d/cocoa/src/TGCocoa.mm @@ -2430,27 +2430,34 @@ void FixAscii(std::vector &text) //______________________________________________________________________________ void TGCocoa::CopyPixmap(Int_t pixmapID, Int_t x, Int_t y) { - assert(pixmapID > (Int_t)fPimpl->GetRootWindowID() && - "CopyPixmap, parameter 'pixmapID' is not a valid id"); assert(fSelectedDrawable > fPimpl->GetRootWindowID() && "CopyPixmap, fSelectedDrawable is not a valid window id"); + CopyPixmapW((WinContext_t) fPimpl->GetDrawable(fSelectedDrawable), pixmapID, x, y); +} + +//______________________________________________________________________________ +void TGCocoa::CopyPixmapW(WinContext_t wctxt, Int_t pixmapID, Int_t x, Int_t y) +{ + assert(pixmapID > (Int_t)fPimpl->GetRootWindowID() && + "CopyPixmapW, parameter 'pixmapID' is not a valid id"); + NSObject * const source = fPimpl->GetDrawable(pixmapID); assert([source isKindOfClass : [QuartzPixmap class]] && "CopyPixmap, source is not a pixmap"); QuartzPixmap * const pixmap = (QuartzPixmap *)source; - NSObject * const drawable = fPimpl->GetDrawable(fSelectedDrawable); + auto drawable = (NSObject * const) wctxt; NSObject * destination = nil; if (drawable.fIsPixmap) { destination = drawable; } else { - NSObject * const window = fPimpl->GetWindow(fSelectedDrawable); + NSObject * const window = (NSObject * const) drawable; if (window.fBackBuffer) { destination = window.fBackBuffer; } else { - Warning("CopyPixmap", "Operation skipped, since destination" + Warning("CopyPixmapW", "Operation skipped, since destination" " window is not double buffered"); return; } diff --git a/graf2d/cocoa/src/TGQuartz.mm b/graf2d/cocoa/src/TGQuartz.mm index fab43c8649a02..f60389eacbf52 100644 --- a/graf2d/cocoa/src/TGQuartz.mm +++ b/graf2d/cocoa/src/TGQuartz.mm @@ -815,6 +815,10 @@ void ConvertPointsROOTToCocoa(Int_t nPoints, const TPoint *xy, std::vectorIsNative()) - pp->ClearDrawable(); - else if (this == GetCanvas()) - pp->NewPage(); - } + // If pad painter uses PS, TPad::Clear() start new page + if (pp && pp->GetPS()) + pp->NewPage(); PaintBorder(GetFillColor(), kTRUE); fCrosshairPos = 0; @@ -3660,23 +3656,40 @@ void TPad::PaintBorder(Color_t color, Bool_t /* tops */) pp->OnPad(this); if (color >= 0) { - TAttLine::Modify(); //Change line attributes only if necessary - TAttFill::Modify(); //Change fill area attributes only if necessary - //With Cocoa we have a transparency. But we also have - //pixmaps, and if you just paint a new content over the old one - //with alpha < 1., you'll be able to see the old content. - if (pp->IsNative() && pp->IsCocoa()) + Bool_t do_paint_box = kTRUE; + + Style_t style = GetFillStyle(); + if (!IsBatch() && (pp->IsCocoa() || (pp->IsNative() && (style > 3000) && (style < 3026)))) pp->ClearDrawable(); - PaintBox(fX1, fY1, fX2, fY2); - } - if (color < 0) + // special only for transparent pads in plain X11; + // Cocoa, GL, Web and PS implement transparency different + if ((style >= 4000) && (style <= 4100) && pp->IsNative() && !pp->IsCocoa() && !pp->GetPS() && !(fCanvas && fCanvas->UseGL()) && !IsWeb() && !IsBatch()) { + if (this == fMother) { + style = 1001; + } else { + // copy all pixmaps + do_paint_box = kFALSE; + Int_t px, py; + XYtoAbsPixel(GetX1(), GetY2(), px, py); + if (fMother) + fMother->CopyBackgroundPixmaps(this, px, py); + pp->SetAttFill({color, 1001}); // use fill color producing opacity + pp->SetOpacity(style - 4000); + } + } else if ((color == 10) && (style > 3000) && (style < 3100)) + color = 1; + + if (do_paint_box) { + pp->SetAttFill({color, style}); + pp->SetAttLine(*this); + PaintBox(fX1, fY1, fX2, fY2); + } + } else color = -color; - if (IsTransparent()) - return; - if (fBorderMode == 0) + if (IsTransparent() || (fBorderMode == 0)) return; // then paint 3d frame (depending on bordermode) @@ -3802,14 +3815,8 @@ void TPad::PaintModified() fPadPaint = 1; { TContext ctxt(this, kTRUE); - if (IsModified() || IsTransparent()) { - if ((fFillStyle < 3026) && (fFillStyle > 3000)) { - auto pp = GetPainter(); - if (pp && pp->IsNative()) - pp->ClearDrawable(); - } + if (IsModified() || IsTransparent()) PaintBorder(GetFillColor(), kTRUE); - } PaintDate(); @@ -3868,82 +3875,35 @@ void TPad::PaintBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Option_t pp->OnPad(this); - TAttFill att = pp->GetAttFill(); - - Int_t style0 = -1111, style = att.GetFillStyle(); - Bool_t draw_border = kFALSE, draw_fill = kFALSE; - if (option && *option == 's') { - style0 = style; - att.SetFillStyle(0); - pp->SetAttFill(att); - style = 0; - draw_border = kTRUE; - } else if (option && *option == 'l') + Style_t style = pp->GetAttFill().GetFillStyle(); + Bool_t draw_border = kFALSE, draw_fill = kFALSE, skip_fill = kFALSE; + if (option && *option == 's') + skip_fill = draw_border = kTRUE; + else if (option && *option == 'l') draw_border = kTRUE; if (style >= 3100 && style < 4000) { Double_t xb[4] = {x1, x1, x2, x2}; Double_t yb[4] = {y1, y2, y2, y1}; PaintFillAreaHatches(4, xb, yb, style); - } else if (pp->GetPS()) { - draw_fill = kTRUE; - if (style == 0) - draw_border = kFALSE; - } else if ((style > 0) && (style < 1000)) { + } else if (style >= 0 && style < 1000) { draw_border = kTRUE; - } else if ((style >= 1000) && (style < 2000)) { + } else if (style >= 1000 && style < 2000) { draw_fill = kTRUE; } else if (style > 3000 && style < 3100) { - if (style < 3026) - pp->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled); - //special case for TAttFillCanvas on real display - if (att.GetFillColor() == 10) { - // SL: reproduce old sequence of painting calls, can have some side effects on opaque pads - att.SetFillColor(1); - pp->SetAttFill(att); - pp->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled); - att.SetFillColor(10); - pp->SetAttFill(att); - } + draw_fill = style < 3026; } else if (style >= 4000 && style <= 4100) { - // For style >=4000 we make the window transparent. - // From 4000 to 4100 the window is 100% transparent to 100% opaque - - //ignore this style option when this is the canvas itself - if (this == fMother) { - //It's clear, that virtual X checks a style (4000) and will render a hollow rect! - if (pp->IsCocoa()) { - style0 = style; - att.SetFillStyle(1000); - pp->SetAttFill(att); - } - draw_fill = kTRUE; - } else { - //draw background by blitting all bottom pads - int px, py; - XYtoAbsPixel(fX1, fY2, px, py); - - if (fMother) { - fMother->CopyBackgroundPixmap(px, py); - CopyBackgroundPixmaps(fMother, this, px, py); - } - - pp->SetOpacity(style - 4000); - } + // transparency styles, supported now by all painters + draw_fill = style > 4000; } else if (style > 0) draw_border = kTRUE; - if (draw_fill) + if (draw_fill && !skip_fill) pp->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled); if (draw_border) pp->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow); - if (style0 != -1111) { - att.SetFillStyle(style0); - pp->SetAttFill(att); - } - Modified(); } @@ -3951,30 +3911,21 @@ void TPad::PaintBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Option_t /// Copy pixmaps of pads laying below pad "stop" into pad "stop". This /// gives the effect of pad "stop" being transparent. -void TPad::CopyBackgroundPixmaps(TPad *start, TPad *stop, Int_t x, Int_t y) +void TPad::CopyBackgroundPixmaps(TPad *stop, Int_t x, Int_t y) { - if (!start) return; - TObject *obj; - if (!fPrimitives) fPrimitives = new TList; - TIter next(start->GetListOfPrimitives()); - while ((obj = next())) { - if (obj->InheritsFrom(TPad::Class())) { - if (obj == stop) break; - ((TPad*)obj)->CopyBackgroundPixmap(x, y); - ((TPad*)obj)->CopyBackgroundPixmaps((TPad*)obj, stop, x, y); - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Copy pixmap of this pad as background of the current pad. + Int_t px, py; + XYtoAbsPixel(GetX1(), GetY2(), px, py); + /// Copy pixmap of this pad as background of the current pad. + if (auto pp = GetPainter()) + pp->CopyDrawable(GetPixmapID(), px - x, py - y); -void TPad::CopyBackgroundPixmap(Int_t x, Int_t y) -{ - int px, py; - XYtoAbsPixel(fX1, fY2, px, py); - if (GetPainter()) - GetPainter()->CopyDrawable(GetPixmapID(), px-x, py-y); + TIter next(GetListOfPrimitives()); + while (auto obj = next()) { + if (obj == stop) + break; + if (auto pad = dynamic_cast(obj)) + pad->CopyBackgroundPixmaps(stop, x, y); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/graf2d/gpad/src/TPadPainter.cxx b/graf2d/gpad/src/TPadPainter.cxx index 491c00c4bd315..8fbffdce21476 100644 --- a/graf2d/gpad/src/TPadPainter.cxx +++ b/graf2d/gpad/src/TPadPainter.cxx @@ -47,7 +47,7 @@ void ConvertPointsAndMergePassX(TVirtualPad *pad, unsigned nPoints, const T *x, void ConvertPointsAndMergeInplacePassY(std::vector &dst); template -void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys, Bool_t close_path); +void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys, Bool_t add_first_point); template void DrawPolyLineAux(TVirtualPad *pad, WinContext_t cont, unsigned nPoints, const T *xs, const T *ys); @@ -89,7 +89,7 @@ gVirtualX or from my own member. So! All attributed, _ALL_ go to/from gVirtualX. void TPadPainter::SetOpacity(Int_t percent) { - gVirtualX->SetOpacity(percent); + gVirtualX->SetOpacityW(fWinContext, percent); } //////////////////////////////////////////////////////////////////////////////// @@ -146,10 +146,9 @@ void TPadPainter::ClearDrawable() void TPadPainter::CopyDrawable(Int_t device, Int_t px, Int_t py) { - gVirtualX->CopyPixmap(device, px, py); + gVirtualX->CopyPixmapW(fWinContext, device, px, py); } - //////////////////////////////////////////////////////////////////////////////// /// Close the current gVirtualX pixmap. @@ -160,7 +159,6 @@ void TPadPainter::DestroyDrawable(Int_t device) fWinContext = (WinContext_t) 0; } - //////////////////////////////////////////////////////////////////////////////// /// Select the window in which the graphics will go. @@ -213,7 +211,9 @@ void TPadPainter::SetAttFill(const TAttFill &att) { TPadPainterBase::SetAttFill(att); - gVirtualX->SetAttFill(fWinContext, att); + TAttFill fill = GetAttFillInternal(IsCocoa()); + + gVirtualX->SetAttFill(fWinContext, fill); } //////////////////////////////////////////////////////////////////////////////// @@ -286,6 +286,9 @@ void TPadPainter::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, EB if (fAttLine.GetLineWidth() <= 0 && mode == TVirtualPadPainter::kHollow) return; + if (fFullyTransparent && mode == TVirtualPadPainter::kFilled) + return; + Int_t px1 = fDoubleBuffer ? gPad->XtoPixel(x1) : gPad->XtoAbsPixel(x1); Int_t px2 = fDoubleBuffer ? gPad->XtoPixel(x2) : gPad->XtoAbsPixel(x2); Int_t py1 = fDoubleBuffer ? gPad->YtoPixel(y1) : gPad->YtoAbsPixel(y1); @@ -310,7 +313,8 @@ void TPadPainter::DrawFillArea(Int_t nPoints, const Double_t *xs, const Double_t return; } - DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys, fAttFill.GetFillStyle() == 0); + // if fully transparent, add first point to draw line + DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys, fFullyTransparent); } @@ -324,7 +328,8 @@ void TPadPainter::DrawFillArea(Int_t nPoints, const Float_t *xs, const Float_t * return; } - DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys, fAttFill.GetFillStyle() == 0); + // if fully transparent, add first point to draw line + DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys, fFullyTransparent); } //////////////////////////////////////////////////////////////////////////////// @@ -790,7 +795,7 @@ void ConvertPointsAndMerge(TVirtualPad *pad, unsigned threshold, unsigned nPoint //////////////////////////////////////////////////////////////////////////////// template -void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys, Bool_t close_path) +void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys, Bool_t add_first_point) { std::vector xy; @@ -808,12 +813,12 @@ void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T else ConvertPointsAndMerge(pad, threshold, nPoints, xs, ys, xy); - //We close the 'polygon' and it'll be rendered as a polyline by gVirtualX. - if (close_path) + //We close the 'polygon' so it can be rendered as a polyline by gVirtualX. + if (add_first_point) xy.push_back(xy.front()); if (xy.size() > 2) - gVirtualX->DrawFillAreaW(cont, xy.size(), &xy[0]); + gVirtualX->DrawFillAreaW(cont, xy.size(), xy.data()); } //////////////////////////////////////////////////////////////////////////////// diff --git a/graf2d/gpad/src/TPadPainterBase.cxx b/graf2d/gpad/src/TPadPainterBase.cxx new file mode 100644 index 0000000000000..ca93ae13088d8 --- /dev/null +++ b/graf2d/gpad/src/TPadPainterBase.cxx @@ -0,0 +1,41 @@ +// @(#)root/gpad:$Id$ +// Author: Sergey Linev 17/04/2026 + +/************************************************************************* + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#include "TPadPainterBase.h" +#include "TColor.h" + + +/** \class TPadPainterBase +\ingroup gpad + +Extends TVirtualPadPainter interface to simplify work with graphical attributes +*/ + +//////////////////////////////////////////////////////////////////////////////// +/// Returns fill attributes after modification +/// Checks for special fill styles 4000 .. 4100 + +TAttFill TPadPainterBase::GetAttFillInternal(Bool_t with_transparency) +{ + Style_t style = GetAttFill().GetFillStyle(); + Color_t color = GetAttFill().GetFillColor(); + + fFullyTransparent = (style == 4000) || (style == 0); + if (fFullyTransparent) { + style = 0; + } else if ((style > 4000) && (style <= 4100)) { + if ((style < 4100) && with_transparency) + color = TColor::GetColorTransparent(color, (style - 4000) / 100.); + style = 1001; + } + + return { color, style }; +} diff --git a/graf2d/gpad/src/TPadPainterPS.cxx b/graf2d/gpad/src/TPadPainterPS.cxx index 0b5a10d80b52e..55b134dc76eeb 100644 --- a/graf2d/gpad/src/TPadPainterPS.cxx +++ b/graf2d/gpad/src/TPadPainterPS.cxx @@ -16,12 +16,12 @@ #include "TPadPainterPS.h" #include "TVirtualPS.h" -#include "TVirtualX.h" #include "TCanvas.h" #include "TPoint.h" #include "TError.h" #include "TImage.h" #include "TROOT.h" +#include "TColor.h" #include "TMath.h" #include "TPad.h" @@ -57,7 +57,9 @@ so actual value can be requested without asking of gVirtualPS instance void TPadPainterPS::SetOpacity(Int_t percent) { - fPS->SetFillStyle(4000 + percent); + TAttFill att = GetAttFill(); + att.SetFillStyle(4000 + percent); + SetAttFill(att); } //////////////////////////////////////////////////////////////////////////////// @@ -67,8 +69,9 @@ void TPadPainterPS::SetAttFill(const TAttFill &att) { TPadPainterBase::SetAttFill(att); - fPS->SetFillColor(att.GetFillColor()); - fPS->SetFillStyle(att.GetFillStyle()); + auto fill = GetAttFillInternal(kTRUE); + fPS->SetFillColor(fill.GetFillColor()); + fPS->SetFillStyle(fill.GetFillStyle()); } //////////////////////////////////////////////////////////////////////////////// @@ -213,7 +216,8 @@ void TPadPainterPS::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, style0 = fPS->GetFillStyle(); if (style0 > 0) fPS->SetFillStyle(0); - } + } else if (fFullyTransparent) + return; fPS->DrawBox(x1, y1, x2, y2); @@ -231,7 +235,8 @@ void TPadPainterPS::DrawFillArea(Int_t nPoints, const Double_t *xs, const Double return; } - fPS->DrawPS(-nPoints, const_cast(xs), const_cast(ys)); + if (!fFullyTransparent || (fPS->GetLineWidth() > 0)) + fPS->DrawPS(-nPoints, const_cast(xs), const_cast(ys)); } @@ -245,7 +250,8 @@ void TPadPainterPS::DrawFillArea(Int_t nPoints, const Float_t *xs, const Float_t return; } - fPS->DrawPS(-nPoints, const_cast(xs), const_cast(ys)); + if (!fFullyTransparent || (fPS->GetLineWidth() > 0)) + fPS->DrawPS(-nPoints, const_cast(xs), const_cast(ys)); } //////////////////////////////////////////////////////////////////////////////// diff --git a/graf2d/win32gdk/inc/TGWin32.h b/graf2d/win32gdk/inc/TGWin32.h index 43c0a92aebac7..236192defbcab 100644 --- a/graf2d/win32gdk/inc/TGWin32.h +++ b/graf2d/win32gdk/inc/TGWin32.h @@ -86,8 +86,6 @@ class TGWin32 : public TVirtualX { void RemovePixmap(GdkDrawable *pix); void SetColor(XWindow_t *ctxt, GdkGC *gc, Int_t ci); void SetInput(Int_t inp); - void MakeOpaqueColors(Int_t percent, ULong_t *orgcolors, Int_t ncolors); - Int_t FindColor(ULong_t pixel, ULong_t *orgcolors, Int_t ncolors); void ImgPickPalette(GdkImage *image, Int_t &ncol, Int_t *&R, Int_t *&G, Int_t *&B); //---- Private methods used for GUI ---- @@ -184,6 +182,7 @@ class TGWin32 : public TVirtualX { void SetDoubleBufferON() override; void SetDrawMode(EDrawMode mode) override; void SetFillColor(Color_t cindex) override; + Color_t GetFillColor() const override; void SetFillStyle(Style_t style) override; Style_t GetFillStyle() const override; void SetLineColor(Color_t cindex) override; @@ -217,6 +216,8 @@ class TGWin32 : public TVirtualX { EDrawMode GetDrawModeW(WinContext_t wctxt) override; void ClearWindowW(WinContext_t wctxt) override; void UpdateWindowW(WinContext_t wctxt, Int_t mode) override; + void SetOpacityW(WinContext_t wctxt, Int_t percent) override; + void CopyPixmapW(WinContext_t wctxt, Int_t wid, Int_t xpos, Int_t ypos) override; void DrawBoxW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode) override; void DrawFillAreaW(WinContext_t wctxt, Int_t n, TPoint *xy) override; diff --git a/graf2d/win32gdk/src/TGWin32.cxx b/graf2d/win32gdk/src/TGWin32.cxx index 9931b6b7f54c7..da3810ee89554 100644 --- a/graf2d/win32gdk/src/TGWin32.cxx +++ b/graf2d/win32gdk/src/TGWin32.cxx @@ -141,8 +141,7 @@ struct XWindow_t { Int_t yclip = 0; ///< y coordinate of the clipping rectangle UInt_t wclip = 0; ///< width of the clipping rectangle UInt_t hclip = 0; ///< height of the clipping rectangle - ULong_t *new_colors = nullptr; ///< new image colors (after processing) - Int_t ncolors = 0; ///< number of different colors + std::vector new_colors; ///< new image colors for transparency (after processing) GdkGC *fGClist[kMAXGC]; ///< array of GC objects for concrete window TVirtualX::EDrawMode drawMode = TVirtualX::kCopy; ///< current draw mode TAttLine fAttLine = {-1, -1, -1}; ///< current line attributes @@ -541,32 +540,6 @@ static ULong_t GetPixelImage(Drawable_t id, Int_t x, Int_t y) return pixel; } -//////////////////////////////////////////////////////////////////////////////// -/// Collect in orgcolors all different original image colors. - -static void CollectImageColors(ULong_t pixel, ULong_t * &orgcolors, - Int_t & ncolors, Int_t & maxcolors) -{ - if (maxcolors == 0) { - ncolors = 0; - maxcolors = 100; - orgcolors = (ULong_t*) ::operator new(maxcolors*sizeof(ULong_t)); - } - - for (int i = 0; i < ncolors; i++) { - if (pixel == orgcolors[i]) return; - } - if (ncolors >= maxcolors) { - orgcolors = (ULong_t *) TStorage::ReAlloc(orgcolors, - maxcolors * 2 * - sizeof(ULong_t), - maxcolors * - sizeof(ULong_t)); - maxcolors *= 2; - } - orgcolors[ncolors++] = pixel; -} - //////////////////////////////////////////////////////////////////////////////// /// debug function for printing event mask @@ -944,7 +917,6 @@ Int_t TGWin32::OpenDisplay(const char *dpyName) GdkPixmap *pixmp1, *pixmp2; GdkColor fore, back; GdkColor color; - int i; HWND hDesktop = ::GetDesktopWindow(); if (!IsWindow(hDesktop) || !IsWindowVisible(hDesktop)) @@ -1044,9 +1016,8 @@ Int_t TGWin32::OpenDisplay(const char *dpyName) // Setup color information fRedDiv = fGreenDiv = fBlueDiv = fRedShift = fGreenShift = fBlueShift = -1; - if ( gdk_visual_get_best_type() == GDK_VISUAL_TRUE_COLOR) { - int i; - for (i = 0; i < int(sizeof(fVisual->blue_mask)*kBitsPerByte); i++) { + if (gdk_visual_get_best_type() == GDK_VISUAL_TRUE_COLOR) { + for (int i = 0; i < int(sizeof(fVisual->blue_mask)*kBitsPerByte); i++) { if (fBlueShift == -1 && ((fVisual->blue_mask >> i) & 1)) { fBlueShift = i; } @@ -1055,7 +1026,7 @@ Int_t TGWin32::OpenDisplay(const char *dpyName) break; } } - for (i = 0; i < int(sizeof(fVisual->green_mask)*kBitsPerByte); i++) { + for (int i = 0; i < int(sizeof(fVisual->green_mask)*kBitsPerByte); i++) { if (fGreenShift == -1 && ((fVisual->green_mask >> i) & 1)) { fGreenShift = i; } @@ -1064,7 +1035,7 @@ Int_t TGWin32::OpenDisplay(const char *dpyName) break; } } - for (i = 0; i < int(sizeof(fVisual->red_mask)*kBitsPerByte); i++) { + for (int i = 0; i < int(sizeof(fVisual->red_mask)*kBitsPerByte); i++) { if (fRedShift == -1 && ((fVisual->red_mask >> i) & 1)) { fRedShift = i; } @@ -1611,12 +1582,11 @@ void TGWin32::CloseWindow() if (gCws->buffer) { gdk_pixmap_unref(gCws->buffer); } - if (gCws->new_colors) { + if (!gCws->new_colors.empty()) { gdk_colormap_free_colors((GdkColormap *) fColormap, - (GdkColor *)gCws->new_colors, gCws->ncolors); + (GdkColor *)gCws->new_colors.data(), gCws->new_colors.size()); - delete [] gCws->new_colors; - gCws->new_colors = nullptr; + gCws->new_colors.clear(); } for (int i = 0; i < kMAXGC; i++) @@ -1648,13 +1618,7 @@ void TGWin32::CloseWindow() void TGWin32::CopyPixmap(int wid, int xpos, int ypos) { - if (fWindows.count(wid) == 0) - return; - - gTws = fWindows[wid].get(); - gdk_window_copy_area(gCws->drawing, gTws->fGClist[kGCpxmp], xpos, ypos, gTws->drawing, - 0, 0, gTws->width, gTws->height); - GdiFlush(); + CopyPixmapW((WinContext_t) gCws, wid, xpos, ypos); } //////////////////////////////////////////////////////////////////////////////// @@ -2148,8 +2112,6 @@ Int_t TGWin32::AddWindowHandle() ctxt->drawing = nullptr; ctxt->window = nullptr; ctxt->buffer = nullptr; - ctxt->new_colors = nullptr; - ctxt->ncolors = 0; ctxt->drawMode = TVirtualX::kCopy; @@ -3130,6 +3092,16 @@ void TGWin32::SetFillColor(Color_t cindex) SetAttFill((WinContext_t) gCws, arg); } +//////////////////////////////////////////////////////////////////////////////// +/// Return current fill color + +Color_t TGWin32::GetFillColor() const +{ + // TODO: remove in ROOT7, no longer used in ROOT + + return gCws ? gCws->fAttFill.GetFillColor() : TAttFill::GetFillColor(); +} + //////////////////////////////////////////////////////////////////////////////// /// Set fill area style. /// fstyle : compound fill area interior style @@ -3147,10 +3119,11 @@ void TGWin32::SetFillStyle(Style_t fstyle) //////////////////////////////////////////////////////////////////////////////// /// Return current fill style -/// FIXME: Only as temporary solution while some code analyze current fill style Style_t TGWin32::GetFillStyle() const { + // TODO: remove in ROOT7, no longer used in ROOT + return gCws ? gCws->fAttFill.GetFillStyle() : TAttFill::GetFillStyle(); } @@ -3263,10 +3236,11 @@ void TGWin32::SetLineStyle(Style_t lstyle) //////////////////////////////////////////////////////////////////////////////// /// Return current line style -/// FIXME: Only as temporary solution while some code analyze current line style Style_t TGWin32::GetLineStyle() const { + // TODO: remove in ROOT7, no longer used in ROOT + return gCws ? gCws->fAttLine.GetLineStyle() : TAttLine::GetLineStyle(); } @@ -3286,10 +3260,11 @@ void TGWin32::SetLineWidth(Width_t width) //////////////////////////////////////////////////////////////////////////////// /// Return current line width -/// FIXME: Only as temporary solution while some code analyze current line wide Width_t TGWin32::GetLineWidth() const { + // TODO: remove in ROOT7, no longer used in ROOT + return gCws ? gCws->fAttLine.GetLineWidth() : TAttLine::GetLineWidth(); } @@ -4063,7 +4038,7 @@ void TGWin32::SetAttText(WinContext_t wctxt, const TAttText &att) //////////////////////////////////////////////////////////////////////////////// -/// Set opacity of a window. This image manipulation routine works +/// Set opacity of a current window. This image manipulation routine works /// by adding to a percent amount of neutral to each pixels RGB. /// Since it requires quite some additional color map entries is it /// only supported on displays with more than > 8 color planes (> 256 @@ -4071,136 +4046,7 @@ void TGWin32::SetAttText(WinContext_t wctxt, const TAttText &att) void TGWin32::SetOpacity(Int_t percent) { - Int_t depth = gdk_visual_get_best_depth(); - - if (depth <= 8) return; - if (percent == 0) return; - - // if 100 percent then just make white - ULong_t *orgcolors = 0; - ULong_t *tmpc = 0; - Int_t maxcolors = 0, ncolors, ntmpc = 0; - - // save previous allocated colors, delete at end when not used anymore - if (gCws->new_colors) { - tmpc = gCws->new_colors; - ntmpc = gCws->ncolors; - } - // get pixmap from server as image - GdkImage *image = gdk_image_get((GdkDrawable*)gCws->drawing, 0, 0, - gCws->width, gCws->height); - - // collect different image colors - int x, y; - for (y = 0; y < (int) gCws->height; y++) { - for (x = 0; x < (int) gCws->width; x++) { - ULong_t pixel = GetPixelImage((Drawable_t)image, x, y); - CollectImageColors(pixel, orgcolors, ncolors, maxcolors); - } - } - if (ncolors == 0) { - gdk_image_unref(image); - ::operator delete(orgcolors); - return; - } - // create opaque counter parts - MakeOpaqueColors(percent, orgcolors, ncolors); - - // put opaque colors in image - for (y = 0; y < (int) gCws->height; y++) { - for (x = 0; x < (int) gCws->width; x++) { - ULong_t pixel = GetPixelImage((Drawable_t)image, x, y); - Int_t idx = FindColor(pixel, orgcolors, ncolors); - PutPixel((Drawable_t)image, x, y, gCws->new_colors[idx]); - } - } - - // put image back in pixmap on server - gdk_draw_image(gCws->drawing, gCws->fGClist[kGCpxmp], (GdkImage *)image, - 0, 0, 0, 0, gCws->width, gCws->height); - GdiFlush(); - - // clean up - if (tmpc) { - gdk_colors_free((GdkColormap *)fColormap, tmpc, ntmpc, 0); - delete[]tmpc; - } - gdk_image_unref(image); - ::operator delete(orgcolors); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Get RGB values for orgcolors, add percent neutral to the RGB and -/// allocate new_colors. - -void TGWin32::MakeOpaqueColors(Int_t percent, ULong_t *orgcolors, Int_t ncolors) -{ - Int_t ret; - if (ncolors <= 0) return; - GdkColor *xcol = new GdkColor[ncolors]; - - int i; - for (i = 0; i < ncolors; i++) { - xcol[i].pixel = orgcolors[i]; - xcol[i].red = xcol[i].green = xcol[i].blue = 0; - } - - GdkColorContext *cc; - cc = gdk_color_context_new(gdk_visual_get_system(), (GdkColormap *)fColormap); - gdk_color_context_query_colors(cc, xcol, ncolors); - gdk_color_context_free(cc); - - UShort_t add = percent * kBIGGEST_RGB_VALUE / 100; - - Int_t val; - for (i = 0; i < ncolors; i++) { - val = xcol[i].red + add; - if (val > kBIGGEST_RGB_VALUE) { - val = kBIGGEST_RGB_VALUE; - } - xcol[i].red = (UShort_t) val; - val = xcol[i].green + add; - if (val > kBIGGEST_RGB_VALUE) { - val = kBIGGEST_RGB_VALUE; - } - xcol[i].green = (UShort_t) val; - val = xcol[i].blue + add; - if (val > kBIGGEST_RGB_VALUE) { - val = kBIGGEST_RGB_VALUE; - } - xcol[i].blue = (UShort_t) val; - - ret = gdk_color_alloc((GdkColormap *)fColormap, &xcol[i]); - - if (!ret) { - Warning("MakeOpaqueColors", - "failed to allocate color %hd, %hd, %hd", xcol[i].red, - xcol[i].green, xcol[i].blue); - // assumes that in case of failure xcol[i].pixel is not changed - } - } - - gCws->new_colors = new ULong_t[ncolors]; - gCws->ncolors = ncolors; - - for (i = 0; i < ncolors; i++) { - gCws->new_colors[i] = xcol[i].pixel; - } - - delete []xcol; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Returns index in orgcolors (and new_colors) for pixel. - -Int_t TGWin32::FindColor(ULong_t pixel, ULong_t * orgcolors, Int_t ncolors) -{ - for (int i = 0; i < ncolors; i++) { - if (pixel == orgcolors[i]) return i; - } - Error("FindColor", "did not find color, should never happen!"); - - return 0; + SetOpacityW((WinContext_t) gCws, percent); } //////////////////////////////////////////////////////////////////////////////// @@ -4310,6 +4156,120 @@ void TGWin32::UpdateWindowW(WinContext_t wctxt, Int_t mode) Update(mode); } +//////////////////////////////////////////////////////////////////////////////// +/// Set opacity of a specified window. This image manipulation routine works +/// by adding to a percent amount of neutral to each pixels RGB. +/// Since it requires quite some additional color map entries is it +/// only supported on displays with more than > 8 color planes (> 256 +/// colors) + +void TGWin32::SetOpacityW(WinContext_t wctxt, Int_t percent) +{ + Int_t depth = gdk_visual_get_best_depth(); + + if ((depth <= 8) || (percent <= 0)) return; + if (percent > 100) percent = 100; + + auto ctxt = (XWindow_t *) wctxt; + + // get pixmap from server as image + GdkImage *image = gdk_image_get((GdkDrawable*)ctxt->drawing, 0, 0, + ctxt->width, ctxt->height); + + if (!image) return; + + std::vector orgcolors; + + // collect different image colors + for (UInt_t y = 0; y < ctxt->height; y++) { + for (UInt_t x = 0; x < ctxt->width; x++) { + ULong_t pixel = GetPixelImage((Drawable_t)image, x, y); + if (std::find(orgcolors.begin(), orgcolors.end(), pixel) == orgcolors.end()) + orgcolors.emplace_back(pixel); + } + } + if (orgcolors.empty()) { + gdk_image_unref(image); + return; + } + + if (!ctxt->new_colors.empty()) { + gdk_colors_free((GdkColormap *)fColormap, ctxt->new_colors.data(), ctxt->new_colors.size(), 0); + ctxt->new_colors.clear(); + } + + std::vector xcol(orgcolors.size()); + + for (std::size_t i = 0; i < orgcolors.size(); i++) { + xcol[i].pixel = orgcolors[i]; + xcol[i].red = xcol[i].green = xcol[i].blue = 0; + } + + GdkColorContext *cc = gdk_color_context_new(gdk_visual_get_system(), (GdkColormap *)fColormap); + gdk_color_context_query_colors(cc, xcol.data(), orgcolors.size()); + gdk_color_context_free(cc); + + // create new colors mixing: "100-percent" of old color and "percent" of new background color + XColor_t &bkgr = GetColor(ctxt->fAttFill.GetFillColor()); + + for (std::size_t i = 0; i < orgcolors.size(); i++) { + xcol[i].red = (UShort_t) TMath::Min((Int_t) xcol[i].red * (100 - percent) / 100 + bkgr.color.red * percent / 100, kBIGGEST_RGB_VALUE); + xcol[i].green = (UShort_t) TMath::Min((Int_t) xcol[i].green * (100 - percent) / 100 + bkgr.color.green * percent / 100, kBIGGEST_RGB_VALUE); + xcol[i].blue = (UShort_t) TMath::Min((Int_t) xcol[i].blue * (100 - percent) / 100 + bkgr.color.blue * percent / 100, kBIGGEST_RGB_VALUE); + + auto ret = gdk_color_alloc((GdkColormap *)fColormap, &xcol[i]); + + if (!ret) { + Warning("SetOpacityW", + "failed to allocate color %hd, %hd, %hd", xcol[i].red, + xcol[i].green, xcol[i].blue); + // assumes that in case of failure xcol[i].pixel is not changed + } + } + + ctxt->new_colors.resize(orgcolors.size()); + + for (std::size_t i = 0; i < orgcolors.size(); i++) + ctxt->new_colors[i] = xcol[i].pixel; + + // put opaque colors in image + for (UInt_t y = 0; y < ctxt->height; y++) { + for (UInt_t x = 0; x < ctxt->width; x++) { + ULong_t pixel = GetPixelImage((Drawable_t)image, x, y); + auto iter = std::find(orgcolors.begin(), orgcolors.end(), pixel); + if (iter != orgcolors.end()) { + auto idx = iter - orgcolors.begin(); + PutPixel((Drawable_t)image, x, y, ctxt->new_colors[idx]); + } + } + } + + // put image back in pixmap on server + gdk_draw_image(ctxt->drawing, ctxt->fGClist[kGCpxmp], (GdkImage *)image, + 0, 0, 0, 0, ctxt->width, ctxt->height); + GdiFlush(); + + // clean up + gdk_image_unref(image); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Copy the pixmap wid at the position xpos, ypos in the specified window. + +void TGWin32::CopyPixmapW(WinContext_t wctxt, Int_t wid, Int_t xpos, Int_t ypos) +{ + if (fWindows.count(wid) == 0) + return; + + auto ctxt = (XWindow_t *) wctxt; + + gTws = fWindows[wid].get(); + gdk_window_copy_area(ctxt->drawing, gTws->fGClist[kGCpxmp], xpos, ypos, gTws->drawing, + 0, 0, gTws->width, gTws->height); + GdiFlush(); +} + + //////////////////////////////////////////////////////////////////////////////// /// Set pointer position. /// ix : New X coordinate of pointer @@ -4405,60 +4365,55 @@ static void PutByte(Byte_t b) void TGWin32::ImgPickPalette(GdkImage * image, Int_t & ncol, Int_t * &R, Int_t * &G, Int_t * &B) { - ULong_t *orgcolors = 0; - Int_t maxcolors = 0, ncolors; + std::vector orgcolors; // collect different image colors - int x, y; - for (x = 0; x < (int) gCws->width; x++) { - for (y = 0; y < (int) gCws->height; y++) { + for (UInt_t x = 0; x < (int) gCws->width; x++) { + for (UInt_t y = 0; y < (int) gCws->height; y++) { ULong_t pixel = GetPixelImage((Drawable_t)image, x, y); - CollectImageColors(pixel, orgcolors, ncolors, maxcolors); + if (std::find(orgcolors.begin(), orgcolors.end(), pixel) == orgcolors.end()) + orgcolors.emplace_back(pixel); } } // get RGB values belonging to pixels - GdkColor *xcol = new GdkColor[ncolors]; + std::vector xcol(orgcolors.size()); - int i; - for (i = 0; i < ncolors; i++) { + for (std::size_t i = 0; i < orgcolors.size(); i++) { xcol[i].pixel = orgcolors[i]; -// xcol[i].red = xcol[i].green = xcol[i].blue = 0; xcol[i].red = GetRValue(xcol[i].pixel); xcol[i].green = GetGValue(xcol[i].pixel); xcol[i].blue = GetBValue(xcol[i].pixel); } - GdkColorContext *cc; - cc = gdk_color_context_new(gdk_visual_get_system(), (GdkColormap *)fColormap); - gdk_color_context_query_colors(cc, xcol, ncolors); + GdkColorContext *cc = gdk_color_context_new(gdk_visual_get_system(), (GdkColormap *)fColormap); + gdk_color_context_query_colors(cc, xcol.data(), orgcolors.size()); gdk_color_context_free(cc); // create RGB arrays and store RGB's for each color and set number of colors // (space must be delete by caller) - R = new Int_t[ncolors]; - G = new Int_t[ncolors]; - B = new Int_t[ncolors]; + R = new Int_t[orgcolors.size()]; + G = new Int_t[orgcolors.size()]; + B = new Int_t[orgcolors.size()]; - for (i = 0; i < ncolors; i++) { + for (std::size_t i = 0; i < orgcolors.size(); i++) { R[i] = xcol[i].red; G[i] = xcol[i].green; B[i] = xcol[i].blue; } - ncol = ncolors; + ncol = (Int_t) orgcolors.size(); // update image with indices (pixels) into the new RGB colormap - for (x = 0; x < (int) gCws->width; x++) { - for (y = 0; y < (int) gCws->height; y++) { + for (UInt_t x = 0; x < gCws->width; x++) { + for (UInt_t y = 0; y < gCws->height; y++) { ULong_t pixel = GetPixelImage((Drawable_t)image, x, y); - Int_t idx = FindColor(pixel, orgcolors, ncolors); - PutPixel((Drawable_t)image, x, y, idx); + auto iter = std::find(orgcolors.begin(), orgcolors.end(), pixel); + if (iter != orgcolors.end()) { + auto idx = iter - orgcolors.begin(); + PutPixel((Drawable_t)image, x, y, idx); + } } } - - // cleanup - delete[]xcol; - ::operator delete(orgcolors); } //////////////////////////////////////////////////////////////////////////////// diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 6d016d8e3cdf6..4646efa97d19e 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -79,10 +79,6 @@ friend struct XWindow_t; UChar_t *image, Drawable_t id); void SetColor(XWindow_t *ctxt, void *gc, Int_t ci); void SetInput(Int_t inp); - void CollectImageColors(ULong_t pixel, ULong_t *&orgcolors, Int_t &ncolors, - Int_t &maxcolors); - void MakeOpaqueColors(Int_t percent, ULong_t *orgcolors, Int_t ncolors); - Int_t FindColor(ULong_t pixel, ULong_t *orgcolors, Int_t ncolors); void ImgPickPalette(RXImage *image, Int_t &ncol, Int_t *&R, Int_t *&G, Int_t *&B); //---- Private methods used for GUI ---- @@ -197,6 +193,7 @@ friend struct XWindow_t; //---- Methods used for old graphics ----- void SetFillColor(Color_t cindex) override; + Color_t GetFillColor() const override; void SetFillStyle(Style_t style) override; Style_t GetFillStyle() const override; void SetLineColor(Color_t cindex) override; @@ -236,6 +233,8 @@ friend struct XWindow_t; EDrawMode GetDrawModeW(WinContext_t wctxt) override; void ClearWindowW(WinContext_t wctxt) override; void UpdateWindowW(WinContext_t wctxt, Int_t mode) override; + void SetOpacityW(WinContext_t wctxt, Int_t percent) override; + void CopyPixmapW(WinContext_t wctxt, Int_t wid, Int_t xpos, Int_t ypos) override; void DrawBoxW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode) override; void DrawFillAreaW(WinContext_t wctxt, Int_t n, TPoint *xy) override; diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index dac0cdc595ce9..3efc79be47e34 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -103,8 +103,7 @@ struct XWindow_t { Int_t fYclip = 0; ///< y coordinate of the clipping rectangle UInt_t fWclip = 0; ///< width of the clipping rectangle UInt_t fHclip = 0; ///< height of the clipping rectangle - ULong_t *fNewColors = 0; ///< new image colors (after processing) - Int_t fNcolors = 0; ///< number of different colors + std::vector fNewColors; ///< extra image colors created for transparency (after processing) Bool_t fShared = 0; ///< notify when window is shared GC fGClist[kMAXGC]; ///< list of GC object, individual for each window TVirtualX::EDrawMode drawMode = TVirtualX::kCopy; ///< current draw mode @@ -423,11 +422,10 @@ void TGX11::CloseWindow() if (gCws->fBuffer) XFreePixmap((Display*)fDisplay, gCws->fBuffer); - if (gCws->fNewColors) { + if (!gCws->fNewColors.empty()) { if (fRedDiv == -1) - XFreeColors((Display*)fDisplay, fColormap, gCws->fNewColors, gCws->fNcolors, 0); - delete [] gCws->fNewColors; - gCws->fNewColors = nullptr; + XFreeColors((Display*)fDisplay, fColormap, gCws->fNewColors.data(), gCws->fNewColors.size(), 0); + gCws->fNewColors.clear(); } if (!gCws->fShared) { // if not QT window @@ -472,11 +470,7 @@ void TGX11::CloseWindow() void TGX11::CopyPixmap(int wid, int xpos, int ypos) { - gTws = fWindows[wid].get(); - - XCopyArea((Display*)fDisplay, gTws->fDrawing, gCws->fDrawing, gTws->fGClist[kGCpxmp], 0, 0, gTws->fWidth, - gTws->fHeight, xpos, ypos); - XFlush((Display*)fDisplay); + CopyPixmapW((WinContext_t) gCws, wid, xpos, ypos); } //////////////////////////////////////////////////////////////////////////////// @@ -1446,7 +1440,6 @@ Int_t TGX11::OpenPixmap(unsigned int w, unsigned int h) gCws->fClip = 0; gCws->fWidth = wval; gCws->fHeight = hval; - gCws->fNewColors = nullptr; gCws->fShared = kFALSE; return wid; @@ -1509,7 +1502,6 @@ Int_t TGX11::InitWindow(ULong_t win) gCws->fClip = 0; gCws->fWidth = wval; gCws->fHeight = hval; - gCws->fNewColors = nullptr; gCws->fShared = kFALSE; return wid; @@ -1535,7 +1527,6 @@ Int_t TGX11::AddWindow(ULong_t qwid, UInt_t w, UInt_t h) gCws->fClip = 0; gCws->fWidth = w; gCws->fHeight = h; - gCws->fNewColors = nullptr; gCws->fShared = kTRUE; return wid; @@ -2281,6 +2272,17 @@ void TGX11::SetFillColor(Color_t cindex) SetAttFill((WinContext_t) gCws, arg); } +//////////////////////////////////////////////////////////////////////////////// +/// Return current fill color + +Color_t TGX11::GetFillColor() const +{ + // TODO: remove in ROOT7, no longer used in the code + + return gCws ? gCws->fAttFill.GetFillColor() : TAttFill::GetFillColor(); +} + + //////////////////////////////////////////////////////////////////////////////// /// Set fill area style. /// @@ -2299,10 +2301,11 @@ void TGX11::SetFillStyle(Style_t fstyle) //////////////////////////////////////////////////////////////////////////////// /// Return current fill style -/// FIXME: Only as temporary solution while some code analyze current fill style Style_t TGX11::GetFillStyle() const { + // TODO: remove in ROOT7, no longer used in the code + return gCws ? gCws->fAttFill.GetFillStyle() : TAttFill::GetFillStyle(); } @@ -2371,10 +2374,11 @@ void TGX11::SetLineStyle(Style_t lstyle) //////////////////////////////////////////////////////////////////////////////// /// Return current line style -/// FIXME: Only as temporary solution while some code analyze current line style Style_t TGX11::GetLineStyle() const { + // TODO: remove in ROOT7, no loner used in ROOT code + return gCws ? gCws->fAttLine.GetLineStyle() : TAttLine::GetLineStyle(); } @@ -2395,10 +2399,11 @@ void TGX11::SetLineWidth(Width_t width) //////////////////////////////////////////////////////////////////////////////// /// Return current line width -/// FIXME: Only as temporary solution while some code analyze current line wide Width_t TGX11::GetLineWidth() const { + // TODO: remove in ROOT7, no loner used in ROOT code + return gCws ? gCws->fAttLine.GetLineWidth() : TAttLine::GetLineWidth(); } @@ -2446,7 +2451,7 @@ void TGX11::SetMarkerStyle(Style_t markerstyle) } //////////////////////////////////////////////////////////////////////////////// -/// Set opacity of a window. This image manipulation routine works +/// Set opacity of a selected window. This image manipulation routine works /// by adding to a percent amount of neutral to each pixels RGB. /// Since it requires quite some additional color map entries is it /// only supported on displays with more than > 8 color planes (> 256 @@ -2454,147 +2459,7 @@ void TGX11::SetMarkerStyle(Style_t markerstyle) void TGX11::SetOpacity(Int_t percent) { - if (fDepth <= 8) return; - if (percent == 0) return; - // if 100 percent then just make white - - ULong_t *orgcolors = nullptr, *tmpc = nullptr; - Int_t maxcolors = 0, ncolors = 0, ntmpc = 0; - - // save previous allocated colors, delete at end when not used anymore - if (gCws->fNewColors) { - tmpc = gCws->fNewColors; - ntmpc = gCws->fNcolors; - } - - // get pixmap from server as image - XImage *image = XGetImage((Display*)fDisplay, gCws->fDrawing, 0, 0, gCws->fWidth, - gCws->fHeight, AllPlanes, ZPixmap); - if (!image) return; - // collect different image colors - int x, y; - for (y = 0; y < (int) gCws->fHeight; y++) { - for (x = 0; x < (int) gCws->fWidth; x++) { - ULong_t pixel = XGetPixel(image, x, y); - CollectImageColors(pixel, orgcolors, ncolors, maxcolors); - } - } - if (ncolors == 0) { - XDestroyImage(image); - ::operator delete(orgcolors); - return; - } - - // create opaque counter parts - MakeOpaqueColors(percent, orgcolors, ncolors); - - if (gCws->fNewColors) { - // put opaque colors in image - for (y = 0; y < (int) gCws->fHeight; y++) { - for (x = 0; x < (int) gCws->fWidth; x++) { - ULong_t pixel = XGetPixel(image, x, y); - Int_t idx = FindColor(pixel, orgcolors, ncolors); - XPutPixel(image, x, y, gCws->fNewColors[idx]); - } - } - } - - // put image back in pixmap on server - XPutImage((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCpxmp], image, 0, 0, 0, 0, - gCws->fWidth, gCws->fHeight); - XFlush((Display*)fDisplay); - - // clean up - if (tmpc) { - if (fRedDiv == -1) - XFreeColors((Display*)fDisplay, fColormap, tmpc, ntmpc, 0); - delete [] tmpc; - } - XDestroyImage(image); - ::operator delete(orgcolors); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Collect in orgcolors all different original image colors. - -void TGX11::CollectImageColors(ULong_t pixel, ULong_t *&orgcolors, Int_t &ncolors, - Int_t &maxcolors) -{ - if (maxcolors == 0) { - ncolors = 0; - maxcolors = 100; - orgcolors = (ULong_t*) ::operator new(maxcolors*sizeof(ULong_t)); - } - - for (int i = 0; i < ncolors; i++) - if (pixel == orgcolors[i]) return; - - if (ncolors >= maxcolors) { - orgcolors = (ULong_t*) TStorage::ReAlloc(orgcolors, - maxcolors*2*sizeof(ULong_t), maxcolors*sizeof(ULong_t)); - maxcolors *= 2; - } - - orgcolors[ncolors++] = pixel; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Get RGB values for orgcolors, add percent neutral to the RGB and -/// allocate fNewColors. - -void TGX11::MakeOpaqueColors(Int_t percent, ULong_t *orgcolors, Int_t ncolors) -{ - if (ncolors == 0) return; - - RXColor *xcol = new RXColor[ncolors]; - - int i; - for (i = 0; i < ncolors; i++) { - xcol[i].pixel = orgcolors[i]; - xcol[i].red = xcol[i].green = xcol[i].blue = 0; - xcol[i].flags = DoRed | DoGreen | DoBlue; - } - QueryColors(fColormap, xcol, ncolors); - - UShort_t add = percent * kBIGGEST_RGB_VALUE / 100; - - Int_t val; - for (i = 0; i < ncolors; i++) { - val = xcol[i].red + add; - if (val > kBIGGEST_RGB_VALUE) val = kBIGGEST_RGB_VALUE; - xcol[i].red = (UShort_t) val; - val = xcol[i].green + add; - if (val > kBIGGEST_RGB_VALUE) val = kBIGGEST_RGB_VALUE; - xcol[i].green = (UShort_t) val; - val = xcol[i].blue + add; - if (val > kBIGGEST_RGB_VALUE) val = kBIGGEST_RGB_VALUE; - xcol[i].blue = (UShort_t) val; - if (!AllocColor(fColormap, &xcol[i])) - Warning("MakeOpaqueColors", "failed to allocate color %hd, %hd, %hd", - xcol[i].red, xcol[i].green, xcol[i].blue); - // assumes that in case of failure xcol[i].pixel is not changed - } - - gCws->fNewColors = new ULong_t[ncolors]; - gCws->fNcolors = ncolors; - - for (i = 0; i < ncolors; i++) - gCws->fNewColors[i] = xcol[i].pixel; - - delete [] xcol; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Returns index in orgcolors (and fNewColors) for pixel. - -Int_t TGX11::FindColor(ULong_t pixel, ULong_t *orgcolors, Int_t ncolors) -{ - for (int i = 0; i < ncolors; i++) - if (pixel == orgcolors[i]) return i; - - Error("FindColor", "did not find color, should never happen!"); - - return 0; + SetOpacityW((WinContext_t) gCws, percent); } //////////////////////////////////////////////////////////////////////////////// @@ -2797,6 +2662,107 @@ void TGX11::UpdateWindowW(WinContext_t wctxt, Int_t mode) } } +//////////////////////////////////////////////////////////////////////////////// +/// Set opacity of a specified window. This image manipulation routine works +/// by adding to a percent amount of neutral to each pixels RGB. +/// Since it requires quite some additional color map entries is it +/// only supported on displays with more than > 8 color planes (> 256 +/// colors). + +void TGX11::SetOpacityW(WinContext_t wctxt, Int_t percent) +{ + if ((fDepth <= 8) || (percent <= 0)) return; + if (percent > 100) percent = 100; + + auto ctxt = (XWindow_t *) wctxt; + + // get pixmap from server as image + XImage *image = XGetImage((Display*)fDisplay, ctxt->fDrawing, 0, 0, ctxt->fWidth, + ctxt->fHeight, AllPlanes, ZPixmap); + if (!image) return; + + // collect different image colors + std::vector orgcolors; + for (UInt_t y = 0; y < ctxt->fHeight; y++) { + for (UInt_t x = 0; x < ctxt->fWidth; x++) { + ULong_t pixel = XGetPixel(image, x, y); + if (std::find(orgcolors.begin(), orgcolors.end(), pixel) == orgcolors.end()) + orgcolors.emplace_back(pixel); + } + } + if (orgcolors.empty()) { + XDestroyImage(image); + return; + } + + // clean up old colors + if (!ctxt->fNewColors.empty()) { + if (fRedDiv == -1) + XFreeColors((Display*)fDisplay, fColormap, ctxt->fNewColors.data(), ctxt->fNewColors.size(), 0); + ctxt->fNewColors.clear(); + } + + std::vector xcol(orgcolors.size()); + + for (std::size_t i = 0; i < orgcolors.size(); i++) { + xcol[i].pixel = orgcolors[i]; + xcol[i].red = xcol[i].green = xcol[i].blue = 0; + xcol[i].flags = DoRed | DoGreen | DoBlue; + } + QueryColors(fColormap, xcol.data(), orgcolors.size()); + + // create new colors mixing: "100-percent" of old color and "percent" of new background color + XColor_t &bkgr = GetColor(ctxt->fAttFill.GetFillColor()); + + for (std::size_t i = 0; i < orgcolors.size(); i++) { + xcol[i].red = (UShort_t) TMath::Min((Int_t) xcol[i].red * (100 - percent) / 100 + bkgr.fRed * percent / 100, kBIGGEST_RGB_VALUE); + xcol[i].green = (UShort_t) TMath::Min((Int_t) xcol[i].green * (100 - percent) / 100 + bkgr.fGreen * percent / 100, kBIGGEST_RGB_VALUE); + xcol[i].blue = (UShort_t) TMath::Min((Int_t) xcol[i].blue * (100 - percent) / 100 + bkgr.fBlue * percent / 100, kBIGGEST_RGB_VALUE); + if (!AllocColor(fColormap, &xcol[i])) + Warning("SetOpacityW", "failed to allocate color %hd, %hd, %hd", + xcol[i].red, xcol[i].green, xcol[i].blue); + // assumes that in case of failure xcol[i].pixel is not changed + } + + ctxt->fNewColors.resize(orgcolors.size()); + + for (std::size_t i = 0; i < orgcolors.size(); i++) + ctxt->fNewColors[i] = xcol[i].pixel; + + // put opaque colors in image + for (UInt_t y = 0; y < ctxt->fHeight; y++) { + for (UInt_t x = 0; x < ctxt->fWidth; x++) { + ULong_t pixel = XGetPixel(image, x, y); + auto iter = std::find(orgcolors.begin(), orgcolors.end(), pixel); + if (iter != orgcolors.end()) { + auto idx = iter - orgcolors.begin(); + XPutPixel(image, x, y, ctxt->fNewColors[idx]); + } + } + } + + // put image back in pixmap on server + XPutImage((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCpxmp], image, 0, 0, 0, 0, + ctxt->fWidth, ctxt->fHeight); + XFlush((Display*)fDisplay); + + XDestroyImage(image); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Copy the pixmap wid at the position xpos, ypos in the specified window. + +void TGX11::CopyPixmapW(WinContext_t wctxt, Int_t wid, Int_t xpos, Int_t ypos) +{ + auto ctxt = (XWindow_t *) wctxt; + + gTws = fWindows[wid].get(); + + XCopyArea((Display*)fDisplay, gTws->fDrawing, ctxt->fDrawing, gTws->fGClist[kGCpxmp], 0, 0, gTws->fWidth, + gTws->fHeight, xpos, ypos); + XFlush((Display*)fDisplay); +} + //////////////////////////////////////////////////////////////////////////////// /// Set pointer position. /// @@ -2879,54 +2845,51 @@ static void PutByte(Byte_t b) void TGX11::ImgPickPalette(RXImage *image, Int_t &ncol, Int_t *&R, Int_t *&G, Int_t *&B) { - ULong_t *orgcolors = nullptr; - Int_t maxcolors = 0, ncolors = 0; + std::vector orgcolors; // collect different image colors - int x, y; - for (x = 0; x < (int) gCws->fWidth; x++) { - for (y = 0; y < (int) gCws->fHeight; y++) { + for (UInt_t x = 0; x < gCws->fWidth; x++) { + for (UInt_t y = 0; y < gCws->fHeight; y++) { ULong_t pixel = XGetPixel(image, x, y); - CollectImageColors(pixel, orgcolors, ncolors, maxcolors); + if (std::find(orgcolors.begin(), orgcolors.end(), pixel) == orgcolors.end()) + orgcolors.emplace_back(pixel); } } // get RGB values belonging to pixels - RXColor *xcol = new RXColor[ncolors]; + std::vector xcol(orgcolors.size()); - int i; - for (i = 0; i < ncolors; i++) { + for (size_t i = 0; i < orgcolors.size(); i++) { xcol[i].pixel = orgcolors[i]; xcol[i].red = xcol[i].green = xcol[i].blue = 0; xcol[i].flags = DoRed | DoGreen | DoBlue; } - QueryColors(fColormap, xcol, ncolors); + QueryColors(fColormap, xcol.data(), orgcolors.size()); // create RGB arrays and store RGB's for each color and set number of colors // (space must be delete by caller) - R = new Int_t[ncolors]; - G = new Int_t[ncolors]; - B = new Int_t[ncolors]; + R = new Int_t[orgcolors.size()]; + G = new Int_t[orgcolors.size()]; + B = new Int_t[orgcolors.size()]; - for (i = 0; i < ncolors; i++) { + for (size_t i = 0; i < orgcolors.size(); i++) { R[i] = xcol[i].red; G[i] = xcol[i].green; B[i] = xcol[i].blue; } - ncol = ncolors; + ncol = (Int_t) orgcolors.size(); // update image with indices (pixels) into the new RGB colormap - for (x = 0; x < (int) gCws->fWidth; x++) { - for (y = 0; y < (int) gCws->fHeight; y++) { + for (UInt_t x = 0; x < gCws->fWidth; x++) { + for (UInt_t y = 0; y < gCws->fHeight; y++) { ULong_t pixel = XGetPixel(image, x, y); - Int_t idx = FindColor(pixel, orgcolors, ncolors); - XPutPixel(image, x, y, idx); + auto iter = std::find(orgcolors.begin(), orgcolors.end(), pixel); + if (iter != orgcolors.end()) { + auto idx = iter - orgcolors.begin(); + XPutPixel(image, x, y, idx); + } } } - - // cleanup - delete [] xcol; - ::operator delete(orgcolors); } //////////////////////////////////////////////////////////////////////////////// @@ -3211,7 +3174,6 @@ Int_t TGX11::AddPixmap(ULong_t pixid, UInt_t w, UInt_t h) gCws->fClip = 0; gCws->fWidth = w; gCws->fHeight = h; - gCws->fNewColors = nullptr; gCws->fShared = kFALSE; return wid; @@ -3234,12 +3196,20 @@ Int_t TGX11::SupportsExtension(const char *ext) const return XQueryExtension((Display*)fDisplay, ext, &major_opcode, &first_event, &first_error); } +//////////////////////////////////////////////////////////////////////////////// +/// Returns window context for specified window id +/// Window context is valid until window not closed or destroyed +/// Provided methods to work with window context like DrawLineW allows to +/// perform actions independently on different windows WinContext_t TGX11::GetWindowContext(Int_t wid) { return (WinContext_t) fWindows[wid].get(); } +//////////////////////////////////////////////////////////////////////////////// +/// Set fill attributes for specified window + void TGX11::SetAttFill(WinContext_t wctxt, const TAttFill &att) { auto ctxt = (XWindow_t *) wctxt; @@ -3289,6 +3259,9 @@ void TGX11::SetAttFill(WinContext_t wctxt, const TAttFill &att) } } +//////////////////////////////////////////////////////////////////////////////// +/// Set line attributes for specified window + void TGX11::SetAttLine(WinContext_t wctxt, const TAttLine &att) { auto ctxt = (XWindow_t *) wctxt; @@ -3348,6 +3321,9 @@ void TGX11::SetAttLine(WinContext_t wctxt, const TAttLine &att) ctxt->fAttLine = att; } +//////////////////////////////////////////////////////////////////////////////// +/// Set marker attributes for specified window + void TGX11::SetAttMarker(WinContext_t wctxt, const TAttMarker &att) { auto ctxt = (XWindow_t *) wctxt; @@ -3842,6 +3818,9 @@ void TGX11::SetAttMarker(WinContext_t wctxt, const TAttMarker &att) } } +//////////////////////////////////////////////////////////////////////////////// +/// Set text attributes for specified window + void TGX11::SetAttText(WinContext_t wctxt, const TAttText &att) { auto ctxt = (XWindow_t *) wctxt; @@ -3910,9 +3889,9 @@ void TGX11::SetAttText(WinContext_t wctxt, const TAttText &att) // use first existing font for (int i = 0; i < kMAXFONT; i++) if (gFont[i].id) { - gCws->textFont = gFont[i].id; - XSetFont((Display*)fDisplay, gCws->fGClist[kGCtext], gCws->textFont->fid); - XSetFont((Display*)fDisplay, gCws->fGClist[kGCinvt], gCws->textFont->fid); + ctxt->textFont = gFont[i].id; + XSetFont((Display*)fDisplay, ctxt->fGClist[kGCtext], ctxt->textFont->fid); + XSetFont((Display*)fDisplay, ctxt->fGClist[kGCinvt], ctxt->textFont->fid); break; } diff --git a/graf3d/gl/inc/TGLPadPainter.h b/graf3d/gl/inc/TGLPadPainter.h index 57426b6e3e27e..88372aa6f492f 100644 --- a/graf3d/gl/inc/TGLPadPainter.h +++ b/graf3d/gl/inc/TGLPadPainter.h @@ -34,6 +34,7 @@ class TGLPadPainter : public TPadPainterBase { Rgl::Pad::GLLimits fLimits; WinContext_t fWinContext; // context of selected drawable + TAttFill fGlFillAtt; // fill attributes used for GL std::vector fVs;//Vertex buffer for tesselator. diff --git a/graf3d/gl/src/TGLPadPainter.cxx b/graf3d/gl/src/TGLPadPainter.cxx index 3c55cef6354e1..2a39bc9e6d2f4 100644 --- a/graf3d/gl/src/TGLPadPainter.cxx +++ b/graf3d/gl/src/TGLPadPainter.cxx @@ -71,7 +71,8 @@ TGLPadPainter::TGLPadPainter() void TGLPadPainter::SetOpacity(Int_t percent) { - gVirtualX->SetOpacity(percent); + // does not work this way + gVirtualX->SetOpacityW(fWinContext, percent); } //////////////////////////////////////////////////////////////////////////////// @@ -100,6 +101,8 @@ void TGLPadPainter::SetAttFill(const TAttFill &att) { TPadPainterBase::SetAttFill(att); + fGlFillAtt = GetAttFillInternal(kTRUE); + // TODO: dismiss in the future, gVirtualX attributes not needed in GL if (fWinContext && gVirtualX) gVirtualX->SetAttFill(fWinContext, att); @@ -183,7 +186,7 @@ Bool_t TGLPadPainter::IsCocoa() const void TGLPadPainter::CopyDrawable(Int_t /* device */, Int_t /* px */, Int_t /* py */) { - // gVirtualX->CopyPixmap(device, px, py); + // gVirtualX->CopyPixmapW(fWinContext, device, px, py); } //////////////////////////////////////////////////////////////////////////////// @@ -436,7 +439,7 @@ void TGLPadPainter::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, return; } - if (IsGradientFill(GetAttFill().GetFillColor())) { + if (IsGradientFill(fGlFillAtt.GetFillColor())) { Double_t xs[] = {x1, x2, x2, x1}; Double_t ys[] = {y1, y1, y2, y2}; DrawPolygonWithGradient(4, xs, ys); @@ -451,7 +454,7 @@ void TGLPadPainter::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glLineWidth(1.f); } else { - const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE, &GetAttFill());//Set filling parameters. + const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE, &fGlFillAtt);//Set filling parameters. glRectd(x1, y1, x2, y2); } } @@ -473,15 +476,15 @@ void TGLPadPainter::DrawFillArea(Int_t n, const Double_t *x, const Double_t *y) return; } - if (IsGradientFill(GetAttFill().GetFillColor())) + if (IsGradientFill(fGlFillAtt.GetFillColor())) return DrawPolygonWithGradient(n, x, y); - if (!GetAttFill().GetFillStyle()) { + if (fFullyTransparent) { fIsHollowArea = kTRUE; return DrawPolyLine(n, x, y); } - const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE, &GetAttFill()); + const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE, &fGlFillAtt); DrawTesselation(n, x, y); } @@ -493,7 +496,7 @@ void TGLPadPainter::DrawFillArea(Int_t n, const Float_t *x, const Float_t *y) { if (fLocked) return; - if (!GetAttFill().GetFillStyle()) { + if (fFullyTransparent) { fIsHollowArea = kTRUE; return DrawPolyLine(n, x, y); } @@ -505,7 +508,7 @@ void TGLPadPainter::DrawFillArea(Int_t n, const Float_t *x, const Float_t *y) fVs[i * 3 + 1] = y[i]; } - const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE, &GetAttFill()); + const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE, &fGlFillAtt); GLUtesselator *t = (GLUtesselator *)fTess.GetTess(); gluBeginPolygon(t); @@ -1081,7 +1084,7 @@ void TGLPadPainter::DrawPolygonWithGradient(Int_t n, const Double_t *x, const Do assert(x != nullptr && "DrawPolygonWithGradient, parameter 'x' is null"); assert(y != nullptr && "DrawPolygonWithGradient, parameter 'y' is null"); - auto grad = dynamic_cast(gROOT->GetColor(GetAttFill().GetFillColor())); + auto grad = dynamic_cast(gROOT->GetColor(fGlFillAtt.GetFillColor())); assert(grad != nullptr && "DrawPolygonWithGradient, the current fill color is not a gradient fill"); if (fLocked) diff --git a/test/stressGraphics_web.ref b/test/stressGraphics_web.ref index de2e6741d1556..891d260693fe3 100644 --- a/test/stressGraphics_web.ref +++ b/test/stressGraphics_web.ref @@ -4,7 +4,7 @@ tpolyline 611 50 3802 50 27412 10485 24438 14774 611 50 hatches 2082 70 7349 100 190000 100000 32444 15000 2082 70 arrows 1915 50 6155 50 55000 20000 40240 20000 1915 50 - patterns 35154 300 82420 850 265000 50000 160000 65000 35154 300 + patterns 49050 300 93717 850 270000 65000 160000 65000 49050 300 crown 1768 50 10343 50 65000 20000 40977 20000 1768 50 piechart 13043 300 23769 300 100000 40000 98889 30000 13077 300 ttext1 2338 50 4816 50 104754 39759 62489 21274 2338 50 diff --git a/tutorials/visualisation/gl/transparentpad.C b/tutorials/visualisation/gl/transparentpad.C index 886cea12490c3..e3d6bccaf95c5 100644 --- a/tutorials/visualisation/gl/transparentpad.C +++ b/tutorials/visualisation/gl/transparentpad.C @@ -1,14 +1,17 @@ /// \file /// \ingroup tutorial_gl /// This macro demonstrates semi-transparent pads. -/// Requires OpenGL or Web-based canvas. +/// +/// One uses fill styles between 4000 and 4100 to configure objects transparency +/// On OpenGL or Mac/Cocoa or Web-based canvas pads will be drawn with transparent colors. +/// On X11 pixmap transformation performed to partially emulate pads transparency +/// Also demonstrated usage of transparent fill styles for stats box /// /// \macro_image(nobatch) /// \macro_code /// /// \authors Timur Pocheptsov, Sergey Linev -// Includes for ACLiC (cling does not need them). #include "TCanvas.h" #include "TStyle.h" #include "TError.h" @@ -19,12 +22,14 @@ void transparentpad(bool gl = true) { gStyle->SetCanvasPreferGL(gl); + // prevent filling of TFrame with solid color + gStyle->SetFrameFillStyle(0); + // 1. Create canvas and check if it support transparent colors - auto c1 = new TCanvas("transparentpad", "transparent pad demo", 10, 10, 900, 500); - if (!c1->UseGL() && !c1->IsWeb()) + auto c1 = new TCanvas("c1", "transparent pad demo", 10, 10, 900, 500); + if (!c1->UseGL() && !c1->IsWeb() && !gVirtualX->InheritsFrom("TGCocoa")) ::Warning("transparentpad", - "You can see the transparency ONLY in a pdf or png output (\"File\"->\"Save As\" ->...)\n" - "To have transparency in a canvas graphics, you need either OpenGL or Web rendering enabled"); + "To have real transparency in a canvas graphics, you need either OpenGL or Mac/Cocoa or Web rendering enabled"); // 2. Some arbitrary histograms. auto h1 = new TH1F("TH1F 1", "TH1F 1", 100, -1.5, 1.5); @@ -38,23 +43,39 @@ void transparentpad(bool gl = true) // 3. Now overlapping transparent pads. auto pad1 = new TPad("transparent pad 1", "transparent pad 1", 0.1, 0.1, 0.7, 0.7); - pad1->SetFillColor(TColor::GetColor((Float_t)1., 0.2, 0.2, 0.25)); // transparent pink, here's the magic! - c1->cd(); - pad1->Draw(); - pad1->cd(); - h1->Draw("lego2"); + pad1->SetFillColor(kPink); + pad1->SetFillStyle(4040); // transparent pink, here's the magic! + c1->Add(pad1); + pad1->Add(h1, "lego2"); auto pad2 = new TPad("transparent pad 2", "transparent pad 2", 0.2, 0.2, 0.8, 0.8); - pad2->SetFillColor(TColor::GetColor((Float_t)0.2, 1., 0.2, 0.25)); // transparent green, here's the magic! - c1->cd(); - pad2->Draw(); - pad2->cd(); - h2->Draw(); + pad2->SetFillColor(kGreen); + pad2->SetFillStyle(4035); // transparent green, here's the magic! + c1->Add(pad2); + pad2->Add(h2); auto pad3 = new TPad("transparent pad 3", "transparent pad 3", 0.3, 0.3, 0.9, 0.9); - pad3->SetFillColor(TColor::GetColor((Float_t)0.2, 1., 1., 0.15)); // transparent blue, here's the magic! - c1->cd(); - pad3->Draw(); - pad3->cd(); - h3->Draw(); + pad3->SetFillColor(kBlue); + pad3->SetFillStyle(4030); // transparent blue, here's the magic! + c1->Add(pad3); + pad3->Add(h3); + + c1->Update(); + + auto stats2 = dynamic_cast(h2->FindObject("stats")); + if (stats2) { + stats2->SetFillColor(kYellow); + stats2->SetFillStyle(4050); // semi-transparent stats box, only with GL + } + + auto stats3 = dynamic_cast(h3->FindObject("stats")); + if (stats3) { + stats3->SetFillColor(kYellow); + stats3->SetFillStyle(4050); // semi-transparent stats box, only with GL + } + + // SVG or PDF or PS image always support transparent colors + // c1->SaveAs("transparentpad.svg"); + + c1->Modified(); }