From 7e19df6fc42164889052a5f91b7edd3abb2d7708 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 3 Dec 2024 15:59:59 +0100 Subject: [PATCH] Build with pave changes --- build/jsroot.js | 201 ++++++++++++++++++++++++---------- changes.md | 3 +- modules/core.mjs | 2 +- modules/hist/TPavePainter.mjs | 2 +- 4 files changed, 150 insertions(+), 58 deletions(-) diff --git a/build/jsroot.js b/build/jsroot.js index 062dd6a46..7590e8215 100644 --- a/build/jsroot.js +++ b/build/jsroot.js @@ -12,7 +12,7 @@ const version_id = 'dev', /** @summary version date * @desc Release date in format day/month/year like '14/04/2022' */ -version_date = '2/12/2024', +version_date = '3/12/2024', /** @summary version id and date * @desc Produced by concatenation of {@link version_id} and {@link version_date} @@ -1176,7 +1176,7 @@ function create$1(typename, target) { extend$1(obj, { fFillColor: gStyle.fStatColor, fFillStyle: gStyle.fStatStyle, fTextFont: gStyle.fStatFont, fTextSize: gStyle.fStatFontSize, fTextColor: gStyle.fStatTextColor, fBorderSize: gStyle.fStatBorderSize, - fOptFit: 0, fOptStat: 0, fFitFormat: '', fStatFormat: '', fParent: null }); + fOptFit: gStyle.fOptFit, fOptStat: gStyle.fOptStat, fFitFormat: gStyle.fFitFormat, fStatFormat: gStyle.fStatFormat, fParent: null }); break; case clTLegend: create$1(clTPave, obj); @@ -66658,6 +66658,8 @@ class TFramePainter extends ObjectPainter { gStyle.fPadRightMargin = 1 - this.fX2NDC; this.fillatt?.saveToStyle('fFrameFillColor', 'fFrameFillStyle'); this.lineatt?.saveToStyle('fFrameLineColor', 'fFrameLineWidth', 'fFrameLineStyle'); + gStyle.fFrameBorderMode = this._borderMode; + gStyle.fFrameBorderSize = this._borderSize; }, 'Store frame position and graphical attributes to gStyle'); menu.separator(); @@ -70410,7 +70412,8 @@ class TPadPainter extends ObjectPainter { leg.fY1NDC = (1 - szy) * (1 - pad.fTopMargin) + szy * pad.fBottomMargin; leg.fX2NDC = 0.99 - pad.fRightMargin; leg.fY2NDC = 0.99 - pad.fTopMargin; - if (opt === undefined) opt = 'autoplace'; + if (opt === undefined) + opt = 'autoplace'; } else { leg.fX1NDC = x1; leg.fY1NDC = y1; @@ -72397,7 +72400,7 @@ drawTPadSnapshot: drawTPadSnapshot, ensureTCanvas: ensureTCanvas }); -const kTakeStyle = BIT(17); +const kTakeStyle = BIT(17), kPosTitle = 'postitle', kAutoPlace = 'autoplace', kDefaultDrawOpt = 'brNDC'; /** @summary Returns true if stat box on default place and can be adjusted * @private */ @@ -72421,8 +72424,8 @@ class TPavePainter extends ObjectPainter { /** @summary constructor * @param {object|string} dom - DOM element for drawing or element id * @param {object} pave - TPave-based object */ - constructor(dom, pave) { - super(dom, pave); + constructor(dom, pave, opt) { + super(dom, pave, opt); this.Enabled = true; this.UseContextMenu = true; } @@ -72512,6 +72515,23 @@ class TPavePainter extends ObjectPainter { }); } + /** @summary Get draw option for the pave + * @desc only stats using fOption directly, all other classes - stored in the pad */ + getPaveDrawOption() { + let opt = this.getDrawOpt(); + if (this.isStats() || !opt) + opt = this.getObject()?.fOption; + return opt || kDefaultDrawOpt; + } + + /** @summary Change pave draw option */ + setPaveDrawOption(opt) { + if (this.isStats()) + this.getObject().fOption = opt; + else + this.storeDrawOpt(opt); + } + /** @summary Draw pave and content * @return {Promise} */ async drawPave(arg) { @@ -72520,7 +72540,8 @@ class TPavePainter extends ObjectPainter { return this; } - const pt = this.getObject(), opt = pt.fOption.toUpperCase(), + const pt = this.getObject(), + opt = this.getPaveDrawOption().toUpperCase(), fp = this.getFramePainter(), pp = this.getPadPainter(), pad = pp.getRootPad(true); let interactive_element, width, height; @@ -72541,8 +72562,9 @@ class TPavePainter extends ObjectPainter { pt.fY1NDC = 0.1; pt.fY2NDC = 0.9; } - } else if (opt.indexOf('NDC') >= 0) { + } else if (pt.fOption.indexOf('NDC') >= 0) { // check if NDC was modified but fInit was not set + // wired - ROOT checks fOption even when absolutely different draw option may be specified, // happens in stressGraphics.cxx, sg30 where stats box not initialized when call C->Update() in batch mode if (pt.fX1NDC < 1e-20 && pt.fX2NDC < 1e-20) { pt.fX1NDC = pt.fX1; @@ -72595,9 +72617,9 @@ class TPavePainter extends ObjectPainter { const main = pt.$main_painter || this.getMainPainter(); if (isFunc(main?.fillStatistic)) { - let dostat = parseInt(pt.fOptStat), dofit = parseInt(pt.fOptFit); - if (!Number.isInteger(dostat) || pt.TestBit(kTakeStyle)) dostat = gStyle.fOptStat; - if (!Number.isInteger(dofit)|| pt.TestBit(kTakeStyle)) dofit = gStyle.fOptFit; + let dostat = pt.fOptStat, dofit = pt.fOptFit; + if (pt.TestBit(kTakeStyle) || !Number.isInteger(dostat)) dostat = gStyle.fOptStat; + if (pt.TestBit(kTakeStyle) || !Number.isInteger(dofit)) dofit = gStyle.fOptFit; // we take statistic from main painter if (main.fillStatistic(this, dostat, dofit)) { @@ -72651,6 +72673,9 @@ class TPavePainter extends ObjectPainter { this.createAttLine({ attr: pt, width: (brd > 0) ? pt.fLineWidth : 0 }); this.createAttFill({ attr: pt }); + // need to fill pave while + if (this.fillatt.empty() && arc_radius) + this.fillatt.setSolidColor(this.getColor(pt.fFillColor) || 'white'); if (pt._typename === clTDiamond) { const h2 = Math.round(height/2), w2 = Math.round(width/2), @@ -72721,7 +72746,7 @@ class TPavePainter extends ObjectPainter { drawBorder(draw_g, width, height, arc_radius, diamond) { const pt = this.getObject(), - opt = pt.fOption.toUpperCase().replaceAll('ARC', '').replaceAll('NDC', ''), + opt = this.getPaveDrawOption().toUpperCase().replaceAll('ARC', '').replaceAll('NDC', ''), noborder = this.isPalette() || (opt.indexOf('NB') >= 0), dx = (opt.indexOf('L') >= 0) ? -1 : ((opt.indexOf('R') >= 0) ? 1 : 0), dy = (opt.indexOf('T') >= 0) ? -1 : ((opt.indexOf('B') >= 0) ? 1 : 0); @@ -73549,7 +73574,8 @@ class TPavePainter extends ObjectPainter { /** @summary Fill context menu items for the TPave object */ fillContextMenuItems(menu) { - const pave = this.getObject(); + const pave = this.getObject(), + set_opt = this.isStats() ? 'SetOption' : 'SetDrawOption'; menu.sub('Shadow'); menu.addSizeMenu('size', 0, 12, 1, pave.fBorderSize, arg => { @@ -73561,7 +73587,7 @@ class TPavePainter extends ObjectPainter { this.interactiveRedraw(true, getColorExec(arg, 'SetShadowColor')); }); const posarr = ['nb', 'tr', 'tl', 'br', 'bl']; - let value = '', remain = pave.fOption; + let value = '', opt = this.getPaveDrawOption(), remain = opt; posarr.forEach(nn => { const p = remain.indexOf(nn); if ((p >= 0) && !value) { @@ -73569,11 +73595,39 @@ class TPavePainter extends ObjectPainter { } }); menu.addSelectMenu('positon', posarr, value || 'nb', arg => { - pave.fOption = arg + remain; - this.interactiveRedraw(true, getColorExec(arg, `exec:SetOption("${pave.fOption}")`)); + arg += remain; + this.setPaveDrawOption(arg); + this.interactiveRedraw(true, `exec:${set_opt}("${arg}")`); }, 'Direction of pave shadow or nb - off'); menu.endsub(); + menu.sub('Corner'); + const parc = opt.toLowerCase().indexOf('arc'); + menu.addchk(parc >= 0, 'arc', flag => { + if (flag) + opt += ' arc'; + else + opt = opt.slice(0, parc) + opt.slice(parc + 3); + this.setPaveDrawOption(opt); + this.interactiveRedraw(true, `exec:${set_opt}("${opt}")`); + }, 'Usage of ARC draw option'); + menu.addSizeMenu('radius', 0, 0.2, 0.02, pave.fCornerRadius, val => { + pave.fCornerRadius = val; + this.interactiveRedraw(true, `exec:SetCornerRadius(${val})`); + }, 'Corner radius when ARC is enabled'); + menu.endsub(); + + if (this.isStats() || this.isPaveText() || this.isPavesText()) { + menu.add('Label', () => menu.input('Enter new label', pave.fLabel).then(lbl => { + pave.fLabel = lbl; + this.interactiveRedraw('pad', `exec:SetLabel("${lbl}")`); + })); + menu.addSizeMenu('Margin', 0, 0.2, 0.02, pave.fMargin, val => { + pave.fMargin = val; + this.interactiveRedraw(true, `exec:SetMargin(${val})`); + }); + } + if (this.isStats()) { menu.add('Default position', () => { pave.fX2NDC = gStyle.fStatX; @@ -73593,7 +73647,13 @@ class TPavePainter extends ObjectPainter { gStyle.fStatTextColor = pave.fTextColor; gStyle.fStatFontSize = pave.fTextSize; gStyle.fStatFont = pave.fTextFont; - }, 'Store stats position and graphical attributes to gStyle'); + gStyle.fFitFormat = pave.fFitFormat; + gStyle.fStatFormat = pave.fStatFormat; + gStyle.fOptStat = pave.fOptStat; + gStyle.fOptFit = pave.fOptFit; + }, 'Store stats attributes to gStyle'); + + menu.separator(); menu.add('SetStatFormat', () => { menu.input('Enter StatFormat', pave.fStatFormat).then(fmt => { @@ -73609,7 +73669,6 @@ class TPavePainter extends ObjectPainter { this.interactiveRedraw(true, `exec:SetFitFormat("${fmt}")`); }); }); - menu.separator(); menu.sub('SetOptStat', () => { menu.input('Enter OptStat', pave.fOptStat, 'int').then(fmt => { pave.fOptStat = fmt; @@ -73657,30 +73716,39 @@ class TPavePainter extends ObjectPainter { menu.endsub(); menu.separator(); + } else if (this.isPaveText() || this.isPavesText()) { + if (this.isPavesText()) { + menu.addSizeMenu('Paves', 1, 10, 1, pave.fNpaves, val => { + pave.fNpaves = val; + this.interactiveRedraw(true, `exec:SetNpaves(${val})`); + }); + } + + if (this.isTitle()) { + menu.add('Default position', () => { + pave.fX1NDC = gStyle.fTitleW > 0 ? gStyle.fTitleX - gStyle.fTitleW/2 : gStyle.fPadLeftMargin; + pave.fY1NDC = gStyle.fTitleY - Math.min(gStyle.fTitleFontSize*1.1, 0.06); + pave.fX2NDC = gStyle.fTitleW > 0 ? gStyle.fTitleX + gStyle.fTitleW/2 : 1 - gStyle.fPadRightMargin; + pave.fY2NDC = gStyle.fTitleY; + pave.fInit = 1; + this.interactiveRedraw(true, 'pave_moved'); + }); + + menu.add('Save to gStyle', () => { + gStyle.fTitleX = (pave.fX2NDC + pave.fX1NDC)/2; + gStyle.fTitleY = pave.fY2NDC; + this.fillatt?.saveToStyle('fTitleColor', 'fTitleStyle'); + gStyle.fTitleTextColor = pave.fTextColor; + gStyle.fTitleFontSize = pave.fTextSize; + gStyle.fTitleFont = pave.fTextFont; + }, 'Store title position and graphical attributes to gStyle'); + } } else if (pave._typename === clTLegend) { menu.add('Autoplace', () => { this.autoPlaceLegend(pave, this.getPadPainter()?.getRootPad(true), true).then(res => { if (res) this.interactiveRedraw(true, 'pave_moved'); }); }); - } else if (this.isTitle()) { - menu.add('Default position', () => { - pave.fX1NDC = gStyle.fTitleW > 0 ? gStyle.fTitleX - gStyle.fTitleW/2 : gStyle.fPadLeftMargin; - pave.fY1NDC = gStyle.fTitleY - Math.min(gStyle.fTitleFontSize*1.1, 0.06); - pave.fX2NDC = gStyle.fTitleW > 0 ? gStyle.fTitleX + gStyle.fTitleW/2 : 1 - gStyle.fPadRightMargin; - pave.fY2NDC = gStyle.fTitleY; - pave.fInit = 1; - this.interactiveRedraw(true, 'pave_moved'); - }); - - menu.add('Save to gStyle', () => { - gStyle.fTitleX = (pave.fX2NDC + pave.fX1NDC)/2; - gStyle.fTitleY = pave.fY2NDC; - this.fillatt?.saveToStyle('fTitleColor', 'fTitleStyle'); - gStyle.fTitleTextColor = pave.fTextColor; - gStyle.fTitleFontSize = pave.fTextSize; - gStyle.fTitleFont = pave.fTextFont; - }, 'Store title position and graphical attributes to gStyle'); } } @@ -73699,6 +73767,16 @@ class TPavePainter extends ObjectPainter { return this.matchObjectType(clTPaveStats); } + /** @summary Returns true when stat box is drawn */ + isPaveText() { + return this.matchObjectType(clTPaveText); + } + + /** @summary Returns true when stat box is drawn */ + isPavesText() { + return this.matchObjectType(clTPavesText); + } + /** @summary Returns true when stat box is drawn */ isPalette() { return this.matchObjectType(clTPaletteAxis); @@ -73706,7 +73784,7 @@ class TPavePainter extends ObjectPainter { /** @summary Returns true when title is drawn */ isTitle() { - return this.matchObjectType(clTPaveText) && (this.getObject()?.fName === kTitle); + return this.isPaveText() && (this.getObject()?.fName === kTitle); } /** @summary Clear text in the pave */ @@ -73795,9 +73873,11 @@ class TPavePainter extends ObjectPainter { /** @summary Update TPave object */ updateObject(obj, opt) { - if (!this.matchObjectType(obj)) return false; + if (!this.matchObjectType(obj)) + return false; - const pave = this.getObject(); + const pave = this.getObject(), + is_auto = opt === kAutoPlace; if (!pave.$modifiedNDC && !this.isDummyPos(obj)) { // if position was not modified interactively, update from source object @@ -73835,24 +73915,24 @@ class TPavePainter extends ObjectPainter { case clTDiamond: case clTPaveText: pave.fLines = clone(obj.fLines); - return true; + break; case clTPavesText: pave.fLines = clone(obj.fLines); pave.fNpaves = obj.fNpaves; - return true; + break; case clTPaveLabel: case clTPaveClass: pave.fLabel = obj.fLabel; - return true; + break; case clTPaveStats: pave.fOptStat = obj.fOptStat; pave.fOptFit = obj.fOptFit; - return true; + break; case clTLegend: { const oldprim = pave.fPrimitives; pave.fPrimitives = obj.fPrimitives; pave.fNColumns = obj.fNColumns; - this.AutoPlace = opt === 'autoplace'; + this.AutoPlace = is_auto; if (oldprim?.arr?.length && (oldprim?.arr?.length === pave.fPrimitives?.arr?.length)) { // try to sync object reference, new object does not displayed automatically // in ideal case one should use snapids in the entries @@ -73867,10 +73947,14 @@ class TPavePainter extends ObjectPainter { case clTPaletteAxis: pave.fBorderSize = 1; pave.fShadowColor = 0; - return true; + break; + default: + return false; } - return false; + this.storeDrawOpt(is_auto ? kDefaultDrawOpt : opt); + + return true; } /** @summary redraw pave object */ @@ -73931,7 +74015,13 @@ class TPavePainter extends ObjectPainter { /** @summary Draw TPave */ static async draw(dom, pave, opt) { - const painter = new TPavePainter(dom, pave); + const arg_opt = opt, + pos_title = (opt === kPosTitle), + is_auto = (opt === kAutoPlace); + if (pos_title || is_auto || (isStr(opt) && (opt.indexOf(';') >= 0))) + opt = ''; // use default - or stored in TPave itself + + const painter = new TPavePainter(dom, pave, opt); return ensureTCanvas(painter, false).then(() => { if (painter.isTitle()) { @@ -73939,7 +74029,7 @@ class TPavePainter extends ObjectPainter { if (prev_painter && (prev_painter !== painter)) { prev_painter.removeFromPadPrimitives(); prev_painter.cleanup(); - } else if ((opt === 'postitle') || painter.isDummyPos(pave)) { + } else if (pos_title || painter.isDummyPos(pave)) { if (painter.setTitlePosition(pave)) painter.$postitle = true; } @@ -73959,7 +74049,7 @@ class TPavePainter extends ObjectPainter { painter.UseContextMenu = true; } - painter.NoFillStats = (opt === 'nofillstats') || (pave.fName !== 'stats'); + painter.NoFillStats = pave.fName !== 'stats'; switch (pave._typename) { case clTPaveLabel: @@ -73975,7 +74065,7 @@ class TPavePainter extends ObjectPainter { painter.paveDrawFunc = painter.drawPaveText; break; case clTLegend: - painter.AutoPlace = (opt === 'autoplace'); + painter.AutoPlace = is_auto; painter.paveDrawFunc = painter.drawLegend; break; case clTPaletteAxis: @@ -73983,7 +74073,7 @@ class TPavePainter extends ObjectPainter { break; } - return painter.drawPave(opt).then(() => { + return painter.drawPave(arg_opt).then(() => { const adjust_title = painter.$postitle && painter.$titlebox; if (adjust_title) @@ -73992,7 +74082,7 @@ class TPavePainter extends ObjectPainter { delete painter.$postitle; delete painter.$titlebox; - return adjust_title ? painter.drawPave(opt) : painter; + return adjust_title ? painter.drawPave(arg_opt) : painter; }); }); } @@ -74001,7 +74091,8 @@ class TPavePainter extends ObjectPainter { var TPavePainter$1 = /*#__PURE__*/Object.freeze({ __proto__: null, -TPavePainter: TPavePainter +TPavePainter: TPavePainter, +kPosTitle: kPosTitle }); const kCARTESIAN = 1, kPOLAR = 2, kCYLINDRICAL = 3, kSPHERICAL = 4, kRAPIDITY = 5, @@ -75380,7 +75471,7 @@ class THistPainter extends ObjectPainter { fTextFont: st.fTitleFont, fTextSize: st.fTitleFontSize, fTextColor: st.fTitleTextColor, fTextAlign: 22 }); if (draw_title) pt.AddText(histo.fTitle); - return TPavePainter.draw(pp, pt, 'postitle').then(p => { p?.setSecondaryId(this, kTitle); return this; }); + return TPavePainter.draw(pp, pt, kPosTitle).then(p => { p?.setSecondaryId(this, kTitle); return this; }); } /** @summary Live change and update of title drawing @@ -153242,7 +153333,7 @@ class TGraphPolarPainter extends ObjectPainter { if (draw_title) pt.AddText(gr.fTitle); - return TPavePainter.draw(pp, pt, 'postitle') + return TPavePainter.draw(pp, pt, kPosTitle) .then(p => { p?.setSecondaryId(this, kTitle); return this; }); } diff --git a/changes.md b/changes.md index 4cf033047..16f41483a 100644 --- a/changes.md +++ b/changes.md @@ -7,7 +7,8 @@ 1. Support "same" option for first histogram, draw direcly on pad 1. Support different angle coordiantes in `TGraphPolargram`, handle 'N' and 'O' draw options 1. Implement 'arc' draw option for `TPave` -1. Support Poisson errors for TH1/TH2, https://root-forum.cern.ch/t/62335/ +1. Provide extensive context menus for all derived from `TPave` classes +1. Support Poisson errors for `TH1`/`TH2`, https://root-forum.cern.ch/t/62335/ 1. Fix - handle `TPave` NDC position also when fInit is not set 1. Fix - correctly position title according to gStyle->GetTitleAlign() 1. Fix - correctly handle tooltip events for `TGraphPolar` diff --git a/modules/core.mjs b/modules/core.mjs index 1bda43561..6608d0adb 100644 --- a/modules/core.mjs +++ b/modules/core.mjs @@ -4,7 +4,7 @@ const version_id = 'dev', /** @summary version date * @desc Release date in format day/month/year like '14/04/2022' */ -version_date = '2/12/2024', +version_date = '3/12/2024', /** @summary version id and date * @desc Produced by concatenation of {@link version_id} and {@link version_date} diff --git a/modules/hist/TPavePainter.mjs b/modules/hist/TPavePainter.mjs index d349bfa57..845d4533c 100644 --- a/modules/hist/TPavePainter.mjs +++ b/modules/hist/TPavePainter.mjs @@ -1207,7 +1207,7 @@ class TPavePainter extends ObjectPainter { } }); menu.addSelectMenu('positon', posarr, value || 'nb', arg => { - arg = arg + remain + arg += remain; this.setPaveDrawOption(arg); this.interactiveRedraw(true, `exec:${set_opt}("${arg}")`); }, 'Direction of pave shadow or nb - off');