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