Split gui_scaling to gui_scaling + hud_scaling as those elements need different handl...
[oweals/minetest.git] / src / touchscreengui.cpp
1 /*
2 Copyright (C) 2014 sapier
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8
9 This program 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 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include "touchscreengui.h"
20 #include "irrlichttypes.h"
21 #include "irr_v2d.h"
22 #include "log.h"
23 #include "keycode.h"
24 #include "settings.h"
25 #include "gettime.h"
26 #include "util/numeric.h"
27 #include "porting.h"
28
29 #include <iostream>
30 #include <algorithm>
31
32 #include <ISceneCollisionManager.h>
33
34 using namespace irr::core;
35
36 extern Settings *g_settings;
37
38 const char** touchgui_button_imagenames = (const char*[]) {
39         "up_arrow.png",
40         "down_arrow.png",
41         "left_arrow.png",
42         "right_arrow.png",
43         "inventory_btn.png",
44         "drop_btn.png",
45         "jump_btn.png",
46         "down.png",
47         "fly_btn.png",
48         "noclip_btn.png",
49         "fast_btn.png",
50         "debug_btn.png",
51         "chat_btn.png",
52         "camera_btn.png",
53         "rangeview_btn.png"
54 };
55
56 static irr::EKEY_CODE id2keycode(touch_gui_button_id id)
57 {
58         std::string key = "";
59         switch (id) {
60                 case forward_id:
61                         key = "forward";
62                         break;
63                 case left_id:
64                         key = "left";
65                         break;
66                 case right_id:
67                         key = "right";
68                         break;
69                 case backward_id:
70                         key = "backward";
71                         break;
72                 case inventory_id:
73                         key = "inventory";
74                         break;
75                 case drop_id:
76                         key = "drop";
77                         break;
78                 case jump_id:
79                         key = "jump";
80                         break;
81                 case crunch_id:
82                         key = "sneak";
83                         break;
84                 case fly_id:
85                         key = "freemove";
86                         break;
87                 case noclip_id:
88                         key = "noclip";
89                         break;
90                 case fast_id:
91                         key = "fastmove";
92                         break;
93                 case debug_id:
94                         key = "toggle_debug";
95                         break;
96                 case chat_id:
97                         key = "chat";
98                         break;
99                 case camera_id:
100                         key = "camera_mode";
101                         break;
102                 case range_id:
103                         key = "rangeselect";
104                         break;
105         }
106         assert(key != "");
107         return keyname_to_keycode(g_settings->get("keymap_" + key).c_str());
108 }
109
110 TouchScreenGUI *g_touchscreengui;
111
112 TouchScreenGUI::TouchScreenGUI(IrrlichtDevice *device, IEventReceiver* receiver):
113         m_device(device),
114         m_guienv(device->getGUIEnvironment()),
115         m_camera_yaw(0.0),
116         m_camera_pitch(0.0),
117         m_visible(false),
118         m_move_id(-1),
119         m_receiver(receiver)
120 {
121         for (unsigned int i=0; i < after_last_element_id; i++) {
122                 m_buttons[i].guibutton     =  0;
123                 m_buttons[i].repeatcounter = -1;
124         }
125
126         m_screensize = m_device->getVideoDriver()->getScreenSize();
127 }
128
129 void TouchScreenGUI::loadButtonTexture(button_info* btn, const char* path)
130 {
131         unsigned int tid;
132         video::ITexture *texture = m_texturesource->getTexture(path,&tid);
133         if (texture) {
134                 btn->guibutton->setUseAlphaChannel(true);
135                 btn->guibutton->setImage(texture);
136                 btn->guibutton->setPressedImage(texture);
137                 btn->guibutton->setScaleImage(true);
138                 btn->guibutton->setDrawBorder(false);
139                 btn->guibutton->setText(L"");
140                 }
141 }
142
143 void TouchScreenGUI::initButton(touch_gui_button_id id, rect<s32> button_rect,
144                 std::wstring caption, bool immediate_release )
145 {
146
147         button_info* btn       = &m_buttons[id];
148         btn->guibutton         = m_guienv->addButton(button_rect, 0, id, caption.c_str());
149         btn->guibutton->grab();
150         btn->repeatcounter     = -1;
151         btn->keycode           = id2keycode(id);
152         btn->immediate_release = immediate_release;
153         btn->ids.clear();
154
155         loadButtonTexture(btn,touchgui_button_imagenames[id]);
156 }
157
158 static int getMaxControlPadSize(float density) {
159         return 200 * density * g_settings->getFloat("hud_scaling");
160 }
161
162 void TouchScreenGUI::init(ISimpleTextureSource* tsrc, float density)
163 {
164         assert(tsrc != 0);
165
166         u32 control_pad_size =
167                         MYMIN((2 * m_screensize.Y) / 3,getMaxControlPadSize(density));
168
169         u32 button_size      = control_pad_size / 3;
170         m_visible            = true;
171         m_texturesource      = tsrc;
172         m_control_pad_rect   = rect<s32>(0, m_screensize.Y - 3 * button_size,
173                         3 * button_size, m_screensize.Y);
174         /*
175         draw control pad
176         0 1 2
177         3 4 5
178         for now only 0, 1, 2, and 4 are used
179         */
180         int number = 0;
181         for (int y = 0; y < 2; ++y)
182                 for (int x = 0; x < 3; ++x, ++number) {
183                         rect<s32> button_rect(
184                                         x * button_size, m_screensize.Y - button_size * (2 - y),
185                                         (x + 1) * button_size, m_screensize.Y - button_size * (1 - y)
186                         );
187                         touch_gui_button_id id = after_last_element_id;
188                         std::wstring caption;
189                         switch (number) {
190                         case 0:
191                                 id = left_id;
192                                 caption = L"<";
193                                 break;
194                         case 1:
195                                 id = forward_id;
196                                 caption = L"^";
197                                 break;
198                         case 2:
199                                 id = right_id;
200                                 caption = L">";
201                                 break;
202                         case 4:
203                                 id = backward_id;
204                                 caption = L"v";
205                                 break;
206                         }
207                         if (id != after_last_element_id) {
208                                 initButton(id, button_rect, caption, false);
209                                 }
210                 }
211
212         /* init inventory button */
213         initButton(inventory_id,
214                         rect<s32>(0, m_screensize.Y - (button_size/2),
215                                         (button_size/2), m_screensize.Y), L"inv", true);
216
217         /* init drop button */
218         initButton(drop_id,
219                         rect<s32>(2.5*button_size, m_screensize.Y - (button_size/2),
220                                         3*button_size, m_screensize.Y), L"drop", true);
221
222         /* init jump button */
223         initButton(jump_id,
224                         rect<s32>(m_screensize.X-(1.75*button_size),
225                                         m_screensize.Y - (0.5*button_size),
226                                         m_screensize.X-(0.25*button_size),
227                                         m_screensize.Y),
228                         L"x",false);
229
230         /* init crunch button */
231         initButton(crunch_id,
232                         rect<s32>(m_screensize.X-(3.25*button_size),
233                                         m_screensize.Y - (0.5*button_size),
234                                         m_screensize.X-(1.75*button_size),
235                                         m_screensize.Y),
236                         L"H",false);
237
238         /* init fly button */
239         initButton(fly_id,
240                         rect<s32>(m_screensize.X - (0.75*button_size),
241                                         m_screensize.Y - (2.25*button_size),
242                                         m_screensize.X, m_screensize.Y - (button_size*1.5)),
243                         L"fly", true);
244
245         /* init noclip button */
246         initButton(noclip_id,
247                         rect<s32>(m_screensize.X - (0.75*button_size), 2.25*button_size,
248                                         m_screensize.X, 3*button_size),
249                         L"clip", true);
250
251         /* init fast button */
252         initButton(fast_id,
253                         rect<s32>(m_screensize.X - (0.75*button_size), 1.5*button_size,
254                                         m_screensize.X, 2.25*button_size),
255                         L"fast", true);
256
257         /* init debug button */
258         initButton(debug_id,
259                         rect<s32>(m_screensize.X - (0.75*button_size), 0.75*button_size,
260                                         m_screensize.X, 1.5*button_size),
261                         L"dbg", true);
262
263         /* init chat button */
264         initButton(chat_id,
265                         rect<s32>(m_screensize.X - (0.75*button_size), 0,
266                                         m_screensize.X, 0.75*button_size),
267                         L"Chat", true);
268
269         /* init camera button */
270         initButton(camera_id,
271                         rect<s32>(m_screensize.X - (1.5*button_size), 0,
272                                         m_screensize.X - (0.75*button_size), 0.75*button_size),
273                         L"cam", true);
274
275         /* init rangeselect button */
276         initButton(range_id,
277                         rect<s32>(m_screensize.X - (2.25*button_size), 0,
278                                         m_screensize.X - (1.5*button_size), 0.75*button_size),
279                         L"far", true);
280 }
281
282 touch_gui_button_id TouchScreenGUI::getButtonID(s32 x, s32 y)
283 {
284         IGUIElement* rootguielement = m_guienv->getRootGUIElement();
285
286         if (rootguielement != NULL) {
287                 gui::IGUIElement *element =
288                                 rootguielement->getElementFromPoint(core::position2d<s32>(x,y));
289
290                 if (element) {
291                         for (unsigned int i=0; i < after_last_element_id; i++) {
292                                 if (element == m_buttons[i].guibutton) {
293                                         return (touch_gui_button_id) i;
294                                 }
295                         }
296                 }
297         }
298         return after_last_element_id;
299 }
300
301 touch_gui_button_id TouchScreenGUI::getButtonID(int eventID)
302 {
303         for (unsigned int i=0; i < after_last_element_id; i++) {
304                 button_info* btn = &m_buttons[i];
305
306                 std::vector<int>::iterator id =
307                                 std::find(btn->ids.begin(),btn->ids.end(), eventID);
308
309                 if (id != btn->ids.end())
310                         return (touch_gui_button_id) i;
311         }
312
313         return after_last_element_id;
314 }
315
316 bool TouchScreenGUI::isHUDButton(const SEvent &event)
317 {
318         // check if hud item is pressed
319         for (std::map<int,rect<s32> >::iterator iter = m_hud_rects.begin();
320                         iter != m_hud_rects.end(); iter++) {
321                 if (iter->second.isPointInside(
322                                 v2s32(event.TouchInput.X,
323                                                 event.TouchInput.Y)
324                         )) {
325                         if ( iter->first < 8) {
326                                 SEvent* translated = new SEvent();
327                                 memset(translated,0,sizeof(SEvent));
328                                 translated->EventType = irr::EET_KEY_INPUT_EVENT;
329                                 translated->KeyInput.Key         = (irr::EKEY_CODE) (KEY_KEY_1 + iter->first);
330                                 translated->KeyInput.Control     = false;
331                                 translated->KeyInput.Shift       = false;
332                                 translated->KeyInput.PressedDown = true;
333                                 m_receiver->OnEvent(*translated);
334                                 m_hud_ids[event.TouchInput.ID]   = translated->KeyInput.Key;
335                                 delete translated;
336                                 return true;
337                         }
338                 }
339         }
340         return false;
341 }
342
343 bool TouchScreenGUI::isReleaseHUDButton(int eventID)
344 {
345         std::map<int,irr::EKEY_CODE>::iterator iter = m_hud_ids.find(eventID);
346
347         if (iter != m_hud_ids.end()) {
348                 SEvent* translated = new SEvent();
349                 memset(translated,0,sizeof(SEvent));
350                 translated->EventType            = irr::EET_KEY_INPUT_EVENT;
351                 translated->KeyInput.Key         = iter->second;
352                 translated->KeyInput.PressedDown = false;
353                 translated->KeyInput.Control     = false;
354                 translated->KeyInput.Shift       = false;
355                 m_receiver->OnEvent(*translated);
356                 m_hud_ids.erase(iter);
357                 delete translated;
358                 return true;
359         }
360         return false;
361 }
362
363 void TouchScreenGUI::ButtonEvent(touch_gui_button_id button,
364                 int eventID, bool action)
365 {
366         button_info* btn = &m_buttons[button];
367         SEvent* translated = new SEvent();
368         memset(translated,0,sizeof(SEvent));
369         translated->EventType            = irr::EET_KEY_INPUT_EVENT;
370         translated->KeyInput.Key         = btn->keycode;
371         translated->KeyInput.Control     = false;
372         translated->KeyInput.Shift       = false;
373         translated->KeyInput.Char        = 0;
374
375         /* add this event */
376         if (action) {
377                 assert(std::find(btn->ids.begin(),btn->ids.end(), eventID) == btn->ids.end());
378
379                 btn->ids.push_back(eventID);
380
381                 if (btn->ids.size() > 1) return;
382
383                 btn->repeatcounter = 0;
384                 translated->KeyInput.PressedDown = true;
385                 translated->KeyInput.Key = btn->keycode;
386                 m_receiver->OnEvent(*translated);
387         }
388         /* remove event */
389         if ((!action) || (btn->immediate_release)) {
390
391                 std::vector<int>::iterator pos =
392                                 std::find(btn->ids.begin(),btn->ids.end(), eventID);
393                 /* has to be in touch list */
394                 assert(pos != btn->ids.end());
395                 btn->ids.erase(pos);
396
397                 if (btn->ids.size() > 0)  { return; }
398
399                 translated->KeyInput.PressedDown = false;
400                 btn->repeatcounter               = -1;
401                 m_receiver->OnEvent(*translated);
402         }
403         delete translated;
404 }
405
406 void TouchScreenGUI::translateEvent(const SEvent &event)
407 {
408         if (!m_visible) {
409                 infostream << "TouchScreenGUI::translateEvent got event but not visible?!" << std::endl;
410                 return;
411         }
412
413         if (event.EventType != EET_TOUCH_INPUT_EVENT) {
414                 return;
415         }
416
417         if (event.TouchInput.Event == ETIE_PRESSED_DOWN) {
418
419                 /* add to own copy of eventlist ...
420                  * android would provide this information but irrlicht guys don't
421                  * wanna design a efficient interface
422                  */
423                 id_status toadd;
424                 toadd.id = event.TouchInput.ID;
425                 toadd.X  = event.TouchInput.X;
426                 toadd.Y  = event.TouchInput.Y;
427                 m_known_ids.push_back(toadd);
428
429                 int eventID = event.TouchInput.ID;
430
431                 touch_gui_button_id button =
432                                 getButtonID(event.TouchInput.X, event.TouchInput.Y);
433
434                 /* handle button events */
435                 if (button != after_last_element_id) {
436                         ButtonEvent(button,eventID,true);
437                 }
438                 else if (isHUDButton(event))
439                 {
440                         /* already handled in isHUDButton() */
441                 }
442                 /* handle non button events */
443                 else {
444                         /* if we don't already have a moving point make this the moving one */
445                         if (m_move_id == -1) {
446                                 m_move_id                  = event.TouchInput.ID;
447                                 m_move_has_really_moved    = false;
448                                 m_move_downtime            = getTimeMs();
449                                 m_move_downlocation        = v2s32(event.TouchInput.X, event.TouchInput.Y);
450                                 m_move_sent_as_mouse_event = false;
451                         }
452                 }
453
454                 m_pointerpos[event.TouchInput.ID] = v2s32(event.TouchInput.X, event.TouchInput.Y);
455         }
456         else if (event.TouchInput.Event == ETIE_LEFT_UP) {
457                 verbosestream << "Up event for pointerid: " << event.TouchInput.ID << std::endl;
458
459                 touch_gui_button_id button = getButtonID(event.TouchInput.ID);
460
461                 /* handle button events */
462                 if (button != after_last_element_id) {
463                         ButtonEvent(button,event.TouchInput.ID,false);
464                 }
465                 /* handle hud button events */
466                 else if (isReleaseHUDButton(event.TouchInput.ID)) {
467                         /* nothing to do here */
468                 }
469                 /* handle the point used for moving view */
470                 else if (event.TouchInput.ID == m_move_id) {
471                         m_move_id = -1;
472
473                         /* if this pointer issued a mouse event issue symmetric release here */
474                         if (m_move_sent_as_mouse_event) {
475                                 SEvent* translated = new SEvent;
476                                 memset(translated,0,sizeof(SEvent));
477                                 translated->EventType               = EET_MOUSE_INPUT_EVENT;
478                                 translated->MouseInput.X            = m_move_downlocation.X;
479                                 translated->MouseInput.Y            = m_move_downlocation.Y;
480                                 translated->MouseInput.Shift        = false;
481                                 translated->MouseInput.Control      = false;
482                                 translated->MouseInput.ButtonStates = 0;
483                                 translated->MouseInput.Event        = EMIE_LMOUSE_LEFT_UP;
484                                 m_receiver->OnEvent(*translated);
485                                 delete translated;
486                         }
487                         else {
488                                 /* do double tap detection */
489                                 doubleTapDetection();
490                         }
491                 }
492                 else {
493                         infostream
494                                 << "TouchScreenGUI::translateEvent released unknown button: "
495                                 << event.TouchInput.ID << std::endl;
496                 }
497
498                 for (std::vector<id_status>::iterator iter = m_known_ids.begin();
499                                 iter != m_known_ids.end(); iter++) {
500                         if (iter->id == event.TouchInput.ID) {
501                                 m_known_ids.erase(iter);
502                                 break;
503                         }
504                 }
505         }
506         else {
507                 assert(event.TouchInput.Event == ETIE_MOVED);
508                 int move_idx = event.TouchInput.ID;
509
510                 if (m_pointerpos[event.TouchInput.ID] ==
511                                 v2s32(event.TouchInput.X, event.TouchInput.Y)) {
512                         return;
513                 }
514
515                 if (m_move_id != -1) {
516                         if ((event.TouchInput.ID == m_move_id) &&
517                                 (!m_move_sent_as_mouse_event)) {
518
519                                 double distance = sqrt(
520                                                 (m_pointerpos[event.TouchInput.ID].X - event.TouchInput.X) *
521                                                 (m_pointerpos[event.TouchInput.ID].X - event.TouchInput.X) +
522                                                 (m_pointerpos[event.TouchInput.ID].Y - event.TouchInput.Y) *
523                                                 (m_pointerpos[event.TouchInput.ID].Y - event.TouchInput.Y));
524
525                                 if ((distance > g_settings->getU16("touchscreen_threshold")) ||
526                                                 (m_move_has_really_moved)) {
527                                         m_move_has_really_moved = true;
528                                         s32 X = event.TouchInput.X;
529                                         s32 Y = event.TouchInput.Y;
530
531                                         // update camera_yaw and camera_pitch
532                                         s32 dx = X - m_pointerpos[event.TouchInput.ID].X;
533                                         s32 dy = Y - m_pointerpos[event.TouchInput.ID].Y;
534
535                                         /* adapt to similar behaviour as pc screen */
536                                         double d         = g_settings->getFloat("mouse_sensitivity") *4;
537                                         double old_yaw   = m_camera_yaw;
538                                         double old_pitch = m_camera_pitch;
539
540                                         m_camera_yaw   -= dx * d;
541                                         m_camera_pitch  = MYMIN(MYMAX( m_camera_pitch + (dy * d),-180),180);
542
543                                         while (m_camera_yaw < 0)
544                                                 m_camera_yaw += 360;
545
546                                         while (m_camera_yaw > 360)
547                                                 m_camera_yaw -= 360;
548
549                                         // update shootline
550                                         m_shootline = m_device
551                                                         ->getSceneManager()
552                                                         ->getSceneCollisionManager()
553                                                         ->getRayFromScreenCoordinates(v2s32(X, Y));
554                                         m_pointerpos[event.TouchInput.ID] = v2s32(X, Y);
555                                 }
556                         }
557                         else if ((event.TouchInput.ID == m_move_id) &&
558                                         (m_move_sent_as_mouse_event)) {
559                                 m_shootline = m_device
560                                                 ->getSceneManager()
561                                                 ->getSceneCollisionManager()
562                                                 ->getRayFromScreenCoordinates(
563                                                                 v2s32(event.TouchInput.X,event.TouchInput.Y));
564                         }
565                 }
566                 else {
567                         handleChangedButton(event);
568                 }
569         }
570 }
571
572 void TouchScreenGUI::handleChangedButton(const SEvent &event)
573 {
574         for (unsigned int i = 0; i < after_last_element_id; i++) {
575
576                 if (m_buttons[i].ids.empty()) {
577                         continue;
578                 }
579                 for(std::vector<int>::iterator iter = m_buttons[i].ids.begin();
580                                 iter != m_buttons[i].ids.end(); iter++) {
581
582                         if (event.TouchInput.ID == *iter) {
583
584                                 int current_button_id =
585                                                 getButtonID(event.TouchInput.X, event.TouchInput.Y);
586
587                                 if (current_button_id == i) {
588                                         continue;
589                                 }
590
591                                 /* remove old button */
592                                 ButtonEvent((touch_gui_button_id) i,*iter,false);
593
594                                 if (current_button_id == after_last_element_id) {
595                                         return;
596                                 }
597                                 ButtonEvent((touch_gui_button_id) current_button_id,*iter,true);
598                                 return;
599
600                         }
601                 }
602         }
603
604         int current_button_id = getButtonID(event.TouchInput.X, event.TouchInput.Y);
605
606         if (current_button_id == after_last_element_id) {
607                 return;
608         }
609
610         button_info* btn = &m_buttons[current_button_id];
611         if (std::find(btn->ids.begin(),btn->ids.end(), event.TouchInput.ID) == btn->ids.end()) {
612                 ButtonEvent((touch_gui_button_id) current_button_id,event.TouchInput.ID,true);
613         }
614
615 }
616
617 bool TouchScreenGUI::doubleTapDetection()
618 {
619         m_key_events[0].down_time = m_key_events[1].down_time;
620         m_key_events[0].x         = m_key_events[1].x;
621         m_key_events[0].y         = m_key_events[1].y;
622         m_key_events[1].down_time = m_move_downtime;
623         m_key_events[1].x         = m_move_downlocation.X;
624         m_key_events[1].y         = m_move_downlocation.Y;
625
626         u32 delta = porting::getDeltaMs(m_key_events[0].down_time,getTimeMs());
627         if (delta > 400)
628                 return false;
629
630         double distance = sqrt(
631                         (m_key_events[0].x - m_key_events[1].x) * (m_key_events[0].x - m_key_events[1].x) +
632                         (m_key_events[0].y - m_key_events[1].y) * (m_key_events[0].y - m_key_events[1].y));
633
634
635         if (distance >(20 + g_settings->getU16("touchscreen_threshold")))
636                 return false;
637
638         SEvent* translated = new SEvent();
639         memset(translated,0,sizeof(SEvent));
640         translated->EventType               = EET_MOUSE_INPUT_EVENT;
641         translated->MouseInput.X            = m_key_events[0].x;
642         translated->MouseInput.Y            = m_key_events[0].y;
643         translated->MouseInput.Shift        = false;
644         translated->MouseInput.Control      = false;
645         translated->MouseInput.ButtonStates = EMBSM_RIGHT;
646
647         // update shootline
648         m_shootline = m_device
649                         ->getSceneManager()
650                         ->getSceneCollisionManager()
651                         ->getRayFromScreenCoordinates(v2s32(m_key_events[0].x, m_key_events[0].y));
652
653         translated->MouseInput.Event = EMIE_RMOUSE_PRESSED_DOWN;
654         verbosestream << "TouchScreenGUI::translateEvent right click press" << std::endl;
655         m_receiver->OnEvent(*translated);
656
657         translated->MouseInput.ButtonStates = 0;
658         translated->MouseInput.Event        = EMIE_RMOUSE_LEFT_UP;
659         verbosestream << "TouchScreenGUI::translateEvent right click release" << std::endl;
660         m_receiver->OnEvent(*translated);
661         delete translated;
662         return true;
663
664 }
665
666 TouchScreenGUI::~TouchScreenGUI()
667 {
668         for (unsigned int i=0; i < after_last_element_id; i++) {
669                 button_info* btn = &m_buttons[i];
670                 if (btn->guibutton != 0) {
671                         btn->guibutton->drop();
672                         btn->guibutton = NULL;
673                 }
674         }
675 }
676
677 void TouchScreenGUI::step(float dtime)
678 {
679         /* simulate keyboard repeats */
680         for (unsigned int i=0; i < after_last_element_id; i++) {
681                 button_info* btn = &m_buttons[i];
682
683                 if (btn->ids.size() > 0) {
684                         btn->repeatcounter += dtime;
685
686                         /* in case we're moving around digging does not happen */
687                         if (m_move_id != -1)
688                                 m_move_has_really_moved = true;
689
690                         if (btn->repeatcounter < 0.2) continue;
691
692                         btn->repeatcounter              = 0;
693                         SEvent translated;
694                         memset(&translated,0,sizeof(SEvent));
695                         translated.EventType            = irr::EET_KEY_INPUT_EVENT;
696                         translated.KeyInput.Key         = btn->keycode;
697                         translated.KeyInput.PressedDown = false;
698                         m_receiver->OnEvent(translated);
699
700                         translated.KeyInput.PressedDown = true;
701                         m_receiver->OnEvent(translated);
702                 }
703         }
704
705         /* if a new placed pointer isn't moved for some time start digging */
706         if ((m_move_id != -1) &&
707                         (!m_move_has_really_moved) &&
708                         (!m_move_sent_as_mouse_event)) {
709
710                 u32 delta = porting::getDeltaMs(m_move_downtime,getTimeMs());
711
712                 if (delta > MIN_DIG_TIME_MS) {
713                         m_shootline = m_device
714                                         ->getSceneManager()
715                                         ->getSceneCollisionManager()
716                                         ->getRayFromScreenCoordinates(
717                                                         v2s32(m_move_downlocation.X,m_move_downlocation.Y));
718
719                         SEvent translated;
720                         memset(&translated,0,sizeof(SEvent));
721                         translated.EventType               = EET_MOUSE_INPUT_EVENT;
722                         translated.MouseInput.X            = m_move_downlocation.X;
723                         translated.MouseInput.Y            = m_move_downlocation.Y;
724                         translated.MouseInput.Shift        = false;
725                         translated.MouseInput.Control      = false;
726                         translated.MouseInput.ButtonStates = EMBSM_LEFT;
727                         translated.MouseInput.Event        = EMIE_LMOUSE_PRESSED_DOWN;
728                         verbosestream << "TouchScreenGUI::step left click press" << std::endl;
729                         m_receiver->OnEvent(translated);
730                         m_move_sent_as_mouse_event         = true;
731                 }
732         }
733 }
734
735 void TouchScreenGUI::resetHud()
736 {
737         m_hud_rects.clear();
738 }
739
740 void TouchScreenGUI::registerHudItem(int index, const rect<s32> &rect)
741 {
742         m_hud_rects[index] = rect;
743 }
744
745 void TouchScreenGUI::Toggle(bool visible)
746 {
747         m_visible = visible;
748         for (unsigned int i=0; i < after_last_element_id; i++) {
749                 button_info* btn = &m_buttons[i];
750                 if (btn->guibutton != 0) {
751                         btn->guibutton->setVisible(visible);
752                 }
753         }
754 }
755
756 void TouchScreenGUI::Hide()
757 {
758         Toggle(false);
759 }
760
761 void TouchScreenGUI::Show()
762 {
763         Toggle(true);
764 }