OSDN Git Service

1da21ee6e59eb31dcf8ca6bcda59bd16f75752f0
[mikumikustudio/libgdx-mikumikustudio.git] / gdx / src / com / badlogic / gdx / scenes / scene2d / utils / ClickListener.java
1 /*******************************************************************************\r
2  * Copyright 2011 See AUTHORS file.\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  * \r
8  *   http://www.apache.org/licenses/LICENSE-2.0\r
9  * \r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  ******************************************************************************/\r
16 \r
17 package com.badlogic.gdx.scenes.scene2d.utils;\r
18 \r
19 import com.badlogic.gdx.Gdx;\r
20 import com.badlogic.gdx.Input.Buttons;\r
21 import com.badlogic.gdx.scenes.scene2d.Actor;\r
22 import com.badlogic.gdx.scenes.scene2d.InputEvent;\r
23 import com.badlogic.gdx.scenes.scene2d.InputListener;\r
24 import com.badlogic.gdx.utils.TimeUtils;\r
25 \r
26 /** Detects mouse over, mouse or finger touch presses, and clicks on an actor. A touch must go down over the actor and is\r
27  * considered pressed as long as it is over the actor or within the {@link #setTapSquareSize(float) tap square}. This behavior\r
28  * makes it easier to press buttons on a touch interface when the initial touch happens near the edge of the actor. Double clicks\r
29  * can be detected using {@link #getTapCount()}. Any touch (not just the first) will trigger this listener. While pressed, other\r
30  * touch downs are ignored.\r
31  * @author Nathan Sweet */\r
32 public class ClickListener extends InputListener {\r
33         private float tapSquareSize = 14, touchDownX = -1, touchDownY = -1;\r
34         private int pressedPointer = -1;\r
35         private int pressedButton = -1;\r
36         private int button;\r
37         private boolean pressed, over, cancelled;\r
38         private long tapCountInterval = (long)(0.4f * 1000000000l);\r
39         private int tapCount;\r
40         private long lastTapTime;\r
41 \r
42         public ClickListener () {\r
43         }\r
44 \r
45         /** @see #setButton(int) */\r
46         public ClickListener (int button) {\r
47                 this.button = button;\r
48         }\r
49 \r
50         public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {\r
51                 if (pressed) return false;\r
52                 if (pointer == 0 && this.button != -1 && button != this.button) return false;\r
53                 pressed = true;\r
54                 pressedPointer = pointer;\r
55                 pressedButton = button;\r
56                 touchDownX = x;\r
57                 touchDownY = y;\r
58                 return true;\r
59         }\r
60 \r
61         public void touchDragged (InputEvent event, float x, float y, int pointer) {\r
62                 if (pointer != pressedPointer || cancelled) return;\r
63                 pressed = isOver(event.getListenerActor(), x, y);\r
64                 if (pressed && pointer == 0 && button != -1 && !Gdx.input.isButtonPressed(button)) pressed = false;\r
65                 if (!pressed) {\r
66                         // Once outside the tap square, don't use the tap square anymore.\r
67                         invalidateTapSquare();\r
68                 }\r
69         }\r
70 \r
71         public void touchUp (InputEvent event, float x, float y, int pointer, int button) {\r
72                 if (pointer == pressedPointer) {\r
73                         if (!cancelled) {\r
74                                 boolean touchUpOver = isOver(event.getListenerActor(), x, y);\r
75                                 // Ignore touch up if the wrong mouse button.\r
76                                 if (touchUpOver && pointer == 0 && this.button != -1 && button != this.button) touchUpOver = false;\r
77                                 if (touchUpOver) {\r
78                                         long time = TimeUtils.nanoTime();\r
79                                         if (time - lastTapTime > tapCountInterval) tapCount = 0;\r
80                                         tapCount++;\r
81                                         lastTapTime = time;\r
82                                         clicked(event, x, y);\r
83                                 }\r
84                         }\r
85                         pressed = false;\r
86                         pressedPointer = -1;\r
87                         pressedButton = -1;\r
88                         cancelled = false;\r
89                 }\r
90         }\r
91 \r
92         public void enter (InputEvent event, float x, float y, int pointer, Actor fromActor) {\r
93                 if (pointer == -1 && !cancelled) over = true;\r
94         }\r
95 \r
96         public void exit (InputEvent event, float x, float y, int pointer, Actor toActor) {\r
97                 if (pointer == -1 && !cancelled) over = false;\r
98         }\r
99 \r
100         /** If a touch down is being monitored, the drag and touch up events are ignored until the next touch up. */\r
101         public void cancel () {\r
102                 if (pressedPointer == -1) return;\r
103                 cancelled = true;\r
104                 over = false;\r
105                 pressed = false;\r
106         }\r
107 \r
108         public void clicked (InputEvent event, float x, float y) {\r
109         }\r
110 \r
111         /** Returns true if the specified position is over the specified actor or within the tap square. */\r
112         public boolean isOver (Actor actor, float x, float y) {\r
113                 Actor hit = actor.hit(x, y, true);\r
114                 if (hit == null || !hit.isDescendantOf(actor)) return inTapSquare(x, y);\r
115                 return true;\r
116         }\r
117 \r
118         public boolean inTapSquare (float x, float y) {\r
119                 if (touchDownX == -1 && touchDownY == -1) return false;\r
120                 return Math.abs(x - touchDownX) < tapSquareSize && Math.abs(y - touchDownY) < tapSquareSize;\r
121         }\r
122 \r
123         /** The tap square will not longer be used for the current touch. */\r
124         public void invalidateTapSquare () {\r
125                 touchDownX = -1;\r
126                 touchDownY = -1;\r
127         }\r
128 \r
129         /** Returns true if a touch is over the actor or within the tap square. */\r
130         public boolean isPressed () {\r
131                 return pressed;\r
132         }\r
133 \r
134         /** Returns true if the mouse or touch is over the actor or pressed and within the tap square. */\r
135         public boolean isOver () {\r
136                 return over || pressed;\r
137         }\r
138 \r
139         public void setTapSquareSize (float halfTapSquareSize) {\r
140                 tapSquareSize = halfTapSquareSize;\r
141         }\r
142 \r
143         public float getTapSquareSize () {\r
144                 return tapSquareSize;\r
145         }\r
146 \r
147         /** @param tapCountInterval time in seconds that must pass for two touch down/up sequences to be detected as consecutive taps. */\r
148         public void setTapCountInterval (float tapCountInterval) {\r
149                 this.tapCountInterval = (long)(tapCountInterval * 1000000000l);\r
150         }\r
151 \r
152         /** Returns the number of taps within the tap count interval for the most recent click event. */\r
153         public int getTapCount () {\r
154                 return tapCount;\r
155         }\r
156 \r
157         public float getTouchDownX () {\r
158                 return touchDownX;\r
159         }\r
160 \r
161         public float getTouchDownY () {\r
162                 return touchDownY;\r
163         }\r
164 \r
165         /** The button that initially pressed this button or -1 if the button is not pressed. */\r
166         public int getPressedButton () {\r
167                 return pressedButton;\r
168         }\r
169 \r
170         /** The pointer that initially pressed this button or -1 if the button is not pressed. */\r
171         public int getPressedPointer () {\r
172                 return pressedPointer;\r
173         }\r
174 \r
175         /** @see #setButton(int) */\r
176         public int getButton () {\r
177                 return button;\r
178         }\r
179 \r
180         /** Sets the button to listen for, all other buttons are ignored. Default is {@link Buttons#LEFT}. Use -1 for any button. */\r
181         public void setButton (int button) {\r
182                 this.button = button;\r
183         }\r
184 }\r