Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #8226: Add a settings menu on left sidebar bottom #8372

Merged
merged 1 commit into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions packages/core/src/browser/common-frontend-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
import debounce = require('lodash.debounce');
import { injectable, inject } from 'inversify';
import { TabBar, Widget, Title } from '@phosphor/widgets';
import { MAIN_MENU_BAR, MenuContribution, MenuModelRegistry } from '../common/menu';
import { MAIN_MENU_BAR, SETTINGS_MENU, MenuContribution, MenuModelRegistry } from '../common/menu';
import { KeybindingContribution, KeybindingRegistry } from './keybinding';
import { FrontendApplicationContribution } from './frontend-application';
import { FrontendApplication, FrontendApplicationContribution } from './frontend-application';
import { CommandContribution, CommandRegistry, Command } from '../common/command';
import { UriAwareCommandHandler } from '../common/uri-command-handler';
import { SelectionService } from '../common/selection-service';
Expand Down Expand Up @@ -76,6 +76,9 @@ export namespace CommonMenus {
export const VIEW_LAYOUT = [...VIEW, '2_layout'];
export const VIEW_TOGGLE = [...VIEW, '3_toggle'];

export const SETTINGS_OPEN = [...SETTINGS_MENU, '1_settings_open'];
export const SETTINGS__THEME = [...SETTINGS_MENU, '2_settings_theme'];

// last menu item
export const HELP = [...MAIN_MENU_BAR, '9_help'];

Expand Down Expand Up @@ -324,7 +327,7 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
@inject(EnvVariablesServer)
protected readonly environments: EnvVariablesServer;

async configure(): Promise<void> {
async configure(app: FrontendApplication): Promise<void> {
const configDirUri = await this.environments.getConfigDirUri();
// Global settings
this.encodingRegistry.registerOverride({
Expand All @@ -351,6 +354,14 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
});
this.themeService.onThemeChange(() => this.updateThemePreference('workbench.colorTheme'));
this.iconThemes.onDidChangeCurrent(() => this.updateThemePreference('workbench.iconTheme'));

app.shell.leftPanelHandler.addMenu({
id: 'settings-menu',
iconClass: 'codicon codicon-settings-gear',
title: 'Settings',
menuPath: SETTINGS_MENU,
order: 0,
});
}

protected updateStyles(): void {
Expand Down Expand Up @@ -516,6 +527,13 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
registry.registerMenuAction(CommonMenus.FILE_SETTINGS_SUBMENU_THEME, {
commandId: CommonCommands.SELECT_ICON_THEME.id
});

registry.registerMenuAction(CommonMenus.SETTINGS__THEME, {
commandId: CommonCommands.SELECT_COLOR_THEME.id
});
registry.registerMenuAction(CommonMenus.SETTINGS__THEME, {
commandId: CommonCommands.SELECT_ICON_THEME.id
});
}

registerCommands(commandRegistry: CommandRegistry): void {
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/browser/frontend-application-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
ApplicationShell, ApplicationShellOptions, DockPanelRenderer, TabBarRenderer,
TabBarRendererFactory, ShellLayoutRestorer,
SidePanelHandler, SidePanelHandlerFactory,
SidebarBottomMenuWidget, SidebarBottomMenuWidgetFactory,
SplitPositionHandler, DockPanelRendererFactory, ApplicationShellLayoutMigration, ApplicationShellLayoutMigrationError
} from './shell';
import { StatusBar, StatusBarImpl } from './status-bar/status-bar';
Expand Down Expand Up @@ -128,6 +129,8 @@ export const frontendApplicationModule = new ContainerModule((bind, unbind, isBo
bind(ApplicationShell).toSelf().inSingletonScope();
bind(SidePanelHandlerFactory).toAutoFactory(SidePanelHandler);
bind(SidePanelHandler).toSelf();
bind(SidebarBottomMenuWidgetFactory).toAutoFactory(SidebarBottomMenuWidget);
bind(SidebarBottomMenuWidget).toSelf();
bind(SplitPositionHandler).toSelf().inSingletonScope();

bindContributionProvider(bind, TabBarToolbarContribution);
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/browser/shell/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
export * from './application-shell';
export * from './shell-layout-restorer';
export * from './side-panel-handler';
export * from './sidebar-bottom-menu-widget';
export * from './split-panels';
export * from './tab-bars';
export * from './view-contribution';
36 changes: 33 additions & 3 deletions packages/core/src/browser/shell/side-panel-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@

import { injectable, inject } from 'inversify';
import { find, map, toArray, some } from '@phosphor/algorithm';
import { TabBar, Widget, DockPanel, Title, Panel, BoxPanel, BoxLayout, SplitPanel } from '@phosphor/widgets';
import { TabBar, Widget, DockPanel, Title, Panel, BoxPanel, BoxLayout, SplitPanel, PanelLayout } from '@phosphor/widgets';
import { MimeData } from '@phosphor/coreutils';
import { Drag } from '@phosphor/dragdrop';
import { AttachedProperty } from '@phosphor/properties';
import { TabBarRendererFactory, TabBarRenderer, SHELL_TABBAR_CONTEXT_MENU, SideTabBar } from './tab-bars';
import { SidebarBottomMenuWidget, SidebarBottomMenuWidgetFactory, SidebarBottomMenu } from './sidebar-bottom-menu-widget';
import { SplitPositionHandler, SplitPositionOptions } from './split-panels';
import { animationFrame } from '../browser';
import { FrontendApplicationStateService } from '../frontend-application-state';
Expand Down Expand Up @@ -64,6 +65,12 @@ export class SidePanelHandler {
* tab bar itself remains visible as long as there is at least one widget.
*/
tabBar: SideTabBar;
/**
* The menu placed on the sidebar bottom.
* Displayed as icons.
* Open menus when on clicks.
*/
bottomMenu: SidebarBottomMenuWidget;
/**
* A tool bar, which displays a title and widget specific command buttons.
*/
Expand Down Expand Up @@ -100,6 +107,7 @@ export class SidePanelHandler {
@inject(TabBarToolbarRegistry) protected tabBarToolBarRegistry: TabBarToolbarRegistry;
@inject(TabBarToolbarFactory) protected tabBarToolBarFactory: () => TabBarToolbar;
@inject(TabBarRendererFactory) protected tabBarRendererFactory: () => TabBarRenderer;
@inject(SidebarBottomMenuWidgetFactory) protected sidebarBottomWidgetFactory: () => SidebarBottomMenuWidget;
@inject(SplitPositionHandler) protected splitPositionHandler: SplitPositionHandler;
@inject(FrontendApplicationStateService) protected readonly applicationStateService: FrontendApplicationStateService;

Expand All @@ -113,6 +121,7 @@ export class SidePanelHandler {
this.side = side;
this.options = options;
this.tabBar = this.createSideBar();
this.bottomMenu = this.createSidebarBottomMenu();
this.toolBar = this.createToolbar();
this.dockPanel = this.createSidePanel();
this.container = this.createContainer();
Expand Down Expand Up @@ -178,6 +187,12 @@ export class SidePanelHandler {
return toolbar;
}

protected createSidebarBottomMenu(): SidebarBottomMenuWidget {
const bottomMenu = this.sidebarBottomWidgetFactory();
bottomMenu.addClass('theia-sidebar-bottom-menu');
return bottomMenu;
}

protected showContextMenu(e: MouseEvent): void {
const title = this.tabBar.currentTitle;
if (!title) {
Expand Down Expand Up @@ -214,9 +229,15 @@ export class SidePanelHandler {
throw new Error('Illegal argument: ' + side);
}
const containerLayout = new BoxLayout({ direction, spacing: 0 });
BoxPanel.setStretch(this.tabBar, 0);
containerLayout.addWidget(this.tabBar);
const sidebarContainerLayout = new PanelLayout();
const sidebarContainer = new Panel({ layout: sidebarContainerLayout });
sidebarContainer.addClass('theia-app-sidebar-container');
sidebarContainerLayout.addWidget(this.tabBar);
sidebarContainerLayout.addWidget(this.bottomMenu);

BoxPanel.setStretch(sidebarContainer, 0);
BoxPanel.setStretch(contentPanel, 1);
containerLayout.addWidget(sidebarContainer);
containerLayout.addWidget(contentPanel);
const boxPanel = new BoxPanel({ layout: containerLayout });
boxPanel.id = 'theia-' + side + '-content-panel';
Expand Down Expand Up @@ -364,6 +385,15 @@ export class SidePanelHandler {
this.dockPanel.addWidget(widget);
}

/**
* Add a menu to the sidebar bottom.
*
* If the menu is already added, it will be ignored.
*/
addMenu(menu: SidebarBottomMenu): void {
this.bottomMenu.addMenu(menu);
}

// should be a property to preserve fn identity
protected updateToolbarTitle = (): void => {
const currentTitle = this.tabBar && this.tabBar.currentTitle;
Expand Down
77 changes: 77 additions & 0 deletions packages/core/src/browser/shell/sidebar-bottom-menu-widget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/********************************************************************************
* Copyright (C) 2020 Alibaba Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { injectable, inject } from 'inversify';
import * as React from 'react';
import { ReactWidget } from '../widgets';
import { ContextMenuRenderer } from '../context-menu-renderer';
import { MenuPath } from '../../common/menu';

export const SidebarBottomMenuWidgetFactory = Symbol('SidebarBottomMenuWidgetFactory');

export interface SidebarBottomMenu {
id: string;
iconClass: string;
title: string;
menuPath: MenuPath;
order: number; // smaller one place lower
}

/**
* The menu widget placed on the bottom of the sidebar.
*/
@injectable()
export class SidebarBottomMenuWidget extends ReactWidget {
protected readonly menus: SidebarBottomMenu[];

@inject(ContextMenuRenderer)
protected readonly contextMenuRenderer: ContextMenuRenderer;

constructor() {
super();
this.menus = [];
}

addMenu(menu: SidebarBottomMenu): void {
datou0412 marked this conversation as resolved.
Show resolved Hide resolved
const exists = this.menus.find(m => m.id === menu.id);
if (exists) {
return;
}
this.menus.push(menu);
this.update();
}

protected onClick(e: React.MouseEvent<HTMLElement, MouseEvent>, menuPath: MenuPath): void {
this.contextMenuRenderer.render({
menuPath,
anchor: {
x: e.clientX,
y: e.clientY,
}
});
}

protected render(): React.ReactNode {
return <React.Fragment>
{this.menus.sort((a, b) => a.order - b.order).map(menu => <i
key={menu.id}
className={menu.iconClass}
title={menu.title}
onClick={e => this.onClick(e, menu.menuPath)}
/>)}
</React.Fragment>;
}
}
39 changes: 38 additions & 1 deletion packages/core/src/browser/style/sidepanel.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
:root {
--theia-private-sidebar-tab-width: 50px;
--theia-private-sidebar-tab-height: 32px;
--theia-private-sidebar-tab-padding-top-and-bottom: 11px;
--theia-private-sidebar-tab-padding-left-and-right: 10px;
--theia-private-sidebar-scrollbar-rail-width: 7px;
--theia-private-sidebar-scrollbar-width: 5px;
--theia-private-sidebar-icon-size: 28px;
Expand All @@ -46,7 +48,7 @@

.p-TabBar.theia-app-sides .p-TabBar-tab {
position: relative;
padding: 11px 10px;
padding: var(--theia-private-sidebar-tab-padding-top-and-bottom) var(--theia-private-sidebar-tab-padding-left-and-right);
background: var(--theia-activityBar-background);
flex-direction: column;
justify-content: center;
Expand Down Expand Up @@ -171,7 +173,42 @@
color: var(--theia-sideBar-foreground);
}

.theia-app-sidebar-container {
min-width: var(--theia-private-sidebar-tab-width);
max-width: var(--theia-private-sidebar-tab-width);
background: var(--theia-activityBar-background);
display: flex;
flex-direction: column;
}

.theia-app-sidebar-container .theia-app-sides {
flex-grow: 1;
}

.theia-app-sidebar-container .theia-sidebar-bottom-menu {
flex-shrink: 0;
}

.p-Widget.theia-sidebar-bottom-menu {
background-color: var(--theia-activityBar-background);
display: flex;
flex-direction: column-reverse;
}

.p-Widget.theia-sidebar-bottom-menu i {
padding: var(--theia-private-sidebar-tab-padding-top-and-bottom) var(--theia-private-sidebar-tab-padding-left-and-right);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
color: var(--theia-activityBar-inactiveForeground);
background-color: var(--theia-activityBar-background);
font-size: var(--theia-private-sidebar-icon-size);
}

.theia-sidebar-bottom-menu i:hover {
color: var(--theia-activityBar-foreground);
}

/*-----------------------------------------------------------------------------
| Perfect scrollbar
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/common/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export type MenuPath = string[];

export const MAIN_MENU_BAR: MenuPath = ['menubar'];

export const SETTINGS_MENU: MenuPath = ['settings_menu'];

export const MenuContribution = Symbol('MenuContribution');

/**
Expand Down
4 changes: 4 additions & 0 deletions packages/keymaps/src/browser/keymaps-frontend-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ export class KeymapsFrontendContribution extends AbstractViewContribution<Keybin
commandId: KeymapsCommands.OPEN_KEYMAPS.id,
order: 'a20'
});
menus.registerMenuAction(CommonMenus.SETTINGS_OPEN, {
commandId: KeymapsCommands.OPEN_KEYMAPS.id,
order: 'a20'
});
}

registerKeybindings(keybindings: KeybindingRegistry): void {
Expand Down
5 changes: 5 additions & 0 deletions packages/preferences/src/browser/preferences-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ export class PreferencesContribution extends AbstractViewContribution<Preference
label: CommonCommands.OPEN_PREFERENCES.label,
order: 'a10',
});
menus.registerMenuAction(CommonMenus.SETTINGS_OPEN, {
commandId: CommonCommands.OPEN_PREFERENCES.id,
label: CommonCommands.OPEN_PREFERENCES.label,
order: 'a10',
});
menus.registerMenuAction(PreferenceMenus.PREFERENCE_EDITOR_CONTEXT_MENU, {
commandId: PreferencesCommands.RESET_PREFERENCE.id,
label: PreferencesCommands.RESET_PREFERENCE.label,
Expand Down