import { MessageLoop } from '@lumino/messaging' ; import { ISignal , Signal } from '@lumino/signaling' ; import { Platform } from '@lumino/domutils' ; import { Panel , PanelLayout , TabBar , Widget } from '@lumino/widgets' ; /**
 * A panel where visible widgets are stacked atop one another.
 *
 * #### Notes
 * This class provides a convenience wrapper around a [[PanelLayout]].
 */ export class EventedPanel extends Panel { /**
     * A signal emitted when a widget is removed from the panel.
     */ get widgetRemoved ( ) : ISignal < EventedPanel , Widget > { return this . _widgetRemoved ; } /**
     * A message handler invoked on a `'child-removed'` message.
     */ protected onChildRemoved ( msg ) { this . _widgetRemoved . emit ( msg . child ) ; } private _widgetRemoved = new Signal < EventedPanel , Widget > ( this ) ; } /**
 * A widget which combines a `TabBar` and a `EventedPanel`.
 *
 * #### Notes
 * This is a simple panel which handles the common case of a tab bar
 * placed next to a content area. The selected tab controls the widget
 * which is shown in the content area.
 *
 * For use cases which require more control than is provided by this
 * panel, the `TabBar` widget may be used independently.
 *
 * TODO: Support setting the direction??
 */ export class TabPanel extends Widget { param options constructor ( options = { } ) { super ( ) ; this . addClass ( 'p-TabPanel' ) ; this . tabBar = new TabBar < Widget > ( options ) ; this . tabBar . addClass ( 'p-TabPanel-tabBar' ) ; this . tabContents = new EventedPanel ( ) ; this . tabContents . addClass ( 'p-TabPanel-tabContents' ) ; this . tabBar . tabMoved . connect ( this . _onTabMoved , this ) ; this . tabBar . currentChanged . connect ( this . _onCurrentChanged , this ) ; this . tabBar . tabCloseRequested . connect ( this . _onTabCloseRequested , this ) ; this . tabBar . tabActivateRequested . connect ( this . _onTabActivateRequested , this ) ; this . tabContents . widgetRemoved . connect ( this . _onWidgetRemoved , this ) ; const layout = new PanelLayout ( ) ; layout . addWidget ( this . tabBar ) ; layout . addWidget ( this . tabContents ) ; this . layout = layout ; } /**
     * A signal emitted when the current tab is changed.
     *
     * #### Notes
     * This signal is emitted when the currently selected tab is changed
     * either through user or programmatic interaction.
     *
     * Notably, this signal is not emitted when the index of the current
     * tab changes due to tabs being inserted, removed, or moved. It is
     * only emitted when the actual current tab node is changed.
     */ get currentChanged ( ) : ISignal < this , TabPanel . ICurrentChangedArgs > { return this . _currentChanged ; } /**
     * Get the index of the currently selected tab.
     *
     * #### Notes
     * This will be `null` if no tab is selected.
     */ get currentIndex ( ) : number | null { const currentIndex = this . tabBar . currentIndex ; return currentIndex === - 1 ? null : currentIndex ; } /**
     * Set the index of the currently selected tab.
     *
     * #### Notes
     * If the index is out of range, it will be set to `null`.
     */ set currentIndex ( value ) { this . tabBar . currentIndex = value === null ? - 1 : value ; } /**
     * Get the currently selected widget.
     *
     * #### Notes
     * This will be `null` if there is no selected tab.
     */ get currentWidget ( ) : Widget | null { const title = this . tabBar . currentTitle ; return title ? title . owner : null ; } /**
     * Set the currently selected widget.
     *
     * #### Notes
     * If the widget is not in the panel, it will be set to `null`.
     */ set currentWidget ( value ) { this . tabBar . currentTitle = value ? value . title : null ; } /**
     * Get the whether the tabs are movable by the user.
     *
     * #### Notes
     * Tabs can always be moved programmatically.
     */ get tabsMovable ( ) : boolean { return this . tabBar . tabsMovable ; } /**
     * Set the whether the tabs are movable by the user.
     *
     * #### Notes
     * Tabs can always be moved programmatically.
     */ set tabsMovable ( value ) { this . tabBar . tabsMovable = value ; } /**
     * The tab bar used by the tab panel.
     *
     * #### Notes
     * Modifying the tab bar directly can lead to undefined behavior.
     */ readonly tabBar : TabBar < Widget > ; /**
     * The panel used by the tab panel.
     *
     * #### Notes
     * Modifying the panel directly can lead to undefined behavior.
     */ readonly tabContents : EventedPanel ; /**
     * A read-only array of the widgets in the panel.
     */ get widgets ( ) : ReadonlyArray < Widget > { return this . tabContents . widgets ; } param widget addWidget ( widget ) { this . insertWidget ( this . widgets . length , widget ) ; } param index param widget insertWidget ( index , widget ) { if ( widget !== this . currentWidget ) { widget . hide ( ) ; } this . tabContents . insertWidget ( index , widget ) ; this . tabBar . insertTab ( index , widget . title ) ; } /**
     * Handle the `currentChanged` signal from the tab bar.
     */ private _onCurrentChanged ( sender , args ) { const { previousIndex , previousTitle , currentIndex , currentTitle } = args ; const previousWidget = previousTitle ? previousTitle . owner : null ; const currentWidget = currentTitle ? currentTitle . owner : null ; if ( previousWidget ) { previousWidget . hide ( ) ; } if ( currentWidget ) { currentWidget . show ( ) ; } this . _currentChanged . emit ( { previousIndex , previousWidget , currentIndex , currentWidget , } ) ; if ( Platform . IS_EDGE || Platform . IS_IE ) { MessageLoop . flush ( ) ; } } /**
     * Handle the `tabActivateRequested` signal from the tab bar.
     */ private _onTabActivateRequested ( sender , args ) { args . title . owner . activate ( ) ; } /**
     * Handle the `tabCloseRequested` signal from the tab bar.
     */ private _onTabCloseRequested ( sender , args ) { args . title . owner . close ( ) ; } /**
     * Handle the `tabMoved` signal from the tab bar.
     */ private _onTabMoved ( sender , args ) { this . tabContents . insertWidget ( args . toIndex , args . title . owner ) ; } /**
     * Handle the `widgetRemoved` signal from the stacked panel.
     */ private _onWidgetRemoved ( sender , widget ) { this . tabBar . removeTab ( widget . title ) ; } private _currentChanged = new Signal < this , TabPanel . ICurrentChangedArgs > ( this ) ; } /**
 * The namespace for the `TabPanel` class statics.
 */ export namespace TabPanel { /**
     * An options object for initializing a tab panel.
     */ export interface IOptions { /**
         * Whether the tabs are movable by the user.
         *
         * The default is `false`.
         */ tabsMovable ? : boolean ; /**
         * The renderer for the panel's tab bar.
         *
         * The default is a shared renderer instance.
         */ renderer ? : TabBar . IRenderer < Widget > ; } /**
     * The arguments object for the `currentChanged` signal.
     */ export interface ICurrentChangedArgs { /**
         * The previously selected index.
         */ previousIndex : number ; /**
         * The previously selected widget.
         */ previousWidget : Widget | null ; /**
         * The currently selected index.
         */ currentIndex : number ; /**
         * The currently selected widget.
         */ currentWidget : Widget | null ; } }