diff --git a/PanoPainter/GameViewController.m b/PanoPainter/GameViewController.m index a8fdd35..7690472 100644 --- a/PanoPainter/GameViewController.m +++ b/PanoPainter/GameViewController.m @@ -344,13 +344,19 @@ std::recursive_mutex lock_mutex; float get_force(UITouch* t) { //glm::pow(t.force / t.maximumPossibleForce, 0.5); - return glm::clamp(t.force / 2.0, 0.0, 1.0); + return glm::clamp(t.force / 1.0, 0.0, 1.0); } std::set ignored_touch; +std::map touch_start; +int max_touch_count = 0; +bool is_tap = true; - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + NSUInteger n = [[event allTouches] count]; UITouch *touch = [[event allTouches] anyObject]; + + max_touch_count = n; CGPoint touchLocation = [touch locationInView:self.view]; float scale = self.view.contentScaleFactor; @@ -365,7 +371,15 @@ std::set ignored_touch; // apple pencil if (touch.type == UITouchType::UITouchTypeStylus) + { pen_down = true; + is_tap = false; + } + else + { + is_tap = true; + touch_start.clear(); + } App::I->ui_task_async([touchLocation, scale, f=force, source] { App::I->mouse_down(0, touchLocation.x * scale, touchLocation.y * scale, f, source, 0); @@ -375,9 +389,11 @@ std::set ignored_touch; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + is_tap = false; NSUInteger n = [[event allTouches] count]; float scale = self.view.contentScaleFactor; - + max_touch_count = std::max(max_touch_count, n); + std::vector valid_touches; for (int i = 0; i < n; i++) { @@ -386,6 +402,11 @@ std::set ignored_touch; if (it == ignored_touch.end()) { valid_touches.push_back(t); + if (touch_start.find(t) == touch_start.end()) + { + auto loc = [t locationInView:self.view]; + touch_start[t] = { loc.x, loc.y }; + } } else { @@ -458,10 +479,35 @@ std::set ignored_touch; } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + static NSTimeInterval last_time = 0; + static int tap_count = 1; + + int n = (int)[[event allTouches] count]; UITouch *touch = [[event allTouches] anyObject]; CGPoint touchLocation = [touch locationInView:self.view]; float scale = self.view.contentScaleFactor; + if (touch.timestamp - last_time < 0.2) + tap_count++; + else + tap_count = 1; + last_time = touch.timestamp; + + glm::vec2 center(0); + float max_dist = 0; + for (UITouch* t : [event allTouches]) + { + auto loc = [t locationInView:self.view]; + center += glm::vec2(loc.x, loc.y); + if (touch_start.find(t) != touch_start.end()) + { + max_dist = std::max(max_dist, glm::distance(touch_start[t], { loc.x, loc.y })); + } + } + center /= (float)n; + //LOG("max touches (%d-%d) (max %d) dist %f", + // n, (int)touch_start.size(), max_touch_count, (int)max_dist); + if (ignored_touch.count(touch)) { ignored_touch.erase(touch); @@ -471,11 +517,13 @@ std::set ignored_touch; kEventSource source = touch.type == UITouchType::UITouchTypeStylus ? kEventSource::Stylus : kEventSource::Touch; pen_down = false; - App::I->ui_task_async([tc=t_count, touchLocation, scale, source] { + App::I->ui_task_async([tc=t_count, touchLocation, scale, source, n, center, max_dist] { if (tc == 2) App::I->gesture_end(); else App::I->mouse_up(0, touchLocation.x * scale, touchLocation.y * scale, source, 0); + if (is_tap || max_dist < 10) + App::I->touch_tap(center, n == 1 ? max_touch_count : n, tap_count); }); t_count = 0; diff --git a/src/app.h b/src/app.h index f151b3f..02d28ba 100644 --- a/src/app.h +++ b/src/app.h @@ -220,6 +220,7 @@ public: bool gesture_start(const glm::vec2& p0, const glm::vec2& p1); bool gesture_move(const glm::vec2& p0, const glm::vec2& p1); bool gesture_end(); + bool touch_tap(const glm::vec2& pos, int fingers, int tap_count); bool key_down(kKey key); bool key_up(kKey key); bool key_char(char key); diff --git a/src/app_events.cpp b/src/app_events.cpp index be6201e..bf44a25 100644 --- a/src/app_events.cpp +++ b/src/app_events.cpp @@ -454,6 +454,18 @@ bool App::gesture_end() ret = main->on_event(&e); return ret == kEventResult::Consumed; } +bool App::touch_tap(const glm::vec2& pos, int fingers, int tap_count) +{ + redraw = true; + TouchEvent e; + e.m_type = kEventType::TouchTap; + e.m_finger_count = fingers; + e.m_tap_count = tap_count; + kEventResult ret = kEventResult::Available; + if (auto* main = layout[main_id]) + ret = main->on_event(&e); + return ret == kEventResult::Consumed; +} bool App::key_down(kKey key) { if (key == kKey::KeySpacebar && vr_active) diff --git a/src/event.h b/src/event.h index c7e0eac..3beeb9b 100644 --- a/src/event.h +++ b/src/event.h @@ -89,6 +89,7 @@ enum class kEventCategory : uint8_t KeyEvent, ButtonEvent, GestureEvent, + TouchEvent, }; enum class kEventType : uint8_t @@ -107,6 +108,7 @@ enum class kEventType : uint8_t GestureStart, GestureMove, GestureEnd, + TouchTap, KeyDown, KeyUp, KeyChar, @@ -158,3 +160,12 @@ public: glm::vec2 m_pos; glm::vec2 m_pos_delta; }; + +class TouchEvent : public Event +{ +public: + TouchEvent() { m_cat = kEventCategory::TouchEvent; } + glm::vec2 m_pos; + int m_finger_count; + int m_tap_count; +}; diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index b6cb81b..428f13e 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -543,6 +543,7 @@ kEventResult NodeCanvas::handle_event(Event* e) MouseEvent* me = static_cast(e); KeyEvent* ke = static_cast(e); GestureEvent* ge = static_cast(e); + TouchEvent* te = static_cast(e); auto loc = (me->m_pos - m_pos) * root()->m_zoom; switch (e->m_type) @@ -631,6 +632,10 @@ kEventResult NodeCanvas::handle_event(Event* e) for (auto& mode : *m_canvas->m_mode) mode->on_GestureEvent(ge); break; + case kEventType::TouchTap: + if (te->m_finger_count == 2) + ActionManager::undo(); + break; default: return kEventResult::Available; break;