From 52ecb5bf560ab517495463b6c392586977a9925b Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Thu, 8 Aug 2019 18:33:39 -0700 Subject: [PATCH] Dialog checkbox (#78533) * add simple checkbox adopt in dialogs * fix wrap * finalize naming --- .../base/browser/ui/checkbox/check-dark.svg | 3 ++ .../base/browser/ui/checkbox/check-light.svg | 3 ++ src/vs/base/browser/ui/checkbox/checkbox.css | 22 ++++++++- src/vs/base/browser/ui/checkbox/checkbox.ts | 49 +++++++++++++++++++ src/vs/base/browser/ui/dialog/dialog.css | 7 ++- src/vs/base/browser/ui/dialog/dialog.ts | 42 +++++++++++++--- .../platform/dialogs/browser/dialogService.ts | 43 ++++++++-------- src/vs/platform/dialogs/common/dialogs.ts | 4 +- src/vs/platform/theme/common/colorRegistry.ts | 4 ++ src/vs/platform/theme/common/styler.ts | 10 +++- .../preferences/browser/settingsWidgets.ts | 8 +-- 11 files changed, 158 insertions(+), 37 deletions(-) create mode 100644 src/vs/base/browser/ui/checkbox/check-dark.svg create mode 100644 src/vs/base/browser/ui/checkbox/check-light.svg diff --git a/src/vs/base/browser/ui/checkbox/check-dark.svg b/src/vs/base/browser/ui/checkbox/check-dark.svg new file mode 100644 index 00000000000..865cc83c347 --- /dev/null +++ b/src/vs/base/browser/ui/checkbox/check-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/checkbox/check-light.svg b/src/vs/base/browser/ui/checkbox/check-light.svg new file mode 100644 index 00000000000..e1a546660ed --- /dev/null +++ b/src/vs/base/browser/ui/checkbox/check-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/checkbox/checkbox.css b/src/vs/base/browser/ui/checkbox/checkbox.css index 65f1dcd2318..26f48b88c02 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.css +++ b/src/vs/base/browser/ui/checkbox/checkbox.css @@ -39,4 +39,24 @@ .hc-black .monaco-custom-checkbox:hover { background: none; -} \ No newline at end of file +} + +.monaco-custom-checkbox.monaco-simple-checkbox { + height: 18px; + width: 18px; + border: 1px solid transparent; + border-radius: 3px; + margin-right: 9px; + margin-left: 0px; + padding: 0px; + opacity: 1; + background-size: 16px !important; +} + +.monaco-custom-checkbox.monaco-simple-checkbox.checked { + background: url('check-light.svg') center center no-repeat; +} + +.monaco-custom-checkbox.monaco-simple-checkbox.checked { + background: url('check-dark.svg') center center no-repeat; +} diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index ed0bcfa0ab1..f5fe47cdd85 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -25,6 +25,12 @@ export interface ICheckboxStyles { inputActiveOptionBackground?: Color; } +export interface ISimpleCheckboxStyles { + checkboxBackground?: Color; + checkboxBorder?: Color; + checkboxForeground?: Color; +} + const defaultOpts = { inputActiveOptionBorder: Color.fromHex('#007ACC00'), inputActiveOptionBackground: Color.fromHex('#0E639C50') @@ -174,3 +180,46 @@ export class Checkbox extends Widget { this.domNode.setAttribute('aria-disabled', String(true)); } } + +export class SimpleCheckbox extends Widget { + private checkbox: Checkbox; + private styles: ISimpleCheckboxStyles; + + readonly domNode: HTMLElement; + + constructor(private title: string, private isChecked: boolean) { + super(); + + this.checkbox = new Checkbox({ title: this.title, isChecked: this.isChecked, actionClassName: 'monaco-simple-checkbox' }); + + this.domNode = this.checkbox.domNode; + + this.styles = {}; + + this.checkbox.onChange(() => { + this.applyStyles(); + }); + } + + get checked(): boolean { + return this.checkbox.checked; + } + + set checked(newIsChecked: boolean) { + this.checkbox.checked = newIsChecked; + + this.applyStyles(); + } + + style(styles: ISimpleCheckboxStyles): void { + this.styles = styles; + + this.applyStyles(); + } + + protected applyStyles(): void { + this.domNode.style.color = this.styles.checkboxForeground ? this.styles.checkboxForeground.toString() : null; + this.domNode.style.backgroundColor = this.styles.checkboxBackground ? this.styles.checkboxBackground.toString() : null; + this.domNode.style.borderColor = this.styles.checkboxBorder ? this.styles.checkboxBorder.toString() : null; + } +} diff --git a/src/vs/base/browser/ui/dialog/dialog.css b/src/vs/base/browser/ui/dialog/dialog.css index e05ed90a949..83d8d7eca66 100644 --- a/src/vs/base/browser/ui/dialog/dialog.css +++ b/src/vs/base/browser/ui/dialog/dialog.css @@ -149,6 +149,11 @@ outline-style: solid; } +.monaco-workbench .dialog-box .dialog-message-row .dialog-message-container .dialog-checkbox-row { + padding: 15px 0px 0px; + display: flex; +} + /** Dialog: Buttons Row */ .monaco-workbench .dialog-box > .dialog-buttons-row { display: flex; @@ -175,4 +180,4 @@ margin: 4px 5px; /* allows button focus outline to be visible */ overflow: hidden; text-overflow: ellipsis; -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index 2b5d836146d..f6b707d975d 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -16,15 +16,23 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { Action } from 'vs/base/common/actions'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { isMacintosh, isLinux } from 'vs/base/common/platform'; +import { SimpleCheckbox, ISimpleCheckboxStyles } from 'vs/base/browser/ui/checkbox/checkbox'; export interface IDialogOptions { cancelId?: number; detail?: string; + checkboxLabel?: string; + checkboxChecked?: boolean; type?: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending'; keyEventProcessor?: (event: StandardKeyboardEvent) => void; } -export interface IDialogStyles extends IButtonStyles { +export interface IDialogResult { + button: number; + checkboxChecked?: boolean; +} + +export interface IDialogStyles extends IButtonStyles, ISimpleCheckboxStyles { dialogForeground?: Color; dialogBackground?: Color; dialogShadow?: Color; @@ -42,6 +50,7 @@ export class Dialog extends Disposable { private buttonsContainer: HTMLElement | undefined; private messageDetailElement: HTMLElement | undefined; private iconElement: HTMLElement | undefined; + private checkbox: SimpleCheckbox | undefined; private toolbarContainer: HTMLElement | undefined; private buttonGroup: ButtonGroup | undefined; private styles: IDialogStyles | undefined; @@ -68,6 +77,19 @@ export class Dialog extends Disposable { this.messageDetailElement = messageContainer.appendChild($('.dialog-message-detail')); this.messageDetailElement.innerText = this.options.detail ? this.options.detail : message; + if (this.options.checkboxLabel) { + const checkboxRowElement = messageContainer.appendChild($('.dialog-checkbox-row')); + + this.checkbox = this._register(new SimpleCheckbox(this.options.checkboxLabel, !!this.options.checkboxChecked)); + + checkboxRowElement.appendChild(this.checkbox.domNode); + + const checkboxMessageElement = checkboxRowElement.appendChild($('.dialog-checkbox-message')); + checkboxMessageElement.innerText = this.options.checkboxLabel; + } + + + const toolbarRowElement = this.element.appendChild($('.dialog-toolbar-row')); this.toolbarContainer = toolbarRowElement.appendChild($('.dialog-toolbar')); } @@ -78,12 +100,12 @@ export class Dialog extends Disposable { } } - async show(): Promise { + async show(): Promise { this.focusToReturn = document.activeElement as HTMLElement; - return new Promise((resolve) => { + return new Promise((resolve) => { if (!this.element || !this.buttonsContainer || !this.iconElement || !this.toolbarContainer) { - resolve(0); + resolve({ button: 0 }); return; } @@ -112,7 +134,7 @@ export class Dialog extends Disposable { this._register(button.onDidClick(e => { EventHelper.stop(e); - resolve(buttonMap[index].index); + resolve({ button: buttonMap[index].index, checkboxChecked: this.checkbox ? this.checkbox.checked : undefined }); })); }); @@ -147,7 +169,7 @@ export class Dialog extends Disposable { const evt = new StandardKeyboardEvent(e); if (evt.equals(KeyCode.Escape)) { - resolve(this.options.cancelId || 0); + resolve({ button: this.options.cancelId || 0, checkboxChecked: this.checkbox ? this.checkbox.checked : undefined }); } })); @@ -187,7 +209,7 @@ export class Dialog extends Disposable { const actionBar = new ActionBar(this.toolbarContainer, {}); const action = new Action('dialog.close', nls.localize('dialogClose', "Close Dialog"), 'dialog-close-action', true, () => { - resolve(this.options.cancelId || 0); + resolve({ button: this.options.cancelId || 0, checkboxChecked: this.checkbox ? this.checkbox.checked : undefined }); return Promise.resolve(); }); @@ -221,6 +243,10 @@ export class Dialog extends Disposable { if (this.buttonGroup) { this.buttonGroup.buttons.forEach(button => button.style(style)); } + + if (this.checkbox) { + this.checkbox.style(style); + } } } } @@ -261,4 +287,4 @@ export class Dialog extends Disposable { return buttonMap; } -} \ No newline at end of file +} diff --git a/src/vs/platform/dialogs/browser/dialogService.ts b/src/vs/platform/dialogs/browser/dialogService.ts index 5a906768029..347e242dd6d 100644 --- a/src/vs/platform/dialogs/browser/dialogService.ts +++ b/src/vs/platform/dialogs/browser/dialogService.ts @@ -40,32 +40,35 @@ export class DialogService implements IDialogService { buttons.push(nls.localize('cancelButton', "Cancel")); } - const severity = this.getSeverity(confirmation.type || 'none'); - const result = await this.show(severity, confirmation.message, buttons, { cancelId: 1, detail: confirmation.detail }); + const dialogDisposables = new DisposableStore(); + const dialog = new Dialog( + this.layoutService.container, + confirmation.message, + buttons, + { + detail: confirmation.detail, + cancelId: 1, + type: confirmation.type, + keyEventProcessor: (event: StandardKeyboardEvent) => { + EventHelper.stop(event, true); + }, + checkboxChecked: confirmation.checkbox ? confirmation.checkbox.checked : undefined, + checkboxLabel: confirmation.checkbox ? confirmation.checkbox.label : undefined + }); - return { confirmed: result === 0 }; - } + dialogDisposables.add(dialog); + dialogDisposables.add(attachDialogStyler(dialog, this.themeService)); - private getSeverity(type: DialogType): Severity { - switch (type) { - case 'error': - return Severity.Error; - case 'warning': - return Severity.Warning; - case 'question': - case 'info': - return Severity.Info; - case 'none': - default: - return Severity.Ignore; - } + const result = await dialog.show(); + dialogDisposables.dispose(); + + return { confirmed: result.button === 0, checkboxChecked: result.checkboxChecked }; } private getDialogType(severity: Severity): DialogType { return (severity === Severity.Info) ? 'question' : (severity === Severity.Error) ? 'error' : (severity === Severity.Warning) ? 'warning' : 'none'; } - async show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise { this.logService.trace('DialogService#show', message); @@ -86,9 +89,9 @@ export class DialogService implements IDialogService { dialogDisposables.add(dialog); dialogDisposables.add(attachDialogStyler(dialog, this.themeService)); - const choice = await dialog.show(); + const result = await dialog.show(); dialogDisposables.dispose(); - return choice; + return result.button; } } diff --git a/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index ea57ce91233..6999633d9f0 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -127,6 +127,8 @@ export const IDialogService = createDecorator('dialogService'); export interface IDialogOptions { cancelId?: number; detail?: string; + checkboxLabel?: string; + checkboxChecked?: boolean; } /** @@ -234,4 +236,4 @@ export function getConfirmMessage(start: string, resourcesToConfirm: URI[]): str message.push(''); return message.join('\n'); -} \ No newline at end of file +} diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 6f356bfe66b..47b428fbb84 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -222,6 +222,10 @@ export const selectListBackground = registerColor('dropdown.listBackground', { d export const selectForeground = registerColor('dropdown.foreground', { dark: '#F0F0F0', light: null, hc: Color.white }, nls.localize('dropdownForeground', "Dropdown foreground.")); export const selectBorder = registerColor('dropdown.border', { dark: selectBackground, light: '#CECECE', hc: contrastBorder }, nls.localize('dropdownBorder', "Dropdown border.")); +export const simpleCheckboxBackground = registerColor('checkbox.background', { dark: selectBackground, light: selectBackground, hc: selectBackground }, nls.localize('checkbox.background', "Background color of checkbox widget.")); +export const simpleCheckboxForeground = registerColor('checkbox.foreground', { dark: selectForeground, light: selectForeground, hc: selectForeground }, nls.localize('checkbox.foreground', "Foreground color of checkbox widget.")); +export const simpleCheckboxBorder = registerColor('checkbox.border', { dark: selectBorder, light: selectBorder, hc: selectBorder }, nls.localize('checkbox.border', "Border color of checkbox widget.")); + export const listFocusBackground = registerColor('list.focusBackground', { dark: '#062F4A', light: '#D6EBFF', hc: null }, nls.localize('listFocusBackground', "List/Tree background color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); export const listFocusForeground = registerColor('list.focusForeground', { dark: null, light: null, hc: null }, nls.localize('listFocusForeground', "List/Tree foreground color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); export const listActiveSelectionBackground = registerColor('list.activeSelectionBackground', { dark: '#094771', light: '#0074E8', hc: null }, nls.localize('listActiveSelectionBackground', "List/Tree background color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); diff --git a/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts index c1732ca1735..40de3567375 100644 --- a/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; -import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry'; +import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground } from 'vs/platform/theme/common/colorRegistry'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; @@ -341,6 +341,9 @@ export interface IDialogStyleOverrides extends IButtonStyleOverrides { dialogBackground?: ColorIdentifier; dialogShadow?: ColorIdentifier; dialogBorder?: ColorIdentifier; + checkboxBorder?: ColorIdentifier; + checkboxBackground?: ColorIdentifier; + checkboxForeground?: ColorIdentifier; } export const defaultDialogStyles = { @@ -351,7 +354,10 @@ export const defaultDialogStyles = { buttonForeground: buttonForeground, buttonBackground: buttonBackground, buttonHoverBackground: buttonHoverBackground, - buttonBorder: contrastBorder + buttonBorder: contrastBorder, + checkboxBorder: simpleCheckboxBorder, + checkboxBackground: simpleCheckboxBackground, + checkboxForeground: simpleCheckboxForeground }; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts index cb7d13e51e5..6a2fbad2b88 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts @@ -16,7 +16,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import 'vs/css!./media/settingsWidgets'; import { localize } from 'vs/nls'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { foreground, inputBackground, inputBorder, inputForeground, listActiveSelectionBackground, listActiveSelectionForeground, listHoverBackground, listHoverForeground, listInactiveSelectionBackground, listInactiveSelectionForeground, registerColor, selectBackground, selectBorder, selectForeground, textLinkForeground, textPreformatForeground, editorWidgetBorder, textLinkActiveForeground } from 'vs/platform/theme/common/colorRegistry'; +import { foreground, inputBackground, inputBorder, inputForeground, listActiveSelectionBackground, listActiveSelectionForeground, listHoverBackground, listHoverForeground, listInactiveSelectionBackground, listInactiveSelectionForeground, registerColor, selectBackground, selectBorder, selectForeground, textLinkForeground, textPreformatForeground, editorWidgetBorder, textLinkActiveForeground, simpleCheckboxBackground, simpleCheckboxForeground, simpleCheckboxBorder } from 'vs/platform/theme/common/colorRegistry'; import { attachButtonStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { disposableTimeout } from 'vs/base/common/async'; @@ -37,9 +37,9 @@ export const settingsSelectBorder = registerColor('settings.dropdownBorder', { d export const settingsSelectListBorder = registerColor('settings.dropdownListBorder', { dark: editorWidgetBorder, light: editorWidgetBorder, hc: editorWidgetBorder }, localize('settingsDropdownListBorder', "(For settings editor preview) Settings editor dropdown list border. This surrounds the options and separates the options from the description.")); // Bool control colors -export const settingsCheckboxBackground = registerColor('settings.checkboxBackground', { dark: selectBackground, light: selectBackground, hc: selectBackground }, localize('settingsCheckboxBackground', "(For settings editor preview) Settings editor checkbox background.")); -export const settingsCheckboxForeground = registerColor('settings.checkboxForeground', { dark: selectForeground, light: selectForeground, hc: selectForeground }, localize('settingsCheckboxForeground', "(For settings editor preview) Settings editor checkbox foreground.")); -export const settingsCheckboxBorder = registerColor('settings.checkboxBorder', { dark: selectBorder, light: selectBorder, hc: selectBorder }, localize('settingsCheckboxBorder', "(For settings editor preview) Settings editor checkbox border.")); +export const settingsCheckboxBackground = registerColor('settings.checkboxBackground', { dark: simpleCheckboxBackground, light: simpleCheckboxBackground, hc: simpleCheckboxBackground }, localize('settingsCheckboxBackground', "(For settings editor preview) Settings editor checkbox background.")); +export const settingsCheckboxForeground = registerColor('settings.checkboxForeground', { dark: simpleCheckboxForeground, light: simpleCheckboxForeground, hc: simpleCheckboxForeground }, localize('settingsCheckboxForeground', "(For settings editor preview) Settings editor checkbox foreground.")); +export const settingsCheckboxBorder = registerColor('settings.checkboxBorder', { dark: simpleCheckboxBorder, light: simpleCheckboxBorder, hc: simpleCheckboxBorder }, localize('settingsCheckboxBorder', "(For settings editor preview) Settings editor checkbox border.")); // Text control colors export const settingsTextInputBackground = registerColor('settings.textInputBackground', { dark: inputBackground, light: inputBackground, hc: inputBackground }, localize('textInputBoxBackground', "(For settings editor preview) Settings editor text input box background.")); -- GitLab