Skip to content

Commit de1fbc1

Browse files
committed
Settings editor - keyboard access, theming
1 parent 00c76ee commit de1fbc1

3 files changed

Lines changed: 77 additions & 25 deletions

File tree

src/vs/workbench/parts/preferences/browser/media/settingsEditor2.css

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,20 @@
114114
min-height: 75px;
115115
}
116116

117+
.settings-editor > .settings-body > .settings-tree-container .monaco-tree-row .content::before {
118+
content: ' ';
119+
display: inline-block;
120+
position: absolute;
121+
width: 10px;
122+
left: -14px;
123+
top: 2px;
124+
bottom: 10px;
125+
}
126+
127+
.settings-editor > .settings-body > .settings-tree-container .monaco-tree .monaco-tree-row {
128+
background-color: initial !important;
129+
}
130+
117131
.settings-editor > .settings-body > .settings-tree-container .setting-item.odd:not(.focused):not(.selected):not(:hover),
118132
.settings-editor > .settings-body > .settings-tree-container .monaco-tree:not(:focus) .setting-item.focused.odd:not(.selected):not(:hover),
119133
.settings-editor > .settings-body > .settings-tree-container .monaco-tree:not(.focused) .setting-item.focused.odd:not(.selected):not(:hover) {
@@ -169,6 +183,7 @@
169183

170184
.settings-editor > .settings-body > .settings-tree-container .setting-measure-container.monaco-tree-row {
171185
padding-left: 15px;
186+
opacity: 0;
172187
}
173188

174189
.settings-editor > .settings-body > .settings-tree-container .setting-item.is-expanded .setting-item-description,
@@ -229,7 +244,7 @@
229244
.settings-editor > .settings-body > .settings-tree-container .setting-item .expand-indicator {
230245
visibility: hidden;
231246
position: absolute;
232-
bottom: -1px;
247+
bottom: -2px;
233248
width: calc(100% - 190px);
234249
text-align: center;
235250
opacity: .5;

src/vs/workbench/parts/preferences/browser/settingsEditor2.ts

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
1919
import { WorkbenchTree } from 'vs/platform/list/browser/listService';
2020
import { ILogService } from 'vs/platform/log/common/log';
2121
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
22-
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
23-
import { IThemeService } from 'vs/platform/theme/common/themeService';
22+
import { attachButtonStyler, attachStyler } from 'vs/platform/theme/common/styler';
23+
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
2424
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
2525
import { EditorOptions } from 'vs/workbench/common/editor';
2626
import { SearchWidget, SettingsTarget, SettingsTargetsWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
@@ -202,10 +202,38 @@ export class SettingsEditor2 extends BaseEditor {
202202
ariaLabel: localize('treeAriaLabel', "Settings"),
203203
showLoading: false,
204204
indentPixels: 0,
205-
twistiePixels: 15
205+
twistiePixels: 15,
206206
});
207207

208+
this._register(registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
209+
const activeListBackground = theme.getColor('list.activeSelectionBackground');
210+
if (activeListBackground) {
211+
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .monaco-tree.focused .monaco-tree-row.focused .content::before { background-color: ${activeListBackground}; }`);
212+
}
213+
214+
const inactiveListBackground = theme.getColor('list.inactiveSelectionBackground');
215+
if (inactiveListBackground) {
216+
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .monaco-tree .monaco-tree-row.focused .content::before { background-color: ${inactiveListBackground}; }`);
217+
}
218+
}));
219+
220+
attachStyler(this.themeService, {
221+
listActiveSelectionBackground: null,
222+
listActiveSelectionForeground: null,
223+
listFocusAndSelectionBackground: null,
224+
listFocusAndSelectionForeground: null,
225+
listFocusBackground: null,
226+
listFocusForeground: null,
227+
listHoverForeground: null,
228+
listHoverBackground: null,
229+
listInactiveSelectionBackground: null,
230+
listInactiveSelectionForeground: null
231+
}, colors => {
232+
this.settingsTree.style(colors);
233+
});
234+
208235
this.settingsTree.onDidChangeFocus(e => {
236+
this.settingsTree.setSelection([e.focus]);
209237
if (this.selectedElement) {
210238
this.settingsTree.refresh(this.selectedElement);
211239
}
@@ -239,7 +267,8 @@ export class SettingsEditor2 extends BaseEditor {
239267
// ConfigurationService displays the error if this fails.
240268
// Force a render afterwards because onDidConfigurationUpdate doesn't fire if the update doesn't result in an effective setting value change
241269
this.configurationService.updateValue(key, value, <ConfigurationTarget>this.settingsTargetsWidget.settingsTarget)
242-
.then(() => this.settingsTree.refresh());
270+
.then(() => this.refreshTree())
271+
.then(() => this.settingsTree.domFocus());
243272

244273
const reportModifiedProps = {
245274
key,

src/vs/workbench/parts/preferences/browser/settingsTree.ts

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import * as DOM from 'vs/base/browser/dom';
77
import { Button } from 'vs/base/browser/ui/button/button';
88
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
9+
import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
910
import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
1011
import { Color } from 'vs/base/common/color';
1112
import { Emitter, Event } from 'vs/base/common/event';
@@ -23,7 +24,7 @@ import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant }
2324
import { SettingsTarget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
2425
import { ISearchResult, ISetting, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences';
2526
import { DefaultSettingsEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
26-
import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
27+
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
2728

2829
const $ = DOM.$;
2930

@@ -187,6 +188,10 @@ export class SettingsDataSource implements IDataSource {
187188
}
188189

189190
getParent(tree: ITree, element: TreeElement): TPromise<any, any> {
191+
if (!element) {
192+
return null;
193+
}
194+
190195
if (!(element instanceof DefaultSettingsEditorModel)) {
191196
return TPromise.wrap(element.parent);
192197
}
@@ -392,6 +397,9 @@ export class SettingsRenderer implements IRenderer {
392397
overridesElement
393398
};
394399

400+
// Prevent clicks from being handled by list
401+
toDispose.push(DOM.addDisposableListener(valueElement, 'mousedown', (e: IMouseEvent) => e.stopPropagation()));
402+
395403
return template;
396404
}
397405

@@ -411,13 +419,13 @@ export class SettingsRenderer implements IRenderer {
411419
}
412420

413421
private elementIsSelected(tree: ITree, element: TreeElement): boolean {
414-
const selection = tree.getFocus();
415-
const selectedElement: TreeElement = selection;
422+
const selection = tree.getSelection();
423+
const selectedElement: TreeElement = selection && selection[0];
416424
return selectedElement && selectedElement.id === element.id;
417425
}
418426

419427
private renderSettingElement(tree: ITree, element: ISettingElement, template: ISettingItemTemplate, measuring?: boolean): void {
420-
const isSelected = this.elementIsSelected(tree, element);
428+
const isSelected = !!this.elementIsSelected(tree, element);
421429
const setting = element.setting;
422430

423431
template.context = element;
@@ -448,12 +456,12 @@ export class SettingsRenderer implements IRenderer {
448456
}
449457
}
450458

451-
this.renderValue(element, template);
459+
this.renderValue(element, isSelected, template);
452460

453461
const resetButton = new Button(template.valueElement);
454462
resetButton.element.title = localize('resetButtonTitle', "Reset");
455463
resetButton.element.classList.add('setting-reset-button');
456-
// resetButton.element.tabIndex = element.isFocused ? 0 : -1; // TODO
464+
resetButton.element.tabIndex = isSelected ? 0 : -1;
457465

458466
attachButtonStyler(resetButton, this.themeService, {
459467
buttonBackground: Color.transparent.toString(),
@@ -475,62 +483,62 @@ export class SettingsRenderer implements IRenderer {
475483
template.overridesElement.textContent = overridesElementText;
476484
}
477485

478-
private renderValue(element: ISettingElement, template: ISettingItemTemplate): void {
486+
private renderValue(element: ISettingElement, isSelected: boolean, template: ISettingItemTemplate): void {
479487
const onChange = value => this._onDidChangeSetting.fire({ key: element.setting.key, value });
480488
template.valueElement.innerHTML = '';
481489
if (element.valueType === 'string' && element.enum) {
482-
this.renderEnum(element, template, onChange);
490+
this.renderEnum(element, isSelected, template, onChange);
483491
} else if (element.valueType === 'boolean') {
484-
this.renderBool(element, template, onChange);
492+
this.renderBool(element, isSelected, template, onChange);
485493
} else if (element.valueType === 'string') {
486-
this.renderText(element, template, onChange);
494+
this.renderText(element, isSelected, template, onChange);
487495
} else if (element.valueType === 'number') {
488-
this.renderText(element, template, value => onChange(parseInt(value)));
496+
this.renderText(element, isSelected, template, value => onChange(parseInt(value)));
489497
} else {
490-
this.renderEditInSettingsJson(element, template);
498+
this.renderEditInSettingsJson(element, isSelected, template);
491499
}
492500
}
493501

494-
private renderBool(element: ISettingElement, template: ISettingItemTemplate, onChange: (value: boolean) => void): void {
502+
private renderBool(element: ISettingElement, isSelected: boolean, template: ISettingItemTemplate, onChange: (value: boolean) => void): void {
495503
const checkboxElement = <HTMLInputElement>DOM.append(template.valueElement, $('input.setting-value-checkbox.setting-value-input'));
496504
checkboxElement.type = 'checkbox';
497505
checkboxElement.checked = element.value;
498-
// checkboxElement.tabIndex = element.isFocused ? 0 : -1; // TODO
506+
checkboxElement.tabIndex = isSelected ? 0 : -1;
499507

500508
template.toDispose.push(DOM.addDisposableListener(checkboxElement, 'change', e => onChange(checkboxElement.checked)));
501509
}
502510

503-
private renderEnum(element: ISettingElement, template: ISettingItemTemplate, onChange: (value: string) => void): void {
511+
private renderEnum(element: ISettingElement, isSelected: boolean, template: ISettingItemTemplate, onChange: (value: string) => void): void {
504512
const idx = element.enum.indexOf(element.value);
505513
const selectBox = new SelectBox(element.enum, idx, this.contextViewService);
506514
template.toDispose.push(selectBox);
507515
template.toDispose.push(attachSelectBoxStyler(selectBox, this.themeService));
508516
selectBox.render(template.valueElement);
509517
if (template.valueElement.firstElementChild) {
510-
// template.valueElement.firstElementChild.setAttribute('tabindex', element.isFocused ? '0' : '-1');
518+
template.valueElement.firstElementChild.setAttribute('tabindex', isSelected ? '0' : '-1');
511519
}
512520

513521
template.toDispose.push(
514522
selectBox.onDidSelect(e => onChange(element.enum[e.index])));
515523
}
516524

517-
private renderText(element: ISettingElement, template: ISettingItemTemplate, onChange: (value: string) => void): void {
525+
private renderText(element: ISettingElement, isSelected: boolean, template: ISettingItemTemplate, onChange: (value: string) => void): void {
518526
const inputBox = new InputBox(template.valueElement, this.contextViewService);
519527
template.toDispose.push(attachInputBoxStyler(inputBox, this.themeService));
520528
template.toDispose.push(inputBox);
521529
inputBox.value = element.value;
522-
// inputBox.inputElement.tabIndex = element.isFocused ? 0 : -1;
530+
inputBox.inputElement.tabIndex = isSelected ? 0 : -1;
523531

524532
template.toDispose.push(
525533
inputBox.onDidChange(e => onChange(e)));
526534
}
527535

528-
private renderEditInSettingsJson(element: ISettingElement, template: ISettingItemTemplate): void {
536+
private renderEditInSettingsJson(element: ISettingElement, isSelected: boolean, template: ISettingItemTemplate): void {
529537
const openSettingsButton = new Button(template.valueElement, { title: true, buttonBackground: null, buttonHoverBackground: null });
530538
openSettingsButton.onDidClick(() => this._onDidOpenSettings.fire());
531539
openSettingsButton.label = localize('editInSettingsJson', "Edit in settings.json");
532540
openSettingsButton.element.classList.add('edit-in-settings-button');
533-
// openSettingsButton.element.tabIndex = element.isFocused ? 0 : -1;
541+
openSettingsButton.element.tabIndex = isSelected ? 0 : -1;
534542

535543
template.toDispose.push(openSettingsButton);
536544
template.toDispose.push(attachButtonStyler(openSettingsButton, this.themeService, {

0 commit comments

Comments
 (0)