experimental/editor: mouse drag select, modifierkeys cleanup.

Change-Id: I8c8de54ad6309424bdf18987ccf3eac6bdd41c19
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/233080
Commit-Queue: Hal Canary <halcanary@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
diff --git a/experimental/editor/editor_application.cpp b/experimental/editor/editor_application.cpp
index 0592560..7949851 100644
--- a/experimental/editor/editor_application.cpp
+++ b/experimental/editor/editor_application.cpp
@@ -148,31 +148,33 @@
 
     void inval() { if (fParent) { fParent->inval(); } }
 
-    bool onMouseWheel(float delta, ModifierKey modifiers) override {
+    bool onMouseWheel(float delta, ModifierKey) override {
         this->scroll(-(int)(delta * fEditor.font().getSpacing()));
         return true;
     }
 
+    bool fMouseDown = false;
+
     bool onMouse(int x, int y, InputState state, ModifierKey modifiers) override {
-        if (InputState::kDown == state) {
-            y += fPos - fMargin;
-            x -= fMargin;
-            editor::Editor::TextPosition pos = fEditor.getPosition(SkIPoint{x, y});
-            #ifdef SK_EDITOR_DEBUG_OUT
-            SkDebugf("select:  line:%d column:%d \n", pos.fParagraphIndex, pos.fTextByteIndex);
-            #endif  // SK_EDITOR_DEBUG_OUT
-            if (pos != editor::Editor::TextPosition()) {
-                fTextPos = pos;
-                this->inval();
-            }
+        bool mouseDown = InputState::kDown == state;
+        if (mouseDown) {
+            fMouseDown = true;
+        } else if (InputState::kUp == state) {
+            fMouseDown = false;
         }
-        return true;
+        bool shiftOrDrag = skstd::Any(modifiers & ModifierKey::kShift) || !mouseDown;
+        if (fMouseDown) {
+            return this->move(fEditor.getPosition({x - fMargin, y + fPos - fMargin}), shiftOrDrag);
+        }
+        return false;
     }
 
-    bool onChar(SkUnichar c, ModifierKey modifiers) override {
-        if (!ModifierKeyIsSet(modifiers & (ModifierKey::kControl |
-                                           ModifierKey::kOption  |
-                                           ModifierKey::kCommand))) {
+    bool onChar(SkUnichar c, ModifierKey modi) override {
+        using skstd::Any;
+        modi &= ~ModifierKey::kFirstPress;
+        if (!Any(modi & (ModifierKey::kControl |
+                         ModifierKey::kOption  |
+                         ModifierKey::kCommand))) {
             if (((unsigned)c < 0x7F && (unsigned)c >= 0x20) || c == '\n') {
                 char ch = (char)c;
                 fEditor.insert(fTextPos, &ch, 1);
@@ -182,7 +184,9 @@
                 return this->moveCursor(editor::Editor::Movement::kRight);
             }
         }
-        if (modifiers == ModifierKey::kControl) {
+        static constexpr ModifierKey kCommandOrControl = ModifierKey::kCommand |
+                                                         ModifierKey::kControl;
+        if (Any(modi & kCommandOrControl) && !Any(modi & ~kCommandOrControl)) {
             switch (c) {
                 case 'p':
                     for (editor::StringView str : fEditor.text()) {
@@ -208,6 +212,7 @@
                         fClipboard.resize(fEditor.copy(fMarkPos, fTextPos, nullptr));
                         fEditor.copy(fMarkPos, fTextPos, fClipboard.data());
                         fTextPos = fEditor.remove(fMarkPos, fTextPos);
+                        fMarkPos = editor::Editor::TextPosition();
                         this->inval();
                         return true;
                     }
@@ -224,12 +229,20 @@
         #endif  // SK_EDITOR_DEBUG_OUT
         return false;
     }
+
     bool moveCursor(editor::Editor::Movement m, bool shift = false) {
+        return this->move(fEditor.move(m, fTextPos), shift);
+    }
+
+    bool move(editor::Editor::TextPosition pos, bool shift) {
+        if (pos == fTextPos || pos == editor::Editor::TextPosition()) {
+            return false;
+        }
         if (shift != fShiftDown) {
-            fMarkPos = shift ? fTextPos :  editor::Editor::TextPosition();
+            fMarkPos = shift ? fTextPos : editor::Editor::TextPosition();
             fShiftDown = shift;
         }
-        fTextPos = fEditor.move(m, fTextPos);
+        fTextPos = pos;
 
         // scroll if needed.
         SkIRect cursor = fEditor.getLocation(fTextPos).roundOut();
@@ -249,10 +262,12 @@
             return false;  // ignore keyup
         }
         // ignore other modifiers.
+        using skstd::Any;
         ModifierKey ctrlAltCmd = modifiers & (ModifierKey::kControl |
                                               ModifierKey::kOption  |
                                               ModifierKey::kCommand);
-        if (!ModifierKeyIsSet(ctrlAltCmd)) {
+        bool shift = Any(modifiers & (ModifierKey::kShift));
+        if (!Any(ctrlAltCmd)) {
             // no modifiers
             switch (key) {
                 case sk_app::Window::Key::kPageDown:
@@ -265,8 +280,7 @@
                 case sk_app::Window::Key::kDown:
                 case sk_app::Window::Key::kHome:
                 case sk_app::Window::Key::kEnd:
-                    return this->moveCursor(convert(key),
-                                            (int)(modifiers & ModifierKey::kShift));
+                    return this->moveCursor(convert(key), shift);
                 case sk_app::Window::Key::kDelete:
                     if (fMarkPos != editor::Editor::TextPosition()) {
                         fTextPos = fEditor.remove(fMarkPos, fTextPos);
@@ -294,14 +308,12 @@
                 default:
                     break;
             }
-        } else if (ModifierKeyIsSet(ctrlAltCmd & (ModifierKey::kControl | ModifierKey::kCommand))) {
+        } else if (skstd::Any(ctrlAltCmd & (ModifierKey::kControl | ModifierKey::kCommand))) {
             switch (key) {
                 case sk_app::Window::Key::kLeft:
-                    return this->moveCursor(editor::Editor::Movement::kWordLeft,
-                                            (int)(modifiers & ModifierKey::kShift));
+                    return this->moveCursor(editor::Editor::Movement::kWordLeft, shift);
                 case sk_app::Window::Key::kRight:
-                    return this->moveCursor(editor::Editor::Movement::kWordRight,
-                                            (int)(modifiers & ModifierKey::kShift));
+                    return this->moveCursor(editor::Editor::Movement::kWordRight, shift);
                 default:
                     break;
             }
diff --git a/include/private/SkBitmaskEnum.h b/include/private/SkBitmaskEnum.h
index 0f7aa15..859a2de 100644
--- a/include/private/SkBitmaskEnum.h
+++ b/include/private/SkBitmaskEnum.h
@@ -11,6 +11,10 @@
 
 namespace skstd {
 template <typename T> struct is_bitmask_enum : std::false_type {};
+
+template <typename E> SK_WHEN(skstd::is_bitmask_enum<E>::value, bool) constexpr Any(E e) {
+    return static_cast<typename std::underlying_type<E>::type>(e) != 0;
+}
 }
 
 template <typename E> SK_WHEN(skstd::is_bitmask_enum<E>::value, E) constexpr operator|(E l, E r) {
@@ -31,4 +35,8 @@
     return l = l & r;
 }
 
+template <typename E> SK_WHEN(skstd::is_bitmask_enum<E>::value, E) constexpr operator~(E e) {
+    return static_cast<E>(~static_cast<typename std::underlying_type<E>::type>(e));
+}
+
 #endif  // SkEnumOperators_DEFINED
diff --git a/samplecode/PerlinPatch.cpp b/samplecode/PerlinPatch.cpp
index 5736e9e..1e036d7 100644
--- a/samplecode/PerlinPatch.cpp
+++ b/samplecode/PerlinPatch.cpp
@@ -168,6 +168,7 @@
     }
 
     Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
+        modi &= ~ModifierKey::kFirstPress;  // ignore this
         if (ModifierKey::kShift == modi) {
             return new PtClick(-1);
         }
diff --git a/tools/ModifierKey.h b/tools/ModifierKey.h
index 5f4d25d..8ebfb76 100644
--- a/tools/ModifierKey.h
+++ b/tools/ModifierKey.h
@@ -18,8 +18,4 @@
 template <> struct is_bitmask_enum<ModifierKey> : std::true_type {};
 }
 
-static inline bool ModifierKeyIsSet(ModifierKey m) {
-    return m != ModifierKey::kNone;
-}
-
 #endif  // ModifierKey_DEFINED
diff --git a/tools/viewer/SlideDir.cpp b/tools/viewer/SlideDir.cpp
index f4c1d6b..c4ac3e4 100644
--- a/tools/viewer/SlideDir.cpp
+++ b/tools/viewer/SlideDir.cpp
@@ -381,7 +381,8 @@
 
 bool SlideDir::onMouse(SkScalar x, SkScalar y, InputState state,
                        ModifierKey modifiers) {
-    if (state == InputState::kMove || ModifierKeyIsSet(modifiers))
+    modifiers &= ~ModifierKey::kFirstPress;
+    if (state == InputState::kMove || skstd::Any(modifiers))
         return false;
 
     if (fFocusController->hasFocus()) {