From f96d5b4e81e5e9a0845e47cdb09e86ee87e2e1e2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 17 May 2022 12:46:52 -0500 Subject: [PATCH] GUI: add touch input primitives --- src/gui/debugWindow.cpp | 21 +++++++ src/gui/gui.cpp | 108 ++++++++++++++++++++++++++++++++++ src/gui/gui.h | 35 ++++++++++- src/gui/piano.cpp | 127 ++++++++++++++++++++++++++++++++-------- 4 files changed, 262 insertions(+), 29 deletions(-) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 71856c8f..9cb64245 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -240,6 +240,27 @@ void FurnaceGUI::drawDebug() { } ImGui::TreePop(); } + if (ImGui::TreeNode("Touch Point Information")) { + ImGui::Text("active:"); + ImGui::Indent(); + for (TouchPoint& i: activePoints) { + ImGui::Text("- %d: %.1f, %.1f (%.2f)",i.id,i.x,i.y,i.x); + } + ImGui::Unindent(); + ImGui::Text("pressed:"); + ImGui::Indent(); + for (TouchPoint& i: pressedPoints) { + ImGui::Text("- %d: %.1f, %.1f (%.2f)",i.id,i.x,i.y,i.x); + } + ImGui::Unindent(); + ImGui::Text("released:"); + ImGui::Indent(); + for (TouchPoint& i: releasedPoints) { + ImGui::Text("- %d: %.1f, %.1f (%.2f)",i.id,i.x,i.y,i.x); + } + ImGui::Unindent(); + ImGui::TreePop(); + } if (ImGui::TreeNode("Playground")) { if (pgSys<0 || pgSys>=e->song.systemLen) pgSys=0; if (ImGui::BeginCombo("System",fmt::sprintf("%d. %s",pgSys+1,e->getSystemName(e->song.system[pgSys])).c_str())) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c33ced04..582ea3f3 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2210,6 +2210,11 @@ int _processEvent(void* instance, SDL_Event* event) { } int FurnaceGUI::processEvent(SDL_Event* ev) { +#ifdef IS_MOBILE + if (ev->type==SDL_APP_WILLENTERBACKGROUND) { + // TODO: save "last state" and potentially suspend engine + } +#endif if (ev->type==SDL_KEYDOWN) { if (!ev->key.repeat && latchTarget==0 && !wantCaptureKeyboard && (ev->key.keysym.mod&(~(KMOD_NUM|KMOD_CAPS|KMOD_SCROLL)))==0) { if (settings.notePreviewBehavior==0) return 1; @@ -2285,6 +2290,95 @@ int FurnaceGUI::processEvent(SDL_Event* ev) { return 1; } +#define FIND_POINT(p,pid) \ + for (TouchPoint& i: activePoints) { \ + if (i.id==pid) { \ + p=&i; \ + } \ + } + +void FurnaceGUI::processPoint(SDL_Event& ev) { + switch (ev.type) { + case SDL_MOUSEMOTION: { + TouchPoint* point=NULL; + FIND_POINT(point,-1); + if (point!=NULL) { + point->x=ev.motion.x; + point->y=ev.motion.y; +#ifdef __APPLE__ + point->x*=dpiScale; + point->y*=dpiScale; +#endif + } + break; + } + case SDL_MOUSEBUTTONDOWN: { + for (size_t i=0; ix*=dpiScale; + newPoint->y*=dpiScale; +#endif + activePoints.push_back(newPoint); + pressedPoints.push_back(newPoint); + break; + } + case SDL_MOUSEBUTTONUP: { + for (size_t i=0; ix=ev.tfinger.x*scrW*dpiScale; + point->y=ev.tfinger.y*scrH*dpiScale; + point->z=ev.tfinger.pressure; + } + break; + } + case SDL_FINGERDOWN: { + for (size_t i=0; i definition; @@ -1084,6 +1105,12 @@ class FurnaceGUI { // SDL_Keycode,int std::map valueKeys; + // currently active touch points + std::vector activePoints; + // one frame points + std::vector pressedPoints; + std::vector releasedPoints; + int arpMacroScroll; int pitchMacroScroll; @@ -1186,10 +1213,11 @@ class FurnaceGUI { bool followLog; // piano - int pianoOctaves; - bool pianoOptions; + int pianoOctaves, pianoOctavesEdit; + bool pianoOptions, pianoSharePosition; float pianoKeyHit[180]; - int pianoOffset; + int pianoOffset, pianoOffsetEdit; + int pianoView; // TX81Z bool hasACED; @@ -1271,6 +1299,7 @@ class FurnaceGUI { void syncSettings(); void commitSettings(); void processDrags(int dragX, int dragY); + void processPoint(SDL_Event& ev); void startSelection(int xCoarse, int xFine, int y, bool fullRow=false); void updateSelection(int xCoarse, int xFine, int y, bool fullRow=false); diff --git a/src/gui/piano.cpp b/src/gui/piano.cpp index a4f0c64c..65c06f9d 100644 --- a/src/gui/piano.cpp +++ b/src/gui/piano.cpp @@ -21,6 +21,8 @@ #include "guiConst.h" #include "imgui.h" #include "imgui_internal.h" +#include +#include "IconsFontAwesome4.h" const float topKeyStarts[5]={ 0.9f/7.0f, 2.1f/7.0f, 3.9f/7.0f, 5.0f/7.0f, 6.1f/7.0f @@ -34,6 +36,10 @@ const int bottomKeyNotes[7]={ 0, 2, 4, 5, 7, 9, 11 }; +const bool isTopKey[12]={ + false, true, false, true, false, false, true, false, true, false, true, false +}; + // TODO: actually implement a piano! void FurnaceGUI::drawPiano() { if (nextWindow==GUI_WINDOW_PIANO) { @@ -44,6 +50,9 @@ void FurnaceGUI::drawPiano() { if (!pianoOpen) return; if (ImGui::Begin("Piano",&pianoOpen,(pianoOptions)?0:ImGuiWindowFlags_NoTitleBar)) { if (ImGui::BeginTable("PianoLayout",pianoOptions?2:1,ImGuiTableFlags_BordersInnerV)) { + int& off=(e->isPlaying() || pianoSharePosition)?pianoOffset:pianoOffsetEdit; + int& oct=(e->isPlaying() || pianoSharePosition)?pianoOctaves:pianoOctavesEdit; + bool view=(pianoView==2)?(!e->isPlaying()):pianoView; if (pianoOptions) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); } @@ -52,7 +61,42 @@ void FurnaceGUI::drawPiano() { ImGui::TableNextRow(); if (pianoOptions) { ImGui::TableNextColumn(); - ImGui::Button("Options"); + if (ImGui::Button(ICON_FA_ARROW_LEFT "##PianoLeft")) { + off--; + if (off<0) off=0; + } + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_ARROW_RIGHT "##PianoRight")) { + off++; + if ((off+oct)>14) off=15-oct; + } + ImGui::SameLine(); + ImGui::Button(ICON_FA_ELLIPSIS_V "##PianoOptions"); + if (ImGui::BeginPopupContextItem("PianoOptions",ImGuiPopupFlags_MouseButtonLeft)) { + ImGui::Text("Key layout:"); + if (ImGui::RadioButton("Automatic",pianoView==2)) { + pianoView=2; + } + if (ImGui::RadioButton("Standard",pianoView==0)) { + pianoView=0; + } + if (ImGui::RadioButton("Continuous",pianoView==1)) { + pianoView=1; + } + ImGui::Checkbox("Share play/edit offset/range",&pianoSharePosition); + ImGui::EndPopup(); + } + + if (ImGui::Button(ICON_FA_MINUS "##PianoOctaveDown")) { + oct--; + if (oct<1) oct=1; + } + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_PLUS "##PianoOctaveUp")) { + oct++; + if (oct>15) oct=15; + if ((off+oct)>14) off=15-oct; + } } ImGui::TableNextColumn(); @@ -70,36 +114,67 @@ void FurnaceGUI::drawPiano() { // render piano //ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("pianoDisplay"))) { - int bottomNotes=7*pianoOctaves; - for (int i=0; i=180) continue; - float pkh=pianoKeyHit[note]*0.5; - ImVec4 color=ImVec4(1.0f-pkh,1.0f-pkh,1.0f-pkh,1.0f); - ImVec2 p0=ImLerp(rect.Min,rect.Max,ImVec2((float)i/bottomNotes,0.0f)); - ImVec2 p1=ImLerp(rect.Min,rect.Max,ImVec2((float)(i+1)/bottomNotes,1.0f)); - p1.x-=dpiScale; - dl->AddRectFilled(p0,p1,ImGui::ColorConvertFloat4ToU32(color)); - } - - for (int i=0; i=180) continue; float pkh=pianoKeyHit[note]*0.5; - ImVec4 color=ImVec4(pkh,pkh,pkh,1.0f); - ImVec2 p0=ImLerp(op0,op1,ImVec2(topKeyStarts[j]-0.05f,0.0f)); - ImVec2 p1=ImLerp(op0,op1,ImVec2(topKeyStarts[j]+0.05f,0.64f)); - dl->AddRectFilled(p0,p1,0xff000000); - p0.x+=dpiScale; + ImVec4 color=isTopKey[i%12]?ImVec4(pkh,pkh,pkh,1.0f):ImVec4(1.0f-pkh,1.0f-pkh,1.0f-pkh,1.0f); + ImVec2 p0=ImLerp(rect.Min,rect.Max,ImVec2((float)i/notes,0.0f)); + ImVec2 p1=ImLerp(rect.Min,rect.Max,ImVec2((float)(i+1)/notes,1.0f)); p1.x-=dpiScale; - p1.y-=dpiScale; dl->AddRectFilled(p0,p1,ImGui::ColorConvertFloat4ToU32(color)); + if ((i%12)==0) { + String label=fmt::sprintf("%d",(note-60)/12); + ImVec2 pText=ImLerp(p0,p1,ImVec2(0.5f,1.0f)); + ImVec2 labelSize=ImGui::CalcTextSize(label.c_str()); + pText.x-=labelSize.x*0.5f; + pText.y-=labelSize.y+ImGui::GetStyle().ItemSpacing.y; + dl->AddText(pText,0xff404040,label.c_str()); + } + } + } else { + int bottomNotes=7*oct; + for (int i=0; i=180) continue; + float pkh=pianoKeyHit[note]*0.5; + ImVec4 color=ImVec4(1.0f-pkh,1.0f-pkh,1.0f-pkh,1.0f); + ImVec2 p0=ImLerp(rect.Min,rect.Max,ImVec2((float)i/bottomNotes,0.0f)); + ImVec2 p1=ImLerp(rect.Min,rect.Max,ImVec2((float)(i+1)/bottomNotes,1.0f)); + p1.x-=dpiScale; + dl->AddRectFilled(p0,p1,ImGui::ColorConvertFloat4ToU32(color)); + if ((i%7)==0) { + String label=fmt::sprintf("%d",(note-60)/12); + ImVec2 pText=ImLerp(p0,p1,ImVec2(0.5f,1.0f)); + ImVec2 labelSize=ImGui::CalcTextSize(label.c_str()); + pText.x-=labelSize.x*0.5f; + pText.y-=labelSize.y+ImGui::GetStyle().ItemSpacing.y; + dl->AddText(pText,0xff404040,label.c_str()); + } + } + + for (int i=0; i=180) continue; + float pkh=pianoKeyHit[note]*0.5; + ImVec4 color=ImVec4(pkh,pkh,pkh,1.0f); + ImVec2 p0=ImLerp(op0,op1,ImVec2(topKeyStarts[j]-0.05f,0.0f)); + ImVec2 p1=ImLerp(op0,op1,ImVec2(topKeyStarts[j]+0.05f,0.64f)); + dl->AddRectFilled(p0,p1,0xff000000); + p0.x+=dpiScale; + p1.x-=dpiScale; + p1.y-=dpiScale; + dl->AddRectFilled(p0,p1,ImGui::ColorConvertFloat4ToU32(color)); + } } }