touchscreengui.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. Copyright (C) 2014 sapier
  3. Copyright (C) 2024 grorp, Gregor Parzefall
  4. <gregor.parzefall@posteo.de>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 2.1 of the License, or
  8. (at your option) any later version.
  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. You should have received a copy of the GNU Lesser General Public License along
  14. with this program; if not, write to the Free Software Foundation, Inc.,
  15. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. */
  17. #pragma once
  18. #include "irrlichttypes.h"
  19. #include <IEventReceiver.h>
  20. #include <IGUIButton.h>
  21. #include <IGUIEnvironment.h>
  22. #include <IrrlichtDevice.h>
  23. #include <memory>
  24. #include <optional>
  25. #include <unordered_map>
  26. #include <vector>
  27. #include "itemdef.h"
  28. #include "client/tile.h"
  29. #include "client/game.h"
  30. using namespace irr;
  31. using namespace irr::core;
  32. using namespace irr::gui;
  33. enum class TapState
  34. {
  35. None,
  36. ShortTap,
  37. LongTap,
  38. };
  39. typedef enum
  40. {
  41. jump_id = 0,
  42. crunch_id,
  43. zoom_id,
  44. aux1_id,
  45. after_last_element_id,
  46. settings_starter_id,
  47. rare_controls_starter_id,
  48. fly_id,
  49. noclip_id,
  50. fast_id,
  51. debug_id,
  52. camera_id,
  53. range_id,
  54. minimap_id,
  55. toggle_chat_id,
  56. chat_id,
  57. inventory_id,
  58. drop_id,
  59. exit_id,
  60. joystick_off_id,
  61. joystick_bg_id,
  62. joystick_center_id
  63. } touch_gui_button_id;
  64. typedef enum
  65. {
  66. AHBB_Dir_Top_Bottom,
  67. AHBB_Dir_Bottom_Top,
  68. AHBB_Dir_Left_Right,
  69. AHBB_Dir_Right_Left
  70. } autohide_button_bar_dir;
  71. #define MIN_DIG_TIME_MS 500
  72. #define BUTTON_REPEAT_DELAY 0.2f
  73. #define SETTINGS_BAR_Y_OFFSET 5
  74. #define RARE_CONTROLS_BAR_Y_OFFSET 5
  75. // Our simulated clicks last some milliseconds so that server-side mods have a
  76. // chance to detect them via l_get_player_control.
  77. // If you tap faster than this value, the simulated clicks are of course shorter.
  78. #define SIMULATED_CLICK_DURATION_MS 50
  79. extern const std::string button_image_names[];
  80. extern const std::string joystick_image_names[];
  81. struct button_info
  82. {
  83. float repeat_counter;
  84. float repeat_delay;
  85. EKEY_CODE keycode;
  86. std::vector<size_t> ids;
  87. IGUIButton *gui_button = nullptr;
  88. bool immediate_release;
  89. enum {
  90. NOT_TOGGLEABLE,
  91. FIRST_TEXTURE,
  92. SECOND_TEXTURE
  93. } toggleable = NOT_TOGGLEABLE;
  94. std::vector<std::string> textures;
  95. };
  96. class AutoHideButtonBar
  97. {
  98. public:
  99. AutoHideButtonBar(IrrlichtDevice *device, IEventReceiver *receiver);
  100. void init(ISimpleTextureSource *tsrc, const std::string &starter_img, int button_id,
  101. const v2s32 &UpperLeft, const v2s32 &LowerRight,
  102. autohide_button_bar_dir dir, float timeout);
  103. ~AutoHideButtonBar();
  104. // add button to be shown
  105. void addButton(touch_gui_button_id id, const wchar_t *caption,
  106. const std::string &btn_image);
  107. // add toggle button to be shown
  108. void addToggleButton(touch_gui_button_id id, const wchar_t *caption,
  109. const std::string &btn_image_1, const std::string &btn_image_2);
  110. // detect button bar button events
  111. bool isButton(const SEvent &event);
  112. // step handler
  113. void step(float dtime);
  114. // return whether the button bar is active
  115. bool active() { return m_active; }
  116. // deactivate the button bar
  117. void deactivate();
  118. // hide the whole button bar
  119. void hide();
  120. // unhide the button bar
  121. void show();
  122. private:
  123. ISimpleTextureSource *m_texturesource = nullptr;
  124. irr::video::IVideoDriver *m_driver;
  125. IGUIEnvironment *m_guienv;
  126. IEventReceiver *m_receiver;
  127. button_info m_starter;
  128. std::vector<std::shared_ptr<button_info>> m_buttons;
  129. v2s32 m_upper_left;
  130. v2s32 m_lower_right;
  131. // show button bar
  132. bool m_active = false;
  133. bool m_visible = true;
  134. // button bar timeout
  135. float m_timeout = 0.0f;
  136. float m_timeout_value = 3.0f;
  137. bool m_initialized = false;
  138. autohide_button_bar_dir m_dir = AHBB_Dir_Right_Left;
  139. };
  140. class TouchScreenGUI
  141. {
  142. public:
  143. TouchScreenGUI(IrrlichtDevice *device, IEventReceiver *receiver);
  144. ~TouchScreenGUI();
  145. void translateEvent(const SEvent &event);
  146. void applyContextControls(const TouchInteractionMode &mode);
  147. void init(ISimpleTextureSource *tsrc);
  148. double getYawChange()
  149. {
  150. double res = m_camera_yaw_change;
  151. m_camera_yaw_change = 0;
  152. return res;
  153. }
  154. double getPitchChange() {
  155. double res = m_camera_pitch_change;
  156. m_camera_pitch_change = 0;
  157. return res;
  158. }
  159. /**
  160. * Returns a line which describes what the player is pointing at.
  161. * The starting point and looking direction are significant,
  162. * the line should be scaled to match its length to the actual distance
  163. * the player can reach.
  164. * The line starts at the camera and ends on the camera's far plane.
  165. * The coordinates do not contain the camera offset.
  166. */
  167. line3d<f32> getShootline() { return m_shootline; }
  168. float getMovementDirection() { return m_joystick_direction; }
  169. float getMovementSpeed() { return m_joystick_speed; }
  170. void step(float dtime);
  171. inline void setUseCrosshair(bool use_crosshair) { m_draw_crosshair = use_crosshair; }
  172. void setVisible(bool visible);
  173. void hide();
  174. void show();
  175. void resetHotbarRects();
  176. void registerHotbarRect(u16 index, const rect<s32> &rect);
  177. std::optional<u16> getHotbarSelection();
  178. private:
  179. bool m_initialized = false;
  180. IrrlichtDevice *m_device;
  181. IGUIEnvironment *m_guienv;
  182. IEventReceiver *m_receiver;
  183. ISimpleTextureSource *m_texturesource;
  184. v2u32 m_screensize;
  185. s32 button_size;
  186. double m_touchscreen_threshold;
  187. bool m_visible; // is the whole touch screen gui visible
  188. std::unordered_map<u16, rect<s32>> m_hotbar_rects;
  189. std::optional<u16> m_hotbar_selection = std::nullopt;
  190. // value in degree
  191. double m_camera_yaw_change = 0.0;
  192. double m_camera_pitch_change = 0.0;
  193. /**
  194. * A line starting at the camera and pointing towards the selected object.
  195. * The line ends on the camera's far plane.
  196. * The coordinates do not contain the camera offset.
  197. */
  198. line3d<f32> m_shootline;
  199. bool m_has_move_id = false;
  200. size_t m_move_id;
  201. bool m_move_has_really_moved = false;
  202. u64 m_move_downtime = 0;
  203. // m_move_pos stays valid even after m_move_id has been released.
  204. v2s32 m_move_pos;
  205. bool m_has_joystick_id = false;
  206. size_t m_joystick_id;
  207. bool m_joystick_has_really_moved = false;
  208. float m_joystick_direction = 0.0f; // assume forward
  209. float m_joystick_speed = 0.0f; // no movement
  210. bool m_joystick_status_aux1 = false;
  211. bool m_fixed_joystick = false;
  212. bool m_joystick_triggers_aux1 = false;
  213. bool m_draw_crosshair = false;
  214. std::shared_ptr<button_info> m_joystick_btn_off = nullptr;
  215. std::shared_ptr<button_info> m_joystick_btn_bg = nullptr;
  216. std::shared_ptr<button_info> m_joystick_btn_center = nullptr;
  217. button_info m_buttons[after_last_element_id];
  218. // gui button detection
  219. touch_gui_button_id getButtonID(s32 x, s32 y);
  220. // gui button by eventID
  221. touch_gui_button_id getButtonID(size_t eventID);
  222. // check if a button has changed
  223. void handleChangedButton(const SEvent &event);
  224. // initialize a button
  225. void initButton(touch_gui_button_id id, const rect<s32> &button_rect,
  226. const std::wstring &caption, bool immediate_release,
  227. float repeat_delay = BUTTON_REPEAT_DELAY);
  228. // initialize a joystick button
  229. std::shared_ptr<button_info> initJoystickButton(touch_gui_button_id id,
  230. const rect<s32> &button_rect, int texture_id,
  231. bool visible = true);
  232. // handle a button event
  233. void handleButtonEvent(touch_gui_button_id bID, size_t eventID, bool action);
  234. // handle pressing hotbar items
  235. bool isHotbarButton(const SEvent &event);
  236. // handle release event
  237. void handleReleaseEvent(size_t evt_id);
  238. // apply joystick status
  239. void applyJoystickStatus();
  240. // map to store the IDs and positions of currently pressed pointers
  241. std::unordered_map<size_t, v2s32> m_pointer_pos;
  242. // settings bar
  243. AutoHideButtonBar m_settings_bar;
  244. // rare controls bar
  245. AutoHideButtonBar m_rare_controls_bar;
  246. v2s32 getPointerPos();
  247. void emitMouseEvent(EMOUSE_INPUT_EVENT type);
  248. TouchInteractionMode m_last_mode = TouchInteractionMode_END;
  249. TapState m_tap_state = TapState::None;
  250. bool m_dig_pressed = false;
  251. u64 m_dig_pressed_until = 0;
  252. bool m_place_pressed = false;
  253. u64 m_place_pressed_until = 0;
  254. };
  255. extern TouchScreenGUI *g_touchscreengui;