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