1 /* 2 * Copyright (C) 2010 The Android Open Source Project 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 * http://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 com.android.hierarchyviewerlib.ui.util; 18 19 import com.android.hierarchyviewerlib.device.ViewNode; 20 21 import java.util.ArrayList; 22 23 public class DrawableViewNode { 24 public ViewNode viewNode; 25 26 public final ArrayList<DrawableViewNode> children = new ArrayList<DrawableViewNode>(); 27 28 public final static int NODE_HEIGHT = 100; 29 30 public final static int NODE_WIDTH = 180; 31 32 public final static int CONTENT_LEFT_RIGHT_PADDING = 9; 33 34 public final static int CONTENT_TOP_BOTTOM_PADDING = 8; 35 36 public final static int CONTENT_INTER_PADDING = 3; 37 38 public final static int INDEX_PADDING = 7; 39 40 public final static int LEAF_NODE_SPACING = 9; 41 42 public final static int NON_LEAF_NODE_SPACING = 15; 43 44 public final static int PARENT_CHILD_SPACING = 50; 45 46 public final static int PADDING = 30; 47 48 public int treeHeight; 49 50 public int treeWidth; 51 52 public boolean leaf; 53 54 public DrawableViewNode parent; 55 56 public int left; 57 58 public double top; 59 60 public int topSpacing; 61 62 public int bottomSpacing; 63 64 public boolean treeDrawn; 65 66 public static class Rectangle { 67 public double x, y, width, height; 68 69 public Rectangle() { 70 71 } 72 73 public Rectangle(Rectangle other) { 74 this.x = other.x; 75 this.y = other.y; 76 this.width = other.width; 77 this.height = other.height; 78 } 79 80 public Rectangle(double x, double y, double width, double height) { 81 this.x = x; 82 this.y = y; 83 this.width = width; 84 this.height = height; 85 } 86 87 @Override 88 public String toString() { 89 return "{" + x + ", " + y + ", " + width + ", " + height + "}"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ 90 } 91 92 } 93 94 public static class Point { 95 public double x, y; 96 97 public Point() { 98 } 99 100 public Point(double x, double y) { 101 this.x = x; 102 this.y = y; 103 } 104 105 @Override 106 public String toString() { 107 return "(" + x + ", " + y + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 108 } 109 } 110 111 public Rectangle bounds = new Rectangle(); 112 113 public DrawableViewNode(ViewNode viewNode) { 114 this.viewNode = viewNode; 115 treeDrawn = !viewNode.willNotDraw; 116 if (viewNode.children.size() == 0) { 117 treeHeight = NODE_HEIGHT; 118 treeWidth = NODE_WIDTH; 119 leaf = true; 120 } else { 121 leaf = false; 122 int N = viewNode.children.size(); 123 treeHeight = 0; 124 treeWidth = 0; 125 for (int i = 0; i < N; i++) { 126 DrawableViewNode child = new DrawableViewNode(viewNode.children.get(i)); 127 children.add(child); 128 child.parent = this; 129 treeHeight += child.treeHeight; 130 treeWidth = Math.max(treeWidth, child.treeWidth); 131 if (i != 0) { 132 DrawableViewNode prevChild = children.get(i - 1); 133 if (prevChild.leaf && child.leaf) { 134 treeHeight += LEAF_NODE_SPACING; 135 prevChild.bottomSpacing = LEAF_NODE_SPACING; 136 child.topSpacing = LEAF_NODE_SPACING; 137 } else { 138 treeHeight += NON_LEAF_NODE_SPACING; 139 prevChild.bottomSpacing = NON_LEAF_NODE_SPACING; 140 child.topSpacing = NON_LEAF_NODE_SPACING; 141 } 142 } 143 treeDrawn |= child.treeDrawn; 144 } 145 treeWidth += NODE_WIDTH + PARENT_CHILD_SPACING; 146 } 147 } 148 149 public void setLeft() { 150 if (parent == null) { 151 left = PADDING; 152 bounds.x = 0; 153 bounds.width = treeWidth + 2 * PADDING; 154 } else { 155 left = parent.left + NODE_WIDTH + PARENT_CHILD_SPACING; 156 } 157 int N = children.size(); 158 for (int i = 0; i < N; i++) { 159 children.get(i).setLeft(); 160 } 161 } 162 163 public void placeRoot() { 164 top = PADDING + (treeHeight - NODE_HEIGHT) / 2.0; 165 double currentTop = PADDING; 166 int N = children.size(); 167 for (int i = 0; i < N; i++) { 168 DrawableViewNode child = children.get(i); 169 child.place(currentTop, top - currentTop); 170 currentTop += child.treeHeight + child.bottomSpacing; 171 } 172 bounds.y = 0; 173 bounds.height = treeHeight + 2 * PADDING; 174 } 175 176 private void place(double treeTop, double rootDistance) { 177 if (treeHeight <= rootDistance) { 178 top = treeTop + treeHeight - NODE_HEIGHT; 179 } else if (rootDistance <= -NODE_HEIGHT) { 180 top = treeTop; 181 } else { 182 if (children.size() == 0) { 183 top = treeTop; 184 } else { 185 top = 186 rootDistance + treeTop - NODE_HEIGHT + (2.0 * NODE_HEIGHT) 187 / (treeHeight + NODE_HEIGHT) * (treeHeight - rootDistance); 188 } 189 } 190 int N = children.size(); 191 double currentTop = treeTop; 192 for (int i = 0; i < N; i++) { 193 DrawableViewNode child = children.get(i); 194 child.place(currentTop, rootDistance); 195 currentTop += child.treeHeight + child.bottomSpacing; 196 rootDistance -= child.treeHeight + child.bottomSpacing; 197 } 198 } 199 200 public DrawableViewNode getSelected(double x, double y) { 201 if (x >= left && x < left + NODE_WIDTH && y >= top && y <= top + NODE_HEIGHT) { 202 return this; 203 } 204 int N = children.size(); 205 for (int i = 0; i < N; i++) { 206 DrawableViewNode selected = children.get(i).getSelected(x, y); 207 if (selected != null) { 208 return selected; 209 } 210 } 211 return null; 212 } 213 214 /* 215 * Moves the node the specified distance up. 216 */ 217 public void move(double distance) { 218 top -= distance; 219 220 // Get the root 221 DrawableViewNode root = this; 222 while (root.parent != null) { 223 root = root.parent; 224 } 225 226 // Figure out the new tree top. 227 double treeTop; 228 if (top + NODE_HEIGHT <= root.top) { 229 treeTop = top + NODE_HEIGHT - treeHeight; 230 } else if (top >= root.top + NODE_HEIGHT) { 231 treeTop = top; 232 } else { 233 if (leaf) { 234 treeTop = top; 235 } else { 236 double distanceRatio = 1 - (root.top + NODE_HEIGHT - top) / (2.0 * NODE_HEIGHT); 237 treeTop = root.top - treeHeight + distanceRatio * (treeHeight + NODE_HEIGHT); 238 } 239 } 240 // Go up the tree and figure out the tree top. 241 DrawableViewNode node = this; 242 while (node.parent != null) { 243 int index = node.viewNode.index; 244 for (int i = 0; i < index; i++) { 245 DrawableViewNode sibling = node.parent.children.get(i); 246 treeTop -= sibling.treeHeight + sibling.bottomSpacing; 247 } 248 node = node.parent; 249 } 250 251 // Update the bounds. 252 root.bounds.y = Math.min(root.top - PADDING, treeTop - PADDING); 253 root.bounds.height = 254 Math.max(treeTop + root.treeHeight + PADDING, root.top + NODE_HEIGHT + PADDING) 255 - root.bounds.y; 256 // Place all the children of the root 257 double currentTop = treeTop; 258 int N = root.children.size(); 259 for (int i = 0; i < N; i++) { 260 DrawableViewNode child = root.children.get(i); 261 child.place(currentTop, root.top - currentTop); 262 currentTop += child.treeHeight + child.bottomSpacing; 263 } 264 265 } 266 } 267