Home | History | Annotate | Download | only in gle2
      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         this.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