• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
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
17package com.android.adt.gscripts;
18
19/**
20 * An {@link IViewRule} for android.widget.AbsoluteLayout and all its derived classes.
21 */
22public class AndroidWidgetAbsoluteLayoutRule extends BaseLayout {
23
24    // ==== Drag'n'drop support ====
25    // The AbsoluteLayout accepts any drag'n'drop anywhere on its surface.
26
27    DropFeedback onDropEnter(INode targetNode, IDragElement[] elements) {
28
29        if (elements.length == 0) {
30            return null;
31        }
32
33        return new DropFeedback(
34            [ "p": null ],      // Point: last cursor position
35            {
36                gc, node, feedback ->
37                // Paint closure for the AbsoluteLayout.
38                // This is called by the canvas when a draw is needed.
39
40                drawFeedback(gc, node, elements, feedback);
41            });
42    }
43
44    void drawFeedback(IGraphics gc,
45                      INode targetNode,
46                      IDragElement[] elements,
47                      DropFeedback feedback) {
48        Rect b = targetNode.getBounds();
49        if (!b.isValid()) {
50            return;
51        }
52
53        // Highlight the receiver
54        gc.setForeground(gc.registerColor(0x00FFFF00));
55        gc.setLineStyle(IGraphics.LineStyle.LINE_SOLID);
56        gc.setLineWidth(2);
57        gc.drawRect(b);
58
59        // Get the drop point
60        Point p = feedback.userData.p;
61
62        if (p == null) {
63            return;
64        }
65
66        int x = p.x;
67        int y = p.y;
68
69        Rect be = elements[0].getBounds();
70
71        if (be.isValid()) {
72            // At least the first element has a bound. Draw rectangles
73            // for all dropped elements with valid bounds, offset at
74            // the drop point.
75            int offsetX = x - be.x;
76            int offsetY = y - be.y;
77            elements.each {
78                drawElement(gc, it, offsetX, offsetY);
79            }
80        } else {
81            // We don't have bounds for new elements. In this case
82            // just draw a mark at the drop point.
83            gc.drawLine(x - 10, y - 10, x + 10, y + 10);
84            gc.drawLine(x + 10, y - 10, x - 10, y + 10);
85            gc.drawOval(x - 10, y - 10, x + 10, y + 10);
86        }
87    }
88
89    DropFeedback onDropMove(INode targetNode,
90                            IDragElement[] elements,
91                            DropFeedback feedback,
92                            Point p) {
93        // Update the data used by the DropFeedback.paintClosure above.
94        feedback.userData.p = p;
95        feedback.requestPaint = true;
96
97        return feedback;
98    }
99
100    void onDropLeave(INode targetNode, IDragElement[] elements, DropFeedback feedback) {
101        // Nothing to do.
102    }
103
104    void onDropped(INode targetNode,
105                   IDragElement[] elements,
106                   DropFeedback feedback,
107                   Point p) {
108
109        Rect b = targetNode.getBounds();
110        if (!b.isValid()) {
111            return;
112        }
113
114        int x = p.x - b.x;
115        int y = p.y - b.y;
116
117        // Collect IDs from dropped elements and remap them to new IDs
118        // if this is a copy or from a different canvas.
119        def idMap = getDropIdMap(targetNode, elements, feedback.isCopy || !feedback.sameCanvas);
120
121        targetNode.editXml("Add elements to AbsoluteLayout") {
122
123            boolean first = true;
124            Point offset = null;
125
126            // Now write the new elements.
127            elements.each { element ->
128                String fqcn = element.getFqcn();
129                Rect be = element.getBounds();
130
131                INode newChild = targetNode.appendChild(fqcn);
132
133                // Copy all the attributes, modifying them as needed.
134                def attrFilter = getLayoutAttrFilter();
135                addAttributes(newChild, element, idMap) {
136                    uri, name, value ->
137                    // TODO need a better way to exclude other layout attributes dynamically
138                    if (uri == ANDROID_URI && name in attrFilter) {
139                        return false; // don't set these attributes
140                    } else {
141                        return value;
142                    }
143                };
144
145                if (first) {
146                    first = false;
147                    if (be.isValid()) {
148                        offset = new Point(x - be.x, y - be.y);
149                    }
150                } else if (offset != null && be.isValid()) {
151                    x = offset.x + be.x;
152                    y = offset.y + be.y;
153                } else {
154                    x += 10;
155                    y += be.isValid() ? be.h : 10;
156                }
157
158                newChild.setAttribute(ANDROID_URI, "layout_x", "${x}dip");
159                newChild.setAttribute(ANDROID_URI, "layout_y", "${y}dip");
160
161                addInnerElements(newChild, element, idMap);
162            }
163        }
164    }
165
166}
167