Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TQt6PadPainter.cxx
Go to the documentation of this file.
1// Author: Sergey Linev, GSI 26/06/2026
2
3/*************************************************************************
4 * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#include "TQt6PadPainter.h"
12#include "TError.h"
13#include "TSystem.h"
14#include "TStyle.h"
15#include "TEnv.h"
16#include "TMath.h"
17#include "TPad.h"
18#include "TPoint.h"
19#include "TROOT.h"
20#include "TColor.h"
21#include "RStipples.h"
22#include "TTFhandle.h"
23#include "TImage.h"
24
25#include <memory>
26#include <map>
27
28#include "QPaintWidget.h"
29
30#include <QRect>
31#include <QImage>
32#include <QPainter>
33#include <QString>
34#include <QColor>
35#include <QPen>
36#include <QBrush>
37
38using namespace ROOT::Experimental;
39
40
41/** \class TQt6PadPainter
42 \ingroup qt6canvas
43 \brief Implement TVirtualPadPainter for Qt6 graphics
44
45 Uses QPainter object which only exists inside paintEvent of Qt.
46*/
47
48//////////////////////////////////////////////////////////////////////////
49/// Set opacity - similar to TVirtualPS usecase
50
51void TQt6PadPainter::SetOpacity(Int_t percent)
52{
54}
55
56
57////////////////////////////////////////////////////////////////////////////////
58///Noop, for non-gl pad TASImage calls gVirtualX->CopyArea.
59
60void TQt6PadPainter::DrawPixels(const unsigned char * /*pixelData*/, UInt_t /*width*/, UInt_t /*height*/,
61 Int_t /*dstX*/, Int_t /*dstY*/, Bool_t /*enableAlphaBlending*/)
62{
63
64}
65
66
67////////////////////////////////////////////////////////////////////////////////
68/// Paint a simple line.
69
71{
72 auto painter = fPaintWidget->getPainter();
73 if (!painter || GetAttLine().GetLineWidth() <= 0)
74 return;
75
76 const Int_t px1 = gPad->XtoAbsPixel(x1);
77 const Int_t py1 = gPad->YtoAbsPixel(y1);
78 const Int_t px2 = gPad->XtoAbsPixel(x2);
79 const Int_t py2 = gPad->YtoAbsPixel(y2);
80
81 painter->setPen(GetLinePen());
82
83 painter->setRenderHint(QPainter::Antialiasing);
84
85 painter->drawLine(QPoint(px1, py1), QPoint(px2, py2));
86}
87
88
89////////////////////////////////////////////////////////////////////////////////
90/// Paint a simple line in normalized coordinates.
91
93{
94 auto painter = fPaintWidget->getPainter();
95 if (!painter || GetAttLine().GetLineWidth() <= 0)
96 return;
97
98 const Int_t px1 = gPad->UtoAbsPixel(u1);
99 const Int_t py1 = gPad->VtoAbsPixel(v1);
100 const Int_t px2 = gPad->UtoAbsPixel(u2);
101 const Int_t py2 = gPad->VtoAbsPixel(v2);
102
103 painter->setPen(GetLinePen());
104
105 painter->setRenderHint(QPainter::Antialiasing);
106
107 painter->drawLine(QPoint(px1, py1), QPoint(px2, py2));
108}
109
110////////////////////////////////////////////////////////////////////////////////
111/// Paint a simple box.
112
114{
116 return;
117
118 auto painter = fPaintWidget->getPainter();
119 if (!painter)
120 return;
121
122 const Int_t px1 = gPad->XtoAbsPixel(x1);
123 const Int_t py1 = gPad->YtoAbsPixel(y1);
124 const Int_t px2 = gPad->XtoAbsPixel(x2);
125 const Int_t py2 = gPad->YtoAbsPixel(y2);
126
128 // draw only border
129 painter->setPen(GetLinePen());
130 painter->setRenderHint(QPainter::Antialiasing);
131 painter->setBrush(Qt::NoBrush);
132 } else {
133 // draw only fill
134 painter->setPen(Qt::NoPen);
135 painter->setBrush(GetFillBrush());
136 }
137
138 QRect rectangle(TMath::Min(px1, px2), TMath::Min(py1, py2), TMath::Abs(px2 - px1), TMath::Abs(py2 - py1));
139 painter->drawRect(rectangle);
140}
141
142////////////////////////////////////////////////////////////////////////////////
143/// Paint filled area.
144
145void TQt6PadPainter::DrawFillArea(Int_t nPoints, const Double_t *xs, const Double_t *ys)
146{
147 auto painter = fPaintWidget->getPainter();
148
149 if (!painter || (GetAttFill().GetFillStyle() <= 0) || (nPoints < 3))
150 return;
151
152 QList<QPointF> points;
153 for (Int_t n = 0; n < nPoints; ++n) {
154 auto px = gPad->XtoAbsPixel(xs[n]);
155 auto py = gPad->YtoAbsPixel(ys[n]);
156 points.push_back({(qreal) px, (qreal) py});
157 }
158
159 painter->setPen(Qt::NoPen);
160 painter->setBrush(GetFillBrush());
161 painter->drawPolygon(points);
162}
163
164////////////////////////////////////////////////////////////////////////////////
165/// Paint filled area.
166
167void TQt6PadPainter::DrawFillArea(Int_t nPoints, const Float_t *xs, const Float_t *ys)
168{
169 auto painter = fPaintWidget->getPainter();
170
171 if (!painter || (GetAttFill().GetFillStyle() <= 0) || (nPoints < 3))
172 return;
173
174 QList<QPointF> points;
175 for (Int_t n = 0; n < nPoints; ++n) {
176 auto px = gPad->XtoAbsPixel(xs[n]);
177 auto py = gPad->YtoAbsPixel(ys[n]);
178 points.push_back({(qreal) px, (qreal) py});
179 }
180
181 painter->setPen(Qt::NoPen);
182 painter->setBrush(GetFillBrush());
183 painter->drawPolygon(points);
184}
185
186////////////////////////////////////////////////////////////////////////////////
187/// Paint Polyline.
188
189void TQt6PadPainter::DrawPolyLine(Int_t nPoints, const Double_t *xs, const Double_t *ys)
190{
191 auto painter = fPaintWidget->getPainter();
192 if (!painter || (GetAttLine().GetLineWidth() <= 0) || (nPoints < 2))
193 return;
194
195 QList<QPointF> points;
196 for (Int_t n = 0; n < nPoints; ++n) {
197 auto px = gPad->XtoAbsPixel(xs[n]);
198 auto py = gPad->YtoAbsPixel(ys[n]);
199 points.push_back({(qreal) px, (qreal) py});
200 }
201
202 painter->setPen(GetLinePen());
203
204 painter->setRenderHint(QPainter::Antialiasing);
205
206 painter->drawPolyline(points);
207}
208
209////////////////////////////////////////////////////////////////////////////////
210/// Paint polyline.
211
212void TQt6PadPainter::DrawPolyLine(Int_t nPoints, const Float_t *xs, const Float_t *ys)
213{
214 auto painter = fPaintWidget->getPainter();
215 if (!painter || (GetAttLine().GetLineWidth() <= 0) || (nPoints < 2))
216 return;
217
218 QList<QPointF> points;
219 for (Int_t n = 0; n < nPoints; ++n) {
220 auto px = gPad->XtoAbsPixel(xs[n]);
221 auto py = gPad->YtoAbsPixel(ys[n]);
222 points.push_back({(qreal) px, (qreal) py});
223 }
224
225 painter->setPen(GetLinePen());
226
227 painter->setRenderHint(QPainter::Antialiasing);
228
229 painter->drawPolyline(points);
230}
231
232////////////////////////////////////////////////////////////////////////////////
233/// Paint polyline in normalized coordinates.
234
236{
237 auto painter = fPaintWidget->getPainter();
238 if (!painter || (GetAttLine().GetLineWidth() <= 0) || (nPoints < 2))
239 return;
240
241 QList<QPointF> points;
242 for (Int_t n = 0; n < nPoints; ++n) {
243 auto px = gPad->UtoAbsPixel(u[n]);
244 auto py = gPad->VtoAbsPixel(v[n]);
245 points.push_back({(qreal) px, (qreal) py});
246 }
247
248 painter->setPen(GetLinePen());
249
250 painter->setRenderHint(QPainter::Antialiasing);
251
252 painter->drawPolyline(points);
253}
254
255////////////////////////////////////////////////////////////////////////////////
256/// Helper function to paint markers
257
258template<typename T>
259void drawMarkersHelper(Int_t nPoints, const T *x, const T *y,
260 const TAttMarker &attr, const QColor &col, QPainter *painter)
261{
262 if (!painter || nPoints < 1)
263 return;
264
265 auto markerLineWidth = TAttMarker::GetMarkerLineWidth(attr.GetMarkerStyle());
266 Int_t markerSize = 0; ///< size of simple markers
267 std::vector<TPoint> markerShape; ///< marker shape points
268 auto markerType = attr.GetMarkerShape(markerSize, markerShape);
269
270 painter->setRenderHint(QPainter::Antialiasing);
271
272 if ((markerType == TAttMarker::kShapeDot) || (markerLineWidth > 0)) {
273 QPen customPen;
274 customPen.setColor(col);
275 customPen.setWidth(markerLineWidth);
276 customPen.setStyle(Qt::SolidLine);
277 painter->setPen(customPen);
278 painter->setBrush(Qt::NoBrush);
279 } else {
280 QBrush customBrush(col);
281 painter->setBrush(customBrush);
282 painter->setPen(Qt::NoPen);
283 }
284
285 for (Int_t n = 0; n < nPoints; ++n) {
286 Int_t px = gPad->XtoAbsPixel(x[n]);
287 Int_t py = gPad->YtoAbsPixel(y[n]);
288
289 QList<QPointF> points;
290 for (auto &pnt : markerShape)
291 points.push_back({(qreal) (px + pnt.fX), (qreal) (py + pnt.fY)});
292
293 switch(markerType) {
295 painter->drawPoint(px, py);
296 break;
299 // hollow or filled circle
300 painter->drawEllipse({px, py}, markerSize / 2, markerSize / 2);
301 break;
303 // hollow polygon
304 painter->drawPolyline(points);
305 break;
307 // filled polygon
308 painter->drawPolygon(points);
309 break;
311 // segmented line
312 painter->drawLines(points);
313 break;
315 // filled triangles
316 for (int i = 0; i < points.size() - 2; i += 3) {
317 // Construct a temporary triangle polygon
318 QPolygonF triangle;
319 triangle << points[i] << points[i + 1] << points[i + 2];
320 // Draw and fill the triangle
321 painter->drawPolygon(triangle);
322 }
323 break;
324 }
325 }
326}
327
328////////////////////////////////////////////////////////////////////////////////
329/// Paint polymarker.
330
332{
333 drawMarkersHelper<Double_t>(nPoints, x, y,
335}
336
337////////////////////////////////////////////////////////////////////////////////
338/// Paint polymarker.
339
341{
342 drawMarkersHelper<Float_t>(nPoints, x, y,
344}
345
346////////////////////////////////////////////////////////////////////////////////
347/// Produce image
348
349void TQt6PadPainter::SaveImage(TVirtualPad * /* pad */, const char * /* fileName */, Int_t /* gtype */) const
350{
351}
352
353////////////////////////////////////////////////////////////////////////////////
354/// Return QColor created from specified TColor
355
357{
358 auto c = gROOT->GetColor(id);
359 if (c)
360 return QColor((int)(c->GetRed() * 255), (int)(c->GetGreen() * 255), (int)(c->GetBlue() * 255), (int)(c->GetAlpha() * 255));
361 return QColor(0, 0, 0);
362}
363
364////////////////////////////////////////////////////////////////////////////////
365/// Return QPen for lines drawing
366
368{
369 auto &att = GetAttLine();
370
371 auto style = att.GetLineStyle();
372
373 QPen customPen;
374 customPen.setColor(GetQColor(att.GetLineColor()));
375 customPen.setWidth(att.GetLineWidth());
376 customPen.setStyle(Qt::SolidLine);
377
378 TString patt;
379
380 if (style > 1)
382
383 if (patt.Length() > 2) {
384 QList<qreal> pattern;
385 std::unique_ptr<TObjArray> tokens(patt.Tokenize(" "));
386 for (Int_t j = 0; j < tokens->GetEntries(); j++) {
387 int it = std::stoi(tokens->At(j)->GetName());
388 pattern.push_back(0.25 * it);
389 }
390 if (pattern.size() > 1) {
391 customPen.setStyle(Qt::CustomDashLine);
392 customPen.setDashPattern(pattern);
393 }
394 }
395
396 return customPen;
397}
398
399////////////////////////////////////////////////////////////////////////////////
400/// Return QBrush for fill drawing drawing
401
403{
404 auto &att = GetAttFill();
405
406 Int_t style = att.GetFillStyle() / 1000;
407
408 if (style == 1)
409 return QBrush(GetQColor(att.GetFillColor()));
410
411 if (style == 3) {
412 Int_t fasi = att.GetFillStyle() % 1000;
413 Int_t stn = (fasi >= 1 && fasi <=25) ? fasi : 2;
414 QBitmap bitmap = QBitmap::fromData(QSize(16, 16), (uchar *)gStipples[stn]);
415 QImage image = bitmap.toImage();
416 image.setColor(0, qRgba(0, 0, 0, 0)); // transparent
417 image.setColor(1, GetQColor(att.GetFillColor()).rgba());
418 return QBrush(QPixmap::fromImage(image.copy()));
419 }
420
421 return QBrush(Qt::NoBrush);
422}
423
424
425////////////////////////////////////////////////////////////////////////////////
426/// Render TTF glyphs on drawable area
427
429{
430 // position inside the pad is provided, therefore shift it to global image
431 px += fPad->UtoAbsPixel(0);
432 py += fPad->VtoAbsPixel(1);
433
434 const TAttText &att = GetAttText();
435
436 auto painter = fPaintWidget->getPainter();
437
438 auto textColor = GetQColor(att.GetTextColor());
439
440 for (UInt_t nglyph = 0; nglyph < ttf.GetNumGlyphs(); nglyph++) {
441 Int_t bx = 0, by = 0;
442 UChar_t *buffer = nullptr;
443 UInt_t width = 0, rows = 0, pitch = 0;
444 if (!ttf.GetGlyphData(nglyph, bx, by, buffer, width, rows, pitch))
445 continue;
446
447 QImage colorFill(width, rows, QImage::Format_ARGB32);
448 colorFill.fill(textColor);
449
450 QPainter maskPainter(&colorFill);
451
452 QImage maskImage(
453 buffer,
454 width,
455 rows,
456 pitch,
457 QImage::Format_Alpha8
458 );
459
460 maskPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
461 maskPainter.drawImage(0, 0, maskImage);
462 maskPainter.end();
463
464 painter->drawImage(QPoint(px + bx, py + by), colorFill);
465 }
466}
467
469{
470 // position inside the pad is provided, therefore shift it to global image
471 px += fPad->UtoAbsPixel(0);
472 py += fPad->VtoAbsPixel(1);
473
474 auto width = img->GetWidth();
475 auto height = img->GetHeight();
476 auto argbBuffer = (const uchar*) img->GetArgbArray();
477
478 auto painter = fPaintWidget->getPainter();
479
480 int bytesPerLine = width * 4;
481
482 // 1. Wrap the raw memory array into a QImage.
483 // This constructor does NOT copy the pixel data; it points directly to your buffer.
484 QImage image(
485 argbBuffer,
486 width,
487 height,
488 bytesPerLine,
489 QImage::Format_ARGB32
490 );
491
492 // 2. Draw the image using QPainter
493 // (0, 0) is the top-left coordinate where the image will be drawn
494 painter->drawImage(px, py, image);
495}
496
497
#define c(i)
Definition RSha256.hxx:101
const unsigned char gStipples[26][32]
Definition RStipples.h:24
short Color_t
Color number (short)
Definition RtypesCore.h:100
unsigned char UChar_t
Unsigned Character 1 byte (unsigned char)
Definition RtypesCore.h:53
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char bitmap
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t TPoint TPoint const char y2
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t points
Option_t Option_t width
Option_t Option_t TPoint TPoint percent
Option_t Option_t style
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t height
Option_t Option_t TPoint TPoint const char y1
void drawMarkersHelper(Int_t nPoints, const T *x, const T *y, const TAttMarker &attr, const QColor &col, QPainter *painter)
Helper function to paint markers.
#define gROOT
Definition TROOT.h:417
R__EXTERN TStyle * gStyle
Definition TStyle.h:442
#define gPad
QPainter * getPainter() const
QBrush GetFillBrush()
Return QBrush for fill drawing drawing.
void SaveImage(TVirtualPad *, const char *, Int_t) const override
Produce image.
void DrawPolyLineNDC(Int_t n, const Double_t *u, const Double_t *v) override
Paint polyline in normalized coordinates.
void DrawPixels(const unsigned char *pixelData, UInt_t width, UInt_t height, Int_t dstX, Int_t dstY, Bool_t enableAlphaBlending) override
Noop, for non-gl pad TASImage calls gVirtualX->CopyArea.
void DrawPolyMarker(Int_t n, const Double_t *x, const Double_t *y) override
Paint polymarker.
void DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags=0) override
Draw image, need to be implemented in correspondent.
static QColor GetQColor(Color_t id)
Return QColor created from specified TColor.
void DrawTTFglyphs(Int_t px, Int_t py, TTFhandle &ttf, ETextMode mode) override
Render TTF glyphs on drawable area.
void DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, EBoxMode mode) override
Paint a simple box.
void DrawPolyLine(Int_t n, const Double_t *x, const Double_t *y) override
Paint Polyline.
void DrawLineNDC(Double_t u1, Double_t v1, Double_t u2, Double_t v2) override
Paint a simple line in normalized coordinates.
void DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2) override
Paint a simple line.
void DrawFillArea(Int_t n, const Double_t *x, const Double_t *y) override
Paint filled area.
QPen GetLinePen()
Return QPen for lines drawing.
virtual void SetFillStyle(Style_t fstyle)
Set the fill area style.
Definition TAttFill.h:42
Marker Attributes class.
Definition TAttMarker.h:22
static Width_t GetMarkerLineWidth(Style_t style)
Internal helper function that returns the line width of the given marker style (0 = filled marker)
@ kShapeTriangles
Definition TAttMarker.h:48
@ kShapeFilledArea
Definition TAttMarker.h:48
@ kShapeFilledCircle
Definition TAttMarker.h:48
Text Attributes class.
Definition TAttText.h:21
virtual Color_t GetTextColor() const
Return the text color.
Definition TAttText.h:37
An abstract interface to image processing library.
Definition TImage.h:29
virtual UInt_t * GetArgbArray()
Definition TImage.h:238
virtual UInt_t GetWidth() const
Definition TImage.h:229
virtual UInt_t GetHeight() const
Definition TImage.h:230
Color_t GetMarkerColor() const override
const TAttText & GetAttText() const override
Get text attributes.
const TAttMarker & GetAttMarker() const override
Get marker attributes.
const TAttFill & GetAttFill() const override
Get fill attributes.
Width_t GetLineWidth() const override
TVirtualPad * fPad
TAttFill fAttFill
current fill attributes
const TAttLine & GetAttLine() const override
Get line attributes.
Style_t GetFillStyle() const override
Basic string class.
Definition TString.h:137
Ssiz_t Length() const
Definition TString.h:426
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2345
const char * GetLineStyleString(Int_t i=1) const
Return line style string (used by PostScript).
Definition TStyle.cxx:1167
Dynamic handle to work with freetype 2 library.
Definition TTFhandle.h:21
UInt_t GetNumGlyphs() const
return number of glyphs
Bool_t GetGlyphData(UInt_t n, Int_t &offx, Int_t &offy, UChar_t *&buffer, UInt_t &width, UInt_t &rows, UInt_t &pitch)
Returns data for glyph bitmap Instead direct access to FT_BitmapGlyph one can obtain all relevant fie...
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition TVirtualPad.h:53
virtual Int_t UtoAbsPixel(Double_t u) const =0
virtual Int_t VtoAbsPixel(Double_t v) const =0
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
Namespace for ROOT features in testing.
Definition TROOT.h:100
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:197
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122