diff --git a/core/base/inc/TVirtualPad.h b/core/base/inc/TVirtualPad.h index dacc3ab1d6a07..e6879422e2b8f 100644 --- a/core/base/inc/TVirtualPad.h +++ b/core/base/inc/TVirtualPad.h @@ -255,7 +255,7 @@ class TVirtualPad : public TObject, public TAttLine, public TAttFill, virtual Int_t IncrementPaletteColor(Int_t i, TString opt) = 0; virtual Int_t NextPaletteColor() = 0; - virtual Bool_t PlaceBox(TObject *o, Double_t w, Double_t h, Double_t &xl, Double_t &yb) = 0; + virtual Bool_t PlaceBox(TObject *o, Double_t w, Double_t h, Double_t &xl, Double_t &yb, Option_t* opt = "lb") = 0; virtual TObject *CreateToolTip(const TBox *b, const char *text, Long_t delayms) = 0; virtual void DeleteToolTip(TObject *tip) = 0; diff --git a/graf2d/gpad/inc/TPad.h b/graf2d/gpad/inc/TPad.h index 09261511aa652..80e0797afccd0 100644 --- a/graf2d/gpad/inc/TPad.h +++ b/graf2d/gpad/inc/TPad.h @@ -386,7 +386,7 @@ friend class TWebCanvas; Int_t NextPaletteColor() override; void DrawCollideGrid(); - Bool_t PlaceBox(TObject *o, Double_t w, Double_t h, Double_t &xl, Double_t &yb) override; + Bool_t PlaceBox(TObject *o, Double_t w, Double_t h, Double_t &xl, Double_t &yb, Option_t* option = "lb") override; virtual void x3d(Option_t *type=""); // Depreciated diff --git a/graf2d/gpad/src/TPad.cxx b/graf2d/gpad/src/TPad.cxx index 4dec0b0413190..af20f25da5120 100644 --- a/graf2d/gpad/src/TPad.cxx +++ b/graf2d/gpad/src/TPad.cxx @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "TROOT.h" @@ -3067,33 +3068,77 @@ Bool_t TPad::Collide(Int_t i, Int_t j, Int_t w, Int_t h) /// /// \return `true` if the box could be placed, `false` if not. /// -/// \param[in] o pointer to the box to be placed -/// \param[in] w box width to be placed -/// \param[in] h box height to be placed -/// \param[out] xl x position of the bottom left corner of the placed box -/// \param[out] yb y position of the bottom left corner of the placed box +/// \param[in] o pointer to the box to be placed +/// \param[in] w box width to be placed +/// \param[in] h box height to be placed +/// \param[out] xl x position of the bottom left corner of the placed box +/// \param[out] yb y position of the bottom left corner of the placed box +/// \param[in] option l=left, r=right, t=top, b=bottom, w=within margins. Order determines +/// priority for placement. Default is "lb" (prioritises horizontal over vertical) -Bool_t TPad::PlaceBox(TObject *o, Double_t w, Double_t h, Double_t &xl, Double_t &yb) +Bool_t TPad::PlaceBox(TObject *o, Double_t w, Double_t h, Double_t &xl, Double_t &yb, Option_t* option) { FillCollideGrid(o); Int_t iw = (int)(fCGnx*w); Int_t ih = (int)(fCGny*h); - Int_t nxmax = fCGnx-iw-1; - Int_t nymax = fCGny-ih-1; + Int_t nxbeg = 0; + Int_t nybeg = 0; + Int_t nxend = fCGnx-iw-1; + Int_t nyend = fCGny-ih-1; + Int_t dx = 1; + Int_t dy = 1; + + bool isFirstVertical = false; + bool isFirstHorizontal = false; + + for (std::size_t i = 0; option[i] != '\0'; ++i) { + char letter = std::tolower(option[i]); + if (letter == 'w') { + nxbeg += fCGnx*GetLeftMargin(); + nybeg += fCGny*GetBottomMargin(); + nxend -= fCGnx*GetRightMargin(); + nyend -= fCGny*GetTopMargin(); + } else if (letter == 't' || letter == 'b') { + isFirstVertical = !isFirstHorizontal; + // go from top to bottom instead of bottom to top + dy = letter == 't' ? -1 : 1; + } else if (letter == 'l' || letter == 'r') { + isFirstHorizontal = !isFirstVertical; + // go from right to left instead of left to right + dx = letter == 'r' ? -1 : 1; + } + } + + if(dx < 0) std::swap(nxbeg, nxend); + if(dy < 0) std::swap(nybeg, nyend); + + auto attemptPlacement = [&](Int_t i, Int_t j) { + if (Collide(i, j, iw, ih)) { + return false; + } else { + xl = (Double_t)(i) / (Double_t)(fCGnx); + yb = (Double_t)(j) / (Double_t)(fCGny); + return true; + } + }; - for (Int_t i = 0; i