1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package traceviewer.ui.tracks
18 
19 import traceviewer.ui.LayoutConstants
20 import traceviewer.ui.RenderState
21 import trebuchet.model.base.Slice
22 import java.awt.Color
23 import java.awt.Dimension
24 import java.awt.FontMetrics
25 import java.awt.Graphics
26 import javax.swing.JComponent
27 
28 open class SliceTrack<in T : Slice>(private val slices: List<T>, private val renderState: RenderState,
29                                     trackHeight: Int = LayoutConstants.TrackHeight) : JComponent() {
30 
31     init {
32         preferredSize = Dimension(0, trackHeight)
33         size = preferredSize
34     }
35 
paintComponentnull36     override fun paintComponent(g: Graphics?) {
37         if (g == null) return
38 
39         val scale = renderState.scale
40         val panX = renderState.panX
41         val y = 0
42         val height = height
43         var x: Int
44         var width: Int
45 
46         val metrics = g.fontMetrics
47         var ty = metrics.ascent
48         ty += (height - ty) / 2
49 
50         slices.forEach {
51             x = ((it.startTime - panX) * scale).toInt()
52             val scaledWidth = (it.endTime - it.startTime) * scale
53             width = maxOf(scaledWidth.toInt(), 1)
54             if (x + width > 0 && x < this.width) {
55                 var color = colorFor(it)
56                 if (scaledWidth < 1) {
57                     color = Color(color.red, color.green, color.blue,
58                             maxOf((255 * scaledWidth).toInt(), 50))
59                 }
60                 g.color = color
61                 g.fillRect(x, y, width, height)
62 
63                 if (height >= metrics.height) {
64                     drawLabel(it, g, metrics, x, ty, width)
65                 }
66             }
67         }
68     }
69 
drawLabelnull70     open fun drawLabel(slice: T, g: Graphics, metrics: FontMetrics, x: Int, y: Int, width: Int) {
71         var strLimit = 0
72         var strWidth = 0
73         while (strLimit < slice.name.length && strWidth <= width) {
74             strWidth += metrics.charWidth(slice.name[strLimit])
75             strLimit++
76         }
77         if (strWidth > width) strLimit--
78         if (strLimit > 2) {
79             g.color = textColor
80             g.drawString(slice.name.substring(0, strLimit), x, y)
81         }
82     }
83 
colorFornull84     open fun colorFor(slice: T): Color {
85         return colors[Math.abs(slice.name.hashCode()) % colors.size]
86     }
87 
<lambda>null88     private fun sliceAt(timestamp: Double) = slices.binarySearch {
89         when {
90             it.startTime > timestamp -> 1
91             it.endTime < timestamp -> -1
92             else -> 0
93         }
94     }.let { if (it < 0) null else slices[it] }
95 
96     companion object Style {
97         private val colors = listOf(
98                 Color(0x0D47A1), Color(0x1565C0), Color(0x1976D2),
99                 Color(0x1A237E), Color(0x283593), Color(0x303F9F),
100                 Color(0x01579B), Color(0x006064), Color(0x004D40),
101                 Color(0x1B5E20), Color(0x37474F), Color(0x263238)
102             )
103 
104         private val textColor = Color(0xff, 0xff, 0xff, 0x7f)
105     }
106 }