]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextDropTargetEffect.java
675cad903a8dcfbbff858218229a51e2e6076f4f
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / custom / StyledTextDropTargetEffect.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2016 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.custom;
15
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.dnd.*;
18 import org.eclipse.swt.graphics.*;
19 import org.eclipse.swt.widgets.*;
20
21 /**
22  * This adapter class provides a default drag under effect (eg. select and scroll)
23  * when a drag occurs over a <code>StyledText</code>.
24  *
25  * <p>Classes that wish to provide their own drag under effect for a <code>StyledText</code>
26  * can extend this class, override the <code>StyledTextDropTargetEffect.dragOver</code>
27  * method and override any other applicable methods in <code>StyledTextDropTargetEffect</code> to
28  * display their own drag under effect.</p>
29  *
30  * Subclasses that override any methods of this class should call the corresponding
31  * <code>super</code> method to get the default drag under effect implementation.
32  *
33  * <p>The feedback value is either one of the FEEDBACK constants defined in
34  * class <code>DND</code> which is applicable to instances of this class,
35  * or it must be built by <em>bitwise OR</em>'ing together
36  * (that is, using the <code>int</code> "|" operator) two or more
37  * of those <code>DND</code> effect constants.
38  * </p>
39  * <dl>
40  * <dt><b>Feedback:</b></dt>
41  * <dd>FEEDBACK_SELECT, FEEDBACK_SCROLL</dd>
42  * </dl>
43  *
44  * @see DropTargetAdapter
45  * @see DropTargetEvent
46  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
47  *
48  * @since 3.3
49  */
50 public class StyledTextDropTargetEffect extends DropTargetEffect {
51         static final int CARET_WIDTH = 2;
52         static final int SCROLL_HYSTERESIS = 100; // milli seconds
53         static final int SCROLL_TOLERANCE = 20; // pixels
54
55         int currentOffset = -1;
56         long scrollBeginTime;
57         int scrollX = -1, scrollY = -1;
58         Listener paintListener;
59
60         /**
61          * Creates a new <code>StyledTextDropTargetEffect</code> to handle the drag under effect on the specified
62          * <code>StyledText</code>.
63          *
64          * @param styledText the <code>StyledText</code> over which the user positions the cursor to drop the data
65          */
66         public StyledTextDropTargetEffect(StyledText styledText) {
67                 super(styledText);
68                 paintListener = event -> {
69                         if (currentOffset != -1) {
70                                 StyledText text = (StyledText) getControl();
71                                 Point position = text.getLocationAtOffset(currentOffset);
72                                 int height = text.getLineHeight(currentOffset);
73                                 event.gc.setBackground(event.display.getSystemColor (SWT.COLOR_BLACK));
74                                 event.gc.fillRectangle(position.x, position.y, CARET_WIDTH, height);
75                         }
76                 };
77         }
78
79         /**
80          * This implementation of <code>dragEnter</code> provides a default drag under effect
81          * for the feedback specified in <code>event.feedback</code>.
82          *
83          * For additional information see <code>DropTargetAdapter.dragEnter</code>.
84          *
85          * Subclasses that override this method should call <code>super.dragEnter(event)</code>
86          * to get the default drag under effect implementation.
87          *
88          * @param event  the information associated with the drag start event
89          *
90          * @see DropTargetAdapter
91          * @see DropTargetEvent
92          */
93         @Override
94         public void dragEnter(DropTargetEvent event) {
95                 currentOffset = -1;
96                 scrollBeginTime = 0;
97                 scrollX = -1;
98                 scrollY = -1;
99                 getControl().removeListener(SWT.Paint, paintListener);
100                 getControl().addListener (SWT.Paint, paintListener);
101         }
102
103         /**
104          * This implementation of <code>dragLeave</code> provides a default drag under effect
105          * for the feedback specified in <code>event.feedback</code>.
106          *
107          * For additional information see <code>DropTargetAdapter.dragLeave</code>.
108          *
109          * Subclasses that override this method should call <code>super.dragLeave(event)</code>
110          * to get the default drag under effect implementation.
111          *
112          * @param event  the information associated with the drag leave event
113          *
114          * @see DropTargetAdapter
115          * @see DropTargetEvent
116          */
117         @Override
118         public void dragLeave(DropTargetEvent event) {
119                 StyledText text = (StyledText) getControl();
120                 if (currentOffset != -1) {
121                         refreshCaret(text, currentOffset, -1);
122                 }
123                 text.removeListener(SWT.Paint, paintListener);
124                 scrollBeginTime = 0;
125                 scrollX = -1;
126                 scrollY = -1;
127         }
128
129         /**
130          * This implementation of <code>dragOver</code> provides a default drag under effect
131          * for the feedback specified in <code>event.feedback</code>.
132          *
133          * For additional information see <code>DropTargetAdapter.dragOver</code>.
134          *
135          * Subclasses that override this method should call <code>super.dragOver(event)</code>
136          * to get the default drag under effect implementation.
137          *
138          * @param event  the information associated with the drag over event
139          *
140          * @see DropTargetAdapter
141          * @see DropTargetEvent
142          * @see DND#FEEDBACK_SELECT
143          * @see DND#FEEDBACK_SCROLL
144          */
145         @Override
146         public void dragOver(DropTargetEvent event) {
147                 int effect = event.feedback;
148                 StyledText text = (StyledText) getControl();
149
150                 Point pt = text.getDisplay().map(null, text, event.x, event.y);
151                 if ((effect & DND.FEEDBACK_SCROLL) == 0) {
152                         scrollBeginTime = 0;
153                         scrollX = scrollY = -1;
154                 } else {
155                         if (text.getCharCount() == 0) {
156                                 scrollBeginTime = 0;
157                                 scrollX = scrollY = -1;
158                         } else {
159                                 if (scrollX != -1 && scrollY != -1 && scrollBeginTime != 0 &&
160                                         (pt.x >= scrollX && pt.x <= (scrollX + SCROLL_TOLERANCE) ||
161                                          pt.y >= scrollY && pt.y <= (scrollY + SCROLL_TOLERANCE))) {
162                                         if (System.currentTimeMillis() >= scrollBeginTime) {
163                                                 Rectangle area = text.getClientArea();
164                                                 GC gc = new GC(text);
165                                                 FontMetrics fm = gc.getFontMetrics();
166                                                 gc.dispose();
167                                                 double charWidth = fm.getAverageCharacterWidth();
168                                                 int scrollAmount = (int) (10*charWidth);
169                                                 if (pt.x < area.x + 3*charWidth) {
170                                                         int leftPixel = text.getHorizontalPixel();
171                                                         text.setHorizontalPixel(leftPixel - scrollAmount);
172                                                 }
173                                                 if (pt.x > area.width - 3*charWidth) {
174                                                         int leftPixel = text.getHorizontalPixel();
175                                                         text.setHorizontalPixel(leftPixel + scrollAmount);
176                                                 }
177                                                 int lineHeight = text.getLineHeight();
178                                                 if (pt.y < area.y + lineHeight) {
179                                                         int topPixel = text.getTopPixel();
180                                                         text.setTopPixel(topPixel - lineHeight);
181                                                 }
182                                                 if (pt.y > area.height - lineHeight) {
183                                                         int topPixel = text.getTopPixel();
184                                                         text.setTopPixel(topPixel + lineHeight);
185                                                 }
186                                                 scrollBeginTime = 0;
187                                                 scrollX = scrollY = -1;
188                                         }
189                                 } else {
190                                         scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
191                                         scrollX = pt.x;
192                                         scrollY = pt.y;
193                                 }
194                         }
195                 }
196
197                 if ((effect & DND.FEEDBACK_SELECT) != 0) {
198                         int[] trailing = new int [1];
199                         int newOffset = text.getOffsetAtPoint(pt.x, pt.y, trailing, false);
200                         newOffset += trailing [0];
201                         if (newOffset != currentOffset) {
202                                 refreshCaret(text, currentOffset, newOffset);
203                                 currentOffset = newOffset;
204                         }
205                 }
206         }
207
208         void refreshCaret(StyledText text, int oldOffset, int newOffset) {
209                 if (oldOffset != newOffset) {
210                         if (oldOffset != -1) {
211                                 Point oldPos = text.getLocationAtOffset(oldOffset);
212                                 int oldHeight = text.getLineHeight(oldOffset);
213                                 text.redraw (oldPos.x, oldPos.y, CARET_WIDTH, oldHeight, false);
214                         }
215                         if (newOffset != -1) {
216                                 Point newPos = text.getLocationAtOffset(newOffset);
217                                 int newHeight = text.getLineHeight(newOffset);
218                                 text.redraw (newPos.x, newPos.y, CARET_WIDTH, newHeight, false);
219                         }
220                 }
221         }
222
223         /**
224          * This implementation of <code>dropAccept</code> provides a default drag under effect
225          * for the feedback specified in <code>event.feedback</code>.
226          *
227          * For additional information see <code>DropTargetAdapter.dropAccept</code>.
228          *
229          * Subclasses that override this method should call <code>super.dropAccept(event)</code>
230          * to get the default drag under effect implementation.
231          *
232          * @param event  the information associated with the drop accept event
233          *
234          * @see DropTargetAdapter
235          * @see DropTargetEvent
236          */
237         @Override
238         public void dropAccept(DropTargetEvent event) {
239                 if (currentOffset != -1) {
240                         StyledText text = (StyledText) getControl();
241                         text.setSelection(currentOffset);
242                         currentOffset = -1;
243                 }
244         }
245 }