• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2018 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import * as m from 'mithril';
16
17import {assertExists} from '../base/logging';
18import {Actions} from '../common/actions';
19import {TrackGroupState, TrackState} from '../common/state';
20
21import {globals} from './globals';
22import {drawGridLines} from './gridline_helper';
23import {Panel, PanelSize} from './panel';
24import {Track} from './track';
25import {TrackContent} from './track_panel';
26import {trackRegistry} from './track_registry';
27import {drawVerticalSelection,
28        drawVerticalLineAtTime} from './vertical_line_helper';
29
30
31interface Attrs {
32  trackGroupId: string;
33}
34
35export class TrackGroupPanel extends Panel<Attrs> {
36  private readonly trackGroupId: string;
37  private shellWidth = 0;
38  private backgroundColor = '#ffffff';  // Updated from CSS later.
39  private summaryTrack: Track;
40
41  constructor({attrs}: m.CVnode<Attrs>) {
42    super();
43    this.trackGroupId = attrs.trackGroupId;
44    const trackCreator = trackRegistry.get(this.summaryTrackState.kind);
45    this.summaryTrack = trackCreator.create(this.summaryTrackState);
46  }
47
48  get trackGroupState(): TrackGroupState {
49    return assertExists(globals.state.trackGroups[this.trackGroupId]);
50  }
51
52  get summaryTrackState(): TrackState {
53    return assertExists(
54        globals.state.tracks[this.trackGroupState.summaryTrackId]);
55  }
56
57  view({attrs}: m.CVnode<Attrs>) {
58    const collapsed = this.trackGroupState.collapsed;
59    const name = StripPathFromExecutable(this.trackGroupState.name);
60    return m(
61        `.track-group-panel[collapsed=${collapsed}]`,
62        m('.shell',
63          m('h1',
64            {
65              title: name,
66            },
67            name,
68            m.trust('&#x200E;')),
69          m('.fold-button',
70            {
71              onclick: (e: MouseEvent) => {
72                globals.dispatch(Actions.toggleTrackGroupCollapsed({
73                  trackGroupId: attrs.trackGroupId,
74                })),
75                e.stopPropagation();
76              }
77            },
78            m('i.material-icons',
79              this.trackGroupState.collapsed ? 'expand_more' : 'expand_less'))),
80        this.summaryTrack ? m(TrackContent, {track: this.summaryTrack}) : null);
81  }
82
83  oncreate(vnode: m.CVnodeDOM<Attrs>) {
84    this.onupdate(vnode);
85  }
86
87  onupdate({dom}: m.CVnodeDOM<Attrs>) {
88    const shell = assertExists(dom.querySelector('.shell'));
89    this.shellWidth = shell.getBoundingClientRect().width;
90    this.backgroundColor =
91        getComputedStyle(dom).getPropertyValue('--collapsed-background');
92  }
93
94  renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
95    const collapsed = this.trackGroupState.collapsed;
96    if (!collapsed) return;
97
98    ctx.save();
99
100    ctx.fillStyle = this.backgroundColor;
101    ctx.fillRect(0, 0, size.width, size.height);
102
103    drawGridLines(
104        ctx,
105        globals.frontendLocalState.timeScale,
106        globals.frontendLocalState.visibleWindowTime,
107        size.width,
108        size.height);
109
110    ctx.translate(this.shellWidth, 0);
111    if (this.summaryTrack) {
112      this.summaryTrack.renderCanvas(ctx);
113    }
114    ctx.restore();
115
116    const localState = globals.frontendLocalState;
117    // Draw vertical line when hovering on the the notes panel.
118    if (localState.showNotePreview) {
119      drawVerticalLineAtTime(ctx,
120                            localState.timeScale,
121                            localState.hoveredTimestamp,
122                            size.height,
123                            `#aaa`);
124    }
125    // Draw vertical line when shift is pressed.
126    if (localState.showTimeSelectPreview) {
127      drawVerticalLineAtTime(ctx,
128                            localState.timeScale,
129                            localState.hoveredTimestamp,
130                            size.height,
131                            `rgb(52,69,150)`);
132    }
133    if (globals.state.currentSelection !== null) {
134      if (globals.state.currentSelection.kind === 'NOTE') {
135        const note = globals.state.notes[globals.state.currentSelection.id];
136        drawVerticalLineAtTime(ctx,
137                               localState.timeScale,
138                               note.timestamp,
139                               size.height,
140                               note.color);
141      }
142      if (globals.state.currentSelection.kind === 'TIMESPAN') {
143        drawVerticalSelection(ctx,
144                              localState.timeScale,
145                              globals.state.currentSelection.startTs,
146                              globals.state.currentSelection.endTs,
147                              size.height,
148                              `rgba(52,69,150,0.3)`);
149      }
150      if (globals.state.currentSelection.kind === 'SLICE' &&
151          globals.sliceDetails.wakeupTs !== undefined) {
152        drawVerticalLineAtTime(
153            ctx,
154            localState.timeScale,
155            globals.sliceDetails.wakeupTs,
156            size.height,
157            `black`);
158      }
159    }
160  }
161}
162
163function StripPathFromExecutable(path: string) {
164  return path.split('/').slice(-1)[0];
165}
166