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