diff --git a/modules/gui/HierarchyPainter.mjs b/modules/gui/HierarchyPainter.mjs index 12ec66051..bbc968c64 100644 --- a/modules/gui/HierarchyPainter.mjs +++ b/modules/gui/HierarchyPainter.mjs @@ -1439,6 +1439,9 @@ class HierarchyPainter extends BasePainter { if (!element_title) element_title = element_name; + if (hitem._filter) + element_name += ' *'; + d3a.attr('title', element_title) .text(element_name + ('_value' in hitem ? ':' : '')) .style('background', hitem._background ? hitem._background : null); @@ -1458,6 +1461,8 @@ class HierarchyPainter extends BasePainter { for (let i = 0; i < hitem._childs.length; ++i) { const chld = hitem._childs[i]; chld._parent = hitem; + if (hitem._filter && chld._name && chld._name.indexOf(hitem._filter) < 0) + continue; if (!this.addItemHtml(chld, d3chlds, i)) break; // if too many items, skip rest } @@ -2121,6 +2126,15 @@ class HierarchyPainter extends BasePainter { if (hitem._childs === undefined) menu.add('Expand', () => this.expandItem(itemname), 'Expand content of object'); else { + if (sett.handle?.pm && hitem._childs.length) { + menu.add('Filter...', () => menu.input('Enter items to select', hitem._filter, f => { + const changed = hitem._filter !== f; + hitem._filter = f; + if (changed) + this.updateTreeNode(hitem); + }), 'Filter out items based on input pattern'); + } + menu.add('Unexpand', () => { hitem._more = true; delete hitem._childs; diff --git a/modules/gui/menu.mjs b/modules/gui/menu.mjs index 82de20567..6798adb74 100644 --- a/modules/gui/menu.mjs +++ b/modules/gui/menu.mjs @@ -1085,9 +1085,14 @@ class JSRootMenu { * @param {string} [kind] - use 'text' (default), 'number', 'float' or 'int' * @protected */ async input(title, value, kind, min, max) { + let onchange = null; + if (isFunc(kind)) { + onchange = kind; + kind = ''; + } if (!kind) kind = 'text'; - const inp_type = (kind === 'int') ? 'number' : 'text'; + const inp_type = (kind === 'int') ? 'number' : 'text', value0 = value; let ranges = ''; if ((value === undefined) || (value === null)) value = ''; @@ -1100,24 +1105,33 @@ class JSRootMenu { const main_content = '
' + - `` + - '
'; + `` + + '', oninit = !onchange ? null : elem => { + const inp = elem.querySelector('.jsroot_dlginp'); + if (inp) + inp.oninput = () => onchange(inp.value); + }; return new Promise(resolveFunc => { - this.runModal(title, main_content, { btns: true, height: 150, width: 400 }).then(element => { - if (!element) + this.runModal(title, main_content, { btns: true, height: 150, width: 400, oninit }).then(element => { + if (!element) { + if (onchange) + onchange(value0); return; - let val = element.querySelector('.jsroot_dlginp').value; + } + let val = element.querySelector('.jsroot_dlginp').value, isok = true; if (kind === 'float') { val = Number.parseFloat(val); - if (Number.isFinite(val)) - resolveFunc(val); + isok = Number.isFinite(val); } else if (kind === 'int') { val = parseInt(val); - if (Number.isInteger(val)) - resolveFunc(val); - } else + isok = Number.isInteger(val); + } + if (isok) { + if (onchange) + onchange(val); resolveFunc(val); + } }); }); } @@ -1654,6 +1668,8 @@ class StandaloneMenu extends JSRootMenu { f = modal.element.select('.jsroot_dialog_footer').select('button'); if (!f.empty()) f.node().focus(); + if (isFunc(args.oninit)) + args.oninit(modal.element.node()); return modal; }