blob: 81c03edd515b17253f67a3324063f630874e621d [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
import com.android.annotations.VisibleForTesting;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* The {@link IncludeOverlay} class renders masks to -partially- hide everything outside
* an included file's own content. This overlay is in use when you are editing an included
* file shown within a different file's context (e.g. "Show In > other").
*/
public class IncludeOverlay extends Overlay {
/** Mask transparency - 0 is transparent, 255 is opaque */
private static final int MASK_TRANSPARENCY = 160;
/** The associated {@link LayoutCanvas}. */
private LayoutCanvas mCanvas;
/**
* Constructs an {@link IncludeOverlay} tied to the given canvas.
*
* @param canvas The {@link LayoutCanvas} to paint the overlay over.
*/
public IncludeOverlay(LayoutCanvas canvas) {
mCanvas = canvas;
}
@Override
public void paint(GC gc) {
ViewHierarchy viewHierarchy = mCanvas.getViewHierarchy();
List<Rectangle> includedBounds = viewHierarchy.getIncludedBounds();
if (includedBounds == null || includedBounds.size() == 0) {
// We don't support multiple included children yet. When that works,
// this code should use a BSP tree to figure out which regions to paint
// to leave holes in the mask.
return;
}
Image image = mCanvas.getImageOverlay().getImage();
if (image == null) {
return;
}
int oldAlpha = gc.getAlpha();
gc.setAlpha(MASK_TRANSPARENCY);
Color bg = gc.getDevice().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
gc.setBackground(bg);
CanvasViewInfo root = viewHierarchy.getRoot();
Rectangle whole = root.getAbsRect();
whole = new Rectangle(whole.x, whole.y, whole.width + 1, whole.height + 1);
Collection<Rectangle> masks = subtractRectangles(whole, includedBounds);
for (Rectangle mask : masks) {
ControlPoint topLeft = LayoutPoint.create(mCanvas, mask.x, mask.y).toControl();
ControlPoint bottomRight = LayoutPoint.create(mCanvas, mask.x + mask.width,
mask.y + mask.height).toControl();
int x1 = topLeft.x;
int y1 = topLeft.y;
int x2 = bottomRight.x;
int y2 = bottomRight.y;
gc.fillRectangle(x1, y1, x2 - x1, y2 - y1);
}
gc.setAlpha(oldAlpha);
}
/**
* Given a Rectangle, remove holes from it (specified as a collection of Rectangles) such
* that the result is a list of rectangles that cover everything that is not a hole.
*
* @param rectangle the rectangle to subtract from
* @param holes the holes to subtract from the rectangle
* @return a list of sub rectangles that remain after subtracting out the given list of holes
*/
@VisibleForTesting
static Collection<Rectangle> subtractRectangles(
Rectangle rectangle, Collection<Rectangle> holes) {
List<Rectangle> result = new ArrayList<Rectangle>();
result.add(rectangle);
for (Rectangle hole : holes) {
List<Rectangle> tempResult = new ArrayList<Rectangle>();
for (Rectangle r : result) {
if (hole.intersects(r)) {
// Clip the hole to fit the rectangle bounds
Rectangle h = hole.intersection(r);
// Split the rectangle
// Above (includes the NW and NE corners)
if (h.y > r.y) {
tempResult.add(new Rectangle(r.x, r.y, r.width, h.y - r.y));
}
// Left (not including corners)
if (h.x > r.x) {
tempResult.add(new Rectangle(r.x, h.y, h.x - r.x, h.height));
}
int hx2 = h.x + h.width;
int hy2 = h.y + h.height;
int rx2 = r.x + r.width;
int ry2 = r.y + r.height;
// Below (includes the SW and SE corners)
if (hy2 < ry2) {
tempResult.add(new Rectangle(r.x, hy2, r.width, ry2 - hy2));
}
// Right (not including corners)
if (hx2 < rx2) {
tempResult.add(new Rectangle(hx2, h.y, rx2 - hx2, h.height));
}
} else {
tempResult.add(r);
}
}
result = tempResult;
}
return result;
}
}