@@ -34,7 +34,7 @@ import { FrontendApplicationStateService } from '../frontend-application-state';
34
34
import { TabBarToolbarRegistry , TabBarToolbarFactory } from './tab-bar-toolbar' ;
35
35
import { ContextKeyService } from '../context-key-service' ;
36
36
import { Emitter } from '../../common/event' ;
37
- import { waitForRevealed , waitForClosed , PINNED_CLASS } from '../widgets' ;
37
+ import { waitForRevealed , waitForClosed , PINNED_CLASS , UnsafeWidgetUtilities } from '../widgets' ;
38
38
import { CorePreferences } from '../core-preferences' ;
39
39
import { BreadcrumbsRendererFactory } from '../breadcrumbs/breadcrumbs-renderer' ;
40
40
import { Deferred } from '../../common/promise-util' ;
@@ -85,10 +85,6 @@ export interface DockPanelRendererFactory {
85
85
*/
86
86
@injectable ( )
87
87
export class DockPanelRenderer implements DockLayout . IRenderer {
88
-
89
- @inject ( TheiaDockPanel . Factory )
90
- protected readonly dockPanelFactory : TheiaDockPanel . Factory ;
91
-
92
88
readonly tabBarClasses : string [ ] = [ ] ;
93
89
94
90
private readonly onDidCreateTabBarEmitter = new Emitter < TabBar < Widget > > ( ) ;
@@ -175,6 +171,7 @@ interface WidgetDragState {
175
171
leaveTimeout ?: number ;
176
172
}
177
173
174
+ export const MAXIMIZED_CLASS = 'theia-maximized' ;
178
175
/**
179
176
* The application shell manages the top-level widgets of the application. Use this class to
180
177
* add, remove, or activate a widget.
@@ -269,6 +266,8 @@ export class ApplicationShell extends Widget {
269
266
protected initializedDeferred = new Deferred < void > ( ) ;
270
267
initialized = this . initializedDeferred . promise ;
271
268
269
+ protected readonly maximizedElement : HTMLElement ;
270
+
272
271
/**
273
272
* Construct a new application shell.
274
273
*/
@@ -286,6 +285,16 @@ export class ApplicationShell extends Widget {
286
285
) {
287
286
super ( options as Widget . IOptions ) ;
288
287
288
+ this . maximizedElement = this . node . ownerDocument . createElement ( 'div' ) ;
289
+ this . maximizedElement . style . position = 'fixed' ;
290
+ this . maximizedElement . style . display = 'none' ;
291
+ this . maximizedElement . style . left = '0px' ;
292
+ this . maximizedElement . style . bottom = '0px' ;
293
+ this . maximizedElement . style . right = '0px' ;
294
+ this . maximizedElement . style . background = 'var(--theia-editor-background)' ;
295
+ this . maximizedElement . style . zIndex = '2000' ;
296
+ this . node . ownerDocument . body . appendChild ( this . maximizedElement ) ;
297
+
289
298
// Merge the user-defined application options with the default options
290
299
this . options = {
291
300
bottomPanel : {
@@ -301,6 +310,13 @@ export class ApplicationShell extends Widget {
301
310
...options ?. rightPanel || { }
302
311
}
303
312
} ;
313
+ if ( corePreferences ) {
314
+ corePreferences . onPreferenceChanged ( preference => {
315
+ if ( preference . preferenceName === 'window.menuBarVisibility' && ( preference . newValue === 'visible' || preference . oldValue === 'visible' ) ) {
316
+ this . handleMenuBarVisibility ( preference . newValue ) ;
317
+ }
318
+ } ) ;
319
+ }
304
320
}
305
321
306
322
@postConstruct ( )
@@ -561,7 +577,7 @@ export class ApplicationShell extends Widget {
561
577
mode : 'multiple-document' ,
562
578
renderer,
563
579
spacing : 0
564
- } ) ;
580
+ } , area => this . doToggleMaximized ( area ) ) ;
565
581
dockPanel . id = MAIN_AREA_ID ;
566
582
dockPanel . widgetAdded . connect ( ( _ , widget ) => this . fireDidAddWidget ( widget ) ) ;
567
583
dockPanel . widgetRemoved . connect ( ( _ , widget ) => this . fireDidRemoveWidget ( widget ) ) ;
@@ -658,7 +674,7 @@ export class ApplicationShell extends Widget {
658
674
mode : 'multiple-document' ,
659
675
renderer,
660
676
spacing : 0
661
- } ) ;
677
+ } , area => this . doToggleMaximized ( area ) ) ;
662
678
dockPanel . id = BOTTOM_AREA_ID ;
663
679
dockPanel . widgetAdded . connect ( ( sender , widget ) => {
664
680
this . refreshBottomPanelToggleButton ( ) ;
@@ -1178,9 +1194,6 @@ export class ApplicationShell extends Widget {
1178
1194
w . title . className = w . title . className . replace ( ' theia-mod-active' , '' ) ;
1179
1195
w = w . parent ;
1180
1196
}
1181
- // Reset the z-index to the default
1182
- // eslint-disable-next-line no-null/no-null
1183
- this . setZIndex ( oldValue . node , null ) ;
1184
1197
}
1185
1198
if ( newValue ) {
1186
1199
let w : Widget | null = newValue ;
@@ -1203,11 +1216,6 @@ export class ApplicationShell extends Widget {
1203
1216
// if widget was undefined, we wouldn't have gotten a panel back before
1204
1217
panel . markAsCurrent ( widget ! . title ) ;
1205
1218
}
1206
- // Add checks to ensure that the 'sash' for left panel is displayed correctly
1207
- if ( newValue . node . className === 'lm-Widget theia-view-container lm-DockPanel-widget' ) {
1208
- // Set the z-index so elements with `position: fixed` contained in the active widget are displayed correctly
1209
- this . setZIndex ( newValue . node , '1' ) ;
1210
- }
1211
1219
1212
1220
// activate another widget if an active widget will be closed
1213
1221
const onCloseRequest = newValue [ 'onCloseRequest' ] ;
@@ -1237,17 +1245,6 @@ export class ApplicationShell extends Widget {
1237
1245
this . onDidChangeActiveWidgetEmitter . fire ( args ) ;
1238
1246
}
1239
1247
1240
- /**
1241
- * Set the z-index of the given element and its ancestors to the value `z`.
1242
- */
1243
- private setZIndex ( element : HTMLElement , z : string | null ) : void {
1244
- element . style . zIndex = z || '' ;
1245
- const parent = element . parentElement ;
1246
- if ( parent && parent !== this . node ) {
1247
- this . setZIndex ( parent , z ) ;
1248
- }
1249
- }
1250
-
1251
1248
/**
1252
1249
* Track the given widget so it is considered in the `current` and `active` state of the shell.
1253
1250
*/
@@ -2118,11 +2115,75 @@ export class ApplicationShell extends Widget {
2118
2115
toggleMaximized ( widget : Widget | undefined = this . currentWidget ) : void {
2119
2116
const area = widget && this . getAreaPanelFor ( widget ) ;
2120
2117
if ( area instanceof TheiaDockPanel && ( area === this . mainPanel || area === this . bottomPanel ) ) {
2121
- area . toggleMaximized ( ) ;
2118
+ this . doToggleMaximized ( area ) ;
2122
2119
this . revealWidget ( widget ! . id ) ;
2123
2120
}
2124
2121
}
2125
2122
2123
+ protected handleMenuBarVisibility ( newValue : string ) : void {
2124
+ if ( newValue === 'visible' ) {
2125
+ const topRect = this . topPanel . node . getBoundingClientRect ( ) ;
2126
+ this . maximizedElement . style . top = `${ topRect . bottom } px` ;
2127
+ } else {
2128
+ this . maximizedElement . style . removeProperty ( 'top' ) ;
2129
+ }
2130
+ }
2131
+
2132
+ protected readonly onDidToggleMaximizedEmitter = new Emitter < Widget > ( ) ;
2133
+ readonly onDidToggleMaximized = this . onDidToggleMaximizedEmitter . event ;
2134
+
2135
+ protected unmaximize : ( ( ) => void ) | undefined ;
2136
+ doToggleMaximized ( area : TheiaDockPanel ) : void {
2137
+ if ( this . unmaximize ) {
2138
+ this . unmaximize ( ) ;
2139
+ this . unmaximize = undefined ;
2140
+ return ;
2141
+ }
2142
+
2143
+ const removedListener = ( ) => {
2144
+ if ( ! area . widgets ( ) . next ( ) . value ) {
2145
+ this . doToggleMaximized ( area ) ;
2146
+ }
2147
+ } ;
2148
+
2149
+ const parent = area . parent as SplitPanel ;
2150
+ const layout = area . parent ?. layout as SplitLayout ;
2151
+ const sizes = layout . relativeSizes ( ) . slice ( ) ;
2152
+ const stretch = SplitPanel . getStretch ( area ) ;
2153
+ const index = parent . widgets . indexOf ( area ) ;
2154
+ parent . layout ?. removeWidget ( area ) ;
2155
+
2156
+ // eslint-disable-next-line no-null/no-null
2157
+ this . maximizedElement . style . display = 'block' ;
2158
+ area . addClass ( MAXIMIZED_CLASS ) ;
2159
+ const topRect = this . topPanel . node . getBoundingClientRect ( ) ;
2160
+ UnsafeWidgetUtilities . attach ( area , this . maximizedElement ) ;
2161
+ this . maximizedElement . style . top = `${ topRect . bottom } px` ;
2162
+ area . fit ( ) ;
2163
+ const observer = new ResizeObserver ( entries => {
2164
+ area . fit ( ) ;
2165
+ } ) ;
2166
+ observer . observe ( this . maximizedElement ) ;
2167
+
2168
+ this . unmaximize = ( ) => {
2169
+ observer . unobserve ( this . maximizedElement ) ;
2170
+ observer . disconnect ( ) ;
2171
+ this . maximizedElement . style . display = 'none' ;
2172
+ area . removeClass ( MAXIMIZED_CLASS ) ;
2173
+ if ( area . isAttached ) {
2174
+ UnsafeWidgetUtilities . detach ( area ) ;
2175
+ }
2176
+ parent ?. insertWidget ( index , area ) ;
2177
+ SplitPanel . setStretch ( area , stretch ) ;
2178
+ layout . setRelativeSizes ( sizes ) ;
2179
+ parent . fit ( ) ;
2180
+ this . onDidToggleMaximizedEmitter . fire ( area ) ;
2181
+ area . widgetRemoved . disconnect ( removedListener ) ;
2182
+ } ;
2183
+
2184
+ area . widgetRemoved . connect ( removedListener ) ;
2185
+ this . onDidToggleMaximizedEmitter . fire ( area ) ;
2186
+ }
2126
2187
}
2127
2188
2128
2189
/**
0 commit comments