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

tree indent guidelines support #8298

Merged
merged 1 commit into from
Aug 5, 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
3 changes: 2 additions & 1 deletion packages/core/src/browser/common-frontend-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1090,7 +1090,7 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
// if not yet contributed by Monaco, check runtime css variables to learn.
// TODO: Following are not yet supported/no respective elements in theia:
// list.focusBackground, list.focusForeground, list.inactiveFocusBackground, list.filterMatchBorder,
// list.dropBackground, listFilterWidget.outline, listFilterWidget.noMatchesOutline, tree.indentGuidesStroke
// list.dropBackground, listFilterWidget.outline, listFilterWidget.noMatchesOutline
// list.invalidItemForeground,
// list.warningForeground, list.errorForeground => tree node needs an respective class
{ id: 'list.activeSelectionBackground', defaults: { dark: '#094771', light: '#0074E8' }, description: '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.' },
Expand All @@ -1100,6 +1100,7 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
{ id: 'list.hoverBackground', defaults: { dark: '#2A2D2E', light: '#F0F0F0' }, description: 'List/Tree background when hovering over items using the mouse.' },
{ id: 'list.hoverForeground', description: 'List/Tree foreground when hovering over items using the mouse.' },
{ id: 'list.filterMatchBackground', defaults: { dark: 'editor.findMatchHighlightBackground', light: 'editor.findMatchHighlightBackground' }, description: 'Background color of the filtered match.' },
{ id: 'tree.inactiveIndentGuidesStroke', defaults: { dark: Color.transparent('tree.indentGuidesStroke', 0.4), light: Color.transparent('tree.indentGuidesStroke', 0.4), hc: Color.transparent('tree.indentGuidesStroke', 0.4) }, description: 'Tree stroke color for the inactive indentation guides.' },

// Editor Group & Tabs colors should be aligned with https://code.visualstudio.com/api/references/theme-color#editor-groups-tabs
{
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/browser/core-preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ export const corePreferenceSchema: PreferenceSchema = {
'scope': 'language-overridable',
'enumDescriptions': Object.keys(SUPPORTED_ENCODINGS).map(key => SUPPORTED_ENCODINGS[key].labelLong),
'included': Object.keys(SUPPORTED_ENCODINGS).length > 1
},
'workbench.tree.renderIndentGuides': {
type: 'string',
enum: ['onHover', 'none', 'always'],
default: 'onHover',
description: 'Controls whether the tree should render indent guides.'
}
}
};
Expand All @@ -85,6 +91,7 @@ export interface CoreConfiguration {
'workbench.iconTheme'?: string | null;
'workbench.silentNotifications': boolean;
'files.encoding': string
'workbench.tree.renderIndentGuides': 'onHover' | 'none' | 'always';
}

export const CorePreferences = Symbol('CorePreferences');
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/browser/style/tree.css
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,16 @@
.theia-tree-element-node {
width: 100%
}

.theia-tree-node-indent {
position: absolute;
height: var(--theia-content-line-height);
border-right: var(--theia-border-width) solid transparent;
}
.theia-tree-node-indent.always,
.theia-TreeContainer:hover .theia-tree-node-indent.hover {
border-color: var(--theia-tree-inactiveIndentGuidesStroke);
}
.theia-tree-node-indent.active {
border-color: var(--theia-tree-indentGuidesStroke);
}
64 changes: 63 additions & 1 deletion packages/core/src/browser/tree/tree-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { ElementExt } from '@phosphor/domutils';
import { TreeWidgetSelection } from './tree-widget-selection';
import { MaybePromise } from '../../common/types';
import { LabelProvider } from '../label-provider';
import { CorePreferences } from '../core-preferences';

const debounce = require('lodash.debounce');

Expand All @@ -52,6 +53,7 @@ export const TREE_NODE_SEGMENT_GROW_CLASS = 'theia-TreeNodeSegmentGrow';
export const EXPANDABLE_TREE_NODE_CLASS = 'theia-ExpandableTreeNode';
export const COMPOSITE_TREE_NODE_CLASS = 'theia-CompositeTreeNode';
export const TREE_NODE_CAPTION_CLASS = 'theia-TreeNodeCaption';
export const TREE_NODE_INDENT_GUIDE_CLASS = 'theia-tree-node-indent';

export const TreeProps = Symbol('TreeProps');

Expand Down Expand Up @@ -162,6 +164,9 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
@inject(LabelProvider)
protected readonly labelProvider: LabelProvider;

@inject(CorePreferences)
protected readonly corePreferences: CorePreferences;

protected shouldScrollToRow = true;

constructor(
Expand Down Expand Up @@ -251,6 +256,11 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
})
]);
}
this.toDispose.push(this.corePreferences.onPreferenceChanged(preference => {
if (preference.preferenceName === 'workbench.tree.renderIndentGuides') {
this.update();
}
}));
}

/**
Expand Down Expand Up @@ -478,7 +488,10 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
* Actually render the node row.
*/
protected doRenderNodeRow({ index, node, depth }: TreeWidget.NodeRow): React.ReactNode {
return this.renderNode(node, { depth });
return <React.Fragment>
{this.renderIndent(node, { depth })}
{this.renderNode(node, { depth })}
</React.Fragment>;
}

/**
Expand Down Expand Up @@ -776,6 +789,55 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
return iconClass.concat(additionalClasses).join(' ');
}

/**
* Render indent for the file tree based on the depth
* @param node the tree node.
* @param depth the depth of the tree node.
*/
protected renderIndent(node: TreeNode, props: NodeProps): React.ReactNode {
const renderIndentGuides = this.corePreferences['workbench.tree.renderIndentGuides'];
if (renderIndentGuides === 'none') {
return undefined;
}

const indentDivs: React.ReactNode[] = [];
let current: TreeNode | undefined = node;
let depth = props.depth;
while (current && depth) {
const classNames: string[] = [TREE_NODE_INDENT_GUIDE_CLASS];
if (this.needsActiveIndentGuideline(current)) {
classNames.push('active');
} else {
classNames.push(renderIndentGuides === 'onHover' ? 'hover' : 'always');
}
const paddingLeft = this.props.leftPadding * depth;
indentDivs.unshift(<div key={depth} className={classNames.join(' ')} style={{
paddingLeft: `${paddingLeft}px`
}} />);
current = current.parent;
depth--;
}
return indentDivs;
}

protected needsActiveIndentGuideline(node: TreeNode): boolean {
const parent = node.parent;
if (!parent || !this.isExpandable(parent)) {
return false;
}
if (SelectableTreeNode.isSelected(parent)) {
return true;
}
if (parent.expanded) {
for (const sibling of parent.children) {
akosyakov marked this conversation as resolved.
Show resolved Hide resolved
if (SelectableTreeNode.isSelected(sibling) && !(this.isExpandable(sibling) && sibling.expanded)) {
return true;
}
}
}
return false;
}

/**
* Render the node given the tree node and node properties.
* @param node the tree node.
Expand Down