Skip to content

Commit 0757803

Browse files
authored
Inspector: Mini-panel for parameters (#32257)
1 parent f9dced0 commit 0757803

File tree

4 files changed

+741
-6
lines changed

4 files changed

+741
-6
lines changed

examples/jsm/inspector/Inspector.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ class Inspector extends RendererInspector {
4242

4343
const profiler = new Profiler();
4444

45-
const parameters = new Parameters();
45+
const parameters = new Parameters( {
46+
builtin: true,
47+
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M14 6m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /><path d="M4 6l8 0" /><path d="M16 6l4 0" /><path d="M8 12m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /><path d="M4 12l2 0" /><path d="M10 12l10 0" /><path d="M17 18m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /><path d="M4 18l11 0" /><path d="M19 18l1 0" /></svg>'
48+
} );
4649
parameters.hide();
4750
profiler.addTab( parameters );
4851

examples/jsm/inspector/ui/Profiler.js

Lines changed: 249 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,17 +187,24 @@ export class Profiler {
187187
this.toggleButton = document.createElement( 'button' );
188188
this.toggleButton.id = 'profiler-toggle';
189189
this.toggleButton.innerHTML = `
190+
<span id="builtin-tabs-container"></span>
190191
<span id="toggle-text">
191192
<span id="fps-counter">-</span>
192193
<span class="fps-label">FPS</span>
193194
</span>
194-
<!-- <span class="toggle-separator"></span> -->
195195
<span id="toggle-icon">
196196
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-device-ipad-horizontal-search"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M11.5 20h-6.5a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v5.5" /><path d="M9 17h2" /><path d="M18 18m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" /><path d="M20.2 20.2l1.8 1.8" /></svg>
197197
</span>
198198
`;
199199
this.toggleButton.onclick = () => this.togglePanel();
200200

201+
this.builtinTabsContainer = this.toggleButton.querySelector( '#builtin-tabs-container' );
202+
203+
// Create mini-panel for builtin tabs (shown when panel is hidden)
204+
this.miniPanel = document.createElement( 'div' );
205+
this.miniPanel.id = 'profiler-mini-panel';
206+
this.miniPanel.className = 'profiler-mini-panel';
207+
201208
this.panel = document.createElement( 'div' );
202209
this.panel.id = 'profiler-panel';
203210

@@ -244,7 +251,7 @@ export class Profiler {
244251

245252
this.panel.append( resizer, header, this.contentWrapper );
246253

247-
this.domElement.append( this.toggleButton, this.panel );
254+
this.domElement.append( this.toggleButton, this.miniPanel, this.panel );
248255

249256
// Set initial position class
250257
this.panel.classList.add( `position-${this.position}` );
@@ -412,11 +419,174 @@ export class Profiler {
412419
this.tabsContainer.appendChild( tab.button );
413420
this.contentWrapper.appendChild( tab.content );
414421

422+
// Apply the current visibility state to the DOM elements
423+
if ( ! tab.isVisible ) {
424+
425+
tab.button.style.display = 'none';
426+
tab.content.style.display = 'none';
427+
428+
}
429+
430+
// If tab is builtin, add it to the profiler-toggle button
431+
if ( tab.builtin ) {
432+
433+
this.addBuiltinTab( tab );
434+
435+
}
436+
415437
// Update panel size when tabs change
416438
this.updatePanelSize();
417439

418440
}
419441

442+
addBuiltinTab( tab ) {
443+
444+
// Create a button for the builtin tab in the profiler-toggle
445+
const builtinButton = document.createElement( 'button' );
446+
builtinButton.className = 'builtin-tab-btn';
447+
448+
// Use icon if provided, otherwise use first letter
449+
if ( tab.icon ) {
450+
451+
builtinButton.innerHTML = tab.icon;
452+
453+
} else {
454+
455+
builtinButton.textContent = tab.button.textContent.charAt( 0 ).toUpperCase();
456+
457+
}
458+
459+
builtinButton.title = tab.button.textContent;
460+
461+
// Create mini-panel content container for this tab
462+
const miniContent = document.createElement( 'div' );
463+
miniContent.className = 'mini-panel-content';
464+
miniContent.style.display = 'none';
465+
466+
// Store references in the tab object
467+
tab.builtinButton = builtinButton;
468+
tab.miniContent = miniContent;
469+
470+
this.miniPanel.appendChild( miniContent );
471+
472+
builtinButton.onclick = ( e ) => {
473+
474+
e.stopPropagation(); // Prevent toggle panel from triggering
475+
476+
const isPanelVisible = this.panel.classList.contains( 'visible' );
477+
478+
if ( isPanelVisible ) {
479+
480+
// Panel is visible - navigate to tab
481+
if ( ! tab.isVisible ) {
482+
483+
tab.show();
484+
485+
}
486+
487+
if ( tab.isDetached ) {
488+
489+
// If tab is detached, just bring its window to front
490+
if ( tab.detachedWindow ) {
491+
492+
this.bringWindowToFront( tab.detachedWindow.panel );
493+
494+
}
495+
496+
} else {
497+
498+
// Activate the tab
499+
this.setActiveTab( tab.id );
500+
501+
}
502+
503+
} else {
504+
505+
// Panel is hidden - toggle mini-panel for this tab
506+
const isCurrentlyActive = miniContent.style.display !== 'none' && miniContent.children.length > 0;
507+
508+
// Hide all other mini-panel contents
509+
this.miniPanel.querySelectorAll( '.mini-panel-content' ).forEach( content => {
510+
511+
content.style.display = 'none';
512+
513+
} );
514+
515+
// Remove active state from all builtin buttons
516+
this.builtinTabsContainer.querySelectorAll( '.builtin-tab-btn' ).forEach( btn => {
517+
518+
btn.classList.remove( 'active' );
519+
520+
} );
521+
522+
if ( isCurrentlyActive ) {
523+
524+
// Toggle off - hide mini-panel and move content back
525+
this.miniPanel.classList.remove( 'visible' );
526+
miniContent.style.display = 'none';
527+
528+
// Move content back to main panel
529+
if ( miniContent.firstChild ) {
530+
531+
tab.content.appendChild( miniContent.firstChild );
532+
533+
}
534+
535+
} else {
536+
537+
// Toggle on - show mini-panel with this tab's content
538+
builtinButton.classList.add( 'active' );
539+
540+
// Move actual content to mini-panel (not clone) if not already there
541+
if ( ! miniContent.firstChild ) {
542+
543+
const actualContent = tab.content.querySelector( '.list-scroll-wrapper' ) || tab.content.firstElementChild;
544+
545+
if ( actualContent ) {
546+
547+
miniContent.appendChild( actualContent );
548+
549+
}
550+
551+
}
552+
553+
// Show after content is moved
554+
miniContent.style.display = 'block';
555+
this.miniPanel.classList.add( 'visible' );
556+
557+
}
558+
559+
}
560+
561+
};
562+
563+
this.builtinTabsContainer.appendChild( builtinButton );
564+
565+
// Store references
566+
tab.builtinButton = builtinButton;
567+
tab.miniContent = miniContent;
568+
tab.profiler = this;
569+
570+
// If the tab was hidden before being added, hide the builtin button
571+
if ( ! tab.isVisible ) {
572+
573+
builtinButton.style.display = 'none';
574+
miniContent.style.display = 'none';
575+
576+
// Hide the builtin-tabs-container if all builtin buttons are hidden
577+
const hasVisibleBuiltinButtons = Array.from( this.builtinTabsContainer.querySelectorAll( '.builtin-tab-btn' ) )
578+
.some( btn => btn.style.display !== 'none' );
579+
580+
if ( ! hasVisibleBuiltinButtons ) {
581+
582+
this.builtinTabsContainer.style.display = 'none';
583+
584+
}
585+
586+
}
587+
588+
}
589+
420590
updatePanelSize() {
421591

422592
// Check if there are any visible tabs in the panel
@@ -1305,6 +1475,83 @@ export class Profiler {
13051475

13061476
const isVisible = this.panel.classList.contains( 'visible' );
13071477

1478+
if ( isVisible ) {
1479+
1480+
// Save mini-panel state before hiding
1481+
this.savedMiniPanelState = {
1482+
isVisible: this.miniPanel.classList.contains( 'visible' ),
1483+
activeTabId: null,
1484+
contentMap: {}
1485+
};
1486+
1487+
// Find which tab was active in mini-panel
1488+
this.miniPanel.querySelectorAll( '.mini-panel-content' ).forEach( content => {
1489+
1490+
if ( content.style.display !== 'none' && content.firstChild ) {
1491+
1492+
// Find the tab that owns this content
1493+
Object.values( this.tabs ).forEach( tab => {
1494+
1495+
if ( tab.miniContent === content ) {
1496+
1497+
this.savedMiniPanelState.activeTabId = tab.id;
1498+
// Move content back to main panel
1499+
tab.content.appendChild( content.firstChild );
1500+
1501+
}
1502+
1503+
} );
1504+
1505+
}
1506+
1507+
} );
1508+
1509+
// Hide mini-panel temporarily
1510+
this.miniPanel.classList.remove( 'visible' );
1511+
1512+
// Hide all mini-panel contents
1513+
this.miniPanel.querySelectorAll( '.mini-panel-content' ).forEach( content => {
1514+
1515+
content.style.display = 'none';
1516+
1517+
} );
1518+
1519+
// Remove active state from builtin buttons
1520+
this.builtinTabsContainer.querySelectorAll( '.builtin-tab-btn' ).forEach( btn => {
1521+
1522+
btn.classList.remove( 'active' );
1523+
1524+
} );
1525+
1526+
} else {
1527+
1528+
// Restore mini-panel state when minimizing
1529+
if ( this.savedMiniPanelState && this.savedMiniPanelState.isVisible && this.savedMiniPanelState.activeTabId ) {
1530+
1531+
const tab = this.tabs[ this.savedMiniPanelState.activeTabId ];
1532+
1533+
if ( tab && tab.miniContent && tab.builtinButton ) {
1534+
1535+
// Restore mini-panel visibility
1536+
this.miniPanel.classList.add( 'visible' );
1537+
tab.miniContent.style.display = 'block';
1538+
tab.builtinButton.classList.add( 'active' );
1539+
1540+
// Move content back to mini-panel
1541+
const actualContent = tab.content.querySelector( '.list-scroll-wrapper, .profiler-content > *' );
1542+
1543+
if ( actualContent ) {
1544+
1545+
tab.miniContent.appendChild( actualContent );
1546+
1547+
}
1548+
1549+
}
1550+
1551+
}
1552+
1553+
}
1554+
13081555
this.detachedWindows.forEach( detachedWindow => {
13091556

13101557
if ( isVisible ) {

0 commit comments

Comments
 (0)