aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MarqueeGesture.java
blob: 4cfd4fe3d56fc5cc59d1fbf0482778c79e4e272b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * 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 org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * A {@link MarqueeGesture} is a gesture for swiping out a selection rectangle.
 * With a modifier key, items that intersect the rectangle can be toggled
 * instead of added to the new selection set.
 */
public class MarqueeGesture extends Gesture {
    /** The {@link Overlay} drawn for the marquee. */
    private MarqueeOverlay mOverlay;

    /** The canvas associated with this gesture. */
    private LayoutCanvas mCanvas;

    /** A copy of the initial selection, when we're toggling the marquee. */
    private Collection<CanvasViewInfo> mInitialSelection;

    /**
     * Creates a new marquee selection (selection swiping).
     *
     * @param canvas The canvas where selection is performed.
     * @param toggle If true, toggle the membership of contained elements
     *            instead of adding it.
     */
    public MarqueeGesture(LayoutCanvas canvas, boolean toggle) {
        mCanvas = canvas;

        if (toggle) {
            List<SelectionItem> selection = canvas.getSelectionManager().getSelections();
            mInitialSelection = new ArrayList<CanvasViewInfo>(selection.size());
            for (SelectionItem item : selection) {
                mInitialSelection.add(item.getViewInfo());
            }
        } else {
            mInitialSelection = Collections.emptySet();
        }
    }

    @Override
    public void update(ControlPoint pos) {
        if (mOverlay == null) {
            return;
        }

        int x = Math.min(pos.x, mStart.x);
        int y = Math.min(pos.y, mStart.y);
        int w = Math.abs(pos.x - mStart.x);
        int h = Math.abs(pos.y - mStart.y);

        mOverlay.updateSize(x, y, w, h);

        // Compute selection overlaps
        LayoutPoint topLeft = ControlPoint.create(mCanvas, x, y).toLayout();
        LayoutPoint bottomRight = ControlPoint.create(mCanvas, x + w, y + h).toLayout();
        mCanvas.getSelectionManager().selectWithin(topLeft, bottomRight, mInitialSelection);
    }

    @Override
    public List<Overlay> createOverlays() {
        mOverlay = new MarqueeOverlay();
        return Collections.<Overlay> singletonList(mOverlay);
    }

    /**
     * An {@link Overlay} for the {@link MarqueeGesture}; paints a selection
     * overlay rectangle matching the mouse coordinate delta between gesture
     * start and the current position.
     */
    private static class MarqueeOverlay extends Overlay {
        /** Rectangle border color. */
        private Color mStroke;

        /** Rectangle fill color. */
        private Color mFill;

        /** Current rectangle coordinates (in terms of control coordinates). */
        private Rectangle mRectangle = new Rectangle(0, 0, 0, 0);

        /** Alpha value of the fill. */
        private int mFillAlpha;

        /** Alpha value of the border. */
        private int mStrokeAlpha;

        /** Constructs a new {@link MarqueeOverlay}. */
        public MarqueeOverlay() {
        }

        /**
         * Updates the size of the marquee rectangle.
         *
         * @param x The top left corner of the rectangle, x coordinate.
         * @param y The top left corner of the rectangle, y coordinate.
         * @param w Rectangle width.
         * @param h Rectangle height.
         */
        public void updateSize(int x, int y, int w, int h) {
            mRectangle.x = x;
            mRectangle.y = y;
            mRectangle.width = w;
            mRectangle.height = h;
        }

        @Override
        public void create(Device device) {
            // TODO: Integrate DrawingStyles with this?
            mStroke = new Color(device, 255, 255, 255);
            mFill = new Color(device, 128, 128, 128);
            mFillAlpha = 64;
            mStrokeAlpha = 255;
        }

        @Override
        public void dispose() {
            mStroke.dispose();
            mFill.dispose();
        }

        @Override
        public void paint(GC gc) {
            if (mRectangle.width > 0 && mRectangle.height > 0) {
                gc.setLineStyle(SWT.LINE_SOLID);
                gc.setLineWidth(1);
                gc.setForeground(mStroke);
                gc.setBackground(mFill);
                gc.setAlpha(mStrokeAlpha);
                gc.drawRectangle(mRectangle);
                gc.setAlpha(mFillAlpha);
                gc.fillRectangle(mRectangle);
            }
        }
    }
}