Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 7e03b2f02e9253e90cb7b416efc56c9b7478b7ac (plain) (blame)
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
/*******************************************************************************
 * Copyright (c) 2012, 2013 Tilera Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     William R. Swanson (Tilera Corporation) - initial API and implementation
 *     Marc Dumais (Ericsson) : Bug 405735
 *******************************************************************************/

package org.eclipse.cdt.visualizer.ui.util;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;


/**
 * Monitors mouse down/move/up events on a specified control (e.g. a canvas)
 * and converts them to semantic events (click, double-click, select, drag, etc.)
 */
public class MouseMonitor
{
	// --- constants ---
	
	/** MouseEvent button ID for Left mouse button */
	public static final int LEFT_BUTTON = 1;
	
	/** MouseEvent button ID for Middle mouse button */
	public static final int MIDDLE_BUTTON = 2;
	
	/** MouseEvent button ID for Right mouse button */
	public static final int RIGHT_BUTTON = 3;
	
	
	/** Mouse drag state value */
	public static final int MOUSE_DRAG_BEGIN = 0;
	
	/** Mouse drag state value */
	public static final int MOUSE_DRAG = 1;

	/** Mouse drag state value */
	public static final int MOUSE_DRAG_END = 2;
	
	/** Distance mouse must move for a mouse-down to be treated as a drag */
	public static final int MOUSE_DRAG_HYSTERESIS = 4;


	// --- members ---
	
	/** Control being monitored */
	protected Control m_control = null;
	
	/** Mouse button listener */
	protected MouseListener m_mouseButtonListener = null;
	
	/** Mouse move listener */
	protected MouseMoveListener m_mouseMoveListener = null;
	
	/** Mouse enter/exit event listener */
	protected MouseTrackListener m_mouseTrackListener = null;
	
	/** Whether mouse button is down. */
	protected boolean m_mouseDown = false;
	
	/** Whether mouse is being dragged. */
	protected boolean m_mouseDrag = false;
	
	/** Mouse-down point. */
	protected Point m_mouseDownPoint = new Point(0,0);
	
	/** Last button down. */
	protected int m_mouseDownButton = 0;
	
	/** Current mouse drag point. */
	protected Point m_dragPoint = new Point(0,0);
	
	/** Drag region. */
	protected Rectangle m_dragRegion = new Rectangle(0,0,0,0);
	
	
	// --- constructors/destructors ---
	
	/** Constructor. */
	public MouseMonitor() {
	}
	
	/** Constructor. */
	public MouseMonitor(Control control) {
		this();
		m_control = control;
		attach(m_control);
	}
	
	/** Dispose method. */
	public void dispose() {
		detach(m_control);
	}

	
	// --- init methods ---
	
	/** Attach event listeners to specified control. */
	protected void attach(Control control) {
		detach(m_control);
		control.addMouseListener(
			m_mouseButtonListener = new MouseListener() {
				public void mouseDown(MouseEvent e) {
					mouseDownHandler(e.button, e.x, e.y, e.stateMask);
				}
				public void mouseUp(MouseEvent e) {
					mouseUpHandler(e.button, e.x, e.y, e.stateMask);
				}
				public void mouseDoubleClick(MouseEvent e) {
					mouseDoubleClickHandler(e.button, e.x, e.y, e.stateMask);
				}
			}
		);
		control.addMouseMoveListener(
			m_mouseMoveListener = new MouseMoveListener() {
				public void mouseMove(MouseEvent e) {
					mouseMoveHandler(e.x, e.y, e.stateMask);
				}
			}
		);
		control.addMouseTrackListener(
			m_mouseTrackListener = new MouseTrackListener() {
				public void mouseEnter(MouseEvent e) {
					mouseEnterHandler(e.x, e.y);
				}
				public void mouseExit(MouseEvent e) {
					mouseExitHandler(e.x, e.y);
				}
				public void mouseHover(MouseEvent e) {
					mouseHoverHandler(e.x, e.y);
				}
			}
		);
	}
	
	/** Detach event listeners from specified control. */
	protected void detach(Control control) {
		if (control == null) return;
		if (m_control != null) {
			if (m_mouseButtonListener != null) {
				m_control.removeMouseListener(m_mouseButtonListener);
				m_mouseButtonListener = null;
			}
			if (m_mouseMoveListener != null) {
				m_control.removeMouseMoveListener(m_mouseMoveListener);
				m_mouseMoveListener = null;
			}
			if (m_mouseTrackListener != null) {
				m_control.removeMouseTrackListener(m_mouseTrackListener);
				m_mouseTrackListener = null;
			}
		}
	}
	
	
	// --- accessors ---
	
	/** Gets associated control */
	public Control getControl() {
		return m_control;
	}
	
	/** Sets associated control */
	public void setControl(Control control) {
		detach(m_control);
		m_control = control;
		attach(m_control);
	}
	
	/** Gets mouse down point of current drag, if any */
	public Point getMouseDownPoint() {
		return m_mouseDownPoint;
	}
	
	/** Gets current drag x,y point. */
	public Point getDragPoint() {
		return m_dragPoint;
	}
	
	/** Gets bounds of most recent drag region. */
	public Rectangle getDragRegion() {
		return m_dragRegion;
	}
	
	
	// --- utilities ---
	
	/** Returns true if either Shift key is down in mouse event modifier key mask. */
	public static boolean isShiftDown(int keys) {
		return ((keys & SWT.SHIFT) != 0);
	}
	
	/** Returns true if either Control key is down in mouse event modifier key mask. */
	public static boolean isControlDown(int keys) {
		return ((keys & SWT.CONTROL) != 0);
	}
	
	/** Returns true if either Alt key is down in mouse event modifier key mask. */
	public static boolean isAltDown(int keys) {
		return ((keys & SWT.ALT) != 0);
	}
	
	
	// --- methods ---
	
	/** Internal -- sets drag point */
	protected void setDragPoint(int x, int y) {
		m_dragPoint.x=x;
		m_dragPoint.y=y;
	}
	
	/** Internal -- sets drag region explicitly */
	protected void setDragRegion(int x, int y, int width, int height) {
		m_dragRegion.x=x;
		m_dragRegion.y=y;
		m_dragRegion.width=width;
		m_dragRegion.height=height;
	}
	
	/** Internal -- sets drag region from specified drag start/end points */
	protected void setDragRegionFromPoints(int x1, int y1, int x2, int y2) {
		if (x1 < x2) {
			m_dragRegion.x = x1;
			m_dragRegion.width = x2 - x1;
		}
		else {
			m_dragRegion.x = x2;
			m_dragRegion.width = x1 - x2;
		}
		if (y1 < y2) {
			m_dragRegion.y = y1;
			m_dragRegion.height = y2 - y1;
		}
		else {
			m_dragRegion.y = y2;
			m_dragRegion.height = y1 - y2;
		}
	}
	
	/** Invoked when mouse button is pressed */
	protected void mouseDownHandler(int button, int x, int y, int keys) {
		// Drag not applicable to right-click
		if (! m_mouseDown && button != RIGHT_BUTTON) {
			m_mouseDown = true;
			m_mouseDownPoint.x = x;
			m_mouseDownPoint.y = y;
			m_mouseDownButton = button;
			setDragPoint(x,y);
			setDragRegion(x,y,0,0);
		}
		mouseDown(button, x, y, keys);
	}
	
