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