Crossfire JXClient, Trunk  R20561
MouseTracker.java
Go to the documentation of this file.
1 /*
2  * This file is part of JXClient, the Fullscreen Java Crossfire Client.
3  *
4  * JXClient is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * JXClient is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with JXClient; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  * Copyright (C) 2005-2008 Yann Chachkoff.
19  * Copyright (C) 2006-2011 Andreas Kirschbaum.
20  */
21 
22 package com.realtime.crossfire.jxclient.gui.misc;
23 
27 import java.awt.Color;
28 import java.awt.Dimension;
29 import java.awt.Graphics;
30 import java.awt.Point;
31 import java.awt.event.MouseEvent;
32 import java.io.IOException;
33 import java.io.Writer;
34 import java.text.DateFormat;
35 import java.text.SimpleDateFormat;
36 import java.util.Date;
37 import org.jetbrains.annotations.NotNull;
38 import org.jetbrains.annotations.Nullable;
39 
47 public class MouseTracker {
48 
53  private static final int CLICK_DISTANCE = 20;
54 
58  private final boolean debugGui;
59 
63  @Nullable
64  private final Writer debugMouse;
65 
69  @NotNull
70  private final DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS ");
71 
75  @Nullable
77 
81  @Nullable
83 
87  private boolean isDragging;
88 
92  private boolean isClicked;
93 
97  @NotNull
98  private final Point clickPosition = new Point();
99 
105  public MouseTracker(final boolean debugGui, @Nullable final Writer debugMouse) {
106  this.debugGui = debugGui;
107  this.debugMouse = debugMouse;
108  }
109 
115  public void mouseClicked(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e) {
116  debugMouseWrite("mouseClicked: "+e+" ["+element+"]");
117  }
118 
124  @SuppressWarnings("UnusedParameters")
125  public void mouseDragged(@Nullable final GUIElement element, @NotNull final MouseEvent e) {
126  debugMouseWrite("mouseDragged: "+e+" ["+element+"]");
127  if (isClicked) {
128  final double distance = clickPosition.distanceSq(e.getLocationOnScreen());
129  if (distance > CLICK_DISTANCE) {
130  debugMouseWrite("mouseDragged: distance "+distance+" is too far for a click event; click point="+clickPosition+", current point="+e.getLocationOnScreen());
131  setClicked(false);
132  }
133  }
134  if (mouseElement != null) {
135  debugMouseWrite(mouseElement+".mouseMoved");
136  mouseElement.mouseMoved(e);
137  }
138  if (isDragging && mouseElement != null) {
139  debugMouseWrite(mouseElement+".mouseDragged");
140  mouseElement.mouseDragged(e);
141  }
142  }
143 
149  public void mouseMoved(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e) {
150  debugMouseWrite("mouseMoved: "+e+" ["+element+"]");
151  enterElement(element, e);
152  if (mouseElement != null) {
153  debugMouseWrite(mouseElement+".mouseMoved");
155  }
156  }
157 
163  public void mousePressed(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e) {
164  debugMouseWrite("mousePressed: "+e+" ["+element+"]");
165  enterElement(element, e);
166  if (mouseElement != null) {
167  debugMouseWrite(mouseElement+".mousePressed");
169  }
170  setDragging(true);
171  clickPosition.setLocation(e.getLocationOnScreen());
172  setClicked(true);
173  }
174 
180  public void mouseReleased(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e) {
181  debugMouseWrite("mouseReleased: "+e+" ["+element+"]");
182  final boolean tmpIsClicked = isClicked;
183  setDragging(false);
184  enterElement(element, e);
185  if (tmpIsClicked && element != null) {
186  // cannot use mouseElement here: it might be invalid if the
187  // previous call to mouseReleased() did close the owner dialog
188  debugMouseWrite(element+".mouseClicked");
189  element.mouseClicked(e);
190  }
191  if (mouseElement != null) {
192  debugMouseWrite(mouseElement+".mouseReleased");
194  }
195  }
196 
202  public void mouseEntered(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e) {
203  debugMouseWrite("mouseEntered: "+e+" ["+element+"]");
204  setClicked(false);
205  if (!isDragging) {
206  enterElement(element, e);
207  }
208  }
209 
214  public void mouseExited(@NotNull final MouseEvent e) {
215  debugMouseWrite("mouseExited: "+e);
216  setClicked(false);
217  if (!isDragging) {
218  enterElement(null, e);
219  }
220  }
221 
227  private void enterElement(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e) {
228  if (mouseElement == element) {
229  return;
230  }
231 
232  final GUIElement tmp = mouseElement;
233  if (tmp != null) {
234  tmp.mouseExited(e);
235  setActiveComponent(null);
236  }
237 
238  mouseElement = element;
239  debugMouseWrite("mouseElement="+mouseElement);
240 
241  if (element != null) {
242  element.mouseEntered(e, debugGui);
243  if (debugGui) {
244  setActiveComponent(element);
245  }
246  }
247  }
248 
253  public void paintActiveComponent(@NotNull final Graphics g) {
254  final AbstractGUIElement component = activeComponent;
255  if (component != null) {
256  final String text = component.getName();
257  final Dimension dimension = GuiUtils.getTextDimension(text, g.getFontMetrics());
258  g.setColor(Color.BLACK);
259  g.fillRect(0, 2, dimension.width+4, dimension.height+8);
260  g.setColor(Color.RED);
261  g.drawString(text, 2, 16);
262  g.drawRect(GuiUtils.getElementX(component), GuiUtils.getElementY(component), component.getWidth()-1, component.getHeight()-1);
263  }
264  }
265 
270  private void debugMouseWrite(@NotNull final CharSequence message) {
271  if (debugMouse == null) {
272  return;
273  }
274 
275  try {
276  debugMouse.append(simpleDateFormat.format(new Date()));
277  debugMouse.append(message);
278  debugMouse.append("\n");
279  debugMouse.flush();
280  } catch (final IOException ex) {
281  System.err.println("Cannot write mouse debug: "+ex.getMessage());
282  System.exit(1);
283  throw new AssertionError(ex);
284  }
285  }
286 
292  private void setActiveComponent(@Nullable final AbstractGUIElement activeComponent) {
293  if (this.activeComponent == activeComponent) {
294  return;
295  }
296 
297  if (this.activeComponent != null) {
298  this.activeComponent.setChanged();
299  }
300  this.activeComponent = activeComponent;
301  if (this.activeComponent != null) {
302  this.activeComponent.setChanged();
303  }
304  debugMouseWrite("activeComponent="+activeComponent);
305  }
306 
312  private void setDragging(final boolean isDragging) {
313  if (this.isDragging == isDragging) {
314  return;
315  }
316 
317  this.isDragging = isDragging;
318  debugMouseWrite("isDragging="+isDragging);
319  }
320 
325  private void setClicked(final boolean isClicked) {
326  if (this.isClicked == isClicked) {
327  return;
328  }
329 
330  this.isClicked = isClicked;
331  debugMouseWrite("isClicked="+isClicked);
332  }
333 
334 }
void mouseClicked(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e)
Handles a mouse clicked event.
void enterElement(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e)
Sets a new mouseElement and generate entered/exited events.
static int getElementY(@NotNull final Component element)
Returns an element's absolute screen coordinate.
Definition: GuiUtils.java:76
final boolean debugGui
Whether GUI elements should be highlighted.
MouseTracker(final boolean debugGui, @Nullable final Writer debugMouse)
Creates a new instance.
static Dimension getTextDimension(@NotNull final String text, @NotNull final FontMetrics fontMetrics)
Returns the extents of a string when rendered in a given Font on this component.
Definition: GuiUtils.java:51
void setChanged()
Records that the contents have changed and must be repainted.
void mouseDragged(@Nullable final GUIElement element, @NotNull final MouseEvent e)
Handles a mouse dragged event.
final Writer debugMouse
The Writer to write mouse debug to or.
void mouseMoved(@NotNull MouseEvent e)
Will be called when the mouse moves within this component.
void mouseEntered(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e)
Handles a mouse entered event.
Interface defining an abstract GUI element.
Definition: GUIElement.java:32
void setClicked(final boolean isClicked)
Updates isClicked.
void debugMouseWrite(@NotNull final CharSequence message)
Writes a message to the mouse debug.
String getName()
Returns the internal name of this gui element.The name is used in skin files for identifying an eleme...
boolean isClicked
Whether a button release event is considered a "click".
GUIElement mouseElement
The gui element in which the mouse is.
void mousePressed(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e)
Handles a mouse pressed event.
Utility class for Gui related functions.
Definition: GuiUtils.java:35
boolean isDragging
Whether a dragging operation is in progress.
void mouseExited(@NotNull MouseEvent e)
Will be called when the mouse has left the bounding box of this element.
final Point clickPosition
The position that was clicked if isClicked is set.
void mouseReleased(@NotNull MouseEvent e)
Will be called when the user has released the mouse.
void setActiveComponent(@Nullable final AbstractGUIElement activeComponent)
Updates activeComponent.
void mouseExited(@NotNull final MouseEvent e)
Handles a mouse exited event.
void mouseDragged(@NotNull MouseEvent e)
Will be called when the mouse moves within this component while the button is pressed.
void mouseReleased(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e)
Handles a mouse released event.
Abstract base class for GUI elements to be shown in Guis.
static int getElementX(@NotNull final Component element)
Returns an element's absolute screen coordinate.
Definition: GuiUtils.java:62
Tracks mouse actions and delivers mouse events to affected GUIElement.
void setDragging(final boolean isDragging)
Updates isDragging.
final DateFormat simpleDateFormat
A formatter for timestamps.
void paintActiveComponent(@NotNull final Graphics g)
Marks the active component in a Graphics instance.
AbstractGUIElement activeComponent
The active component.
static final int CLICK_DISTANCE
The maximum distance the mouse may have moved between the mouse pressed and the mouse released even t...
void mousePressed(@NotNull MouseEvent e)
Will be called when the user has pressed the mouse inside this element.
void mouseMoved(@Nullable final AbstractGUIElement element, @NotNull final MouseEvent e)
Handles a mouse moved event.