	/** Invoked when mouse is moved */
	protected void mouseMoveHandler(int x, int y, int keys) {
		if (m_mouseDown) {
			if (! m_mouseDrag) {
				// allow a small hysteresis before we start dragging, so clicks with a little movement don't cause drags
				int distance = Math.abs(x - m_mouseDownPoint.x) + Math.abs(y - m_mouseDownPoint.y);
				if (distance > MOUSE_DRAG_HYSTERESIS) {
					m_mouseDrag = true;
					
					// initialize mouse drag
					drag(m_mouseDownButton, m_mouseDownPoint.x, m_mouseDownPoint.y, keys, MOUSE_DRAG_BEGIN);
				}
			}
			if (m_mouseDrag) {
				// update mouse drag
				int dx = x - m_mouseDownPoint.x;
				int dy = y - m_mouseDownPoint.y;
				setDragPoint(x,y);
				setDragRegionFromPoints(m_mouseDownPoint.x, m_mouseDownPoint.y, x, y);
				drag(m_mouseDownButton, dx, dy, keys, MOUSE_DRAG);
			}
		}
		mouseMove(x, y, keys);
	}
	
	/** Invoked when mouse button is released */
	protected void mouseUpHandler(int button, int x, int y, int keys) {
		if (m_mouseDown) {
			if (m_mouseDrag) {
				// finish mouse drag
				int dx = x - m_mouseDownPoint.x;
				int dy = y - m_mouseDownPoint.y;
				setDragPoint(x,y);
				setDragRegionFromPoints(m_mouseDownPoint.x, m_mouseDownPoint.y, x, y);
				drag(m_mouseDownButton, dx, dy, keys, MOUSE_DRAG_END);
				m_mouseDrag = false;
			}
			else {
				if (button == RIGHT_BUTTON) {
					contextMenu(x, y, keys);
				}
				else {
					select(x, y, keys);
				}
			}
			m_mouseDown = false;
		}
		mouseUp(button, x, y, keys);
	}

	/** Invoked when mouse button is double-clicked */
	protected void mouseDoubleClickHandler(int button, int x, int y, int keys) {
		mouseDoubleClick(button, x, y, keys);
	}

	/** Invoked when mouse pointer enters control region */
	protected void mouseEnterHandler(int x, int y) {
		if (! m_mouseDown) {
			mouseEnter(x, y);
		}
	}

	/** Invoked when mouse pointer exits control region */
	protected void mouseExitHandler(int x, int y) {
		if (! m_mouseDown) {
			mouseExit(x, y);
		}
	}
	
	/** Invoked when mouse pointer hovers over control */
	protected void mouseHoverHandler(int x, int y) {
		if (! m_mouseDown) {
			mouseHover(x, y);
		}
	}
	
	
	// --- event handlers ---
	
	// These are intended to be overridden by derived types.
	// A user of this class need only override methods for events
	// that need to be tracked.
	
	/** Invoked when mouse button is pressed */
	public void mouseDown(int button, int x, int y, int keys) {}
	
	/** Invoked when mouse is moved */
	public void mouseMove(int x, int y, int keys) {}
	
	/** Invoked when mouse button is released */
	public void mouseUp(int button, int x, int y, int keys) {}
	
	/** Invoked for a selection click at the specified point. */
	public void select(int x, int y, int keys) {}
	
	/** Invoked for a context menu click at the specified point. */
	public void contextMenu(int x, int y, int keys) {}
	
	/** Invoked when mouse button is double-clicked */
	public void mouseDoubleClick(int button, int x, int y, int keys) {}
	
	/** Invoked when mouse is dragged (moved with mouse button down).
	 *  Drag state indicates stage of drag:
	 *  - MOUSE_DRAG_BEGIN -- dx, dy offset from initial mouse down point (initial mouse down)
	 *  - MOUSE_DRAG       -- dx, dy of intermediate drag offset (initial mouse down, then each mouse move)
	 *  - MOUSE_DRAG_END   -- dx, dy of final drag offset (mouse up)
	 *  The pattern of calls is always: BEGIN, DRAG(+), END.
	 */
	public void drag(int button, int x, int y, int keys, int dragState) {}
	
	/** Invoked when mouse pointer enters control region */
	public void mouseEnter(int x, int y) {}

	/** Invoked when mouse pointer exits control region */
	public void mouseExit(int x, int y) {}
	
	/** Invoked when mouse pointer hovers over control */
	public void mouseHover(int x, int y) {}

}

Back to the top