Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e6d1c7d

Browse files
committed
Sketchbook explorer
1 parent 51d4dc6 commit e6d1c7d

File tree

9 files changed

+265
-31
lines changed

9 files changed

+265
-31
lines changed

‎arduino-ide-extension/src/browser/contributions/open-sketch-external.ts‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ export class OpenSketchExternal extends SketchContribution {
99

1010
registerCommands(registry: CommandRegistry): void {
1111
registry.registerCommand(OpenSketchExternal.Commands.OPEN_EXTERNAL, {
12-
execute: () => this.openExternal()
12+
execute: (arg) => {
13+
this.openExternal(arg?.uri?.toString())
14+
}
1315
});
1416
}
1517

@@ -28,8 +30,12 @@ export class OpenSketchExternal extends SketchContribution {
2830
});
2931
}
3032

31-
protected async openExternal(): Promise<void> {
32-
const uri = await this.sketchServiceClient.currentSketchFile();
33+
protected async openExternal(uri?: string): Promise<void> {
34+
35+
// if a uri is not passed in, use the current sketch
36+
if (!uri) {
37+
uri = await this.sketchServiceClient.currentSketchFile();
38+
}
3339
if (uri) {
3440
const exists = this.fileService.exists(new URI(uri));
3541
if (exists) {

‎arduino-ide-extension/src/browser/data/arduino.color-theme.json‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@
8181
],
8282
"colors": {
8383
"list.highlightForeground": "#005c5f",
84-
"list.activeSelectionBackground": "#005c5f",
84+
"list.activeSelectionForeground": "#424242",
85+
"list.activeSelectionBackground": "#DAE3E3",
86+
"list.inactiveSelectionForeground": "#424242",
87+
"list.inactiveSelectionBackground": "#DAE3E3",
88+
"list.hoverBackground": "#ECF1F1",
8589
"progressBar.background": "#005c5f",
8690
"editor.background": "#ffffff",
8791
"editorCursor.foreground": "#434f54",
Lines changed: 10 additions & 0 deletions
Loading[フレーム]

‎arduino-ide-extension/src/browser/style/sketchbook.css‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,13 @@
1818
.sketchbook-trees-container {
1919
height: 99%;
2020
}
21+
22+
.sketchbook-tree__opts {
23+
background: url('./sketchbook-opts-icon.svg') center center no-repeat;
24+
width: var(--theia-icon-size);
25+
height: var(--theia-icon-size);
26+
}
27+
28+
.theia-TreeNodeSegmentGrow {
29+
flex: 1;
30+
}

‎arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-commands.ts‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ import { Command } from '@theia/core/lib/common/command';
22

33
export namespace SketchbookCommands {
44

5-
export const OPEN: Command = {
6-
id: 'arduino-sketchbook--open-sketch',
7-
label: 'Open Sketch',
8-
iconClass: 'fa fa-play-circle'
9-
};
10-
115
export const OPEN_NEW_WINDOW: Command = {
126
id: 'arduino-sketchbook--open-sketch-new-window',
137
label: 'Open Sketch in New Window',
14-
iconClass: 'fa fa-check'
8+
};
9+
10+
export const REVEAL_IN_FINDER: Command = {
11+
id: 'arduino-sketchbook--reveal-in-finder',
12+
label: 'Open Containing Folder',
13+
};
14+
15+
export const OPEN_SKETCHBOOK_CONTEXT_MENU: Command = {
16+
id: 'arduino-sketchbook--open-sketch-context-menu',
17+
label: 'Contextual menu'
1518
};
1619

1720
}

‎arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-model.ts‎

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import { inject, injectable } from 'inversify';
22
import URI from '@theia/core/lib/common/uri';
3-
import { FileTreeModel } from '@theia/filesystem/lib/browser';
3+
import { FileNode,FileTreeModel } from '@theia/filesystem/lib/browser';
44
import { FileService } from '@theia/filesystem/lib/browser/file-service';
55
import { ConfigService } from '../../../common/protocol';
66
import { SketchbookTree } from './sketchbook-tree';
77
import { ArduinoPreferences } from '../../arduino-preferences';
8+
import { SelectableTreeNode, TreeNode } from '@theia/core/lib/browser/tree';
9+
import { SketchbookCommands } from './sketchbook-commands';
10+
import { OpenerService, open } from '@theia/core/lib/browser';
11+
import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
12+
import { CommandRegistry } from '@theia/core/lib/common/command';
813

914
@injectable()
1015
export class SketchbookTreeModel extends FileTreeModel {
@@ -15,14 +20,102 @@ export class SketchbookTreeModel extends FileTreeModel {
1520
@inject(ArduinoPreferences)
1621
protected readonly arduinoPreferences: ArduinoPreferences;
1722

23+
@inject(CommandRegistry)
24+
protected commandRegistry: CommandRegistry;
25+
1826
@inject(ConfigService)
1927
protected readonly configService: ConfigService;
2028

29+
@inject(OpenerService)
30+
protected readonly openerService: OpenerService;
31+
32+
@inject(SketchesServiceClientImpl)
33+
protected readonly sketchServiceClient: SketchesServiceClientImpl;
34+
2135
async updateRoot(): Promise<void> {
2236
const config = await this.configService.getConfiguration();
2337
const fileStat = await this.fileService.resolve(new URI(config.sketchDirUri));
2438
const showAllFiles = this.arduinoPreferences['arduino.sketchbook.showAllFiles'];
2539
this.tree.root = SketchbookTree.RootNode.create(fileStat, showAllFiles);
2640
}
2741

42+
async openNode(raw?: TreeNode | undefined) {
43+
const node = raw || this.selectedNodes[0];
44+
45+
if (!node) { return }
46+
47+
// if it's a sketch dir, or a file from another sketch, open in new window
48+
const sketchRoot = await this.getSketchRoot(node);
49+
if (sketchRoot) {
50+
this.commandRegistry.executeCommand(SketchbookCommands.OPEN_NEW_WINDOW.id, { node: sketchRoot })
51+
return;
52+
}
53+
54+
if (node) {
55+
this.doOpenNode(node);
56+
this.onOpenNodeEmitter.fire(node);
57+
}
58+
}
59+
60+
// selectNode gets called when the user single-clicks on an item
61+
selectNode(node: Readonly<SelectableTreeNode>): void {
62+
super.selectNode(node);
63+
64+
this.previewNode(node);
65+
}
66+
67+
protected async doOpenNode(node: TreeNode) {
68+
69+
if (node.visible === false) {
70+
return;
71+
} else if (FileNode.is(node)) {
72+
open(this.openerService, node.uri);
73+
} else {
74+
super.doOpenNode(node);
75+
}
76+
}
77+
78+
async previewNode(node: Readonly<SelectableTreeNode>) {
79+
80+
const sketchNode = await this.getSketchRoot(node);
81+
if (sketchNode) {
82+
return;
83+
}
84+
85+
if (node) {
86+
this.doOpenNode(node);
87+
this.onOpenNodeEmitter.fire(node);
88+
}
89+
}
90+
91+
private async getSketchRoot(node: TreeNode): Promise<false | TreeNode> {
92+
93+
// it's a sketch dir, return it straight away
94+
if (SketchbookTree.SketchDirNode.is(node)) {
95+
return node;
96+
}
97+
98+
// check if the node is a file that belongs to another sketch
99+
const sketch = await this.sketchServiceClient.currentSketch();
100+
if (FileNode.is(node) && sketch && node.uri.toString().indexOf(sketch.uri) !== 0) {
101+
return this.recursivelyFindSketchRoot(node);
102+
}
103+
104+
return false;
105+
}
106+
107+
private recursivelyFindSketchRoot(node: TreeNode): TreeNode | false {
108+
109+
if (node && SketchbookTree.SketchDirNode.is(node)) {
110+
return node;
111+
}
112+
113+
if (node && node.parent) {
114+
return this.recursivelyFindSketchRoot(node.parent);
115+
}
116+
117+
// can't find a root, return false
118+
return false;
119+
}
120+
28121
}

‎arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx‎

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import * as React from 'react';
22
import { inject, injectable, postConstruct } from 'inversify';
33
import { TreeNode } from '@theia/core/lib/browser/tree/tree';
44
import { CommandRegistry } from '@theia/core/lib/common/command';
5-
import { NodeProps, TreeProps, TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS } from '@theia/core/lib/browser/tree/tree-widget';
5+
import { NodeProps, TreeProps, TREE_NODE_CONTENT_CLASS,TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS } from '@theia/core/lib/browser/tree/tree-widget';
66
import { EditorManager } from '@theia/editor/lib/browser/editor-manager';
77
import { FileTreeWidget } from '@theia/filesystem/lib/browser';
88
import { ContextMenuRenderer } from '@theia/core/lib/browser/context-menu-renderer';
99
import { SketchbookTree } from './sketchbook-tree';
1010
import { SketchbookTreeModel } from './sketchbook-tree-model';
1111
import { ArduinoPreferences } from '../../arduino-preferences';
12+
import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
1213

1314
@injectable()
1415
export class SketchbookTreeWidget extends FileTreeWidget {
@@ -19,6 +20,11 @@ export class SketchbookTreeWidget extends FileTreeWidget {
1920
@inject(ArduinoPreferences)
2021
protected readonly arduinoPreferences: ArduinoPreferences;
2122

23+
@inject(SketchesServiceClientImpl)
24+
protected readonly sketchServiceClient: SketchesServiceClientImpl;
25+
26+
private currentSketchUri = '';
27+
2228
constructor(
2329
@inject(TreeProps) readonly props: TreeProps,
2430
@inject(SketchbookTreeModel) readonly model: SketchbookTreeModel,
@@ -41,6 +47,9 @@ export class SketchbookTreeWidget extends FileTreeWidget {
4147
}
4248
}));
4349
this.updateModel();
50+
// cache the current open sketch uri
51+
const currentSketch = await this.sketchServiceClient.currentSketch();
52+
this.currentSketchUri = currentSketch && currentSketch.uri || '';
4453
}
4554

4655
async updateModel(): Promise<void> {
@@ -65,6 +74,28 @@ export class SketchbookTreeWidget extends FileTreeWidget {
6574
</React.Fragment>
6675
}
6776

77+
/**
78+
* Render the node given the tree node and node properties.
79+
* @param node the tree node.
80+
* @param props the node properties.
81+
*/
82+
protected renderNode(node: TreeNode, props: NodeProps): React.ReactNode {
83+
if (!TreeNode.isVisible(node)) {
84+
return undefined;
85+
}
86+
const attributes = this.createNodeAttributes(node, props);
87+
const content = <div className={TREE_NODE_CONTENT_CLASS}>
88+
{this.renderExpansionToggle(node, props)}
89+
{this.decorateIcon(node, this.renderIcon(node, props))}
90+
{this.renderCaptionAffixes(node, props, 'captionPrefixes')}
91+
{this.renderCaption(node, props)}
92+
{this.renderCaptionAffixes(node, props, 'captionSuffixes')}
93+
{this.renderTailDecorations(node, props)}
94+
</div>;
95+
return React.createElement('div', attributes, content);
96+
}
97+
98+
6899
protected hoveredNodeId: string | undefined;
69100
protected setHoverNodeId(id: string | undefined): void {
70101
this.hoveredNodeId = id;
@@ -79,29 +110,33 @@ export class SketchbookTreeWidget extends FileTreeWidget {
79110
};
80111
}
81112

82-
protected renderInlineCommands(node: TreeNode, props: NodeProps): React.ReactNode {
83-
if (SketchbookTree.SketchDirNode.is(node) && node.commands && node.id === this.hoveredNodeId) {
113+
// TODO: fix node "any" type
114+
protected renderInlineCommands(node: any, props: NodeProps): React.ReactNode {
115+
116+
if (SketchbookTree.SketchDirNode.is(node) && (node.commands && node.id === this.hoveredNodeId || this.currentSketchUri === node?.uri.toString())) {
84117
return Array.from(new Set(node.commands)).map(command => this.renderInlineCommand(command.id, node));
85118
}
86119
return undefined;
87120
}
88121

89122
protected renderInlineCommand(commandId: string, node: SketchbookTree.SketchDirNode): React.ReactNode {
90123
const command = this.commandRegistry.getCommand(commandId);
91-
const icon = command?.iconClass;
92124
const args = { model: this.model, node: node };
93-
if (command && icon&&this.commandRegistry.isEnabled(commandId, args) && this.commandRegistry.isVisible(commandId, args)) {
94-
const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS, icon,'theia-tree-view-inline-action'].join(' ');
95-
return <div
125+
if (command && this.commandRegistry.isEnabled(commandId, args) && this.commandRegistry.isVisible(commandId, args)) {
126+
const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS, 'theia-tree-view-inline-action'].join(' ');
127+
return (<div
96128
key={`${commandId}--${node.id}`}
97129
className={className}
98130
title={command?.label || command.id}
99-
onClick={event => {
131+
onClick={(event) => {
100132
event.preventDefault();
101133
event.stopPropagation();
102-
this.commandRegistry.executeCommand(commandId, Object.assign(args, { event: event.nativeEvent }))
103-
}}
104-
/>;
134+
this.commandRegistry.executeCommand(commandId, Object.assign(args, { event: event.nativeEvent }));
135+
}
136+
}
137+
>
138+
<div className='sketchbook-tree__opts' />
139+
</div>);
105140
}
106141
return undefined;
107142
}

‎arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class SketchbookTree extends FileTree {
4141
if (DirNode.is(node)) {
4242
const sketch = await this.sketchesService.maybeLoadSketch(node.uri.toString());
4343
if (sketch) {
44-
Object.assign(node, { type: 'sketch', commands: [SketchbookCommands.OPEN,SketchbookCommands.OPEN_NEW_WINDOW] });
44+
Object.assign(node, { type: 'sketch', commands: [SketchbookCommands.OPEN_SKETCHBOOK_CONTEXT_MENU] });
4545
if (!showAllFiles) {
4646
delete (node as any).expanded;
4747
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /