Repository: bokeh/bokeh

Issue:
Make BoxEditTool match PolyDrawTool UI
The new [drawing tools in Bokeh 0.12.14](http://bokeh.pydata.org/en/latest/docs/user_guide/tools.html) are great, but there seems to be one inconsistency: BoxEditTool uses a shift tap to start a new shape, while PolyDrawTool uses double tap.  In both cases the user is starting an operation that will involve collecting multiple taps at different locations, so it seems to me that this should be the same user action in both cases. To make the interfaces more consistent, and possibly to make box drawing more feasible on tablets, can BoxEditTool be changed to start with a double tap instead of a shift tap?


Discussion:
~~Let me know when this will be worked on, because currently UI events are under a complete rewrite.~~
I would be +0 to making it start with *either*, so that the current behavior does not change or go away. 
Seems fine for both to start with *either* a shift-tap or a double-tap, sure!
@philippjfr would you be able to add this?
I'd be happy to, presumably not for 0.12.15 though?
If you can do it before friday, then yes

Resolving patch:
diff --git a/bokeh/models/tools.py b/bokeh/models/tools.py
--- a/bokeh/models/tools.py
+++ b/bokeh/models/tools.py
@@ -909,7 +909,9 @@ class BoxEditTool(EditTool, Drag, Tap):
 
     The supported actions include:
 
-    * Add box: Hold shift then click and drag anywhere on the plot.
+    * Add box: Hold shift then click and drag anywhere on the plot or
+      double tap once to start drawing, move the mouse and double tap
+      again to finish drawing.
 
     * Move box: Click and drag an existing box, the box will be
       dropped once you let go of the mouse button.


Test patch:
diff --git a/bokehjs/test/models/tools/edit/box_edit_tool.ts b/bokehjs/test/models/tools/edit/box_edit_tool.ts
--- a/bokehjs/test/models/tools/edit/box_edit_tool.ts
+++ b/bokehjs/test/models/tools/edit/box_edit_tool.ts
@@ -185,13 +185,13 @@ describe("BoxEditTool", () =>
 
       let drag_event = make_gesture_event(300, 300, true);
       testcase.draw_tool_view._pan_start(drag_event);
-      expect(testcase.draw_tool_view._basepoint).to.be.deep.equal([300, 300]);
+      expect(testcase.draw_tool_view._draw_basepoint).to.be.deep.equal([300, 300]);
       drag_event = make_gesture_event(200, 200, true);
       testcase.draw_tool_view._pan(drag_event);
-      expect(testcase.draw_tool_view._basepoint).to.be.deep.equal([300, 300]);
+      expect(testcase.draw_tool_view._draw_basepoint).to.be.deep.equal([300, 300]);
       testcase.draw_tool_view._pan_end(drag_event);
 
-      expect(testcase.draw_tool_view._basepoint).to.be.equal(null);
+      expect(testcase.draw_tool_view._draw_basepoint).to.be.equal(null);
       expect(testcase.data_source.selected.indices).to.be.deep.equal([]);
       expect(testcase.data_source.data['x']).to.be.deep.equal([0, 0.5, 1, -0.1327433628318584]);
       expect(testcase.data_source.data['y']).to.be.deep.equal([0, 0.5, 1, 0.1694915254237288]);
@@ -199,5 +199,28 @@ describe("BoxEditTool", () =>
       expect(testcase.data_source.data['height']).to.be.deep.equal([0.3, 0.2, 0.1, 0.3389830508474576]);
       expect(testcase.data_source.data['z']).to.be.deep.equal([null, null, null, "Test"]);
     });
+
+    it("should draw box on doubletap and move", function(): void {
+      const testcase = make_testcase();
+      const hit_test_stub = sinon.stub(testcase.glyph_view, "hit_test");
+      hit_test_stub.returns(null);
+
+      let drag_event = make_gesture_event(300, 300, true);
+      testcase.draw_tool_view._doubletap(drag_event);
+      expect(testcase.draw_tool_view._draw_basepoint).to.be.deep.equal([300, 300]);
+      drag_event = make_gesture_event(200, 200, true);
+      testcase.draw_tool_view._move(drag_event);
+      expect(testcase.draw_tool_view._draw_basepoint).to.be.deep.equal([300, 300]);
+      testcase.draw_tool_view._doubletap(drag_event);
+
+      expect(testcase.draw_tool_view._draw_basepoint).to.be.equal(null);
+      expect(testcase.data_source.selected.indices).to.be.deep.equal([]);
+      expect(testcase.data_source.data['x']).to.be.deep.equal([0, 0.5, 1, -0.1327433628318584]);
+      expect(testcase.data_source.data['y']).to.be.deep.equal([0, 0.5, 1, 0.1694915254237288]);
+      expect(testcase.data_source.data['width']).to.be.deep.equal([0.1, 0.2, 0.3, 0.35398230088495575]);
+      expect(testcase.data_source.data['height']).to.be.deep.equal([0.3, 0.2, 0.1, 0.3389830508474576]);
+      expect(testcase.data_source.data['z']).to.be.deep.equal([null, null, null, "Test"]);
+    });
+
   }),
 );