From b28e6cdf8a11a0842a79c46d7fc956ebdc86ff29 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 26 Nov 2025 13:56:44 +0100 Subject: [PATCH 1/8] Add possibility to filter items in the hierarchy --- modules/gui/HierarchyPainter.mjs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/modules/gui/HierarchyPainter.mjs b/modules/gui/HierarchyPainter.mjs index 12ec66051..3af5d2b7a 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 (hitem._childs.length > 10) { + menu.add('Filter...', () => menu.input('Enter items to select', hitem._filter).then(f => { + const changed = hitem._filter !== f; + hitem._filter = f; + if (changed) + this.updateTreeNode(hitem); + })); + } + menu.add('Unexpand', () => { hitem._more = true; delete hitem._childs; From 01e4c259ce3268afb7abb1d4116181d0df983533 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 26 Nov 2025 16:00:45 +0100 Subject: [PATCH 2/8] Allow to filter only classes marked with pm These are TTree and TGeoManager --- modules/gui/HierarchyPainter.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gui/HierarchyPainter.mjs b/modules/gui/HierarchyPainter.mjs index 3af5d2b7a..553abdcb2 100644 --- a/modules/gui/HierarchyPainter.mjs +++ b/modules/gui/HierarchyPainter.mjs @@ -2126,7 +2126,7 @@ class HierarchyPainter extends BasePainter { if (hitem._childs === undefined) menu.add('Expand', () => this.expandItem(itemname), 'Expand content of object'); else { - if (hitem._childs.length > 10) { + if (sett.handle?.pm && (hitem._childs.length > 10)) { menu.add('Filter...', () => menu.input('Enter items to select', hitem._filter).then(f => { const changed = hitem._filter !== f; hitem._filter = f; From f3e13f9bc30ce91aa3d689318b6d1fc47a2c090f Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 26 Nov 2025 16:23:36 +0100 Subject: [PATCH 3/8] Implement live tracking of changes in the input field --- modules/gui/menu.mjs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/gui/menu.mjs b/modules/gui/menu.mjs index 82de20567..9b66fde8f 100644 --- a/modules/gui/menu.mjs +++ b/modules/gui/menu.mjs @@ -1085,6 +1085,11 @@ 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'; @@ -1101,10 +1106,16 @@ class JSRootMenu { const main_content = '
' + `` + - '
'; + '', + oninit = !onchange ? null : elem => { + const inp = elem.querySelector('.jsroot_dlginp'); + console.log('input element', inp) + if (inp) + inp.oninput = () => onchange(inp.value); + }; return new Promise(resolveFunc => { - this.runModal(title, main_content, { btns: true, height: 150, width: 400 }).then(element => { + this.runModal(title, main_content, { btns: true, height: 150, width: 400, oninit }).then(element => { if (!element) return; let val = element.querySelector('.jsroot_dlginp').value; @@ -1654,6 +1665,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; } From 34012b39135e2fc7a2d6ec6feb5fa80fe349efdc Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 26 Nov 2025 16:23:53 +0100 Subject: [PATCH 4/8] Use live tracking of filter input --- modules/gui/HierarchyPainter.mjs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/gui/HierarchyPainter.mjs b/modules/gui/HierarchyPainter.mjs index 553abdcb2..d4b83f6fe 100644 --- a/modules/gui/HierarchyPainter.mjs +++ b/modules/gui/HierarchyPainter.mjs @@ -2127,7 +2127,12 @@ class HierarchyPainter extends BasePainter { menu.add('Expand', () => this.expandItem(itemname), 'Expand content of object'); else { if (sett.handle?.pm && (hitem._childs.length > 10)) { - menu.add('Filter...', () => menu.input('Enter items to select', hitem._filter).then(f => { + 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); + }).then(f => { const changed = hitem._filter !== f; hitem._filter = f; if (changed) From f967d4bb469a1a7f688b28a0e290075376e64c37 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 26 Nov 2025 16:29:12 +0100 Subject: [PATCH 5/8] If live change func provided - call also it at the end --- modules/gui/menu.mjs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/gui/menu.mjs b/modules/gui/menu.mjs index 9b66fde8f..528d5d386 100644 --- a/modules/gui/menu.mjs +++ b/modules/gui/menu.mjs @@ -1105,11 +1105,9 @@ class JSRootMenu { const main_content = '
' + - `` + - '
', - oninit = !onchange ? null : elem => { + `` + + '', oninit = !onchange ? null : elem => { const inp = elem.querySelector('.jsroot_dlginp'); - console.log('input element', inp) if (inp) inp.oninput = () => onchange(inp.value); }; @@ -1118,17 +1116,19 @@ class JSRootMenu { this.runModal(title, main_content, { btns: true, height: 150, width: 400, oninit }).then(element => { if (!element) 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); + } }); }); } From aad3d502c4a1fd664efad02e0afa5c92d6e78c96 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 26 Nov 2025 16:29:27 +0100 Subject: [PATCH 6/8] Simplify live change in hpainter --- modules/gui/HierarchyPainter.mjs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/gui/HierarchyPainter.mjs b/modules/gui/HierarchyPainter.mjs index d4b83f6fe..5a00db4fc 100644 --- a/modules/gui/HierarchyPainter.mjs +++ b/modules/gui/HierarchyPainter.mjs @@ -2126,17 +2126,12 @@ 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 > 10)) { + 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); - }).then(f => { - const changed = hitem._filter !== f; - hitem._filter = f; - if (changed) - this.updateTreeNode(hitem); })); } From 170b652e150c7701206cecae0ffa1e09ba94651f Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 26 Nov 2025 16:33:43 +0100 Subject: [PATCH 7/8] Also handle cancel press when handling live change --- modules/gui/menu.mjs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/gui/menu.mjs b/modules/gui/menu.mjs index 528d5d386..6798adb74 100644 --- a/modules/gui/menu.mjs +++ b/modules/gui/menu.mjs @@ -1092,7 +1092,7 @@ class JSRootMenu { } 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 = ''; @@ -1114,8 +1114,11 @@ class JSRootMenu { return new Promise(resolveFunc => { this.runModal(title, main_content, { btns: true, height: 150, width: 400, oninit }).then(element => { - if (!element) + if (!element) { + if (onchange) + onchange(value0); return; + } let val = element.querySelector('.jsroot_dlginp').value, isok = true; if (kind === 'float') { val = Number.parseFloat(val); From bd34bb3717e4ccbd909d15f86936cf265e66d270 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 26 Nov 2025 16:33:53 +0100 Subject: [PATCH 8/8] Add title for filter menu --- modules/gui/HierarchyPainter.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gui/HierarchyPainter.mjs b/modules/gui/HierarchyPainter.mjs index 5a00db4fc..bbc968c64 100644 --- a/modules/gui/HierarchyPainter.mjs +++ b/modules/gui/HierarchyPainter.mjs @@ -2132,7 +2132,7 @@ class HierarchyPainter extends BasePainter { hitem._filter = f; if (changed) this.updateTreeNode(hitem); - })); + }), 'Filter out items based on input pattern'); } menu.add('Unexpand', () => {