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 17 package com.android.ide.eclipse.adt.internal.editors.layout.gle2; 18 19 import com.android.annotations.VisibleForTesting; 20 21 import org.eclipse.swt.SWT; 22 import org.eclipse.swt.graphics.Color; 23 import org.eclipse.swt.graphics.GC; 24 import org.eclipse.swt.graphics.Image; 25 import org.eclipse.swt.graphics.Rectangle; 26 27 import java.util.ArrayList; 28 import java.util.Collection; 29 import java.util.List; 30 31 /** 32 * The {@link IncludeOverlay} class renders masks to -partially- hide everything outside 33 * an included file's own content. This overlay is in use when you are editing an included 34 * file shown within a different file's context (e.g. "Show In > other"). 35 */ 36 public class IncludeOverlay extends Overlay { 37 /** Mask transparency - 0 is transparent, 255 is opaque */ 38 private static final int MASK_TRANSPARENCY = 160; 39 40 /** The associated {@link LayoutCanvas}. */ 41 private LayoutCanvas mCanvas; 42 43 /** 44 * Constructs an {@link IncludeOverlay} tied to the given canvas. 45 * 46 * @param canvas The {@link LayoutCanvas} to paint the overlay over. 47 */ 48 public IncludeOverlay(LayoutCanvas canvas) { 49 mCanvas = canvas; 50 } 51 52 @Override 53 public void paint(GC gc) { 54 ViewHierarchy viewHierarchy = mCanvas.getViewHierarchy(); 55 List<Rectangle> includedBounds = viewHierarchy.getIncludedBounds(); 56 if (includedBounds == null || includedBounds.size() == 0) { 57 // We don't support multiple included children yet. When that works, 58 // this code should use a BSP tree to figure out which regions to paint 59 // to leave holes in the mask. 60 return; 61 } 62 63 Image image = mCanvas.getImageOverlay().getImage(); 64 if (image == null) { 65 return; 66 } 67 68 int oldAlpha = gc.getAlpha(); 69 gc.setAlpha(MASK_TRANSPARENCY); 70 Color bg = gc.getDevice().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); 71 gc.setBackground(bg); 72 73 CanvasViewInfo root = viewHierarchy.getRoot(); 74 Rectangle whole = root.getAbsRect(); 75 whole = new Rectangle(whole.x, whole.y, whole.width + 1, whole.height + 1); 76 Collection<Rectangle> masks = subtractRectangles(whole, includedBounds); 77 78 for (Rectangle mask : masks) { 79 ControlPoint topLeft = LayoutPoint.create(mCanvas, mask.x, mask.y).toControl(); 80 ControlPoint bottomRight = LayoutPoint.create(mCanvas, mask.x + mask.width, 81 mask.y + mask.height).toControl(); 82 int x1 = topLeft.x; 83 int y1 = topLeft.y; 84 int x2 = bottomRight.x; 85 int y2 = bottomRight.y; 86 87 gc.fillRectangle(x1, y1, x2 - x1, y2 - y1); 88 } 89 90 gc.setAlpha(oldAlpha); 91 } 92 93 /** 94 * Given a Rectangle, remove holes from it (specified as a collection of Rectangles) such 95 * that the result is a list of rectangles that cover everything that is not a hole. 96 * 97 * @param rectangle the rectangle to subtract from 98 * @param holes the holes to subtract from the rectangle 99 * @return a list of sub rectangles that remain after subtracting out the given list of holes 100 */ 101 @VisibleForTesting 102 static Collection<Rectangle> subtractRectangles( 103 Rectangle rectangle, Collection<Rectangle> holes) { 104 List<Rectangle> result = new ArrayList<Rectangle>(); 105 result.add(rectangle); 106 107 for (Rectangle hole : holes) { 108 List<Rectangle> tempResult = new ArrayList<Rectangle>(); 109 for (Rectangle r : result) { 110 if (hole.intersects(r)) { 111 // Clip the hole to fit the rectangle bounds 112 Rectangle h = hole.intersection(r); 113 114 // Split the rectangle 115 116 // Above (includes the NW and NE corners) 117 if (h.y > r.y) { 118 tempResult.add(new Rectangle(r.x, r.y, r.width, h.y - r.y)); 119 } 120 121 // Left (not including corners) 122 if (h.x > r.x) { 123 tempResult.add(new Rectangle(r.x, h.y, h.x - r.x, h.height)); 124 } 125 126 int hx2 = h.x + h.width; 127 int hy2 = h.y + h.height; 128 int rx2 = r.x + r.width; 129 int ry2 = r.y + r.height; 130 131 // Below (includes the SW and SE corners) 132 if (hy2 < ry2) { 133 tempResult.add(new Rectangle(r.x, hy2, r.width, ry2 - hy2)); 134 } 135 136 // Right (not including corners) 137 if (hx2 < rx2) { 138 tempResult.add(new Rectangle(hx2, h.y, rx2 - hx2, h.height)); 139 } 140 } else { 141 tempResult.add(r); 142 } 143 } 144 145 result = tempResult; 146 } 147 148 return result; 149 } 150 } 151