Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/2d/physics/touch_screen_button.cpp
9906 views
1
/**************************************************************************/
2
/* touch_screen_button.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "touch_screen_button.h"
32
33
#include "scene/main/viewport.h"
34
35
void TouchScreenButton::set_texture_normal(const Ref<Texture2D> &p_texture) {
36
if (texture_normal == p_texture) {
37
return;
38
}
39
if (texture_normal.is_valid()) {
40
texture_normal->disconnect(CoreStringName(changed), callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
41
}
42
texture_normal = p_texture;
43
if (texture_normal.is_valid()) {
44
texture_normal->connect(CoreStringName(changed), callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw), CONNECT_REFERENCE_COUNTED);
45
}
46
queue_redraw();
47
}
48
49
Ref<Texture2D> TouchScreenButton::get_texture_normal() const {
50
return texture_normal;
51
}
52
53
void TouchScreenButton::set_texture_pressed(const Ref<Texture2D> &p_texture_pressed) {
54
if (texture_pressed == p_texture_pressed) {
55
return;
56
}
57
if (texture_pressed.is_valid()) {
58
texture_pressed->disconnect(CoreStringName(changed), callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
59
}
60
texture_pressed = p_texture_pressed;
61
if (texture_pressed.is_valid()) {
62
texture_pressed->connect(CoreStringName(changed), callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw), CONNECT_REFERENCE_COUNTED);
63
}
64
queue_redraw();
65
}
66
67
Ref<Texture2D> TouchScreenButton::get_texture_pressed() const {
68
return texture_pressed;
69
}
70
71
void TouchScreenButton::set_bitmask(const Ref<BitMap> &p_bitmask) {
72
bitmask = p_bitmask;
73
}
74
75
Ref<BitMap> TouchScreenButton::get_bitmask() const {
76
return bitmask;
77
}
78
79
void TouchScreenButton::set_shape(const Ref<Shape2D> &p_shape) {
80
if (shape == p_shape) {
81
return;
82
}
83
if (shape.is_valid()) {
84
shape->disconnect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
85
}
86
shape = p_shape;
87
if (shape.is_valid()) {
88
shape->connect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
89
}
90
queue_redraw();
91
}
92
93
Ref<Shape2D> TouchScreenButton::get_shape() const {
94
return shape;
95
}
96
97
void TouchScreenButton::set_shape_centered(bool p_shape_centered) {
98
shape_centered = p_shape_centered;
99
queue_redraw();
100
}
101
102
bool TouchScreenButton::is_shape_visible() const {
103
return shape_visible;
104
}
105
106
void TouchScreenButton::set_shape_visible(bool p_shape_visible) {
107
shape_visible = p_shape_visible;
108
queue_redraw();
109
}
110
111
bool TouchScreenButton::is_shape_centered() const {
112
return shape_centered;
113
}
114
115
void TouchScreenButton::_accessibility_action_click(const Variant &p_data) {
116
_press(0);
117
_release();
118
}
119
120
void TouchScreenButton::_notification(int p_what) {
121
switch (p_what) {
122
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
123
RID ae = get_accessibility_element();
124
ERR_FAIL_COND(ae.is_null());
125
126
Rect2 dst_rect(Point2(), texture_normal.is_valid() ? texture_normal->get_size() : Size2());
127
128
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_BUTTON);
129
130
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_CLICK, callable_mp(this, &TouchScreenButton::_accessibility_action_click));
131
132
DisplayServer::get_singleton()->accessibility_update_set_transform(ae, get_transform());
133
DisplayServer::get_singleton()->accessibility_update_set_bounds(ae, dst_rect);
134
} break;
135
136
case NOTIFICATION_DRAW: {
137
if (!is_inside_tree()) {
138
return;
139
}
140
if (!Engine::get_singleton()->is_editor_hint() && !DisplayServer::get_singleton()->is_touchscreen_available() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) {
141
return;
142
}
143
144
if (finger_pressed != -1) {
145
if (texture_pressed.is_valid()) {
146
draw_texture(texture_pressed, Point2());
147
} else if (texture_normal.is_valid()) {
148
draw_texture(texture_normal, Point2());
149
}
150
151
} else {
152
if (texture_normal.is_valid()) {
153
draw_texture(texture_normal, Point2());
154
}
155
}
156
157
if (!shape_visible) {
158
return;
159
}
160
if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
161
return;
162
}
163
if (shape.is_valid()) {
164
Color draw_col = get_tree()->get_debug_collisions_color();
165
166
Vector2 pos;
167
if (shape_centered && texture_normal.is_valid()) {
168
pos = texture_normal->get_size() * 0.5;
169
}
170
171
draw_set_transform_matrix(get_canvas_transform().translated_local(pos));
172
shape->draw(get_canvas_item(), draw_col);
173
}
174
} break;
175
176
case NOTIFICATION_ENTER_TREE: {
177
if (!Engine::get_singleton()->is_editor_hint() && !DisplayServer::get_singleton()->is_touchscreen_available() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) {
178
return;
179
}
180
queue_redraw();
181
182
if (!Engine::get_singleton()->is_editor_hint()) {
183
set_process_input(is_visible_in_tree());
184
}
185
} break;
186
187
case NOTIFICATION_EXIT_TREE: {
188
if (is_pressed()) {
189
_release(true);
190
}
191
} break;
192
193
case NOTIFICATION_VISIBILITY_CHANGED: {
194
if (Engine::get_singleton()->is_editor_hint()) {
195
break;
196
}
197
if (is_visible_in_tree()) {
198
set_process_input(true);
199
} else {
200
set_process_input(false);
201
if (is_pressed()) {
202
_release();
203
}
204
}
205
} break;
206
207
case NOTIFICATION_SUSPENDED:
208
case NOTIFICATION_PAUSED: {
209
if (is_pressed()) {
210
_release();
211
}
212
} break;
213
}
214
}
215
216
bool TouchScreenButton::is_pressed() const {
217
return finger_pressed != -1;
218
}
219
220
void TouchScreenButton::set_action(const String &p_action) {
221
action = p_action;
222
}
223
224
String TouchScreenButton::get_action() const {
225
return action;
226
}
227
228
void TouchScreenButton::input(const Ref<InputEvent> &p_event) {
229
ERR_FAIL_COND(p_event.is_null());
230
231
if (!is_visible_in_tree()) {
232
return;
233
}
234
235
const InputEventScreenTouch *st = Object::cast_to<InputEventScreenTouch>(*p_event);
236
237
if (passby_press) {
238
const InputEventScreenDrag *sd = Object::cast_to<InputEventScreenDrag>(*p_event);
239
240
if (st && !st->is_pressed() && finger_pressed == st->get_index()) {
241
_release();
242
}
243
244
if ((st && st->is_pressed()) || sd) {
245
int index = st ? st->get_index() : sd->get_index();
246
Point2 coord = st ? st->get_position() : sd->get_position();
247
248
if (finger_pressed == -1 || index == finger_pressed) {
249
if (_is_point_inside(coord)) {
250
if (finger_pressed == -1) {
251
_press(index);
252
}
253
} else {
254
if (finger_pressed != -1) {
255
_release();
256
}
257
}
258
}
259
}
260
261
} else {
262
if (st) {
263
if (st->is_pressed()) {
264
const bool can_press = finger_pressed == -1;
265
if (!can_press) {
266
return; //already fingering
267
}
268
269
if (_is_point_inside(st->get_position())) {
270
_press(st->get_index());
271
}
272
} else {
273
if (st->get_index() == finger_pressed) {
274
_release();
275
}
276
}
277
}
278
}
279
}
280
281
bool TouchScreenButton::_is_point_inside(const Point2 &p_point) {
282
Point2 coord = (get_global_transform_with_canvas()).affine_inverse().xform(p_point);
283
284
bool touched = false;
285
bool check_rect = true;
286
287
if (shape.is_valid()) {
288
check_rect = false;
289
290
Vector2 pos;
291
if (shape_centered && texture_normal.is_valid()) {
292
pos = texture_normal->get_size() * 0.5;
293
}
294
295
touched = shape->collide(Transform2D().translated_local(pos), unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5)));
296
}
297
298
if (bitmask.is_valid()) {
299
check_rect = false;
300
if (!touched && Rect2(Point2(), bitmask->get_size()).has_point(coord)) {
301
if (bitmask->get_bitv(coord)) {
302
touched = true;
303
}
304
}
305
}
306
307
if (!touched && check_rect) {
308
if (texture_normal.is_valid()) {
309
touched = Rect2(Size2(), texture_normal->get_size()).has_point(coord);
310
}
311
}
312
313
return touched;
314
}
315
316
void TouchScreenButton::_press(int p_finger_pressed) {
317
finger_pressed = p_finger_pressed;
318
319
if (action != StringName()) {
320
Input::get_singleton()->action_press(action);
321
Ref<InputEventAction> iea;
322
iea.instantiate();
323
iea->set_action(action);
324
iea->set_pressed(true);
325
get_viewport()->push_input(iea, true);
326
}
327
328
emit_signal(SceneStringName(pressed));
329
queue_redraw();
330
}
331
332
void TouchScreenButton::_release(bool p_exiting_tree) {
333
finger_pressed = -1;
334
335
if (action != StringName()) {
336
Input::get_singleton()->action_release(action);
337
if (!p_exiting_tree) {
338
Ref<InputEventAction> iea;
339
iea.instantiate();
340
iea->set_action(action);
341
iea->set_pressed(false);
342
get_viewport()->push_input(iea, true);
343
}
344
}
345
346
if (!p_exiting_tree) {
347
emit_signal(SNAME("released"));
348
queue_redraw();
349
}
350
}
351
352
#ifdef DEBUG_ENABLED
353
Rect2 TouchScreenButton::_edit_get_rect() const {
354
if (texture_normal.is_null()) {
355
return CanvasItem::_edit_get_rect();
356
}
357
358
return Rect2(Size2(), texture_normal->get_size());
359
}
360
361
bool TouchScreenButton::_edit_use_rect() const {
362
return texture_normal.is_valid();
363
}
364
#endif // DEBUG_ENABLED
365
366
Rect2 TouchScreenButton::get_anchorable_rect() const {
367
if (texture_normal.is_null()) {
368
return CanvasItem::get_anchorable_rect();
369
}
370
371
return Rect2(Size2(), texture_normal->get_size());
372
}
373
374
void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) {
375
visibility = p_mode;
376
queue_redraw();
377
}
378
379
TouchScreenButton::VisibilityMode TouchScreenButton::get_visibility_mode() const {
380
return visibility;
381
}
382
383
void TouchScreenButton::set_passby_press(bool p_enable) {
384
passby_press = p_enable;
385
}
386
387
bool TouchScreenButton::is_passby_press_enabled() const {
388
return passby_press;
389
}
390
391
#ifndef DISABLE_DEPRECATED
392
bool TouchScreenButton::_set(const StringName &p_name, const Variant &p_value) {
393
if (p_name == CoreStringName(normal)) { // Compatibility with Godot 3.x.
394
set_texture_normal(p_value);
395
return true;
396
} else if (p_name == SceneStringName(pressed)) { // Compatibility with Godot 3.x.
397
set_texture_pressed(p_value);
398
return true;
399
}
400
return false;
401
}
402
#endif // DISABLE_DEPRECATED
403
404
void TouchScreenButton::_bind_methods() {
405
ClassDB::bind_method(D_METHOD("set_texture_normal", "texture"), &TouchScreenButton::set_texture_normal);
406
ClassDB::bind_method(D_METHOD("get_texture_normal"), &TouchScreenButton::get_texture_normal);
407
408
ClassDB::bind_method(D_METHOD("set_texture_pressed", "texture"), &TouchScreenButton::set_texture_pressed);
409
ClassDB::bind_method(D_METHOD("get_texture_pressed"), &TouchScreenButton::get_texture_pressed);
410
411
ClassDB::bind_method(D_METHOD("set_bitmask", "bitmask"), &TouchScreenButton::set_bitmask);
412
ClassDB::bind_method(D_METHOD("get_bitmask"), &TouchScreenButton::get_bitmask);
413
414
ClassDB::bind_method(D_METHOD("set_shape", "shape"), &TouchScreenButton::set_shape);
415
ClassDB::bind_method(D_METHOD("get_shape"), &TouchScreenButton::get_shape);
416
417
ClassDB::bind_method(D_METHOD("set_shape_centered", "bool"), &TouchScreenButton::set_shape_centered);
418
ClassDB::bind_method(D_METHOD("is_shape_centered"), &TouchScreenButton::is_shape_centered);
419
420
ClassDB::bind_method(D_METHOD("set_shape_visible", "bool"), &TouchScreenButton::set_shape_visible);
421
ClassDB::bind_method(D_METHOD("is_shape_visible"), &TouchScreenButton::is_shape_visible);
422
423
ClassDB::bind_method(D_METHOD("set_action", "action"), &TouchScreenButton::set_action);
424
ClassDB::bind_method(D_METHOD("get_action"), &TouchScreenButton::get_action);
425
426
ClassDB::bind_method(D_METHOD("set_visibility_mode", "mode"), &TouchScreenButton::set_visibility_mode);
427
ClassDB::bind_method(D_METHOD("get_visibility_mode"), &TouchScreenButton::get_visibility_mode);
428
429
ClassDB::bind_method(D_METHOD("set_passby_press", "enabled"), &TouchScreenButton::set_passby_press);
430
ClassDB::bind_method(D_METHOD("is_passby_press_enabled"), &TouchScreenButton::is_passby_press_enabled);
431
432
ClassDB::bind_method(D_METHOD("is_pressed"), &TouchScreenButton::is_pressed);
433
434
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_normal", "get_texture_normal");
435
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_pressed", "get_texture_pressed");
436
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "bitmask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_bitmask", "get_bitmask");
437
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape");
438
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shape_centered"), "set_shape_centered", "is_shape_centered");
439
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shape_visible"), "set_shape_visible", "is_shape_visible");
440
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "passby_press"), "set_passby_press", "is_passby_press_enabled");
441
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action", PROPERTY_HINT_INPUT_NAME, "show_builtin,loose_mode"), "set_action", "get_action");
442
ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_mode", PROPERTY_HINT_ENUM, "Always,TouchScreen Only"), "set_visibility_mode", "get_visibility_mode");
443
444
ADD_SIGNAL(MethodInfo("pressed"));
445
ADD_SIGNAL(MethodInfo("released"));
446
447
BIND_ENUM_CONSTANT(VISIBILITY_ALWAYS);
448
BIND_ENUM_CONSTANT(VISIBILITY_TOUCHSCREEN_ONLY);
449
}
450
451
TouchScreenButton::TouchScreenButton() {
452
unit_rect.instantiate();
453
unit_rect->set_size(Vector2(1, 1));
454
}
455
456