From 9d066ffbf73da7e72f74c5cd928c7b00a4335dda Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 25 Apr 2017 20:10:02 +0200 Subject: [PATCH] theming - buttons --- src/vs/base/browser/ui/button/button.css | 48 ++----------- src/vs/base/browser/ui/button/button.ts | 68 ++++++++++++++++++- src/vs/platform/theme/common/colorRegistry.ts | 3 +- src/vs/platform/theme/common/styler.ts | 10 ++- .../parts/files/browser/views/emptyView.ts | 4 ++ .../git/browser/views/empty/emptyView.ts | 6 +- .../parts/git/browser/views/huge/hugeView.ts | 5 +- .../views/noworkspace/noworkspaceView.ts | 4 ++ .../search/browser/media/searchviewlet.css | 8 +++ .../parts/search/browser/searchWidget.ts | 7 +- 10 files changed, 111 insertions(+), 52 deletions(-) diff --git a/src/vs/base/browser/ui/button/button.css b/src/vs/base/browser/ui/button/button.css index 101e0adc3ae..44a56a4e88f 100644 --- a/src/vs/base/browser/ui/button/button.css +++ b/src/vs/base/browser/ui/button/button.css @@ -3,11 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-button.disabled { - opacity: 0.4; - cursor: default; -} - .monaco-text-button { -moz-box-sizing: border-box; box-sizing: border-box; @@ -22,47 +17,12 @@ text-decoration: none !important; } -/*Theming support*/ - -.vs .monaco-button.monaco-text-button, -.vs-dark .monaco-button.monaco-text-button, -.hc-black .monaco-button.monaco-text-button { - color: white; -} - -.vs .monaco-button.monaco-text-button:hover, -.vs-dark .monaco-button.monaco-text-button:hover, -.hc-black .monaco-button.monaco-text-button:hover { - color: white !important; -} - -.vs .monaco-button.monaco-text-button { - background: #007ACC; -} - -.vs-dark .monaco-button.monaco-text-button { - background: #0E639C; -} - -.monaco-button.monaco-text-button:not(.disabled):hover, -.vs-dark .monaco-button.monaco-text-button:not(.disabled):hover, -.hc-black .monaco-button.monaco-text-button:not(.disabled):hover { - background: #006BB3; -} - -.monaco-button.monaco-text-button:not(.disabled):active { - background: #005F9E; -} - -.monaco-button:not(.disabled):hover { - background-color: #DDD -} - -.vs-dark .monaco-button:not(.disabled):hover, -.hc-black .monaco-button:not(.disabled):hover { - background-color: #2f3334; +.monaco-button.disabled { + opacity: 0.4; + cursor: default; } +/* Theming support */ .vs .monaco-text-button:focus, .vs-dark .monaco-text-button:focus { diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index cec07d6a46e..912f87f54bc 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -11,16 +11,45 @@ import DOM = require('vs/base/browser/dom'); import { Builder, $ } from 'vs/base/browser/builder'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; +import { Color } from "vs/base/common/color"; +import { mixin } from "vs/base/common/objects"; + +export interface IButtonOptions extends IButtonStyles { +} + +export interface IButtonStyles { + buttonBackground?: Color; + buttonHoverBackground?: Color; + buttonForeground?: Color; +} + +const defaultOptions: IButtonStyles = { + buttonBackground: Color.fromHex('#0E639C'), + buttonHoverBackground: Color.fromHex('#006BB3'), + buttonForeground: Color.white +}; export class Button extends EventEmitter { private $el: Builder; + private options: IButtonOptions; - constructor(container: Builder); - constructor(container: HTMLElement); - constructor(container: any) { + private buttonBackground: Color; + private buttonHoverBackground: Color; + private buttonForeground: Color; + + constructor(container: Builder, options?: IButtonOptions); + constructor(container: HTMLElement, options?: IButtonOptions); + constructor(container: any, options?: IButtonOptions) { super(); + this.options = options || Object.create(null); + mixin(this.options, defaultOptions, false); + + this.buttonBackground = this.options.buttonBackground; + this.buttonHoverBackground = this.options.buttonHoverBackground; + this.buttonForeground = this.options.buttonForeground; + this.$el = $('a.monaco-button').attr({ 'tabIndex': '0', 'role': 'button' @@ -50,6 +79,39 @@ export class Button extends EventEmitter { DOM.EventHelper.stop(event, true); } }); + + this.$el.on(DOM.EventType.MOUSE_OVER, (e: MouseEvent) => { + if (!this.$el.hasClass('disabled')) { + const hoverBackground = this.buttonHoverBackground ? this.buttonHoverBackground.toString() : null; + if (hoverBackground) { + this.$el.style('background-color', hoverBackground); + } + } + }); + + this.$el.on(DOM.EventType.MOUSE_OUT, (e: MouseEvent) => { + this.applyStyles(); // restore standard styles + }); + + this.applyStyles(); + } + + style(styles: IButtonStyles): void { + this.buttonForeground = styles.buttonForeground; + this.buttonBackground = styles.buttonBackground; + this.buttonHoverBackground = styles.buttonHoverBackground; + + this.applyStyles(); + } + + private applyStyles(): void { + if (this.$el) { + const background = this.buttonBackground ? this.buttonBackground.toString() : null; + const foreground = this.buttonForeground ? this.buttonForeground.toString() : null; + + this.$el.style('color', foreground); + this.$el.style('background-color', background); + } } getElement(): HTMLElement { diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 4aeb7b34e2f..96052726c8e 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -166,8 +166,9 @@ export const listDropBackground = registerColor('listDropBackground', { dark: '# export const pickerGroupForeground = registerColor('pickerGroupForeground', { dark: Color.fromHex('#0097FB').transparent(0.6), light: Color.fromHex('#007ACC').transparent(0.6), hc: Color.white }, nls.localize('pickerGroupForeground', "Quick picker color for grouping labels.")); export const pickerGroupBorder = registerColor('pickerGroupBorder', { dark: '#3F3F46', light: '#CCCEDB', hc: Color.white }, nls.localize('pickerGroupBorder', "Quick picker color for grouping borders.")); +export const buttonForeground = registerColor('buttonForeground', { dark: Color.white, light: Color.white, hc: Color.white }, nls.localize('buttonForeground', "Button foreground color.")); export const buttonBackground = registerColor('buttonBackground', { dark: '#0E639C', light: '#007ACC', hc: null }, nls.localize('buttonBackground', "Button background color.")); -export const buttonHoverBackground = registerColor('buttonHoverBackground', { dark: '#007ACC', light: '#006BB3', hc: null }, nls.localize('buttonHoverBackground', "Button background color when hovering.")); +export const buttonHoverBackground = registerColor('buttonHoverBackground', { dark: '#006BB3', light: '#006BB3', hc: null }, nls.localize('buttonHoverBackground', "Button background color when hovering.")); export const scrollbarShadow = registerColor('scrollbarShadow', { dark: '#000000', light: '#DDDDDD', hc: null }, nls.localize('scrollbarShadow', "Scrollbar shadow to indicate that the view is scrolled.")); export const scrollbarSliderBackground = registerColor('scrollbarSliderBackground', { dark: Color.fromHex('#797979').transparent(0.4), light: Color.fromHex('#646464').transparent(0.4), hc: Color.fromHex('#6FC3DF').transparent(0.6) }, nls.localize('scrollbarSliderBackground', "Slider background color.")); diff --git a/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts index 017d3eef027..6b6aaee18be 100644 --- a/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -6,7 +6,7 @@ 'use strict'; import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; -import { inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectBorder, inputBorder, foreground, editorBackground, highContrastBorder, inputActiveOptionBorder, listFocusBackground, listActiveSelectionBackground, listActiveSelectionForeground, listFocusAndSelectionBackground, listFocusAndSelectionForeground, listInactiveFocusBackground, listInactiveSelectionBackground, listHoverBackground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, infoBorder, infoBackground, warningBorder, warningBackground, errorBorder, errorBackground, highContrastOutline } from 'vs/platform/theme/common/colorRegistry'; +import { inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectBorder, inputBorder, foreground, editorBackground, highContrastBorder, inputActiveOptionBorder, listFocusBackground, listActiveSelectionBackground, listActiveSelectionForeground, listFocusAndSelectionBackground, listFocusAndSelectionForeground, listInactiveFocusBackground, listInactiveSelectionBackground, listHoverBackground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, infoBorder, infoBackground, warningBorder, warningBackground, errorBorder, errorBackground, highContrastOutline, buttonForeground, buttonBackground, buttonHoverBackground } from 'vs/platform/theme/common/colorRegistry'; import { IDisposable } from "vs/base/common/lifecycle"; import { SIDE_BAR_SECTION_HEADER_BACKGROUND } from "vs/workbench/common/theme"; @@ -190,4 +190,12 @@ export function attachHeaderViewStyler(widget: IThemable, themeService: IThemeSe headerBackground: (style && style.headerBackground) || SIDE_BAR_SECTION_HEADER_BACKGROUND, headerHighContrastBorder: (style && style.highContrastBorder) || highContrastBorder }); +} + +export function attachButtonStyler(widget: IThemable, themeService: IThemeService, style?: { buttonForeground?: ColorIdentifier, buttonBackground?: ColorIdentifier, buttonHoverBackground?: ColorIdentifier }): IDisposable { + return attachStyler(themeService, widget, { + buttonForeground: (style && style.buttonForeground) || buttonForeground, + buttonBackground: (style && style.buttonBackground) || buttonBackground, + buttonHoverBackground: (style && style.buttonHoverBackground) || buttonHoverBackground + }); } \ No newline at end of file diff --git a/src/vs/workbench/parts/files/browser/views/emptyView.ts b/src/vs/workbench/parts/files/browser/views/emptyView.ts index 7ba1b1c87f0..510fb8eab7b 100644 --- a/src/vs/workbench/parts/files/browser/views/emptyView.ts +++ b/src/vs/workbench/parts/files/browser/views/emptyView.ts @@ -16,12 +16,15 @@ import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { CollapsibleView } from 'vs/base/browser/ui/splitview/splitview'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/fileActions'; +import { attachButtonStyler } from "vs/platform/theme/common/styler"; +import { IThemeService } from "vs/platform/theme/common/themeService"; export class EmptyView extends CollapsibleView { private openFolderButton: Button; constructor( private actionRunner: IActionRunner, + @IThemeService private themeService: IThemeService, @IInstantiationService private instantiationService: IInstantiationService ) { super({ @@ -44,6 +47,7 @@ export class EmptyView extends CollapsibleView { let section = $('div.section').appendTo(container); this.openFolderButton = new Button(section); + attachButtonStyler(this.openFolderButton, this.themeService); this.openFolderButton.label = nls.localize('openFolder', "Open Folder"); this.openFolderButton.addListener('click', () => { const actionClass = env.isMacintosh ? OpenFileFolderAction : OpenFolderAction; diff --git a/src/vs/workbench/parts/git/browser/views/empty/emptyView.ts b/src/vs/workbench/parts/git/browser/views/empty/emptyView.ts index 49af1b5d95b..ae554e66dfa 100644 --- a/src/vs/workbench/parts/git/browser/views/empty/emptyView.ts +++ b/src/vs/workbench/parts/git/browser/views/empty/emptyView.ts @@ -21,6 +21,8 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; import { IGitService } from 'vs/workbench/parts/git/common/git'; +import { attachButtonStyler } from "vs/platform/theme/common/styler"; +import { IThemeService } from "vs/platform/theme/common/themeService"; var $ = Builder.$; @@ -50,7 +52,8 @@ export class EmptyView extends EventEmitter.EventEmitter implements GitView.IVie @IGitService gitService: IGitService, @IInstantiationService instantiationService: IInstantiationService, @IMessageService messageService: IMessageService, - @IFileService fileService: IFileService + @IFileService fileService: IFileService, + @IThemeService private themeService: IThemeService ) { super(); @@ -95,6 +98,7 @@ export class EmptyView extends EventEmitter.EventEmitter implements GitView.IVie var initSection = $('.section').appendTo(this.$el); this.initButton = new Button(initSection); + attachButtonStyler(this.initButton, this.themeService); this.initButton.label = nls.localize('gitinit', 'Initialize Git Repository'); this.initButton.addListener('click', (e) => { DOM.EventHelper.stop(e); diff --git a/src/vs/workbench/parts/git/browser/views/huge/hugeView.ts b/src/vs/workbench/parts/git/browser/views/huge/hugeView.ts index 8bc38d1b0f4..12439642a7d 100644 --- a/src/vs/workbench/parts/git/browser/views/huge/hugeView.ts +++ b/src/vs/workbench/parts/git/browser/views/huge/hugeView.ts @@ -16,6 +16,8 @@ import * as dom from 'vs/base/browser/dom'; import { IGitService } from 'vs/workbench/parts/git/common/git'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Button } from 'vs/base/browser/ui/button/button'; +import { attachButtonStyler } from "vs/platform/theme/common/styler"; +import { IThemeService } from "vs/platform/theme/common/themeService"; const $ = dom.$; @@ -24,7 +26,7 @@ export class HugeView extends ee.EventEmitter implements view.IView { ID = 'huge'; private _element: HTMLElement; - constructor( @IGitService private gitService: IGitService) { + constructor( @IGitService private gitService: IGitService, @IThemeService private themeService: IThemeService) { super(); } @@ -49,6 +51,7 @@ export class HugeView extends ee.EventEmitter implements view.IView { pre.textContent = 'git.allowLargeRepositories'; const button = new Button(this._element); + attachButtonStyler(button, this.themeService); button.label = nls.localize('allo', "Allow large repositories"); button.addListener('click', (e) => { dom.EventHelper.stop(e); diff --git a/src/vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView.ts b/src/vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView.ts index 564402ef651..71588fb4a11 100644 --- a/src/vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView.ts +++ b/src/vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView.ts @@ -17,6 +17,8 @@ import { Button } from 'vs/base/browser/ui/button/button'; import { IActionRunner, IAction } from 'vs/base/common/actions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/fileActions'; +import { attachButtonStyler } from "vs/platform/theme/common/styler"; +import { IThemeService } from "vs/platform/theme/common/themeService"; const $ = builder.$; export class NoWorkspaceView @@ -29,6 +31,7 @@ export class NoWorkspaceView constructor( private actionRunner: IActionRunner, @IInstantiationService private instantiationService: IInstantiationService, + @IThemeService private themeService: IThemeService ) { super(); } @@ -50,6 +53,7 @@ export class NoWorkspaceView ].join('')).getHTMLElement(); this._openFolderButton = new Button(this._element); + attachButtonStyler(this._openFolderButton, this.themeService); this._openFolderButton.label = nls.localize('openFolder', "Open Folder"); this._openFolderButton.addListener('click', () => { const actionClass = env.isMacintosh ? OpenFileFolderAction : OpenFolderAction; diff --git a/src/vs/workbench/parts/search/browser/media/searchviewlet.css b/src/vs/workbench/parts/search/browser/media/searchviewlet.css index 7832527b214..c223b283c85 100644 --- a/src/vs/workbench/parts/search/browser/media/searchviewlet.css +++ b/src/vs/workbench/parts/search/browser/media/searchviewlet.css @@ -410,6 +410,14 @@ color: #FFF; } +.vs .search-viewlet .search-widget .toggle-replace-button:hover { + background-color: rgba(0, 0, 0, 0.1) !important; +} + +.vs-dark .search-viewlet .search-widget .toggle-replace-button:hover { + background-color: rgba(255, 255, 255, 0.1) !important; +} + .vs .search-viewlet .search-widget .toggle-replace-button.collapse { background-image: url('expando-collapsed.svg'); } diff --git a/src/vs/workbench/parts/search/browser/searchWidget.ts b/src/vs/workbench/parts/search/browser/searchWidget.ts index 8659282904a..ecc5658ac00 100644 --- a/src/vs/workbench/parts/search/browser/searchWidget.ts +++ b/src/vs/workbench/parts/search/browser/searchWidget.ts @@ -27,8 +27,9 @@ import { isSearchViewletFocussed, appendKeyBindingLabel } from 'vs/workbench/par import { CONTEXT_FIND_WIDGET_NOT_VISIBLE } from 'vs/editor/contrib/find/common/findController'; import { HistoryNavigator } from 'vs/base/common/history'; import * as Constants from 'vs/workbench/parts/search/common/constants'; -import { attachInputBoxStyler, attachFindInputBoxStyler } from 'vs/platform/theme/common/styler'; +import { attachInputBoxStyler, attachFindInputBoxStyler, attachButtonStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { SIDE_BAR_BACKGROUND } from "vs/workbench/common/theme"; export interface ISearchWidgetOptions { value?: string; @@ -202,6 +203,10 @@ export class SearchWidget extends Widget { private renderToggleReplaceButton(parent: HTMLElement): void { this.toggleReplaceButton = this._register(new Button(parent)); + attachButtonStyler(this.toggleReplaceButton, this.themeService, { + buttonBackground: SIDE_BAR_BACKGROUND, + buttonHoverBackground: SIDE_BAR_BACKGROUND + }); this.toggleReplaceButton.icon = 'toggle-replace-button collapse'; this.toggleReplaceButton.addListener('click', () => this.onToggleReplaceButton()); this.toggleReplaceButton.getElement().title = nls.localize('search.replace.toggle.button.title', "Toggle Replace");