3
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
+ import { localize } from 'vs/nls' ;
6
7
import { lastOrDefault } from 'vs/base/common/arrays' ;
7
8
import { deepClone } from 'vs/base/common/objects' ;
8
9
import { ThemeIcon } from 'vs/base/common/themables' ;
10
+ import { buttonForeground } from 'vs/platform/theme/common/colorRegistry' ;
11
+ import { chartsBlue , chartsGreen , chartsOrange , chartsPurple , chartsRed , chartsYellow } from 'vs/platform/theme/common/colors/chartsColors' ;
12
+ import { asCssVariable , ColorIdentifier , registerColor } from 'vs/platform/theme/common/colorUtils' ;
9
13
import { ISCMHistoryItem , ISCMHistoryItemGraphNode , ISCMHistoryItemViewModel } from 'vs/workbench/contrib/scm/common/history' ;
14
+ import { rot } from 'vs/base/common/numbers' ;
10
15
11
16
const SWIMLANE_HEIGHT = 22 ;
12
17
const SWIMLANE_WIDTH = 11 ;
13
18
const CIRCLE_RADIUS = 4 ;
14
19
const SWIMLANE_CURVE_RADIUS = 5 ;
15
20
16
- const graphColors = [ '#007ACC' , '#BC3FBC' , '#BF8803' , '#CC6633' , '#F14C4C' , '#16825D' ] ;
17
-
18
- function getNextColorIndex ( colorIndex : number ) : number {
19
- return colorIndex < graphColors . length - 1 ? colorIndex + 1 : 1 ;
20
- }
21
-
22
- function getLabelColorIndex ( historyItem : ISCMHistoryItem , colorMap : Map < string , number > ) : number | undefined {
21
+ /**
22
+ * History graph colors (local, remote, base)
23
+ */
24
+ export const historyItemGroupLocal = registerColor ( 'scm.historyGraph.historyItemGroupLocal' , chartsBlue , localize ( 'scm.historyGraph.historyItemGroupLocal' , "Local history item group color." ) ) ;
25
+ export const historyItemGroupRemote = registerColor ( 'scm.historyGraph.historyItemGroupRemote' , chartsPurple , localize ( 'scm.historyItemGroupRemote' , "Remote history item group color." ) ) ;
26
+ export const historyItemGroupBase = registerColor ( 'scm.historyGraph.historyItemGroupBase' , chartsOrange , localize ( 'scm.historyItemGroupBase' , "Base history item group color." ) ) ;
27
+
28
+ /**
29
+ * History item hover color
30
+ */
31
+ export const historyItemGroupHoverLabelForeground = registerColor ( 'scm.historyGraph.historyItemGroupHoverLabelForeground' , buttonForeground , localize ( 'scm.historyItemGroupHoverLabelForeground' , "History item group hover label foreground color." ) ) ;
32
+
33
+ /**
34
+ * History graph color registry
35
+ */
36
+ export const colorRegistry : ColorIdentifier [ ] = [
37
+ registerColor ( 'scm.historyGraph.green' , chartsGreen , localize ( 'scm.historyGraph.green' , "The green color used in history graph." ) ) ,
38
+ registerColor ( 'scm.historyGraph.red' , chartsRed , localize ( 'scm.historyGraph.red' , "The red color used in history graph." ) ) ,
39
+ registerColor ( 'scm.historyGraph.yellow' , chartsYellow , localize ( 'scm.historyGraph.yellow' , "The yellow color used in history graph." ) ) ,
40
+ ] ;
41
+
42
+ function getLabelColorIdentifier ( historyItem : ISCMHistoryItem , colorMap : Map < string , ColorIdentifier > ) : ColorIdentifier | undefined {
23
43
for ( const label of historyItem . labels ?? [ ] ) {
24
44
const colorIndex = colorMap . get ( label . title ) ;
25
45
if ( colorIndex !== undefined ) {
@@ -30,22 +50,22 @@ function getLabelColorIndex(historyItem: ISCMHistoryItem, colorMap: Map<string,
30
50
return undefined ;
31
51
}
32
52
33
- function createPath ( stroke : string ) : SVGPathElement {
53
+ function createPath ( colorIdentifier : string ) : SVGPathElement {
34
54
const path = document . createElementNS ( 'http://www.w3.org/2000/svg' , 'path' ) ;
35
55
path . setAttribute ( 'fill' , 'none' ) ;
36
- path . setAttribute ( 'stroke' , stroke ) ;
37
56
path . setAttribute ( 'stroke-width' , '1px' ) ;
38
57
path . setAttribute ( 'stroke-linecap' , 'round' ) ;
58
+ path . style . stroke = asCssVariable ( colorIdentifier ) ;
39
59
40
60
return path ;
41
61
}
42
62
43
- function drawCircle ( index : number , radius : number , fill : string ) : SVGCircleElement {
63
+ function drawCircle ( index : number , radius : number , colorIdentifier : string ) : SVGCircleElement {
44
64
const circle = document . createElementNS ( 'http://www.w3.org/2000/svg' , 'circle' ) ;
45
65
circle . setAttribute ( 'cx' , `${ SWIMLANE_WIDTH * ( index + 1 ) } ` ) ;
46
66
circle . setAttribute ( 'cy' , `${ SWIMLANE_WIDTH } ` ) ;
47
67
circle . setAttribute ( 'r' , `${ radius } ` ) ;
48
- circle . setAttribute ( ' fill' , fill ) ;
68
+ circle . style . fill = asCssVariable ( colorIdentifier ) ;
49
69
50
70
return circle ;
51
71
}
@@ -82,11 +102,11 @@ export function renderSCMHistoryItemGraph(historyItemViewModel: ISCMHistoryItemV
82
102
const circleIndex = inputIndex !== - 1 ? inputIndex : inputSwimlanes . length ;
83
103
84
104
// Circle color - use the output swimlane color if present, otherwise the input swimlane color
85
- const circleColorIndex = circleIndex < outputSwimlanes . length ? outputSwimlanes [ circleIndex ] . color : inputSwimlanes [ circleIndex ] . color ;
105
+ const circleColor = circleIndex < outputSwimlanes . length ? outputSwimlanes [ circleIndex ] . color : inputSwimlanes [ circleIndex ] . color ;
86
106
87
107
let outputSwimlaneIndex = 0 ;
88
108
for ( let index = 0 ; index < inputSwimlanes . length ; index ++ ) {
89
- const color = graphColors [ inputSwimlanes [ index ] . color ] ;
109
+ const color = inputSwimlanes [ index ] . color ;
90
110
91
111
// Current commit
92
112
if ( inputSwimlanes [ index ] . id === historyItem . id ) {
@@ -153,7 +173,7 @@ export function renderSCMHistoryItemGraph(historyItemViewModel: ISCMHistoryItemV
153
173
154
174
// Draw -\
155
175
const d : string [ ] = [ ] ;
156
- const path = createPath ( graphColors [ outputSwimlanes [ parentOutputIndex ] . color ] ) ;
176
+ const path = createPath ( outputSwimlanes [ parentOutputIndex ] . color ) ;
157
177
158
178
// Draw \
159
179
d . push ( `M ${ SWIMLANE_WIDTH * parentOutputIndex } ${ SWIMLANE_HEIGHT / 2 } ` ) ;
@@ -169,34 +189,34 @@ export function renderSCMHistoryItemGraph(historyItemViewModel: ISCMHistoryItemV
169
189
170
190
// Draw | to *
171
191
if ( inputIndex !== - 1 ) {
172
- const path = drawVerticalLine ( SWIMLANE_WIDTH * ( circleIndex + 1 ) , 0 , SWIMLANE_HEIGHT / 2 , graphColors [ inputSwimlanes [ inputIndex ] . color ] ) ;
192
+ const path = drawVerticalLine ( SWIMLANE_WIDTH * ( circleIndex + 1 ) , 0 , SWIMLANE_HEIGHT / 2 , inputSwimlanes [ inputIndex ] . color ) ;
173
193
svg . append ( path ) ;
174
194
}
175
195
176
196
// Draw | from *
177
197
if ( historyItem . parentIds . length > 0 ) {
178
- const path = drawVerticalLine ( SWIMLANE_WIDTH * ( circleIndex + 1 ) , SWIMLANE_HEIGHT / 2 , SWIMLANE_HEIGHT , graphColors [ circleColorIndex ] ) ;
198
+ const path = drawVerticalLine ( SWIMLANE_WIDTH * ( circleIndex + 1 ) , SWIMLANE_HEIGHT / 2 , SWIMLANE_HEIGHT , circleColor ) ;
179
199
svg . append ( path ) ;
180
200
}
181
201
182
202
// Draw *
183
203
if ( historyItem . parentIds . length > 1 ) {
184
204
// Multi-parent node
185
- const circleOuter = drawCircle ( circleIndex , CIRCLE_RADIUS + 1 , graphColors [ circleColorIndex ] ) ;
205
+ const circleOuter = drawCircle ( circleIndex , CIRCLE_RADIUS + 1 , circleColor ) ;
186
206
svg . append ( circleOuter ) ;
187
207
188
- const circleInner = drawCircle ( circleIndex , CIRCLE_RADIUS - 1 , graphColors [ circleColorIndex ] ) ;
208
+ const circleInner = drawCircle ( circleIndex , CIRCLE_RADIUS - 1 , circleColor ) ;
189
209
svg . append ( circleInner ) ;
190
210
} else {
191
211
// HEAD
192
212
// TODO@lszomoru - implement a better way to determine if the commit is HEAD
193
213
if ( historyItem . labels ?. some ( l => ThemeIcon . isThemeIcon ( l . icon ) && l . icon . id === 'target' ) ) {
194
- const outerCircle = drawCircle ( circleIndex , CIRCLE_RADIUS + 2 , graphColors [ circleColorIndex ] ) ;
214
+ const outerCircle = drawCircle ( circleIndex , CIRCLE_RADIUS + 2 , circleColor ) ;
195
215
svg . append ( outerCircle ) ;
196
216
}
197
217
198
218
// Node
199
- const circle = drawCircle ( circleIndex , CIRCLE_RADIUS , graphColors [ circleColorIndex ] ) ;
219
+ const circle = drawCircle ( circleIndex , CIRCLE_RADIUS , circleColor ) ;
200
220
svg . append ( circle ) ;
201
221
}
202
222
@@ -207,7 +227,7 @@ export function renderSCMHistoryItemGraph(historyItemViewModel: ISCMHistoryItemV
207
227
return svg ;
208
228
}
209
229
210
- export function toISCMHistoryItemViewModelArray ( historyItems : ISCMHistoryItem [ ] , colorMap = new Map < string , number > ( ) ) : ISCMHistoryItemViewModel [ ] {
230
+ export function toISCMHistoryItemViewModelArray ( historyItems : ISCMHistoryItem [ ] , colorMap = new Map < string , string > ( ) ) : ISCMHistoryItemViewModel [ ] {
211
231
let colorIndex = - 1 ;
212
232
const viewModels : ISCMHistoryItemViewModel [ ] = [ ] ;
213
233
@@ -227,7 +247,7 @@ export function toISCMHistoryItemViewModelArray(historyItems: ISCMHistoryItem[],
227
247
if ( ! firstParentAdded ) {
228
248
outputSwimlanes . push ( {
229
249
id : historyItem . parentIds [ 0 ] ,
230
- color : getLabelColorIndex ( historyItem , colorMap ) ?? node . color
250
+ color : getLabelColorIdentifier ( historyItem , colorMap ) ?? node . color
231
251
} ) ;
232
252
firstParentAdded = true ;
233
253
}
@@ -241,11 +261,15 @@ export function toISCMHistoryItemViewModelArray(historyItems: ISCMHistoryItem[],
241
261
// Add unprocessed parent(s) to the output
242
262
for ( let i = firstParentAdded ? 1 : 0 ; i < historyItem . parentIds . length ; i ++ ) {
243
263
// Color index (label -> next color)
244
- colorIndex = getLabelColorIndex ( historyItem , colorMap ) ?? getNextColorIndex ( colorIndex ) ;
264
+ let colorIdentifier = getLabelColorIdentifier ( historyItem , colorMap ) ;
265
+ if ( ! colorIdentifier ) {
266
+ colorIndex = rot ( colorIndex + 1 , colorRegistry . length ) ;
267
+ colorIdentifier = colorRegistry [ colorIndex ] ;
268
+ }
245
269
246
270
outputSwimlanes . push ( {
247
271
id : historyItem . parentIds [ i ] ,
248
- color : colorIndex
272
+ color : colorIdentifier
249
273
} ) ;
250
274
}
251
275
}
0 commit comments