Home | History | Annotate | Download | only in util
      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