From 9520c41d1f07c8df428ac07bfdc598e795c5582f Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 1 Sep 2026 15:06:55 +0200 Subject: [PATCH 1/8] [tpie] remove gVirtualX usage in non-opaque moving line drawing is used. Replace gVirtualX by pad painter --- graf2d/graf/src/TPie.cxx | 153 ++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 82 deletions(-) diff --git a/graf2d/graf/src/TPie.cxx b/graf2d/graf/src/TPie.cxx index 6af6cb767dd83..45566c2bce259 100644 --- a/graf2d/graf/src/TPie.cxx +++ b/graf2d/graf/src/TPie.cxx @@ -14,7 +14,8 @@ #include "TROOT.h" #include "TVirtualPad.h" -#include "TVirtualX.h" +#include "TVirtualPadPainter.h" +#include "TCanvasImp.h" #include "TArc.h" #include "TLegend.h" #include "TMath.h" @@ -356,11 +357,12 @@ void TPie::DrawGhost() { MakeSlices(); + auto &parent = *gPad; + auto pp = parent.GetPainter(); + pp->SetAttLine({ kBlack, 1 ,2 }); + // XY metric - Double_t radXY = 1.; - if (fIs3D) { - radXY = TMath::Sin(fAngle3D/180.*TMath::Pi()); - } + Double_t radXY = !fIs3D ? 1. : TMath::Sin(fAngle3D/180.*TMath::Pi()); for (Int_t i = 0; i < fNvals && fIs3D;++i) { Float_t minphi = (fSlices[i*2]+gAngularOffset+.5)*TMath::Pi()/180.; @@ -371,9 +373,7 @@ void TPie::DrawGhost() Double_t x0 = gX+radOffset*TMath::Cos(avgphi); Double_t y0 = gY+radOffset*TMath::Sin(avgphi)*radXY-fHeight; - gVirtualX->DrawLine( gPad->XtoAbsPixel(x0), gPad->YtoAbsPixel(y0), - gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(minphi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(minphi)*radXY) ); + pp->DrawLine(x0, y0, x0+gRadius*TMath::Cos(minphi), y0+gRadius*TMath::Sin(minphi)*radXY); Int_t ndiv = 10; Double_t dphi = (maxphi-minphi)/ndiv; @@ -384,28 +384,17 @@ void TPie::DrawGhost() // Loop to draw the arc for (Int_t j=0;jDrawLine( gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(phi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(phi)*radXY), - gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(phi+dphi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(phi+dphi)*radXY)); + pp->DrawLine(x0+gRadius*TMath::Cos(phi), y0+gRadius*TMath::Sin(phi)*radXY, + x0+gRadius*TMath::Cos(phi+dphi), y0+gRadius*TMath::Sin(phi+dphi)*radXY); } - gVirtualX->DrawLine( gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(maxphi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(maxphi)*radXY), - gPad->XtoAbsPixel(x0), gPad->YtoAbsPixel(y0) ); - - gVirtualX->DrawLine(gPad->XtoAbsPixel(x0), - gPad->YtoAbsPixel(y0), - gPad->XtoAbsPixel(x0), - gPad->YtoAbsPixel(y0+fHeight)); - gVirtualX->DrawLine(gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(minphi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(minphi)*radXY), - gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(minphi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(minphi)*radXY+fHeight)); - gVirtualX->DrawLine(gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(maxphi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(maxphi)*radXY), - gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(maxphi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(maxphi)*radXY+fHeight)); + pp->DrawLine(x0+gRadius*TMath::Cos(maxphi), y0+gRadius*TMath::Sin(maxphi)*radXY, x0, y0); + + pp->DrawLine(x0, y0, x0, y0+fHeight); + pp->DrawLine(x0+gRadius*TMath::Cos(minphi), y0+gRadius*TMath::Sin(minphi)*radXY, + x0+gRadius*TMath::Cos(minphi), y0+gRadius*TMath::Sin(minphi)*radXY+fHeight); + pp->DrawLine(x0+gRadius*TMath::Cos(maxphi), y0+gRadius*TMath::Sin(maxphi)*radXY, + x0+gRadius*TMath::Cos(maxphi), y0+gRadius*TMath::Sin(maxphi)*radXY+fHeight); } @@ -419,9 +408,7 @@ void TPie::DrawGhost() Double_t x0 = gX+radOffset*TMath::Cos(avgphi); Double_t y0 = gY+radOffset*TMath::Sin(avgphi)*radXY; - gVirtualX->DrawLine( gPad->XtoAbsPixel(x0), gPad->YtoAbsPixel(y0), - gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(minphi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(minphi)*radXY) ); + pp->DrawLine(x0, y0, x0+gRadius*TMath::Cos(minphi), y0+gRadius*TMath::Sin(minphi)*radXY); Int_t ndiv = 10; @@ -433,15 +420,11 @@ void TPie::DrawGhost() // Loop to draw the arc for (Int_t j=0;jDrawLine( gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(phi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(phi)*radXY), - gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(phi+dphi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(phi+dphi)*radXY)); + pp->DrawLine(x0+gRadius*TMath::Cos(phi), y0+gRadius*TMath::Sin(phi)*radXY, + x0+gRadius*TMath::Cos(phi+dphi), y0+gRadius*TMath::Sin(phi+dphi)*radXY); } - gVirtualX->DrawLine( gPad->XtoAbsPixel(x0+gRadius*TMath::Cos(maxphi)), - gPad->YtoAbsPixel(y0+gRadius*TMath::Sin(maxphi)*radXY), - gPad->XtoAbsPixel(x0), gPad->YtoAbsPixel(y0) ); + pp->DrawLine(x0+gRadius*TMath::Cos(maxphi), y0+gRadius*TMath::Sin(maxphi)*radXY, x0, y0); } } @@ -450,23 +433,26 @@ void TPie::DrawGhost() void TPie::ExecuteEvent(Int_t event, Int_t px, Int_t py) { - if (!gPad) return; - if (!gPad->IsEditable() && event != kMouseEnter) return; + if (!gPad || !gPad->IsEditable()) return; + + auto &parent = *gPad; + + Bool_t opaque = parent.OpaqueMoving(); if (gCurrent_slice<=-10) { - gPad->SetCursor(kCross); + parent.SetCursor(kCross); return; } MakeSlices(); - static bool isMovingPie(kFALSE); - static bool isMovingSlice(kFALSE); - static bool isResizing(kFALSE); - static bool isRotating(kFALSE); - static bool onBorder(kFALSE); - bool isRedrawing(kFALSE); - static Int_t prev_event(-1); + static bool isMovingPie = kFALSE; + static bool isMovingSlice = kFALSE; + static bool isResizing = kFALSE; + static bool isRotating = kFALSE; + static bool onBorder = kFALSE; + bool isRedrawing = kFALSE; + static Int_t prev_event = -1; static Int_t oldpx, oldpy; // Portion of pie considered as "border" @@ -495,10 +481,6 @@ void TPie::ExecuteEvent(Int_t event, Int_t px, Int_t py) switch(event) { case kArrowKeyPress: case kButton1Down: - // Change cursor to show pie's movement. - gVirtualX->SetLineColor(1); - gVirtualX->SetLineWidth(2); - // Current center and radius. gX = fX; gY = fY; @@ -513,35 +495,36 @@ void TPie::ExecuteEvent(Int_t event, Int_t px, Int_t py) if (gCurrent_rad>=fRadius-2.*dr && gCurrent_rad<=fRadius+dr && !isMovingPie && !isMovingSlice && !isResizing) { if (gCurrent_ang>=angstep8 || gCurrent_angSetCursor(kRightSide); + parent.SetCursor(kRightSide); else if (gCurrent_ang>=angstep1 && gCurrent_angSetCursor(kTopRight); + parent.SetCursor(kTopRight); else if (gCurrent_ang>=angstep2 && gCurrent_angSetCursor(kTopSide); + parent.SetCursor(kTopSide); else if (gCurrent_ang>=angstep3 && gCurrent_angSetCursor(kTopLeft); + parent.SetCursor(kTopLeft); else if (gCurrent_ang>=angstep4 && gCurrent_ang<=angstep5) - gPad->SetCursor(kLeftSide); + parent.SetCursor(kLeftSide); else if (gCurrent_ang>=angstep5 && gCurrent_angSetCursor(kBottomLeft); + parent.SetCursor(kBottomLeft); else if (gCurrent_ang>=angstep6 && gCurrent_angSetCursor(kBottomSide); + parent.SetCursor(kBottomSide); else if (gCurrent_ang>=angstep7 && gCurrent_angSetCursor(kBottomRight); + parent.SetCursor(kBottomRight); onBorder = kTRUE; } else { onBorder = kFALSE; if (gCurrent_rad>fRadius*.6) { - gPad->SetCursor(kPointer); + parent.SetCursor(kPointer); } else if (gCurrent_rad<=fRadius*.3) { - gPad->SetCursor(kHand); + parent.SetCursor(kHand); } else if (gCurrent_rad<=fRadius*.6 && gCurrent_rad>=fRadius*.3) { - gPad->SetCursor(kRotate); + parent.SetCursor(kRotate); } } oldpx = px; oldpy = py; - if (isMovingPie || isMovingSlice) gPad->SetCursor(kMove); + if (isMovingPie || isMovingSlice) + parent.SetCursor(kMove); break; case kArrowKeyRelease: @@ -567,27 +550,32 @@ void TPie::ExecuteEvent(Int_t event, Int_t px, Int_t py) mdy = gPad->PixeltoY(dy); if (isMovingPie || isMovingSlice) { - gPad->SetCursor(kMove); + parent.SetCursor(kMove); if (isMovingSlice) { Float_t avgphi = fSlices[gCurrent_slice*2+1]*TMath::Pi()/180.; - if (!gPad->OpaqueMoving()) DrawGhost(); + if (!opaque) + DrawGhost(); gRadiusOffset += TMath::Cos(avgphi)*mdx +TMath::Sin(avgphi)*mdy/radXY; if (gRadiusOffset<0) gRadiusOffset = .0; gIsUptSlice = kTRUE; - if (!gPad->OpaqueMoving()) DrawGhost(); + if (!opaque) + DrawGhost(); } else { - if (!gPad->OpaqueMoving()) DrawGhost(); + if (!opaque) + DrawGhost(); gX += mdx; gY += mdy; - if (!gPad->OpaqueMoving()) DrawGhost(); + if (!opaque) + DrawGhost(); } } else if (isResizing) { - if (!gPad->OpaqueResizing()) DrawGhost(); + if (!opaque) + DrawGhost(); Float_t dr1 = mdx*TMath::Cos(gCurrent_ang)+mdy*TMath::Sin(gCurrent_ang)/radXY; if (gRadius+dr1>=minRad) { @@ -596,9 +584,11 @@ void TPie::ExecuteEvent(Int_t event, Int_t px, Int_t py) gRadius = minRad; } - if (!gPad->OpaqueResizing()) DrawGhost(); + if (!opaque) + DrawGhost(); } else if (isRotating) { - if (!gPad->OpaqueMoving()) DrawGhost(); + if (!opaque) + DrawGhost(); Double_t xx = gPad->AbsPixeltoX(px); Double_t yy = gPad->AbsPixeltoY(py); @@ -607,17 +597,19 @@ void TPie::ExecuteEvent(Int_t event, Int_t px, Int_t py) Double_t dy1 = yy-gY; Double_t ang = TMath::ATan2(dy1,dx1); - if (ang<0) ang += TMath::TwoPi(); + if (ang < 0) + ang += TMath::TwoPi(); gAngularOffset = (ang-gCurrent_ang)*180/TMath::Pi(); - if (!gPad->OpaqueMoving()) DrawGhost(); + if (!opaque) + DrawGhost(); } oldpx = px; oldpy = py; - if ( ((isMovingPie || isMovingSlice || isRotating) && gPad->OpaqueMoving()) || + if ( ((isMovingPie || isMovingSlice || isRotating) && opaque) || (isResizing && gPad->OpaqueResizing()) ) { isRedrawing = kTRUE; // event = kButton1Up; @@ -643,7 +635,8 @@ void TPie::ExecuteEvent(Int_t event, Int_t px, Int_t py) fPieSlices[gCurrent_slice]->SetRadiusOffset(gRadiusOffset); SetAngularOffset(fAngularOffset+gAngularOffset); - if (isRedrawing && (isMovingPie || isMovingSlice)) gPad->SetCursor(kMove); + if (isRedrawing && (isMovingPie || isMovingSlice)) + parent.SetCursor(kMove); if (isMovingPie) isMovingPie = kFALSE; if (isMovingSlice) isMovingSlice = kFALSE; @@ -654,14 +647,10 @@ void TPie::ExecuteEvent(Int_t event, Int_t px, Int_t py) gCurrent_ang += gAngularOffset/180.*TMath::Pi(); } - gPad->Modified(kTRUE); - + parent.Modified(kTRUE); gIsUptSlice = kFALSE; - gVirtualX->SetLineColor(-1); - gVirtualX->SetLineWidth(-1); - break; case kButton1Locate: @@ -669,7 +658,7 @@ void TPie::ExecuteEvent(Int_t event, Int_t px, Int_t py) while (true) { px = py = 0; - event = gVirtualX->RequestLocator(1, 1, px, py); + event = parent.GetCanvasImp()->RequestLocator(px, py); ExecuteEvent(kButton1Motion, px, py); From 547446c74cbd7ab4d347a8cda66b2d3f918b7f12 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 1 Sep 2026 16:28:03 +0200 Subject: [PATCH 2/8] [tpie] optimize DrawGhost As first step, combine 3d and normal loops over slices to draw contour lines. Take into account coordinate transformation --- graf2d/graf/src/TPie.cxx | 80 +++++++++++++++------------------------- 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/graf2d/graf/src/TPie.cxx b/graf2d/graf/src/TPie.cxx index 45566c2bce259..273a0e1c3fd69 100644 --- a/graf2d/graf/src/TPie.cxx +++ b/graf2d/graf/src/TPie.cxx @@ -359,72 +359,52 @@ void TPie::DrawGhost() auto &parent = *gPad; auto pp = parent.GetPainter(); - pp->SetAttLine({ kBlack, 1 ,2 }); + pp->SetAttLine({ kBlack, 1, 2 }); // XY metric - Double_t radXY = !fIs3D ? 1. : TMath::Sin(fAngle3D/180.*TMath::Pi()); + Double_t radXY = !fIs3D ? 1. : TMath::Sin(fAngle3D/180.*TMath::Pi()), x0 = 0, y0 = 0; - for (Int_t i = 0; i < fNvals && fIs3D;++i) { - Float_t minphi = (fSlices[i*2]+gAngularOffset+.5)*TMath::Pi()/180.; - Float_t avgphi = (fSlices[i*2+1]+gAngularOffset)*TMath::Pi()/180.; - Float_t maxphi = (fSlices[i*2+2]+gAngularOffset-.5)*TMath::Pi()/180.; - - Double_t radOffset = (i == gCurrent_slice ? gRadiusOffset : fPieSlices[i]->GetRadiusOffset()); - Double_t x0 = gX+radOffset*TMath::Cos(avgphi); - Double_t y0 = gY+radOffset*TMath::Sin(avgphi)*radXY-fHeight; - - pp->DrawLine(x0, y0, x0+gRadius*TMath::Cos(minphi), y0+gRadius*TMath::Sin(minphi)*radXY); - - Int_t ndiv = 10; - Double_t dphi = (maxphi-minphi)/ndiv; - - if (dphi>.15) ndiv = (Int_t) ((maxphi-minphi)/.15); - dphi = (maxphi-minphi)/ndiv; - - // Loop to draw the arc - for (Int_t j=0;jDrawLine(x0+gRadius*TMath::Cos(phi), y0+gRadius*TMath::Sin(phi)*radXY, - x0+gRadius*TMath::Cos(phi+dphi), y0+gRadius*TMath::Sin(phi+dphi)*radXY); - } - - pp->DrawLine(x0+gRadius*TMath::Cos(maxphi), y0+gRadius*TMath::Sin(maxphi)*radXY, x0, y0); + auto drawLine = [pp, &parent, &x0, &y0](double x1, double y1, double x2, double y2) { + x1 = parent.XtoPad(x0 + x1); + x2 = parent.XtoPad(x0 + x2); + y1 = parent.YtoPad(y0 + y1); + y2 = parent.YtoPad(y0 + y2); + pp->DrawLine(x1, y1, x2, y2); - pp->DrawLine(x0, y0, x0, y0+fHeight); - pp->DrawLine(x0+gRadius*TMath::Cos(minphi), y0+gRadius*TMath::Sin(minphi)*radXY, - x0+gRadius*TMath::Cos(minphi), y0+gRadius*TMath::Sin(minphi)*radXY+fHeight); - pp->DrawLine(x0+gRadius*TMath::Cos(maxphi), y0+gRadius*TMath::Sin(maxphi)*radXY, - x0+gRadius*TMath::Cos(maxphi), y0+gRadius*TMath::Sin(maxphi)*radXY+fHeight); - } + }; - - // Loop over slices - for (Int_t i=0;i= 0; loop3d--) + for (Int_t i = 0; i < fNvals; ++i) { Float_t minphi = (fSlices[i*2]+gAngularOffset+.5)*TMath::Pi()/180.; Float_t avgphi = (fSlices[i*2+1]+gAngularOffset)*TMath::Pi()/180.; Float_t maxphi = (fSlices[i*2+2]+gAngularOffset-.5)*TMath::Pi()/180.; Double_t radOffset = (i == gCurrent_slice ? gRadiusOffset : fPieSlices[i]->GetRadiusOffset()); - Double_t x0 = gX+radOffset*TMath::Cos(avgphi); - Double_t y0 = gY+radOffset*TMath::Sin(avgphi)*radXY; - - pp->DrawLine(x0, y0, x0+gRadius*TMath::Cos(minphi), y0+gRadius*TMath::Sin(minphi)*radXY); - + x0 = gX + radOffset*TMath::Cos(avgphi); + y0 = gY + radOffset*TMath::Sin(avgphi)*radXY - loop3d * fHeight; // draw layer beyond - Int_t ndiv = 10; - Double_t dphi = (maxphi-minphi)/ndiv; + drawLine(0, 0, gRadius*TMath::Cos(minphi), gRadius*TMath::Sin(minphi)*radXY); - if (dphi>.15) ndiv = (Int_t) ((maxphi-minphi)/.15); - dphi = (maxphi-minphi)/ndiv; + Double_t dphi = (maxphi - minphi); + Int_t ndiv = dphi > 1.5 ? (Int_t) (dphi/.15) : 10; + dphi = dphi /ndiv; // Loop to draw the arc - for (Int_t j=0;jDrawLine(x0+gRadius*TMath::Cos(phi), y0+gRadius*TMath::Sin(phi)*radXY, - x0+gRadius*TMath::Cos(phi+dphi), y0+gRadius*TMath::Sin(phi+dphi)*radXY); + for (Int_t j = 0; j < ndiv; ++j) { + Double_t phi = minphi + dphi * j; + drawLine(gRadius*TMath::Cos(phi), gRadius*TMath::Sin(phi)*radXY, + gRadius*TMath::Cos(phi+dphi), gRadius*TMath::Sin(phi+dphi)*radXY); } - pp->DrawLine(x0+gRadius*TMath::Cos(maxphi), y0+gRadius*TMath::Sin(maxphi)*radXY, x0, y0); + drawLine(gRadius*TMath::Cos(maxphi), gRadius*TMath::Sin(maxphi)*radXY, 0, 0); + + if (loop3d) { + drawLine(0, 0, 0, fHeight); + drawLine(gRadius*TMath::Cos(minphi), gRadius*TMath::Sin(minphi)*radXY, + gRadius*TMath::Cos(minphi), gRadius*TMath::Sin(minphi)*radXY+fHeight); + drawLine(gRadius*TMath::Cos(maxphi), gRadius*TMath::Sin(maxphi)*radXY, + gRadius*TMath::Cos(maxphi), gRadius*TMath::Sin(maxphi)*radXY+fHeight); + } } } From 47ab6fbeb88196276d5021ec9305fb0f03c187c5 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 1 Sep 2026 18:05:33 +0200 Subject: [PATCH 3/8] [diamond] remove gVirtualX usage Make ExecuteEvent very simiar ro TBox --- graf2d/graf/src/TDiamond.cxx | 357 ++++++++++++++--------------------- 1 file changed, 146 insertions(+), 211 deletions(-) diff --git a/graf2d/graf/src/TDiamond.cxx b/graf2d/graf/src/TDiamond.cxx index c4d9e68145401..361e8e3cc6d7d 100644 --- a/graf2d/graf/src/TDiamond.cxx +++ b/graf2d/graf/src/TDiamond.cxx @@ -16,7 +16,8 @@ #include "TROOT.h" #include "TDiamond.h" #include "TVirtualPad.h" -#include "TVirtualX.h" +#include "TVirtualPadPainter.h" +#include "TCanvasImp.h" #include "TMath.h" @@ -107,261 +108,195 @@ void TDiamond::Draw(Option_t *option) void TDiamond::ExecuteEvent(Int_t event, Int_t px, Int_t py) { - if (!gPad) return; + if (!gPad || !gPad->IsEditable()) return; + + auto &parent = *gPad; const Int_t kMaxDiff = 5; const Int_t kMinSize = 20; - static Int_t px1, px2, py1, py2, pxl, pyl, pxt, pyt, pxold, pyold; - static Int_t px1p, px2p, py1p, py2p; - static Int_t pTx,pTy,pLx,pLy,pRx,pRy,pBx,pBy; - static Double_t x1c,x2c,x3c,x4c; - static Bool_t pTop, pL, pR, pBot, pINSIDE; - static Int_t i,x[5], y[5]; - Int_t wx, wy; - TVirtualPad *parent; - Bool_t opaque = gPad->OpaqueMoving(); - Bool_t ropaque = gPad->OpaqueResizing(); - - if (!gPad->IsEditable()) return; - - parent = gPad; + static Int_t px1, px2, py1, py2, dpx1, dpy2, px1p, px2p, py1p, py2p; + static enum { pNone, pTop, pL, pR, pBot, pINSIDE } mode = pNone; + static Double_t oldX1, oldY1, oldX2, oldY2; + static Bool_t hasOld = kFALSE; + Bool_t opaque = parent.OpaqueMoving(); + Bool_t ropaque = parent.OpaqueResizing(); + + auto paint_or_set = [&parent,this](Bool_t paint) + { + auto x1 = parent.AbsPixeltoX(px1); + auto y1 = parent.AbsPixeltoY(py1); + auto x2 = parent.AbsPixeltoX(px2); + auto y2 = parent.AbsPixeltoY(py2); + if (!paint) { + SetX1(parent.PadtoX(x1)); + SetY1(parent.PadtoY(y1)); + SetX2(parent.PadtoX(x2)); + SetY2(parent.PadtoY(y2)); + } else { + auto pp = parent.GetPainter(); + Double_t arrx[5] = { x1, (x1+x2) / 2, x2, (x1+x2) / 2, x1 }; + Double_t arry[5] = { (y1+y2)/2, y2, (y1+y2)/2, y1, (y1+y2)/2 }; + pp->SetAttLine({GetFillColor() > 0 ? GetFillColor() : (Color_t) kBlack, 1, 2}); + pp->DrawPolyLine(5, arrx, arry); + } + }; switch (event) { case kArrowKeyPress: case kButton1Down: - gVirtualX->SetLineColor(-1); - TAttLine::Modify(); //Change line attributes only if necessary - if (GetFillColor()) - gVirtualX->SetLineColor(GetFillColor()); - else - gVirtualX->SetLineColor(1); - gVirtualX->SetLineWidth(2); + oldX1 = GetX1(); + oldY1 = GetY1(); + oldX2 = GetX2(); + oldY2 = GetY2(); + hasOld = kTRUE; // No break !!! case kMouseMotion: - px1 = gPad->XtoAbsPixel(GetX1()); - py1 = gPad->YtoAbsPixel(GetY1()); - px2 = gPad->XtoAbsPixel(GetX2()); - py2 = gPad->YtoAbsPixel(GetY2()); - - if (px1 < px2) { - pxl = px1; - pxt = px2; - } else { - pxl = px2; - pxt = px1; - } - if (py1 < py2) { - pyl = py1; - pyt = py2; + px1 = parent.XtoAbsPixel(parent.XtoPad(GetX1())); + py1 = parent.YtoAbsPixel(parent.YtoPad(GetY1())); + px2 = parent.XtoAbsPixel(parent.XtoPad(GetX2())); + py2 = parent.YtoAbsPixel(parent.YtoPad(GetY2())); + if (px1 > px2) + std::swap(px1, px2); + if (py1 < py2) + std::swap(py1, py2); + + px1p = parent.XtoAbsPixel(parent.GetX1()) + parent.GetBorderSize(); + py1p = parent.YtoAbsPixel(parent.GetY1()) - parent.GetBorderSize(); + px2p = parent.XtoAbsPixel(parent.GetX2()) - parent.GetBorderSize(); + py2p = parent.YtoAbsPixel(parent.GetY2()) + parent.GetBorderSize(); + if (px1p > px2p) + std::swap(px1p, px2p); + if (py1p < py2p) + std::swap(py1p, py2p); + + if ((TMath::Abs(px-(px1+px2)/2) < kMaxDiff) && (TMath::Abs(py - py2) < kMaxDiff)) { // top edge + mode = pTop; + parent.SetCursor(kTopSide); + } else if ((TMath::Abs(px-(px1+px2)/2) < kMaxDiff) && (TMath::Abs(py - py1) < kMaxDiff)) { // bottom edge + mode = pBot; + parent.SetCursor(kBottomSide); + } else if ((TMath::Abs(py-(py1+py2)/2) < kMaxDiff) && (TMath::Abs(px - px1) < kMaxDiff)) { // left edge + mode = pL; + parent.SetCursor(kLeftSide); + } else if ((TMath::Abs(py-(py1+py2)/2) < kMaxDiff) && (TMath::Abs(px - px2) < kMaxDiff)) { // right edge + mode = pR; + parent.SetCursor(kRightSide); + } else if (IsInside(parent.PadtoX(parent.AbsPixeltoX(px)), parent.PadtoY(parent.AbsPixeltoY(py)))) { + mode = pINSIDE; + dpx1 = px - px1; // cursor position relative to top-left corner + dpy2 = py - py2; + parent.SetCursor(event == kButton1Down ? kMove : kCross); } else { - pyl = py2; - pyt = py1; + mode = pNone; + parent.SetCursor(kCross); } - px1p = parent->XtoAbsPixel(parent->GetX1()) + parent->GetBorderSize(); - py1p = parent->YtoAbsPixel(parent->GetY1()) - parent->GetBorderSize(); - px2p = parent->XtoAbsPixel(parent->GetX2()) - parent->GetBorderSize(); - py2p = parent->YtoAbsPixel(parent->GetY2()) + parent->GetBorderSize(); + fResizing = mode == pTop || mode == pL || mode == pR || mode == pBot; - pTx = pBx = (pxl+pxt)/2; - pLy = pRy = (pyl+pyt)/2; - pTy = pyl; - pBy = pyt; - pLx = pxl; - pRx = pxt; - - pTop = pL = pR = pBot = pINSIDE = kFALSE; - - if ((TMath::Abs(px-(pxl+pxt)/2) < kMaxDiff) && - (TMath::Abs(py - pyl) < kMaxDiff)) { // top edge - pxold = pxl; pyold = pyl; pTop = kTRUE; - gPad->SetCursor(kTopSide); - } - - if ((TMath::Abs(px-(pxl+pxt)/2) < kMaxDiff) && - (TMath::Abs(py - pyt) < kMaxDiff)) { // bottom edge - pxold = pxt; pyold = pyt; pBot = kTRUE; - gPad->SetCursor(kBottomSide); - } - - if ((TMath::Abs(py-(pyl+pyt)/2) < kMaxDiff) && - (TMath::Abs(px - pxl) < kMaxDiff)) { // left edge - pxold = pxl; pyold = pyl; pL = kTRUE; - gPad->SetCursor(kLeftSide); - } - - if ((TMath::Abs(py-(pyl+pyt)/2) < kMaxDiff) && - (TMath::Abs(px - pxt) < kMaxDiff)) { // right edge - pxold = pxt; pyold = pyt; pR = kTRUE; - gPad->SetCursor(kRightSide); - } - - x1c = (py-pTy)*(pTx-pLx)/(pTy-pLy)+pTx; - x2c = (py-pTy)*(pRx-pTx)/(pRy-pTy)+pTx; - x3c = (py-pRy)*(pRx-pBx)/(pRy-pBy)+pRx; - x4c = (py-pBy)*(pBx-pLx)/(pBy-pLy)+pBx; - - if (px > x1c+kMaxDiff && px < x2c-kMaxDiff && - px > x4c+kMaxDiff && px < x3c-kMaxDiff) { // inside box - pxold = px; pyold = py; pINSIDE = kTRUE; - if (event == kButton1Down) - gPad->SetCursor(kMove); - else - gPad->SetCursor(kCross); - } - - fResizing = kFALSE; - if (pTop || pL || pR || pBot) - fResizing = kTRUE; - - if (!pTop && !pL && !pR && !pBot && !pINSIDE) - gPad->SetCursor(kCross); + if ((!opaque && mode == pINSIDE) || (!ropaque && fResizing)) + paint_or_set(true); break; case kArrowKeyRelease: case kButton1Motion: - - wx = wy = 0; - x[0] = x[2] = x[4] = (px1+px2)/2; - x[1] = px2; - x[3] = px1; - y[0] = y[4] = py1; - y[2] = py2; - y[1] = y[3] = (py1+py2)/2; - if (pTop) { - for (i=0;i<4;i++) gVirtualX->DrawLine(x[i], y[i], x[i+1], y[i+1]); - py2 += py - pyold; - if (py2 > py1-kMinSize) { py2 = py1-kMinSize; wy = py2; } - if (py2 < py2p) { py2 = py2p; wy = py2; } - y[2] = py2; - y[1] = y[3] = (py1+py2)/2; - for (i=0;i<4;i++) gVirtualX->DrawLine(x[i], y[i], x[i+1], y[i+1]); - } - if (pBot) { - for (i=0;i<4;i++) gVirtualX->DrawLine(x[i], y[i], x[i+1], y[i+1]); - py1 += py - pyold; - if (py1 < py2+kMinSize) { py1 = py2+kMinSize; wy = py1; } - if (py1 > py1p) { py1 = py1p; wy = py1; } - y[0] = y[4] = py1; - y[1] = y[3] = (py1+py2)/2; - for (i=0;i<4;i++) gVirtualX->DrawLine(x[i], y[i], x[i+1], y[i+1]); - } - if (pL) { - for (i=0;i<4;i++) gVirtualX->DrawLine(x[i], y[i], x[i+1], y[i+1]); - px1 += px - pxold; - if (px1 > px2-kMinSize) { px1 = px2-kMinSize; wx = px1; } - if (px1 < px1p) { px1 = px1p; wx = px1; } - x[3] = px1; - x[0] = x[2] = x[4] = (px1+px2)/2; - for (i=0;i<4;i++) gVirtualX->DrawLine(x[i], y[i], x[i+1], y[i+1]); + switch (mode) { + case pNone: return; + case pTop: + if (!ropaque) paint_or_set(kTRUE); + py2 = TMath::Max(py2p, TMath::Min(py, py1 - kMinSize)); + paint_or_set(!ropaque); + break; + case pBot: + if (!ropaque) paint_or_set(kTRUE); + py1 = TMath::Min(py1p, TMath::Max(py, py2 + kMinSize)); + paint_or_set(!ropaque); + break; + case pL: + if (!ropaque) paint_or_set(kTRUE); + px1 = TMath::Max(px1p, TMath::Min(px, px2 - kMinSize)); + paint_or_set(!ropaque); + break; + case pR: + if (!ropaque) paint_or_set(kTRUE); + px2 = TMath::Min(px2p, TMath::Max(px, px1 + kMinSize)); + paint_or_set(!ropaque); + break; + case pINSIDE: + if (!opaque) paint_or_set(kTRUE); + px2 += px - dpx1 - px1; + px1 = px - dpx1; + py1 += py - dpy2 - py2; + py2 = py - dpy2; + if (px1 < px1p) { px2 += px1p - px1; px1 = px1p; } + if (px2 > px2p) { px1 -= px2 - px2p; px2 = px2p; } + if (py1 > py1p) { py2 -= py1 - py1p; py1 = py1p; } + if (py2 < py2p) { py1 += py2p - py2; py2 = py2p; } + paint_or_set(!opaque); + break; } - if (pR) { - for (i=0;i<4;i++) gVirtualX->DrawLine(x[i], y[i], x[i+1], y[i+1]); - px2 += px - pxold; - if (px2 < px1+kMinSize) { px2 = px1+kMinSize; wx = px2; } - if (px2 > px2p) { px2 = px2p; wx = px2; } - x[1] = px2; - x[0] = x[2] = x[4] = (px1+px2)/2; - for (i=0;i<4;i++) gVirtualX->DrawLine(x[i], y[i], x[i+1], y[i+1]); - } - if (pINSIDE) { - for (i=0;i<4;i++) gVirtualX->DrawLine(x[i], y[i], x[i+1], y[i+1]); - Int_t dx = px - pxold; - Int_t dy = py - pyold; - px1 += dx; py1 += dy; px2 += dx; py2 += dy; - if (px1 < px1p) { dx = px1p - px1; px1 += dx; px2 += dx; wx = px+dx; } - if (px2 > px2p) { dx = px2 - px2p; px1 -= dx; px2 -= dx; wx = px-dx; } - if (py1 > py1p) { dy = py1 - py1p; py1 -= dy; py2 -= dy; wy = py-dy; } - if (py2 < py2p) { dy = py2p - py2; py1 += dy; py2 += dy; wy = py+dy; } - x[0] = x[2] = x[4] = (px1+px2)/2; - x[1] = px2; - x[3] = px1; - y[0] = y[4] = py1; - y[2] = py2; - y[1] = y[3] = (py1+py2)/2; - for (i=0;i<4;i++) gVirtualX->DrawLine(x[i], y[i], x[i+1], y[i+1]); - } - - if (wx || wy) { - if (wx) px = wx; - if (wy) py = wy; - gVirtualX->Warp(px, py); - } - - pxold = px; - pyold = py; - if ((pINSIDE && opaque) || (fResizing && ropaque)) { - if (pTop || pBot || pL || pR) { - fX1 = gPad->AbsPixeltoX(px1); - fY1 = gPad->AbsPixeltoY(py1); - fX2 = gPad->AbsPixeltoX(px2); - fY2 = gPad->AbsPixeltoY(py2); + if ((mode == pINSIDE && opaque) || (fResizing && ropaque)) { + switch(mode) { + case pINSIDE: parent.ShowGuidelines(this, event, 'i', true); break; + case pL: parent.ShowGuidelines(this, event, 'l', true); break; + case pR: parent.ShowGuidelines(this, event, 'r', true); break; + case pTop: parent.ShowGuidelines(this, event, 't', true); break; + case pBot: parent.ShowGuidelines(this, event, 'b', true); break; + default: break; // not involved } - if (pINSIDE) { - fX1 = gPad->AbsPixeltoX(px1); - fY1 = gPad->AbsPixeltoY(py1); - fX2 = gPad->AbsPixeltoX(px2); - fY2 = gPad->AbsPixeltoY(py2); - // if it was not a pad that was moved then it must have been - // a box or something like that so we have to redraw the pad - if (parent == gPad) gPad->Modified(kTRUE); - } - - if (pINSIDE) gPad->ShowGuidelines(this, event, 'i', true); - if (pTop) gPad->ShowGuidelines(this, event, 't', true); - if (pBot) gPad->ShowGuidelines(this, event, 'b', true); - if (pL) gPad->ShowGuidelines(this, event, 'l', true); - if (pR) gPad->ShowGuidelines(this, event, 'r', true); - - if (pTop || pL || pR || pBot) - gPad->Modified(kTRUE); + parent.Modified(kTRUE); } break; case kButton1Up: - if (opaque) { - gPad->ShowGuidelines(this, event); - } else { - if (pTop || pBot || pL || pR || pINSIDE) { - fX1 = gPad->AbsPixeltoX(px1); - fY1 = gPad->AbsPixeltoY(py1); - fX2 = gPad->AbsPixeltoX(px2); - fY2 = gPad->AbsPixeltoY(py2); - } - - if (pINSIDE) { - // if it was not a pad that was moved then it must have been - // a box or something like that so we have to redraw the pad - if (parent == gPad) gPad->Modified(kTRUE); + if (opaque || ropaque) + parent.ShowGuidelines(this, event); + + if (gROOT->IsEscaped()) { + gROOT->SetEscape(kFALSE); + if (opaque && (mode != pNone)) { + if (hasOld) { + SetX1(oldX1); + SetY1(oldY1); + SetX2(oldX2); + SetY2(oldY2); + } + hasOld = kFALSE; + mode = pNone; + fResizing = kFALSE; + parent.ModifiedUpdate(); } + break; } - if (pTop || pL || pR || pBot) gPad->Modified(kTRUE); + if ((!opaque && mode == pINSIDE) || (!ropaque && fResizing)) + paint_or_set(kFALSE); - if (!opaque) { - gVirtualX->SetLineColor(-1); - gVirtualX->SetLineWidth(-1); - } + if (mode != pNone) + parent.Modified(kTRUE); + + mode = pNone; + fResizing = kFALSE; + hasOld = kFALSE; break; case kButton1Locate: - + // Sergey: code is never used, has to be removed in ROOT7 ExecuteEvent(kButton1Down, px, py); while (true) { px = py = 0; - event = gVirtualX->RequestLocator(1, 1, px, py); + event = parent.GetCanvasImp()->RequestLocator(px, py); ExecuteEvent(kButton1Motion, px, py); From 708b481d0388855a1d779ce3dd7f70abb14144f3 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 1 Sep 2026 18:11:55 +0200 Subject: [PATCH 4/8] Sync TBox and TDiamond execute events Both are very similar, therefore make similar changes. Do not store pad coordinates in the static variables, use in both firstPaint flaf --- graf2d/graf/src/TBox.cxx | 33 ++++++++++++++------------------- graf2d/graf/src/TDiamond.cxx | 33 ++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/graf2d/graf/src/TBox.cxx b/graf2d/graf/src/TBox.cxx index 394fa18a47bf7..2615567298021 100644 --- a/graf2d/graf/src/TBox.cxx +++ b/graf2d/graf/src/TBox.cxx @@ -245,7 +245,6 @@ void TBox::ExecuteEvent(Int_t event, Int_t px, Int_t py) constexpr Int_t kMinSize = 20; static Int_t px1, px2, py1, py2, dpx1, dpy2; - static Int_t px1p, px2p, py1p, py2p; static Double_t oldX1, oldY1, oldX2, oldY2; static Bool_t hasOld = kFALSE; static enum { pNone, pA, pB, pC, pD, pTop, pL, pR, pBot, pINSIDE } mode = pNone; @@ -310,17 +309,6 @@ void TBox::ExecuteEvent(Int_t event, Int_t px, Int_t py) if (py1 < py2) std::swap(py1, py2); - px1p = parent.XtoAbsPixel(parent.GetX1()) + parent.GetBorderSize(); - py1p = parent.YtoAbsPixel(parent.GetY1()) - parent.GetBorderSize(); - px2p = parent.XtoAbsPixel(parent.GetX2()) - parent.GetBorderSize(); - py2p = parent.YtoAbsPixel(parent.GetY2()) + parent.GetBorderSize(); - if (px1p > px2p) - std::swap(px1p, px2p); - if (py1p < py2p) - std::swap(py1p, py2p); - - mode = pNone; - if (TMath::Abs(px - px1) <= kMaxDiff && TMath::Abs(py - py2) <= kMaxDiff) { mode = pA; parent.SetCursor(kTopLeft); @@ -349,21 +337,27 @@ void TBox::ExecuteEvent(Int_t event, Int_t px, Int_t py) dpx1 = px - px1; // cursor position relative to top-left corner dpy2 = py - py2; mode = pINSIDE; - if (event == kButton1Down) - parent.SetCursor(kMove); - else - parent.SetCursor(kCross); + parent.SetCursor(event == kButton1Down ? kMove : kCross); + } else { + mode = pNone; + parent.SetCursor(kCross); } fResizing = (mode != pNone) && (mode != pINSIDE); firstPaint = kTRUE; - if (mode == pNone) - parent.SetCursor(kCross); break; case kArrowKeyRelease: - case kButton1Motion: + case kButton1Motion: { + Int_t px1p = parent.XtoAbsPixel(parent.GetX1()) + parent.GetBorderSize(); + Int_t py1p = parent.YtoAbsPixel(parent.GetY1()) - parent.GetBorderSize(); + Int_t px2p = parent.XtoAbsPixel(parent.GetX2()) - parent.GetBorderSize(); + Int_t py2p = parent.YtoAbsPixel(parent.GetY2()) + parent.GetBorderSize(); + if (px1p > px2p) + std::swap(px1p, px2p); + if (py1p < py2p) + std::swap(py1p, py2p); switch (mode) { case pNone: @@ -443,6 +437,7 @@ void TBox::ExecuteEvent(Int_t event, Int_t px, Int_t py) } break; + } case kButton1Up: if (opaque || ropaque) diff --git a/graf2d/graf/src/TDiamond.cxx b/graf2d/graf/src/TDiamond.cxx index 361e8e3cc6d7d..15b0551c55d6c 100644 --- a/graf2d/graf/src/TDiamond.cxx +++ b/graf2d/graf/src/TDiamond.cxx @@ -115,8 +115,9 @@ void TDiamond::ExecuteEvent(Int_t event, Int_t px, Int_t py) const Int_t kMaxDiff = 5; const Int_t kMinSize = 20; - static Int_t px1, px2, py1, py2, dpx1, dpy2, px1p, px2p, py1p, py2p; + static Int_t px1, px2, py1, py2, dpx1, dpy2; static enum { pNone, pTop, pL, pR, pBot, pINSIDE } mode = pNone; + static bool firstPaint = kFALSE; static Double_t oldX1, oldY1, oldX2, oldY2; static Bool_t hasOld = kFALSE; Bool_t opaque = parent.OpaqueMoving(); @@ -133,6 +134,8 @@ void TDiamond::ExecuteEvent(Int_t event, Int_t px, Int_t py) SetY1(parent.PadtoY(y1)); SetX2(parent.PadtoX(x2)); SetY2(parent.PadtoY(y2)); + } else if (firstPaint) { + firstPaint = kFALSE; } else { auto pp = parent.GetPainter(); Double_t arrx[5] = { x1, (x1+x2) / 2, x2, (x1+x2) / 2, x1 }; @@ -166,15 +169,6 @@ void TDiamond::ExecuteEvent(Int_t event, Int_t px, Int_t py) if (py1 < py2) std::swap(py1, py2); - px1p = parent.XtoAbsPixel(parent.GetX1()) + parent.GetBorderSize(); - py1p = parent.YtoAbsPixel(parent.GetY1()) - parent.GetBorderSize(); - px2p = parent.XtoAbsPixel(parent.GetX2()) - parent.GetBorderSize(); - py2p = parent.YtoAbsPixel(parent.GetY2()) + parent.GetBorderSize(); - if (px1p > px2p) - std::swap(px1p, px2p); - if (py1p < py2p) - std::swap(py1p, py2p); - if ((TMath::Abs(px-(px1+px2)/2) < kMaxDiff) && (TMath::Abs(py - py2) < kMaxDiff)) { // top edge mode = pTop; parent.SetCursor(kTopSide); @@ -198,16 +192,24 @@ void TDiamond::ExecuteEvent(Int_t event, Int_t px, Int_t py) } fResizing = mode == pTop || mode == pL || mode == pR || mode == pBot; - - if ((!opaque && mode == pINSIDE) || (!ropaque && fResizing)) - paint_or_set(true); + firstPaint = kTRUE; break; case kArrowKeyRelease: - case kButton1Motion: + case kButton1Motion: { + Int_t px1p = parent.XtoAbsPixel(parent.GetX1()) + parent.GetBorderSize(); + Int_t py1p = parent.YtoAbsPixel(parent.GetY1()) - parent.GetBorderSize(); + Int_t px2p = parent.XtoAbsPixel(parent.GetX2()) - parent.GetBorderSize(); + Int_t py2p = parent.YtoAbsPixel(parent.GetY2()) + parent.GetBorderSize(); + if (px1p > px2p) + std::swap(px1p, px2p); + if (py1p < py2p) + std::swap(py1p, py2p); + switch (mode) { - case pNone: return; + case pNone: + return; case pTop: if (!ropaque) paint_or_set(kTRUE); py2 = TMath::Max(py2p, TMath::Min(py, py1 - kMinSize)); @@ -255,6 +257,7 @@ void TDiamond::ExecuteEvent(Int_t event, Int_t px, Int_t py) } break; + } case kButton1Up: From 14286008ec88fb135a39667ffc6c0b6764fcc9f5 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Sep 2026 10:35:32 +0200 Subject: [PATCH 5/8] [box] extend TBox::ExecuteEvent Via event argument provide flag when onlyX or onlyY can be changed. It can be used then in derived classes like TSliderBox --- graf2d/graf/src/TBox.cxx | 100 ++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/graf2d/graf/src/TBox.cxx b/graf2d/graf/src/TBox.cxx index 2615567298021..260bdd353136d 100644 --- a/graf2d/graf/src/TBox.cxx +++ b/graf2d/graf/src/TBox.cxx @@ -240,6 +240,16 @@ void TBox::ExecuteEvent(Int_t event, Int_t px, Int_t py) if (!parent.IsEditable() && event != kMouseEnter) return; Bool_t isBox = !(InheritsFrom("TPave") || InheritsFrom("TWbox")); + Bool_t canX = kTRUE, canY = kTRUE, liveUpdate = kFALSE; + + if (event >= 10000) { + // special config from TSliderBox, where only single dimension can be changed + Int_t mask = event / 10000; + liveUpdate = kTRUE; + canX = mask & 1; + canY = mask & 2; + event = event % 10000; + } constexpr Int_t kMaxDiff = 7; constexpr Int_t kMinSize = 20; @@ -253,29 +263,36 @@ void TBox::ExecuteEvent(Int_t event, Int_t px, Int_t py) Bool_t ropaque = parent.OpaqueResizing(); // convert to user coordinates and either paint ot set back - auto paint_or_set = [&parent,isBox,this](Bool_t paint) + auto paint_or_set = [&parent,isBox,canX, canY,liveUpdate,this](Bool_t paint) { auto x1 = parent.AbsPixeltoX(px1); auto y1 = parent.AbsPixeltoY(py1); auto x2 = parent.AbsPixeltoX(px2); auto y2 = parent.AbsPixeltoY(py2); - if (!paint) { + if (paint) { + if (firstPaint) + firstPaint = kFALSE; + else { + auto pp = parent.GetPainter(); + pp->SetAttLine({GetFillColor() > 0 ? GetFillColor() : (Color_t) 1, GetLineStyle(), 2}); + pp->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow); + } + } + if (liveUpdate || !paint) { if (isBox) { x1 = parent.PadtoX(x1); x2 = parent.PadtoX(x2); y1 = parent.PadtoY(y1); y2 = parent.PadtoY(y2); } - SetX1(x1); - SetY1(y1); - SetX2(x2); - SetY2(y2); - } else if (firstPaint) { - firstPaint = kFALSE; - } else { - auto pp = parent.GetPainter(); - pp->SetAttLine({GetFillColor() > 0 ? GetFillColor() : (Color_t) 1, GetLineStyle(), 2}); - pp->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow); + if (canX) { + SetX1(x1); + SetX2(x2); + } + if (canY) { + SetY1(y1); + SetY2(y2); + } } }; @@ -310,37 +327,40 @@ void TBox::ExecuteEvent(Int_t event, Int_t px, Int_t py) std::swap(py1, py2); if (TMath::Abs(px - px1) <= kMaxDiff && TMath::Abs(py - py2) <= kMaxDiff) { - mode = pA; - parent.SetCursor(kTopLeft); + mode = canX && canY ? pA : (canX ? pL : pTop); } else if (TMath::Abs(px - px2) <= kMaxDiff && TMath::Abs(py - py2) <= kMaxDiff) { - mode = pB; - parent.SetCursor(kTopRight); + mode = canX && canY ? pB : (canX ? pR : pTop); } else if (TMath::Abs(px - px2) <= kMaxDiff && TMath::Abs(py - py1) <= kMaxDiff) { - mode = pC; - parent.SetCursor(kBottomRight); + mode = canX && canY ? pC : (canX ? pR : pBot); } else if (TMath::Abs(px - px1) <= kMaxDiff && TMath::Abs(py - py1) <= kMaxDiff) { - mode = pD; - parent.SetCursor(kBottomLeft); + mode = canX && canY ? pD : (canX ? pL : pBot); } else if ((px > px1 + kMaxDiff && px < px2 - kMaxDiff) && TMath::Abs(py - py2) < kMaxDiff) { - mode = pTop; - parent.SetCursor(kTopSide); + mode = canY ? pTop : pNone; } else if ((px > px1 + kMaxDiff && px < px2 - kMaxDiff) && TMath::Abs(py - py1) < kMaxDiff) { - mode = pBot; - parent.SetCursor(kBottomSide); + mode = canY ? pBot : pNone; } else if ((py > py2 + kMaxDiff && py < py1 - kMaxDiff) && TMath::Abs(px - px1) < kMaxDiff) { - mode = pL; - parent.SetCursor(kLeftSide); + mode = canX ? pL : pNone; } else if ((py > py2 + kMaxDiff && py < py1 - kMaxDiff) && TMath::Abs(px - px2) < kMaxDiff) { - mode = pR; - parent.SetCursor(kRightSide); + mode = canX ? pR : pNone; } else if ((px > px1+kMaxDiff && px < px2-kMaxDiff) && (py > py2+kMaxDiff && py < py1-kMaxDiff)) { dpx1 = px - px1; // cursor position relative to top-left corner dpy2 = py - py2; mode = pINSIDE; - parent.SetCursor(event == kButton1Down ? kMove : kCross); } else { mode = pNone; - parent.SetCursor(kCross); + } + + switch (mode) { + case pNone: parent.SetCursor(kCross); break; + case pA: parent.SetCursor(kTopLeft); break; + case pB: parent.SetCursor(kTopRight); break; + case pC: parent.SetCursor(kBottomRight); break; + case pD: parent.SetCursor(kBottomLeft); break; + case pTop: parent.SetCursor(kTopSide); break; + case pL: parent.SetCursor(kLeftSide); break; + case pR: parent.SetCursor(kRightSide); break; + case pBot: parent.SetCursor(kBottomSide); break; + case pINSIDE: parent.SetCursor(event == kButton1Down ? kMove : kCross); break; } fResizing = (mode != pNone) && (mode != pINSIDE); @@ -408,14 +428,18 @@ void TBox::ExecuteEvent(Int_t event, Int_t px, Int_t py) break; case pINSIDE: if (!opaque) paint_or_set(kTRUE); - px2 += px - dpx1 - px1; - px1 = px - dpx1; - py1 += py - dpy2 - py2; - py2 = py - dpy2; - if (px1 < px1p) { px2 += px1p - px1; px1 = px1p; } - if (px2 > px2p) { px1 -= px2 - px2p; px2 = px2p; } - if (py1 > py1p) { py2 -= py1 - py1p; py1 = py1p; } - if (py2 < py2p) { py1 += py2p - py2; py2 = py2p; } + if (canX) { + px2 += px - dpx1 - px1; + px1 = px - dpx1; + if (px1 < px1p) { px2 += px1p - px1; px1 = px1p; } + if (px2 > px2p) { px1 -= px2 - px2p; px2 = px2p; } + } + if (canY) { + py1 += py - dpy2 - py2; + py2 = py - dpy2; + if (py1 > py1p) { py2 -= py1 - py1p; py1 = py1p; } + if (py2 < py2p) { py1 += py2p - py2; py2 = py2p; } + } paint_or_set(!opaque); break; } From d3a12b6b4c1a1b2e8b02ed1d920d0bec45603ae0 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Sep 2026 10:37:32 +0200 Subject: [PATCH 6/8] Rewrite TSliderBox::ExecuteEvent Use functionality of TBox::ExecuteEvent instead reimplementing it again. Depending on vertical or horizontal orientation of TSlider, either only X or only Y axis can be modified by the ExecuteEvent Also when setting min/max value back to TSlider, respect border values of TSlider itself. --- graf2d/gpad/inc/TSliderBox.h | 16 +-- graf2d/gpad/src/TSliderBox.cxx | 244 ++++----------------------------- 2 files changed, 36 insertions(+), 224 deletions(-) diff --git a/graf2d/gpad/inc/TSliderBox.h b/graf2d/gpad/inc/TSliderBox.h index 4942f865a7e92..95f15edb8304b 100644 --- a/graf2d/gpad/inc/TSliderBox.h +++ b/graf2d/gpad/inc/TSliderBox.h @@ -2,7 +2,7 @@ // Author: Rene Brun 23/11/96 /************************************************************************* - * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -12,7 +12,6 @@ #ifndef ROOT_TSliderBox #define ROOT_TSliderBox - #include "TWbox.h" class TSlider; @@ -20,22 +19,19 @@ class TSlider; class TSliderBox : public TWbox { protected: - TSlider *fSlider; ///< Pointer to slider + TSlider *fSlider = nullptr; ///< Pointer to slider - TSliderBox(const TSliderBox& sb) - : TWbox(sb), fSlider(sb.fSlider) { } - TSliderBox& operator=(const TSliderBox& sb) - {if(this!=&sb) {TWbox::operator=(sb); fSlider=sb.fSlider;} - return *this; } + TSliderBox(const TSliderBox&) = delete; + TSliderBox& operator=(const TSliderBox&) = delete; public: TSliderBox(); TSliderBox(Double_t x1, Double_t y1,Double_t x2 ,Double_t y2, - Color_t color=18, Short_t bordersize=2 ,Short_t bordermode=-1); + Color_t color=18, Short_t bordersize=2, Short_t bordermode=-1); ~TSliderBox() override; void ExecuteEvent(Int_t event, Int_t px, Int_t py) override; void SavePrimitive(std::ostream &out, Option_t *option = "") override; - void SetSlider(TSlider*slider) { fSlider=slider; } + void SetSlider(TSlider*slider) { fSlider = slider; } ClassDefOverride(TSliderBox,1) //The moving box of a TSlider }; diff --git a/graf2d/gpad/src/TSliderBox.cxx b/graf2d/gpad/src/TSliderBox.cxx index 409532ed1de98..307d62382c085 100644 --- a/graf2d/gpad/src/TSliderBox.cxx +++ b/graf2d/gpad/src/TSliderBox.cxx @@ -2,7 +2,7 @@ // Author: Rene Brun 23/11/96 /************************************************************************* - * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -12,7 +12,7 @@ #include "TROOT.h" #include "TSlider.h" #include "TSliderBox.h" -#include "TVirtualX.h" +#include "TMath.h" #include @@ -48,230 +48,47 @@ TSliderBox::~TSliderBox() { } + //////////////////////////////////////////////////////////////////////////////// /// Interaction with a slider. void TSliderBox::ExecuteEvent(Int_t event, Int_t px, Int_t py) { - if (!gPad) return; - - const Int_t kMaxDiff = 5; - const Int_t kMinSize = 20; - - static Int_t px1, px2, py1, py2, pxl, pyl, pxt, pyt, pxold, pyold; - static Int_t px1p, px2p, py1p, py2p; - static Bool_t pL, pR, pTop, pBot, pINSIDE; - Int_t wx, wy; - Bool_t doing_again = kFALSE; - Bool_t opaque = gPad->OpaqueMoving(); - Bool_t ropaque = gPad->OpaqueResizing(); - - TVirtualPad *parent = gPad; - - Int_t border = parent->GetBorderSize(); - Int_t pxpadmin = parent->XtoAbsPixel(parent->GetX1()) + border; - Int_t pxpadmax = parent->XtoAbsPixel(parent->GetX2()) - border; - Int_t pypadmin = parent->YtoAbsPixel(parent->GetY1()) - border; - Int_t pypadmax = parent->YtoAbsPixel(parent->GetY2()) + border; - - Bool_t vertical = kTRUE; - if (pxpadmax-pxpadmin > pypadmin-pypadmax) vertical = kFALSE; - -again: - - switch (event) { + Bool_t vertical = fSlider ? fSlider->GetAbsWNDC() < fSlider->GetAbsHNDC() : kTRUE; - case kButton1Down: + TWbox::ExecuteEvent((vertical ? 20000 : 10000) + event, px, py); - gVirtualX->SetLineColor(-1); - TAttLine::Modify(); //Change line attributes only if necessary - if (GetFillColor()) - gVirtualX->SetLineColor(GetFillColor()); - else - gVirtualX->SetLineColor(1); - gVirtualX->SetLineWidth(2); - - // No break !!! + if (!fSlider) + return; - case kMouseMotion: + Int_t bordersize = fSlider->GetBorderSize(); + Double_t dx = fSlider->PixeltoX(bordersize); + Double_t dy = fSlider->PixeltoY(-bordersize); + Double_t v1, v2, d; - px1 = gPad->XtoAbsPixel(GetX1()); - py1 = gPad->YtoAbsPixel(GetY1()); - px2 = gPad->XtoAbsPixel(GetX2()); - py2 = gPad->YtoAbsPixel(GetY2()); + // Give control to object using the slider + if (vertical) { + v1 = GetY1(); + v2 = GetY2(); + d = TMath::Min(0.3, dy); + } else { + v1 = GetX1(); + v2 = GetX2(); + d = TMath::Min(0.3, dx); + } + fSlider->SetMinimum(TMath::Max(0., (v1 - d) / (1 - 2*d))); + fSlider->SetMaximum(TMath::Min(1., (v2 - d) / (1 - 2*d))); - if (px1 < px2) { - pxl = px1; - pxt = px2; - } else { - pxl = px2; - pxt = px1; - } - if (py1 < py2) { - pyl = py1; - pyt = py2; + if (event == kButton1Up) { + if (vertical) { + SetX1(dx); SetX2(1 - dx); } else { - pyl = py2; - pyt = py1; - } - - px1p = pxpadmin; - py1p = pypadmin; - px2p = pxpadmax; - py2p = pypadmax; - - pL = pR = pTop = pBot = pINSIDE = kFALSE; - - if (vertical && (px > pxl+kMaxDiff && px < pxt-kMaxDiff) && - std::abs(py - pyl) < kMaxDiff) { // top edge - pxold = pxl; pyold = pyl; pTop = kTRUE; - gPad->SetCursor(kTopSide); - } - - if (vertical && (px > pxl+kMaxDiff && px < pxt-kMaxDiff) && - std::abs(py - pyt) < kMaxDiff) { // bottom edge - pxold = pxt; pyold = pyt; pBot = kTRUE; - gPad->SetCursor(kBottomSide); - } - - if (!vertical && (py > pyl+kMaxDiff && py < pyt-kMaxDiff) && - std::abs(px - pxl) < kMaxDiff) { // left edge - pxold = pxl; pyold = pyl; pL = kTRUE; - gPad->SetCursor(kLeftSide); - } - - if (!vertical && (py > pyl+kMaxDiff && py < pyt-kMaxDiff) && - std::abs(px - pxt) < kMaxDiff) { // right edge - pxold = pxt; pyold = pyt; pR = kTRUE; - gPad->SetCursor(kRightSide); - } - - if ((px > pxl+kMaxDiff && px < pxt-kMaxDiff) && - (py > pyl+kMaxDiff && py < pyt-kMaxDiff)) { // inside box - pxold = px; pyold = py; pINSIDE = kTRUE; - if (event == kButton1Down) - gPad->SetCursor(kMove); - else - gPad->SetCursor(kCross); - } - - fResizing = kFALSE; - if ( pL || pR || pTop || pBot) - fResizing = kTRUE; - - if ( !pL && !pR && !pTop && !pBot && !pINSIDE) - gPad->SetCursor(kCross); - - break; - - case kButton1Motion: - - wx = wy = 0; - - if (pTop) { - if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); - py2 += py - pyold; - if (py2 > py1-kMinSize) { py2 = py1-kMinSize; wy = py2; } - if (py2 < py2p) { py2 = py2p; wy = py2; } - if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); - } - if (pBot) { - if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); - py1 += py - pyold; - if (py1 < py2+kMinSize) { py1 = py2+kMinSize; wy = py1; } - if (py1 > py1p) { py1 = py1p; wy = py1; } - if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); - } - if (pL) { - if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); - px1 += px - pxold; - if (px1 > px2-kMinSize) { px1 = px2-kMinSize; wx = px1; } - if (px1 < px1p) { px1 = px1p; wx = px1; } - if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); - } - if (pR) { - if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); - px2 += px - pxold; - if (px2 < px1+kMinSize) { px2 = px1+kMinSize; wx = px2; } - if (px2 > px2p) { px2 = px2p; wx = px2; } - if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); - } - if (pINSIDE) { - if (!opaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); // draw the old box - Int_t dx = px - pxold; - Int_t dy = py - pyold; - px1 += dx; py1 += dy; px2 += dx; py2 += dy; - if (px1 < px1p) { dx = px1p - px1; px1 += dx; px2 += dx; wx = px+dx; } - if (px2 > px2p) { dx = px2 - px2p; px1 -= dx; px2 -= dx; wx = px-dx; } - if (py1 > py1p) { dy = py1 - py1p; py1 -= dy; py2 -= dy; wy = py-dy; } - if (py2 < py2p) { dy = py2p - py2; py1 += dy; py2 += dy; wy = py+dy; } - if (!opaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); // draw the new box - } - - if (wx || wy) { - if (wx) px = wx; - if (wy) py = wy; - gVirtualX->Warp(px, py); - } - - pxold = px; - pyold = py; - - if ((pINSIDE && opaque) || (fResizing && ropaque)) { - event = kButton1Up; - doing_again = kTRUE; - goto again; - } - - break; - - case kButton1Up: - - if (pTop || pBot || pL || pR || pINSIDE) { - fX1 = gPad->AbsPixeltoX(px1); - fY1 = gPad->AbsPixeltoY(py1); - fX2 = gPad->AbsPixeltoX(px2); - fY2 = gPad->AbsPixeltoY(py2); - } - - if (pINSIDE) { - // if it was not a pad that was moved then it must have been - // a box or something like that so we have to redraw the pad - if (parent == gPad) gPad->Modified(kTRUE); - if (!doing_again) gPad->SetCursor(kCross); + SetY1(dy); SetY2(1 - dy); } - - if (pTop || pBot || pL || pR ) - gPad->Modified(kTRUE); - - // Restore original event type - if (doing_again) - event = kButton1Motion; - else { - gVirtualX->SetLineColor(-1); - gVirtualX->SetLineWidth(-1); - } - - break; } - - // Give control to object using the slider - - Float_t xpmin,xpmax; - if (vertical) { - xpmin = Float_t(pypadmin-py1)/Float_t(pypadmin-pypadmax); - xpmax = Float_t(pypadmin-py2)/Float_t(pypadmin-pypadmax); - } else { //vertical slider - xpmin = Float_t(px1-pxpadmin)/Float_t(pxpadmax-pxpadmin); - xpmax = Float_t(px2-pxpadmin)/Float_t(pxpadmax-pxpadmin); - } - fSlider->SetMinimum(xpmin); - fSlider->SetMaximum(xpmax); - //A user method to execute? - Int_t lenMethod = strlen(fSlider->GetMethod()); - if (event == kButton1Up && lenMethod > 0 ) { + if (event == kButton1Up && (strlen(fSlider->GetMethod()) > 0)) { gPad->SetCursor(kWatch); gROOT->ProcessLine(fSlider->GetMethod()); return; @@ -279,9 +96,8 @@ void TSliderBox::ExecuteEvent(Int_t event, Int_t px, Int_t py) //An object connected to this slider? TObject *obj = fSlider->GetObject(); - if (obj) { - obj->ExecuteEvent(event,0,0); - } + if (obj) + obj->ExecuteEvent(event, 0, 0); } //////////////////////////////////////////////////////////////////////////////// From bc505814c4322588255713503ced6dc004560bc5 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Sep 2026 10:37:51 +0200 Subject: [PATCH 7/8] [ellipse] Remove TVirtualX.h include --- graf2d/graf/src/TEllipse.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/graf2d/graf/src/TEllipse.cxx b/graf2d/graf/src/TEllipse.cxx index d56251034a593..52459f5ef26b8 100644 --- a/graf2d/graf/src/TEllipse.cxx +++ b/graf2d/graf/src/TEllipse.cxx @@ -9,17 +9,18 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include +#include "TEllipse.h" +#include #include + #include "TROOT.h" #include "TBuffer.h" -#include "TEllipse.h" +#include "TAttMarker.h" #include "TVirtualPad.h" #include "TVirtualPadPainter.h" #include "TMath.h" #include "TPoint.h" -#include "TVirtualX.h" constexpr Double_t kPI = TMath::Pi(); From dd417428139b57f3c1ed6bd8b0b278afab66b912 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Sep 2026 11:02:34 +0200 Subject: [PATCH 8/8] [pad] remove TVirtualX.h include Now most of graphics classes do not use gVirtualX directly --- graf2d/gpad/src/TPad.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/graf2d/gpad/src/TPad.cxx b/graf2d/gpad/src/TPad.cxx index eef5ae44bc75e..85497b4c92e64 100644 --- a/graf2d/gpad/src/TPad.cxx +++ b/graf2d/gpad/src/TPad.cxx @@ -30,7 +30,6 @@ #include "TBaseClass.h" #include "TClassTable.h" #include "TVirtualPS.h" -#include "TVirtualX.h" #include "TVirtualViewer3D.h" #include "TView.h" #include "TPoint.h"