#include "Screens.h" #ifdef CC_BUILD_TOUCH #include "Widgets.h" #include "Game.h" #include "Event.h" #include "Platform.h" #include "Inventory.h" #include "Drawer2D.h" #include "Graphics.h" #include "Funcs.h" #include "TexturePack.h" #include "Model.h" #include "Generator.h" #include "Server.h" #include "Chat.h" #include "ExtMath.h" #include "Window.h" #include "Camera.h" #include "Http.h" #include "Block.h" #include "Menus.h" #include "World.h" #include "Input.h" #include "Utils.h" #include "Options.h" /* Enumeration of on-screen buttons for touch GUI */ #define ONSCREEN_BTN_CHAT (1 << 0) #define ONSCREEN_BTN_LIST (1 << 1) #define ONSCREEN_BTN_SPAWN (1 << 2) #define ONSCREEN_BTN_SETSPAWN (1 << 3) #define ONSCREEN_BTN_FLY (1 << 4) #define ONSCREEN_BTN_NOCLIP (1 << 5) #define ONSCREEN_BTN_SPEED (1 << 6) #define ONSCREEN_BTN_HALFSPEED (1 << 7) #define ONSCREEN_BTN_CAMERA (1 << 8) #define ONSCREEN_BTN_DELETE (1 << 9) #define ONSCREEN_BTN_PICK (1 << 10) #define ONSCREEN_BTN_PLACE (1 << 11) #define ONSCREEN_BTN_SWITCH (1 << 12) #define ONSCREEN_MAX_BTNS 13 static int GetOnscreenButtons(void) { #define DEFAULT_SP_ONSCREEN (ONSCREEN_BTN_FLY | ONSCREEN_BTN_SPEED) #define DEFAULT_MP_ONSCREEN (ONSCREEN_BTN_FLY | ONSCREEN_BTN_SPEED | ONSCREEN_BTN_CHAT) return Options_GetInt(OPT_TOUCH_BUTTONS, 0, Int32_MaxValue, Server.IsSinglePlayer ? DEFAULT_SP_ONSCREEN : DEFAULT_MP_ONSCREEN); } static int GetOnscreenHAligns(void) { return Options_GetInt(OPT_TOUCH_HALIGN, 0, Int32_MaxValue, 0); } /*########################################################################################################################* *---------------------------------------------------TouchControlsScreen---------------------------------------------------* *#########################################################################################################################*/ #define ONSCREEN_PAGE_BTNS 4 #define ONSCREEN_NUM_PAGES 4 static struct TouchOnscreenScreen { Screen_Body struct ButtonWidget back, left, right; struct ButtonWidget btns[ONSCREEN_PAGE_BTNS]; struct FontDesc font; int page; } TouchOnscreenScreen; static struct Widget* touchOnscreen_widgets[3 + ONSCREEN_PAGE_BTNS]; static const char* const touchOnscreen[ONSCREEN_PAGE_BTNS * ONSCREEN_NUM_PAGES] = { "Chat", "Tablist", "Spawn", "Set spawn", "Fly", "Noclip", "Speed", "Half speed", "Third person", "Delete", "Pick", "Place", "Switch hotbar", "---", "---", "---", }; static void TouchOnscreen_UpdateButton(struct TouchOnscreenScreen* s, struct ButtonWidget* btn) { PackedCol grey = PackedCol_Make(0x7F, 0x7F, 0x7F, 0xFF); int buttons = GetOnscreenButtons(); int haligns = GetOnscreenHAligns(); const char* label; char buffer[64]; cc_string str; int bit; bit = 1 << btn->meta.val; btn->color = (buttons & bit) ? PACKEDCOL_WHITE : grey; String_InitArray(str, buffer); label = touchOnscreen[btn->meta.val]; if ((buttons & bit) && (haligns & bit)) { String_Format1(&str, "%c: Left aligned", label); } else if (buttons & bit) { String_Format1(&str, "%c: Right aligned", label); } else { String_AppendConst(&str, label); } ButtonWidget_Set(btn, &str, &s->font); } static void TouchOnscreen_UpdateAll(struct TouchOnscreenScreen* s) { int i; for (i = 0; i < ONSCREEN_PAGE_BTNS; i++) { TouchOnscreen_UpdateButton(s, &s->btns[i]); } } static void TouchOnscreen_Any(void* screen, void* w) { struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; struct ButtonWidget* btn = (struct ButtonWidget*)w; int buttons = GetOnscreenButtons(); int haligns = GetOnscreenHAligns(); int bit = 1 << btn->meta.val; if ((buttons & bit) & (haligns & bit)) { buttons &= ~bit; haligns &= ~bit; } else if (buttons & bit) { haligns |= bit; } else { buttons |= bit; } Options_SetInt(OPT_TOUCH_BUTTONS, buttons); Options_SetInt(OPT_TOUCH_HALIGN, haligns); TouchOnscreen_UpdateButton(s, btn); TouchScreen_Refresh(); } static void TouchOnscreen_More(void* s, void* w) { TouchCtrlsScreen_Show(); } static void TouchOnscreen_Left(void* screen, void* b); static void TouchOnscreen_Right(void* screen, void* b); static void TouchOnscreen_RemakeWidgets(struct TouchOnscreenScreen* s) { int i; int offset = s->page * ONSCREEN_PAGE_BTNS; s->widgets = touchOnscreen_widgets; s->numWidgets = 0; s->maxWidgets = Array_Elems(touchOnscreen_widgets); for (i = 0; i < ONSCREEN_PAGE_BTNS; i++) { ButtonWidget_Add(s, &s->btns[i], 300, TouchOnscreen_Any); s->btns[i].meta.val = i + offset; } ButtonWidget_Add(s, &s->back, 400, TouchOnscreen_More); ButtonWidget_Add(s, &s->left, 40, TouchOnscreen_Left); ButtonWidget_Add(s, &s->right, 40, TouchOnscreen_Right); Widget_SetDisabled(&s->left, s->page == 0); Widget_SetDisabled(&s->right, s->page == ONSCREEN_NUM_PAGES - 1); } static void TouchOnscreen_Left(void* screen, void* b) { struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; s->page--; TouchOnscreen_RemakeWidgets(s); Gui_Refresh((struct Screen*)s); TouchOnscreen_UpdateAll(s); } static void TouchOnscreen_Right(void* screen, void* b) { struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; s->page++; TouchOnscreen_RemakeWidgets(s); Gui_Refresh((struct Screen*)s); TouchOnscreen_UpdateAll(s); } static void TouchOnscreenScreen_ContextRecreated(void* screen) { struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; Screen_UpdateVb(screen); TouchOnscreen_UpdateAll(s); ButtonWidget_SetConst(&s->back, "Done", &s->font); ButtonWidget_SetConst(&s->left, "<", &s->font); ButtonWidget_SetConst(&s->right, ">", &s->font); } static void TouchOnscreenScreen_Layout(void* screen) { struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; int i; for (i = 0; i < ONSCREEN_PAGE_BTNS; i++) { Widget_SetLocation(&s->btns[i], ANCHOR_CENTRE, ANCHOR_CENTRE, 0, -75 + i * 50); } Menu_LayoutBack(&s->back); Widget_SetLocation(&s->left, ANCHOR_CENTRE, ANCHOR_CENTRE, -220, 0); Widget_SetLocation(&s->right, ANCHOR_CENTRE, ANCHOR_CENTRE, 220, 0); } static void TouchOnscreenScreen_Init(void* screen) { struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; s->page = 0; Gui_MakeTitleFont(&s->font); TouchOnscreen_RemakeWidgets(s); TouchOnscreen_UpdateAll(screen); s->maxVertices = Screen_CalcDefaultMaxVertices(s); } static void TouchOnscreenScreen_Free(void* screen) { struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; Font_Free(&s->font); } static const struct ScreenVTABLE TouchOnscreenScreen_VTABLE = { TouchOnscreenScreen_Init, Screen_NullUpdate, TouchOnscreenScreen_Free, MenuScreen_Render2, Screen_BuildMesh, Menu_InputDown, Screen_InputUp, Screen_TKeyPress, Screen_TText, Menu_PointerDown, Screen_PointerUp, Menu_PointerMove, Screen_TMouseScroll, TouchOnscreenScreen_Layout, Screen_ContextLost, TouchOnscreenScreen_ContextRecreated }; void TouchOnscreenScreen_Show(void) { struct TouchOnscreenScreen* s = &TouchOnscreenScreen; s->grabsInput = true; s->closable = true; s->VTABLE = &TouchOnscreenScreen_VTABLE; Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCHMORE); } /*########################################################################################################################* *---------------------------------------------------TouchControlsScreen---------------------------------------------------* *#########################################################################################################################*/ #define TOUCHCTRLS_BTNS 5 static struct TouchCtrlsScreen { Screen_Body struct ButtonWidget back; struct ButtonWidget btns[TOUCHCTRLS_BTNS]; struct FontDesc font; } TouchCtrlsScreen; static struct Widget* touchCtrls_widgets[TOUCHCTRLS_BTNS + 1]; static const char* GetTapDesc(int mode) { if (mode == INPUT_MODE_PLACE) return "Tap: Place"; if (mode == INPUT_MODE_DELETE) return "Tap: Delete"; return "Tap: None"; } static void TouchCtrls_UpdateTapText(void* screen) { struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; ButtonWidget_SetConst(&s->btns[0], GetTapDesc(Input_TapMode), &s->font); s->dirty = true; } static const char* GetHoldDesc(int mode) { if (mode == INPUT_MODE_PLACE) return "Hold: Place"; if (mode == INPUT_MODE_DELETE) return "Hold: Delete"; return "Hold: None"; } static void TouchCtrls_UpdateHoldText(void* screen) { struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; ButtonWidget_SetConst(&s->btns[1], GetHoldDesc(Input_HoldMode), &s->font); s->dirty = true; } static void TouchCtrls_UpdateSensitivity(void* screen) { cc_string value; char valueBuffer[STRING_SIZE]; struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; String_InitArray(value, valueBuffer); String_Format1(&value, "Sensitivity: %i", &Camera.Sensitivity); ButtonWidget_Set(&s->btns[2], &value, &s->font); s->dirty = true; } static void TouchCtrls_UpdateScale(void* screen) { cc_string value; char valueBuffer[STRING_SIZE]; struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; String_InitArray(value, valueBuffer); String_AppendConst(&value, "Scale: "); String_AppendFloat(&value, Gui.RawTouchScale, 1); ButtonWidget_Set(&s->btns[3], &value, &s->font); s->dirty = true; } static void TouchCtrls_More(void* s, void* w) { TouchMoreScreen_Show(); } static void TouchCtrls_Onscreen(void* s, void* w) { TouchOnscreenScreen_Show(); } static void TouchCtrls_Tap(void* s, void* w) { Input_TapMode = (Input_TapMode + 1) % INPUT_MODE_COUNT; TouchCtrls_UpdateTapText(s); } static void TouchCtrls_Hold(void* s, void* w) { Input_HoldMode = (Input_HoldMode + 1) % INPUT_MODE_COUNT; TouchCtrls_UpdateHoldText(s); } static void TouchCtrls_SensitivityDone(const cc_string* value, cc_bool valid) { int sensitivity; if (!valid) return; Convert_ParseInt(value, &sensitivity); Camera.Sensitivity = sensitivity; Options_Set(OPT_SENSITIVITY, value); TouchCtrls_UpdateSensitivity(&TouchCtrlsScreen); } static void TouchCtrls_Sensitivity(void* screen, void* w) { struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; static struct MenuInputDesc desc; cc_string value; char valueBuffer[STRING_SIZE]; String_InitArray(value, valueBuffer); MenuInput_Int(desc, 1, 200, 30); String_AppendInt(&value, Camera.Sensitivity); MenuInputOverlay_Show(&desc, &value, TouchCtrls_SensitivityDone, true); /* Fix Sensitivity button getting stuck as 'active' */ /* (input overlay swallows subsequent pointer events) */ s->btns[2].active = 0; } static void TouchCtrls_ScaleDone(const cc_string* value, cc_bool valid) { if (!valid) return; Convert_ParseFloat(value, &Gui.RawTouchScale); Options_Set(OPT_TOUCH_SCALE, value); TouchCtrls_UpdateScale(&TouchCtrlsScreen); Gui_LayoutAll(); } static void TouchCtrls_Scale(void* screen, void* w) { struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; static struct MenuInputDesc desc; cc_string value; char valueBuffer[STRING_SIZE]; String_InitArray(value, valueBuffer); MenuInput_Float(desc, 0.25f, 5.0f, 1.0f); String_AppendFloat(&value, Gui.RawTouchScale, 1); MenuInputOverlay_Show(&desc, &value, TouchCtrls_ScaleDone, true); s->btns[3].active = 0; } static const struct SimpleButtonDesc touchCtrls_btns[5] = { { -102, -50, "", TouchCtrls_Tap }, { 102, -50, "", TouchCtrls_Hold }, { -102, 0, "", TouchCtrls_Sensitivity }, { 102, 0, "", TouchCtrls_Scale }, { 0, 50, "On-screen controls", TouchCtrls_Onscreen } }; static void TouchCtrlsScreen_ContextLost(void* screen) { struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; Font_Free(&s->font); Screen_ContextLost(screen); } static void TouchCtrlsScreen_ContextRecreated(void* screen) { struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; Gui_MakeTitleFont(&s->font); Screen_UpdateVb(screen); Menu_SetButtons(s->btns, &s->font, touchCtrls_btns, TOUCHCTRLS_BTNS); ButtonWidget_SetConst(&s->back, "Done", &s->font); TouchCtrls_UpdateTapText(s); TouchCtrls_UpdateHoldText(s); TouchCtrls_UpdateSensitivity(s); TouchCtrls_UpdateScale(s); } static void TouchCtrlsScreen_Layout(void* screen) { struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; Menu_LayoutButtons(s->btns, touchCtrls_btns, TOUCHCTRLS_BTNS); Menu_LayoutBack(&s->back); } static void TouchCtrlsScreen_Init(void* screen) { struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; s->widgets = touchCtrls_widgets; s->numWidgets = 0; s->maxWidgets = Array_Elems(touchCtrls_widgets); Menu_AddButtons(s, s->btns, 195, touchCtrls_btns, 4); Menu_AddButtons(s, s->btns + 4, 400, touchCtrls_btns + 4, 1); ButtonWidget_Add(s, &s->back, 400, TouchCtrls_More); s->maxVertices = Screen_CalcDefaultMaxVertices(s); } static const struct ScreenVTABLE TouchCtrlsScreen_VTABLE = { TouchCtrlsScreen_Init, Screen_NullUpdate, Screen_NullFunc, MenuScreen_Render2, Screen_BuildMesh, Menu_InputDown, Screen_InputUp, Screen_TKeyPress, Screen_TText, Menu_PointerDown, Screen_PointerUp, Menu_PointerMove, Screen_TMouseScroll, TouchCtrlsScreen_Layout, TouchCtrlsScreen_ContextLost, TouchCtrlsScreen_ContextRecreated }; void TouchCtrlsScreen_Show(void) { struct TouchCtrlsScreen* s = &TouchCtrlsScreen; s->grabsInput = true; s->closable = true; s->VTABLE = &TouchCtrlsScreen_VTABLE; Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCHMORE); } /*########################################################################################################################* *-----------------------------------------------------TouchMoreScreen-----------------------------------------------------* *#########################################################################################################################*/ #define TOUCHMORE_BTNS 6 static struct TouchMoreScreen { Screen_Body struct ButtonWidget back; struct ButtonWidget btns[TOUCHMORE_BTNS]; } TouchMoreScreen; static struct Widget* touchMore_widgets[TOUCHMORE_BTNS + 1]; static void TouchMore_Take(void* s, void* w) { Gui_Remove((struct Screen*)&TouchMoreScreen); Game_ScreenshotRequested = true; } static void TouchMore_Screen(void* s, void* w) { Gui_Remove((struct Screen*)&TouchMoreScreen); Game_ToggleFullscreen(); } static void TouchMore_Ctrls(void* s, void* w) { TouchCtrlsScreen_Show(); } static void TouchMore_Menu(void* s, void* w) { Gui_Remove((struct Screen*)&TouchMoreScreen); Gui_ShowPauseMenu(); } static void TouchMore_Game(void* s, void* w) { Gui_Remove((struct Screen*)&TouchMoreScreen); } static void TouchMore_Chat(void* s, void* w) { Gui_Remove((struct Screen*)&TouchMoreScreen); ChatScreen_OpenInput(&String_Empty); } static void TouchMore_Fog(void* s, void* w) { Game_CycleViewDistance(); } static const struct SimpleButtonDesc touchMore_btns[TOUCHMORE_BTNS] = { { -102, -50, "Screenshot", TouchMore_Take }, { -102, 0, "Fullscreen", TouchMore_Screen }, { 102, -50, "Chat", TouchMore_Chat }, { 102, 0, "Fog", TouchMore_Fog }, { 0, 50, "Controls", TouchMore_Ctrls }, { 0, 100, "Main menu", TouchMore_Menu } }; static void TouchMoreScreen_ContextRecreated(void* screen) { struct TouchMoreScreen* s = (struct TouchMoreScreen*)screen; struct FontDesc titleFont; Gui_MakeTitleFont(&titleFont); Screen_UpdateVb(screen); Menu_SetButtons(s->btns, &titleFont, touchMore_btns, TOUCHMORE_BTNS); ButtonWidget_SetConst(&s->back, "Back to game", &titleFont); Font_Free(&titleFont); } static void TouchMoreScreen_Layout(void* screen) { struct TouchMoreScreen* s = (struct TouchMoreScreen*)screen; Menu_LayoutButtons(s->btns, touchMore_btns, TOUCHMORE_BTNS); Menu_LayoutBack(&s->back); } static void TouchMoreScreen_Init(void* screen) { struct TouchMoreScreen* s = (struct TouchMoreScreen*)screen; s->widgets = touchMore_widgets; s->numWidgets = 0; s->maxWidgets = Array_Elems(touchMore_widgets); Menu_AddButtons(s, s->btns, 195, touchMore_btns, 4); Menu_AddButtons(s, s->btns + 4, 400, touchMore_btns + 4, 2); ButtonWidget_Add(s, &s->back, 400, TouchMore_Game); s->maxVertices = Screen_CalcDefaultMaxVertices(s); } static const struct ScreenVTABLE TouchMoreScreen_VTABLE = { TouchMoreScreen_Init, Screen_NullUpdate, Screen_NullFunc, MenuScreen_Render2, Screen_BuildMesh, Menu_InputDown, Screen_InputUp, Screen_TKeyPress, Screen_TText, Menu_PointerDown, Screen_PointerUp, Menu_PointerMove, Screen_TMouseScroll, TouchMoreScreen_Layout, Screen_ContextLost, TouchMoreScreen_ContextRecreated }; void TouchMoreScreen_Show(void) { struct TouchMoreScreen* s = &TouchMoreScreen; s->grabsInput = true; s->closable = true; s->VTABLE = &TouchMoreScreen_VTABLE; Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCHMORE); } /*########################################################################################################################* *--------------------------------------------------------TouchScreen------------------------------------------------------* *#########################################################################################################################*/ #define TOUCH_EXTRA_BTNS 2 #define TOUCH_MAX_BTNS (ONSCREEN_MAX_BTNS + TOUCH_EXTRA_BTNS + 1) struct TouchButtonDesc { const char* text; cc_uint8 bind, x, y; Widget_LeftClick OnClick; cc_bool* enabled; }; static struct TouchScreen { Screen_Body const struct TouchButtonDesc* descs; int numOnscreen, numBtns; struct FontDesc font; struct ThumbstickWidget thumbstick; struct ButtonWidget onscreen[ONSCREEN_MAX_BTNS]; struct ButtonWidget btns[TOUCH_EXTRA_BTNS], more; } TouchScreen; static struct Widget* touch_widgets[ONSCREEN_MAX_BTNS + TOUCH_EXTRA_BTNS + 2] = { NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, NULL, NULL,NULL, (struct Widget*)&TouchScreen.thumbstick, (struct Widget*)&TouchScreen.more }; #define TOUCH_MAX_VERTICES (THUMBSTICKWIDGET_MAX + TOUCH_MAX_BTNS * BUTTONWIDGET_MAX) static void TouchScreen_ChatClick(void* s, void* w) { ChatScreen_OpenInput(&String_Empty); } static void TouchScreen_RespawnClick(void* s, void* w) { Bind_OnTriggered[BIND_RESPAWN](0); } static void TouchScreen_SetSpawnClick(void* s, void* w) { Bind_OnTriggered[BIND_SET_SPAWN](0); } static void TouchScreen_FlyClick(void* s, void* w) { Bind_OnTriggered[BIND_FLY](0); } static void TouchScreen_NoclipClick(void* s, void* w) { Bind_OnTriggered[BIND_NOCLIP](0); } static void TouchScreen_CameraClick(void* s, void* w) { Bind_OnTriggered[BIND_THIRD_PERSON](0); } static void TouchScreen_MoreClick(void* s, void* w) { TouchMoreScreen_Show(); } static void TouchScreen_SwitchClick(void* s, void* w) { Inventory_SwitchHotbar(); } static void TouchScreen_DeleteClick(void* s, void* w) { InputHandler_DeleteBlock(); } /* TODO: also Send CPEClick packet */ static void TouchScreen_PlaceClick(void* s, void* w) { InputHandler_PlaceBlock(); } static void TouchScreen_PickClick(void* s, void* w) { InputHandler_PickBlock(); } static void TouchScreen_TabClick(void* s, void* w) { struct Screen* tablist = Gui_GetScreen(GUI_PRIORITY_TABLIST); if (tablist) { Gui_Remove(tablist); } else { TabListOverlay_Show(true); } } static void TouchScreen_SpeedClick(void* s, void* w) { struct HacksComp* hacks = &Entities.CurPlayer->Hacks; if (hacks->Enabled) hacks->Speeding = !hacks->Speeding; } static void TouchScreen_HalfClick(void* s, void* w) { struct HacksComp* hacks = &Entities.CurPlayer->Hacks; if (hacks->Enabled) hacks->HalfSpeeding = !hacks->HalfSpeeding; } static void TouchScreen_BindClick(void* screen, void* widget) { struct TouchScreen* s = (struct TouchScreen*)screen; struct ButtonWidget* btn = (struct ButtonWidget*)widget; int i = btn->meta.val; Input_Set(KeyBind_Mappings[s->descs[i].bind].button1, true); } static const struct TouchButtonDesc onscreenDescs[ONSCREEN_MAX_BTNS] = { { "Chat", 0,0,0, TouchScreen_ChatClick }, { "Tablist", 0,0,0, TouchScreen_TabClick }, { "Respawn", 0,0,0, TouchScreen_RespawnClick, &LocalPlayer_Instances[0].Hacks.CanRespawn }, { "Set spawn", 0,0,0, TouchScreen_SetSpawnClick, &LocalPlayer_Instances[0].Hacks.CanRespawn }, { "Fly", 0,0,0, TouchScreen_FlyClick, &LocalPlayer_Instances[0].Hacks.CanFly }, { "Noclip", 0,0,0, TouchScreen_NoclipClick, &LocalPlayer_Instances[0].Hacks.CanNoclip }, { "Speed", 0,0,0, TouchScreen_SpeedClick, &LocalPlayer_Instances[0].Hacks.CanSpeed }, { "\xabSpeed", 0,0,0, TouchScreen_HalfClick, &LocalPlayer_Instances[0].Hacks.CanSpeed }, { "Camera", 0,0,0, TouchScreen_CameraClick, &LocalPlayer_Instances[0].Hacks.CanUseThirdPerson }, { "Delete", 0,0,0, TouchScreen_DeleteClick }, { "Pick", 0,0,0, TouchScreen_PickClick }, { "Place", 0,0,0, TouchScreen_PlaceClick }, { "Hotbar", 0,0,0, TouchScreen_SwitchClick } }; static const struct TouchButtonDesc normDescs[1] = { { "\x1E", BIND_JUMP, 50, 10, TouchScreen_BindClick } }; static const struct TouchButtonDesc hackDescs[2] = { { "\x1E", BIND_FLY_UP, 50, 70, TouchScreen_BindClick }, { "\x1F", BIND_FLY_DOWN, 50, 10, TouchScreen_BindClick } }; #define TOUCHSCREEN_BTN_COLOR PackedCol_Make(255, 255, 255, 200) static void TouchScreen_InitButtons(struct TouchScreen* s) { struct HacksComp* hacks = &Entities.CurPlayer->Hacks; const struct TouchButtonDesc* desc; int buttons = GetOnscreenButtons(); int i, j; for (i = 0; i < ONSCREEN_MAX_BTNS + TOUCH_EXTRA_BTNS; i++) s->widgets[i] = NULL; for (i = 0, j = 0; i < ONSCREEN_MAX_BTNS; i++) { if (!(buttons & (1 << i))) continue; desc = &onscreenDescs[i]; ButtonWidget_Init(&s->onscreen[j], 100, desc->OnClick); if (desc->enabled) Widget_SetDisabled(&s->onscreen[j], !(*desc->enabled)); s->onscreen[j].meta.val = i; s->onscreen[j].color = TOUCHSCREEN_BTN_COLOR; s->widgets[j] = (struct Widget*)&s->onscreen[j]; j++; } s->numOnscreen = j; if (hacks->Flying || hacks->Noclip) { s->descs = hackDescs; s->numBtns = Array_Elems(hackDescs); } else { s->descs = normDescs; s->numBtns = Array_Elems(normDescs); } for (i = 0; i < s->numBtns; i++) { s->widgets[i + ONSCREEN_MAX_BTNS] = (struct Widget*)&s->btns[i]; ButtonWidget_Init(&s->btns[i], 60, s->descs[i].OnClick); s->btns[i].color = TOUCHSCREEN_BTN_COLOR; s->btns[i].meta.val = i; } } void TouchScreen_Refresh(void) { struct TouchScreen* s = &TouchScreen; /* InitButtons changes number of widgets, hence */ /* must destroy graphics resources BEFORE that */ Screen_ContextLost(s); TouchScreen_InitButtons(s); Gui_Refresh((struct Screen*)s); } static void TouchScreen_HacksChanged(void* s) { TouchScreen_Refresh(); } static void TouchScreen_ContextLost(void* screen) { struct TouchScreen* s = (struct TouchScreen*)screen; Font_Free(&s->font); Screen_ContextLost(screen); } static void TouchScreen_ContextRecreated(void* screen) { struct TouchScreen* s = (struct TouchScreen*)screen; const struct TouchButtonDesc* desc; int i; Screen_UpdateVb(screen); Gui_MakeTitleFont(&s->font); for (i = 0; i < s->numOnscreen; i++) { desc = &onscreenDescs[s->onscreen[i].meta.val]; ButtonWidget_SetConst(&s->onscreen[i], desc->text, &s->font); } for (i = 0; i < s->numBtns; i++) { desc = &s->descs[i]; ButtonWidget_SetConst(&s->btns[i], desc->text, &s->font); } ButtonWidget_SetConst(&s->more, "...", &s->font); } static void TouchScreen_Render(void* screen, float delta) { if (Gui.InputGrab) return; Screen_Render2Widgets(screen, delta); } static int TouchScreen_PointerDown(void* screen, int id, int x, int y) { struct TouchScreen* s = (struct TouchScreen*)screen; struct Widget* w; int i; //Chat_Add1("POINTER DOWN: %i", &id); if (Gui.InputGrab) return false; i = Screen_DoPointerDown(screen, id, x, y); if (i < ONSCREEN_MAX_BTNS) return i >= 0; /* Clicking on other buttons then */ w = s->widgets[i]; w->active |= id; /* Clicking on jump or fly buttons should still move camera */ for (i = 0; i < s->numBtns; i++) { if (w == (struct Widget*)&s->btns[i]) return TOUCH_TYPE_GUI | TOUCH_TYPE_CAMERA; } return TOUCH_TYPE_GUI; } static void TouchScreen_PointerUp(void* screen, int id, int x, int y) { struct TouchScreen* s = (struct TouchScreen*)screen; int i; //Chat_Add1("POINTER UP: %i", &id); s->thumbstick.active &= ~id; s->more.active &= ~id; for (i = 0; i < s->numBtns; i++) { if (!(s->btns[i].active & id)) continue; if (s->descs[i].bind < BIND_COUNT) { Input_Set(KeyBind_Mappings[s->descs[i].bind].button1, false); } s->btns[i].active &= ~id; return; } } static void TouchScreen_LayoutOnscreen(struct TouchScreen* s, cc_uint8 alignment) { int haligns = GetOnscreenHAligns(); cc_uint8 halign; int i, index, x, y; for (i = 0, x = 10, y = 10; i < s->numOnscreen; i++) { index = s->onscreen[i].meta.val; halign = (haligns & (1 << index)) ? ANCHOR_MIN : ANCHOR_MAX; if (halign != alignment) continue; Widget_SetLocation(&s->onscreen[i], halign, ANCHOR_MIN, x, y); if (s->onscreen[i].y + s->onscreen[i].height <= s->btns[0].y){ y += 40; continue; } // overflowed onto jump/fly buttons, move to next column y = 10; x += 110; Widget_SetLocation(&s->onscreen[i], halign, ANCHOR_MIN, x, y); } } static void TouchScreen_Layout(void* screen) { struct TouchScreen* s = (struct TouchScreen*)screen; const struct TouchButtonDesc* desc; float scale = Gui.RawTouchScale; int i, height; /* Need to align these relative to the hotbar */ height = HUDScreen_LayoutHotbar(); for (i = 0; i < s->numBtns; i++) { desc = &s->descs[i]; Widget_SetLocation(&s->btns[i], ANCHOR_MAX, ANCHOR_MAX, desc->x, desc->y); s->btns[i].yOffset += height; /* TODO: Maybe move scaling to be part of button instead */ s->btns[i].minWidth = Display_ScaleX(60 * scale); s->btns[i].minHeight = Display_ScaleY(60 * scale); Widget_Layout(&s->btns[i]); } TouchScreen_LayoutOnscreen(s, ANCHOR_MIN); TouchScreen_LayoutOnscreen(s, ANCHOR_MAX); Widget_SetLocation(&s->more, ANCHOR_CENTRE, ANCHOR_MIN, 0, 10); Widget_SetLocation(&s->thumbstick, ANCHOR_MIN, ANCHOR_MAX, 30, 5); s->thumbstick.yOffset += height; s->thumbstick.scale = scale; Widget_Layout(&s->thumbstick); } static void TouchScreen_GetMovement(struct LocalPlayer* p, float* xMoving, float* zMoving) { ThumbstickWidget_GetMovement(&TouchScreen.thumbstick, xMoving, zMoving); } static struct LocalPlayerInput touchInput = { TouchScreen_GetMovement }; static void TouchScreen_Init(void* screen) { struct TouchScreen* s = (struct TouchScreen*)screen; s->widgets = touch_widgets; s->numWidgets = Array_Elems(touch_widgets); s->maxVertices = TOUCH_MAX_VERTICES; Event_Register_(&UserEvents.HacksStateChanged, screen, TouchScreen_HacksChanged); Event_Register_(&UserEvents.HackPermsChanged, screen, TouchScreen_HacksChanged); TouchScreen_InitButtons(s); ButtonWidget_Init(&s->more, 40, TouchScreen_MoreClick); s->more.color = TOUCHSCREEN_BTN_COLOR; ThumbstickWidget_Init(&s->thumbstick); LocalPlayerInput_Add(&touchInput); } static void TouchScreen_Free(void* s) { Event_Unregister_(&UserEvents.HacksStateChanged, s, TouchScreen_HacksChanged); Event_Unregister_(&UserEvents.HackPermsChanged, s, TouchScreen_HacksChanged); LocalPlayerInput_Remove(&touchInput); } static const struct ScreenVTABLE TouchScreen_VTABLE = { TouchScreen_Init, Screen_NullUpdate, TouchScreen_Free, TouchScreen_Render, Screen_BuildMesh, Screen_FInput, Screen_InputUp, Screen_FKeyPress, Screen_FText, TouchScreen_PointerDown, TouchScreen_PointerUp, Screen_FPointer, Screen_FMouseScroll, TouchScreen_Layout, TouchScreen_ContextLost, TouchScreen_ContextRecreated }; void TouchScreen_Show(void) { struct TouchScreen* s = &TouchScreen; s->VTABLE = &TouchScreen_VTABLE; if (!Gui.TouchUI) return; Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCH); } #endif