1 /*
2  * Copyright (C) 2008 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.hierarchyviewer.ui;
18 
19 import com.android.hierarchyviewer.scene.ViewHierarchyScene;
20 import com.android.hierarchyviewer.scene.ViewNode;
21 
22 import javax.swing.JComponent;
23 import javax.swing.BorderFactory;
24 import java.awt.Color;
25 import java.awt.Dimension;
26 import java.awt.Graphics;
27 import java.awt.Insets;
28 import java.awt.event.MouseAdapter;
29 import java.awt.event.MouseEvent;
30 import java.util.Set;
31 
32 class LayoutRenderer extends JComponent {
33     private static final int EMULATED_SCREEN_WIDTH = 320;
34     private static final int EMULATED_SCREEN_HEIGHT = 480;
35     private static final int SCREEN_MARGIN = 24;
36 
37     private boolean showExtras;
38     private ViewHierarchyScene scene;
39     private JComponent sceneView;
40 
LayoutRenderer(ViewHierarchyScene scene, JComponent sceneView)41     LayoutRenderer(ViewHierarchyScene scene, JComponent sceneView) {
42         this.scene = scene;
43         this.sceneView = sceneView;
44 
45         setOpaque(true);
46         setBorder(BorderFactory.createEmptyBorder(0, 0, 12, 0));
47         setBackground(Color.BLACK);
48         setForeground(Color.WHITE);
49 
50         addMouseListener(new MouseAdapter() {
51             @Override
52             public void mousePressed(MouseEvent event) {
53                 selectChild(event.getX(), event.getY());
54             }
55         });
56     }
57 
58     @Override
getPreferredSize()59     public Dimension getPreferredSize() {
60         return new Dimension(EMULATED_SCREEN_WIDTH + SCREEN_MARGIN,
61                 EMULATED_SCREEN_HEIGHT + SCREEN_MARGIN);
62     }
63 
64     @Override
paintComponent(Graphics g)65     protected void paintComponent(Graphics g) {
66         g.setColor(getBackground());
67         g.fillRect(0, 0, getWidth(), getHeight());
68 
69         Insets insets = getInsets();
70         g.clipRect(insets.left, insets.top,
71                 getWidth() - insets.left - insets.right,
72                 getHeight() - insets.top - insets.bottom);
73 
74         if (scene == null) {
75             return;
76         }
77 
78         ViewNode root = scene.getRoot();
79         if (root == null) {
80             return;
81         }
82 
83         int x = (getWidth() - insets.left - insets.right - root.width) / 2;
84         int y = (getHeight() - insets.top - insets.bottom - root.height) / 2;
85         g.translate(insets.left + x, insets.top + y);
86 
87         g.setColor(getForeground());
88         g.drawRect(root.left, root.top, root.width - 1, root.height - 1);
89         g.clipRect(root.left - 1, root.top - 1, root.width + 1, root.height + 1);
90         drawChildren(g, root, -root.scrollX, -root.scrollY);
91 
92         Set<?> selection = scene.getSelectedObjects();
93         if (selection.size() > 0) {
94             ViewNode node = (ViewNode) selection.iterator().next();
95             g.setColor(Color.RED);
96             Graphics s = g.create();
97             ViewNode p = node.parent;
98             while (p != null) {
99                 s.translate(p.left - p.scrollX, p.top - p.scrollY);
100                 p = p.parent;
101             }
102             if (showExtras && node.image != null) {
103                 s.drawImage(node.image, node.left, node.top, null);
104             }
105             s.drawRect(node.left, node.top, node.width - 1, node.height - 1);
106             s.dispose();
107         }
108 
109         g.translate(-insets.left - x, -insets.top - y);
110     }
111 
drawChildren(Graphics g, ViewNode root, int x, int y)112     private void drawChildren(Graphics g, ViewNode root, int x, int y) {
113         g.translate(x, y);
114         for (ViewNode node : root.children) {
115             if (!node.willNotDraw) {
116                 g.drawRect(node.left, node.top, node.width - 1, node.height - 1);
117             }
118 
119             if (node.children.size() > 0) {
120                 drawChildren(g, node,
121                         node.left - node.parent.scrollX,
122                         node.top - node.parent.scrollY);
123             }
124         }
125         g.translate(-x, -y);
126     }
127 
setShowExtras(boolean showExtras)128     public void setShowExtras(boolean showExtras) {
129         this.showExtras = showExtras;
130         repaint();
131     }
132 
selectChild(int x, int y)133     private void selectChild(int x, int y) {
134 
135         if (scene == null) {
136             return;
137         }
138 
139         ViewNode root = scene.getRoot();
140         if (root == null) {
141             return;
142         }
143 
144         Insets insets = getInsets();
145 
146         int xoffset = (getWidth() - insets.left - insets.right - root.width) / 2 + insets.left + 1;
147         int yoffset = (getHeight() - insets.top - insets.bottom - root.height) / 2 + insets.top + 1;
148 
149         x -= xoffset;
150         y -= yoffset;
151         if (x >= 0 && x < EMULATED_SCREEN_WIDTH && y >= 0 && y < EMULATED_SCREEN_HEIGHT) {
152             ViewNode hit = findChild(root, root, x, y);
153             scene.setFocusedObject(hit);
154             sceneView.repaint();
155         }
156     }
157 
findChild(ViewNode root, ViewNode besthit, int x, int y)158     private ViewNode findChild(ViewNode root, ViewNode besthit, int x, int y) {
159         ViewNode hit = besthit;
160         for (ViewNode node : root.children) {
161 
162             if (node.left <= x && x < node.left + node.width &&
163                 node.top <= y && y < node.top + node.height) {
164                 if (node.width <= hit.width && node.height <= hit.height) {
165                     hit = node;
166                 }
167             }
168 
169             if (node.children.size() > 0) {
170                 hit = findChild(node, hit,
171                         x - (node.left - node.parent.scrollX),
172                         y - (node.top - node.parent.scrollY));
173             }
174         }
175         return hit;
176     }
177 }
178