1<!-- Copyright (C) 2019 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--> 15<template> 16 <md-card-content class="container"> 17 <md-card class="rects" v-if="hasScreenView"> 18 <md-whiteframe md-tag="md-toolbar" md-elevation="0" class="card-toolbar md-transparent md-dense"> 19 <h2 class="md-title">Screen</h2> 20 </md-whiteframe> 21 <md-whiteframe md-elevation="8"> 22 <rects :bounds="bounds" :rects="rects" :highlight="highlight" @rect-click="onRectClick" /> 23 </md-whiteframe> 24 </md-card> 25 <md-card class="hierarchy"> 26 <md-whiteframe md-tag="md-toolbar" md-elevation="0" class="card-toolbar md-transparent md-dense"> 27 <h2 class="md-title" style="flex: 1;">Hierarchy</h2> 28 <md-checkbox v-model="store.onlyVisible">Only visible</md-checkbox> 29 <md-checkbox v-model="store.flattened">Flat</md-checkbox> 30 </md-whiteframe> 31 <tree-view class="data-card" :item="tree" @item-selected="itemSelected" :selected="hierarchySelected" :filter="hierarchyFilter" :flattened="store.flattened" ref="hierarchy" /> 32 </md-card> 33 <md-card class="properties"> 34 <md-whiteframe md-tag="md-toolbar" md-elevation="0" class="card-toolbar md-transparent md-dense"> 35 <h2 class="md-title" style="flex: 1">Properties</h2> 36 <div class="filter"> 37 <input id="filter" type="search" placeholder="Filter..." v-model="propertyFilterString" /> 38 </div> 39 </md-whiteframe> 40 <tree-view class="data-card" :item="selectedTree" :filter="propertyFilter" /> 41 </md-card> 42 </md-card-content> 43</template> 44<script> 45import TreeView from './TreeView.vue' 46import Timeline from './Timeline.vue' 47import Rects from './Rects.vue' 48 49import { transform_json } from './transform.js' 50import { format_transform_type, is_simple_transform } from './matrix_utils.js' 51import { DATA_TYPES } from './decode.js' 52 53function formatColorTransform(vals) { 54 const fixedVals = vals.map(v => v.toFixed(1)); 55 var formatted = ``; 56 for (var i = 0; i < fixedVals.length; i += 4) { 57 formatted += `[`; 58 formatted += fixedVals.slice(i, i + 4).join(", "); 59 formatted += `] `; 60 } 61 return formatted; 62} 63 64 65function formatProto(obj) { 66 if (!obj || !obj.$type) { 67 return; 68 } 69 if (obj.$type.name === 'RectProto') { 70 return `(${obj.left}, ${obj.top}) - (${obj.right}, ${obj.bottom})`; 71 } else if (obj.$type.name === 'FloatRectProto') { 72 return `(${obj.left.toFixed(3)}, ${obj.top.toFixed(3)}) - (${obj.right.toFixed(3)}, ${obj.bottom.toFixed(3)})`; 73 } else if (obj.$type.name === 'PositionProto') { 74 return `(${obj.x.toFixed(3)}, ${obj.y.toFixed(3)})`; 75 } else if (obj.$type.name === 'SizeProto') { 76 return `${obj.w} x ${obj.h}`; 77 } else if (obj.$type.name === 'ColorProto') { 78 return `r:${obj.r} g:${obj.g} \n b:${obj.b} a:${obj.a}`; 79 } else if (obj.$type.name === 'TransformProto') { 80 var transform_type = format_transform_type(obj); 81 if (is_simple_transform(obj)) { 82 return `${transform_type}`; 83 } 84 return `${transform_type} dsdx:${obj.dsdx.toFixed(3)} dtdx:${obj.dtdx.toFixed(3)} dsdy:${obj.dsdy.toFixed(3)} dtdy:${obj.dtdy.toFixed(3)}`; 85 } else if (obj.$type.name === 'ColorTransformProto') { 86 var formated = formatColorTransform(obj.val); 87 return `${formated}`; 88 } 89} 90 91export default { 92 name: 'traceview', 93 data() { 94 return { 95 propertyFilterString: "", 96 selectedTree: {}, 97 hierarchySelected: null, 98 lastSelectedStableId: null, 99 bounds: {}, 100 rects: [], 101 tree: null, 102 highlight: null, 103 } 104 }, 105 methods: { 106 itemSelected(item) { 107 this.hierarchySelected = item; 108 this.selectedTree = transform_json(item.obj, item.name, { 109 skip: item.skip, 110 formatter: formatProto 111 }); 112 this.highlight = item.highlight; 113 this.lastSelectedStableId = item.stableId; 114 this.$emit('focus'); 115 }, 116 onRectClick(item) { 117 if (item) { 118 this.itemSelected(item); 119 } 120 }, 121 setData(item) { 122 this.tree = item; 123 this.rects = [...item.rects].reverse(); 124 this.bounds = item.bounds; 125 126 this.hierarchySelected = null; 127 this.selectedTree = {}; 128 this.highlight = null; 129 130 function find_item(item, stableId) { 131 if (item.stableId === stableId) { 132 return item; 133 } 134 if (Array.isArray(item.children)) { 135 for (var child of item.children) { 136 var found = find_item(child, stableId); 137 if (found) { 138 return found; 139 } 140 } 141 } 142 return null; 143 } 144 145 if (this.lastSelectedStableId) { 146 var found = find_item(item, this.lastSelectedStableId); 147 if (found) { 148 this.itemSelected(found); 149 } 150 } 151 }, 152 arrowUp() { 153 return this.$refs.hierarchy.selectPrev(); 154 }, 155 arrowDown() { 156 return this.$refs.hierarchy.selectNext(); 157 }, 158 }, 159 created() { 160 this.setData(this.file.data[this.file.selectedIndex]); 161 }, 162 watch: { 163 selectedIndex() { 164 this.setData(this.file.data[this.file.selectedIndex]); 165 } 166 }, 167 props: ['store', 'file'], 168 computed: { 169 selectedIndex() { 170 return this.file.selectedIndex; 171 }, 172 hierarchyFilter() { 173 return this.store.onlyVisible ? (c, flattened) => { 174 return c.visible || c.childrenVisible && !flattened; 175 } : null; 176 }, 177 propertyFilter() { 178 var filterStrings = this.propertyFilterString.split(","); 179 var positive = []; 180 var negative = []; 181 filterStrings.forEach((f) => { 182 if (f.startsWith("!")) { 183 var str = f.substring(1); 184 negative.push((s) => s.indexOf(str) === -1); 185 } else { 186 var str = f; 187 positive.push((s) => s.indexOf(str) !== -1); 188 } 189 }); 190 var filter = (item) => { 191 var apply = (f) => f(item.name); 192 return (positive.length === 0 || positive.some(apply)) && 193 (negative.length === 0 || negative.every(apply)); 194 }; 195 filter.includeChildren = true; 196 return filter; 197 }, 198 hasScreenView() { 199 return this.file.type !== DATA_TYPES.TRANSACTION; 200 }, 201 }, 202 components: { 203 'tree-view': TreeView, 204 'rects': Rects, 205 } 206} 207 208</script> 209<style> 210.rects { 211 flex: none; 212 margin: 8px; 213} 214 215.hierarchy, 216.properties { 217 flex: 1; 218 margin: 8px; 219 min-width: 400px; 220} 221 222.hierarchy>.tree-view, 223.properties>.tree-view { 224 margin: 16px; 225} 226 227.data-card { 228 overflow: auto; 229 max-height: 48em; 230} 231 232</style> 233