Mgv7: Auto-set lowest mountain generation level
[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 #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 void TouchScreenGUI::translateEvent(const SEvent &event)
421 {
422         if (!m_visible) {
423                 infostream << "TouchScreenGUI::translateEvent got event but not visible?!" << std::endl;
424                 return;
425         }
426
427         if (event.EventType != EET_TOUCH_INPUT_EVENT) {
428                 return;
429         }
430
431         if (event.TouchInput.Event == ETIE_PRESSED_DOWN) {
432
433                 /* add to own copy of eventlist ...
434                  * android would provide this information but irrlicht guys don't
435                  * wanna design a efficient interface
436                  */
437                 id_status toadd;
438                 toadd.id = event.TouchInput.ID;
439                 toadd.X  = event.TouchInput.X;
440                 toadd.Y  = event.TouchInput.Y;
441                 m_known_ids.push_back(toadd);
442
443                 int eventID = event.TouchInput.ID;
444
445                 touch_gui_button_id button =
446                                 getButtonID(event.TouchInput.X, event.TouchInput.Y);
447
448                 /* handle button events */
449                 if (button != after_last_element_id) {
450                         ButtonEvent(button,eventID,true);
451                 }
452                 else if (isHUDButton(event))
453                 {
454                         /* already handled in isHUDButton() */
455                 }
456                 /* handle non button events */
457                 else {
458                         /* if we don't already have a moving point make this the moving one */
459                         if (m_move_id == -1) {
460                                 m_move_id                  = event.TouchInput.ID;
461                                 m_move_has_really_moved    = false;
462                                 m_move_downtime            = getTimeMs();
463                                 m_move_downlocation        = v2s32(event.TouchInput.X, event.TouchInput.Y);
464                                 m_move_sent_as_mouse_event = false;
465                         }
466                 }
467
468                 m_pointerpos[event.TouchInput.ID] = v2s32(event.TouchInput.X, event.TouchInput.Y);
469         }
470         else if (event.TouchInput.Event == ETIE_LEFT_UP) {
471                 verbosestream << "Up event for pointerid: " << event.TouchInput.ID << std::endl;
472
473                 touch_gui_button_id button = getButtonID(event.TouchInput.ID);
474
475                 /* handle button events */
476                 if (button != after_last_element_id) {
477                         ButtonEvent(button,event.TouchInput.ID,false);
478                 }
479                 /* handle hud button events */
480                 else if (isReleaseHUDButton(event.TouchInput.ID)) {
481                         /* nothing to do here */
482                 }
483                 /* handle the point used for moving view */
484                 else if (event.TouchInput.ID == m_move_id) {
485                         m_move_id = -1;
486
487                         /* if this pointer issued a mouse event issue symmetric release here */
488                         if (m_move_sent_as_mouse_event) {
489                                 SEvent* translated = new SEvent;
490                                 memset(translated,0,sizeof(SEvent));
491                                 translated->EventType               = EET_MOUSE_INPUT_EVENT;
492                                 translated->MouseInput.X            = m_move_downlocation.X;
493                                 translated->MouseInput.Y            = m_move_downlocation.Y;
494                                 translated->MouseInput.Shift        = false;
495                                 translated->MouseInput.Control      = false;
496                                 translated->MouseInput.ButtonStates = 0;
497                                 translated->MouseInput.Event        = EMIE_LMOUSE_LEFT_UP;
498                                 m_receiver->OnEvent(*translated);
499                                 delete translated;
500                         }
501                         else {
502                                 /* do double tap detection */
503                                 doubleTapDetection();
504                         }
505                 }
506                 else {
507                         infostream
508                                 << "TouchScreenGUI::translateEvent released unknown button: "
509                                 << event.TouchInput.ID << std::endl;
510                 }
511
512                 for (std::vector<id_status>::iterator iter = m_known_ids.begin();
513                                 iter != m_known_ids.end(); iter++) {
514                         if (iter->id == event.TouchInput.ID) {
515                                 m_known_ids.erase(iter);
516                                 break;
517                         }
518                 }
519         }
520         else {
521                 assert(event.TouchInput.Event == ETIE_MOVED);
522                 int move_idx = event.TouchInput.ID;
523
524                 if (m_pointerpos[event.TouchInput.ID] ==
525                                 v2s32(event.TouchInput.X, event.TouchInput.Y)) {
526                         return;
527                 }
528
529                 if (m_move_id != -1) {
530                         if ((event.TouchInput.ID == m_move_id) &&
531                                 (!m_move_sent_as_mouse_event)) {
532
533                                 double distance = sqrt(
534                                                 (m_pointerpos[event.TouchInput.ID].X - event.TouchInput.X) *
535                                                 (m_pointerpos[event.TouchInput.ID].X - event.TouchInput.X) +
536                                                 (m_pointerpos[event.TouchInput.ID].Y - event.TouchInput.Y) *
537                                                 (m_pointerpos[event.TouchInput.ID].Y - event.TouchInput.Y));
538
539                                 if ((distance > g_settings->getU16("touchscreen_threshold")) ||
540                                                 (m_move_has_really_moved)) {
541                                         m_move_has_really_moved = true;
542                                         s32 X = event.TouchInput.X;
543                                         s32 Y = event.TouchInput.Y;
544
545                                         // update camera_yaw and camera_pitch
546                                         s32 dx = X - m_pointerpos[event.TouchInput.ID].X;
547                                         s32 dy = Y - m_pointerpos[event.TouchInput.ID].Y;
548
549                                         /* adapt to similar behaviour as pc screen */
550                                         double d         = g_settings->getFloat("mouse_sensitivity") *4;
551                                         double old_yaw   = m_camera_yaw;
552                                         double old_pitch = m_camera_pitch;
553
554                                         m_camera_yaw   -= dx * d;
555                                         m_camera_pitch  = MYMIN(MYMAX( m_camera_pitch + (dy * d),-180),180);
556
557                                         while (m_camera_yaw < 0)
558                                                 m_camera_yaw += 360;
559
560                                         while (m_camera_yaw > 360)
561                                                 m_camera_yaw -= 360;
562
563                                         // update shootline
564                                         m_shootline = m_device
565                                                         ->getSceneManager()
566                                                         ->getSceneCollisionManager()
567                                                         ->getRayFromScreenCoordinates(v2s32(X, Y));
568                                         m_pointerpos[event.TouchInput.ID] = v2s32(X, Y);
569                                 }
570                         }
571                         else if ((event.TouchInput.ID == m_move_id) &&
572                                         (m_move_sent_as_mouse_event)) {
573                                 m_shootline = m_device
574                                                 ->getSceneManager()
575                                                 ->getSceneCollisionManager()
576                                                 ->getRayFromScreenCoordinates(
577                                                                 v2s32(event.TouchInput.X,event.TouchInput.Y));
578                         }
579                 }
580                 else {
581                         handleChangedButton(event);
582                 }
583         }
584 }
585
586 void TouchScreenGUI::handleChangedButton(const SEvent &event)
587 {
588         for (unsigned int i = 0; i < after_last_element_id; i++) {
589
590                 if (m_buttons[i].ids.empty()) {
591                         continue;
592                 }
593                 for(std::vector<int>::iterator iter = m_buttons[i].ids.begin();
594                                 iter != m_buttons[i].ids.end(); iter++) {
595
596                         if (event.TouchInput.ID == *iter) {
597
598                                 int current_button_id =
599                                                 getButtonID(event.TouchInput.X, event.TouchInput.Y);
600
601                                 if (current_button_id == i) {
602                                         continue;
603                                 }
604
605                                 /* remove old button */
606                                 ButtonEvent((touch_gui_button_id) i,*iter,false);
607
608                                 if (current_button_id == after_last_element_id) {
609                                         return;
610                                 }
611                                 ButtonEvent((touch_gui_button_id) current_button_id,*iter,true);
612                                 return;
613
614                         }
615                 }
616         }
617
618         int current_button_id = getButtonID(event.TouchInput.X, event.TouchInput.Y);
619
620         if (current_button_id == after_last_element_id) {
621                 return;
622         }
623
624         button_info* btn = &m_buttons[current_button_id];
625         if (std::find(btn->ids.begin(),btn->ids.end(), event.TouchInput.ID) == btn->ids.end()) {
626                 ButtonEvent((touch_gui_button_id) current_button_id,event.TouchInput.ID,true);
627         }
628
629 }
630
631 bool TouchScreenGUI::doubleTapDetection()
632 {
633         m_key_events[0].down_time = m_key_events[1].down_time;
634         m_key_events[0].x         = m_key_events[1].x;
635         m_key_events[0].y         = m_key_events[1].y;
636         m_key_events[1].down_time = m_move_downtime;
637         m_key_events[1].x         = m_move_downlocation.X;
638         m_key_events[1].y         = m_move_downlocation.Y;
639
640         u32 delta = porting::getDeltaMs(m_key_events[0].down_time,getTimeMs());
641         if (delta > 400)
642                 return false;
643
644         double distance = sqrt(
645                         (m_key_events[0].x - m_key_events[1].x) * (m_key_events[0].x - m_key_events[1].x) +
646                         (m_key_events[0].y - m_key_events[1].y) * (m_key_events[0].y - m_key_events[1].y));
647
648
649         if (distance >(20 + g_settings->getU16("touchscreen_threshold")))
650                 return false;
651
652         SEvent* translated = new SEvent();
653         memset(translated,0,sizeof(SEvent));
654         translated->EventType               = EET_MOUSE_INPUT_EVENT;
655         translated->MouseInput.X            = m_key_events[0].x;
656         translated->MouseInput.Y            = m_key_events[0].y;
657         translated->MouseInput.Shift        = false;
658         translated->MouseInput.Control      = false;
659         translated->MouseInput.ButtonStates = EMBSM_RIGHT;
660
661         // update shootline
662         m_shootline = m_device
663                         ->getSceneManager()
664                         ->getSceneCollisionManager()
665                         ->getRayFromScreenCoordinates(v2s32(m_key_events[0].x, m_key_events[0].y));
666
667         translated->MouseInput.Event = EMIE_RMOUSE_PRESSED_DOWN;
668         verbosestream << "TouchScreenGUI::translateEvent right click press" << std::endl;
669         m_receiver->OnEvent(*translated);
670
671         translated->MouseInput.ButtonStates = 0;
672         translated->MouseInput.Event        = EMIE_RMOUSE_LEFT_UP;
673         verbosestream << "TouchScreenGUI::translateEvent right click release" << std::endl;
674         m_receiver->OnEvent(*translated);
675         delete translated;
676         return true;
677
678 }
679
680 TouchScreenGUI::~TouchScreenGUI()
681 {
682         for (unsigned int i=0; i < after_last_element_id; i++) {
683                 button_info* btn = &m_buttons[i];
684                 if (btn->guibutton != 0) {
685                         btn->guibutton->drop();
686                         btn->guibutton = NULL;
687                 }
688         }
689 }
690
691 void TouchScreenGUI::step(float dtime)
692 {
693         /* simulate keyboard repeats */
694         for (unsigned int i=0; i < after_last_element_id; i++) {
695                 button_info* btn = &m_buttons[i];
696
697                 if (btn->ids.size() > 0) {
698                         btn->repeatcounter += dtime;
699
700                         /* in case we're moving around digging does not happen */
701                         if (m_move_id != -1)
702                                 m_move_has_really_moved = true;
703
704                         if (btn->repeatcounter < btn->repeatdelay) continue;
705
706                         btn->repeatcounter              = 0;
707                         SEvent translated;
708                         memset(&translated,0,sizeof(SEvent));
709                         translated.EventType            = irr::EET_KEY_INPUT_EVENT;
710                         translated.KeyInput.Key         = btn->keycode;
711                         translated.KeyInput.PressedDown = false;
712                         m_receiver->OnEvent(translated);
713
714                         translated.KeyInput.PressedDown = true;
715                         m_receiver->OnEvent(translated);
716                 }
717         }
718
719         /* if a new placed pointer isn't moved for some time start digging */
720         if ((m_move_id != -1) &&
721                         (!m_move_has_really_moved) &&
722                         (!m_move_sent_as_mouse_event)) {
723
724                 u32 delta = porting::getDeltaMs(m_move_downtime,getTimeMs());
725
726                 if (delta > MIN_DIG_TIME_MS) {
727                         m_shootline = m_device
728                                         ->getSceneManager()
729                                         ->getSceneCollisionManager()
730                                         ->getRayFromScreenCoordinates(
731                                                         v2s32(m_move_downlocation.X,m_move_downlocation.Y));
732
733                         SEvent translated;
734                         memset(&translated,0,sizeof(SEvent));
735                         translated.EventType               = EET_MOUSE_INPUT_EVENT;
736                         translated.MouseInput.X            = m_move_downlocation.X;
737                         translated.MouseInput.Y            = m_move_downlocation.Y;
738                         translated.MouseInput.Shift        = false;
739                         translated.MouseInput.Control      = false;
740                         translated.MouseInput.ButtonStates = EMBSM_LEFT;
741                         translated.MouseInput.Event        = EMIE_LMOUSE_PRESSED_DOWN;
742                         verbosestream << "TouchScreenGUI::step left click press" << std::endl;
743                         m_receiver->OnEvent(translated);
744                         m_move_sent_as_mouse_event         = true;
745                 }
746         }
747 }
748
749 void TouchScreenGUI::resetHud()
750 {
751         m_hud_rects.clear();
752 }
753
754 void TouchScreenGUI::registerHudItem(int index, const rect<s32> &rect)
755 {
756         m_hud_rects[index] = rect;
757 }
758
759 void TouchScreenGUI::Toggle(bool visible)
760 {
761         m_visible = visible;
762         for (unsigned int i=0; i < after_last_element_id; i++) {
763                 button_info* btn = &m_buttons[i];
764                 if (btn->guibutton != 0) {
765                         btn->guibutton->setVisible(visible);
766                 }
767         }
768 }
769
770 void TouchScreenGUI::Hide()
771 {
772         Toggle(false);
773 }
774
775 void TouchScreenGUI::Show()
776 {
777         Toggle(true);
778 }