1// Copyright (C) 2023 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 m from 'mithril'; 16 17import {copyToClipboard} from '../../base/clipboard'; 18import {Icons} from '../../base/semantic_icons'; 19import {time, Time} from '../../base/time'; 20import {Actions} from '../../common/actions'; 21import { 22 setTimestampFormat, 23 TimestampFormat, 24 timestampFormat, 25} from '../../core/timestamp_format'; 26import {raf} from '../../core/raf_scheduler'; 27import {Anchor} from '../../widgets/anchor'; 28import {MenuDivider, MenuItem, PopupMenu2} from '../../widgets/menu'; 29import {globals} from '../globals'; 30 31// import {MenuItem, PopupMenu2} from './menu'; 32 33interface TimestampAttrs { 34 // The timestamp to print, this should be the absolute, raw timestamp as 35 // found in trace processor. 36 ts: time; 37 // Custom text value to show instead of the default HH:MM:SS.mmm uuu nnn 38 // formatting. 39 display?: m.Children; 40 extraMenuItems?: m.Child[]; 41} 42 43export class Timestamp implements m.ClassComponent<TimestampAttrs> { 44 view({attrs}: m.Vnode<TimestampAttrs>) { 45 const {ts} = attrs; 46 return m( 47 PopupMenu2, 48 { 49 trigger: m( 50 Anchor, 51 { 52 onmouseover: () => { 53 globals.dispatch(Actions.setHoverCursorTimestamp({ts})); 54 }, 55 onmouseout: () => { 56 globals.dispatch( 57 Actions.setHoverCursorTimestamp({ts: Time.INVALID}), 58 ); 59 }, 60 }, 61 attrs.display ?? renderTimestamp(ts), 62 ), 63 }, 64 m(MenuItem, { 65 icon: Icons.Copy, 66 label: `Copy raw value`, 67 onclick: () => { 68 copyToClipboard(ts.toString()); 69 }, 70 }), 71 m( 72 MenuItem, 73 { 74 label: 'Time format', 75 }, 76 menuItemForFormat(TimestampFormat.Timecode, 'Timecode'), 77 menuItemForFormat(TimestampFormat.UTC, 'Realtime (UTC)'), 78 menuItemForFormat(TimestampFormat.TraceTz, 'Realtime (Trace TZ)'), 79 menuItemForFormat(TimestampFormat.Seconds, 'Seconds'), 80 menuItemForFormat(TimestampFormat.Raw, 'Raw'), 81 menuItemForFormat( 82 TimestampFormat.RawLocale, 83 'Raw (with locale-specific formatting)', 84 ), 85 ), 86 attrs.extraMenuItems ? [m(MenuDivider), attrs.extraMenuItems] : null, 87 ); 88 } 89} 90 91export function menuItemForFormat( 92 value: TimestampFormat, 93 label: string, 94): m.Children { 95 return m(MenuItem, { 96 label, 97 active: value === timestampFormat(), 98 onclick: () => { 99 setTimestampFormat(value); 100 raf.scheduleFullRedraw(); 101 }, 102 }); 103} 104 105function renderTimestamp(time: time): m.Children { 106 const fmt = timestampFormat(); 107 const domainTime = globals.toDomainTime(time); 108 switch (fmt) { 109 case TimestampFormat.UTC: 110 case TimestampFormat.TraceTz: 111 case TimestampFormat.Timecode: 112 return renderTimecode(domainTime); 113 case TimestampFormat.Raw: 114 return domainTime.toString(); 115 case TimestampFormat.RawLocale: 116 return domainTime.toLocaleString(); 117 case TimestampFormat.Seconds: 118 return Time.formatSeconds(domainTime); 119 default: 120 const x: never = fmt; 121 throw new Error(`Invalid timestamp ${x}`); 122 } 123} 124 125export function renderTimecode(time: time): m.Children { 126 const {dhhmmss, millis, micros, nanos} = Time.toTimecode(time); 127 return m( 128 'span.pf-timecode', 129 m('span.pf-timecode-hms', dhhmmss), 130 '.', 131 m('span.pf-timecode-millis', millis), 132 m('span.pf-timecode-micros', micros), 133 m('span.pf-timecode-nanos', nanos), 134 ); 135} 136