@@ -573,6 +573,11 @@ def devtools(self, *kwargs):
573573 self .browser .ShowDevTools ()
574574
575575
576+ is_mouse_down = False
577+ is_drag = False
578+ is_drag_leave = False # Mouse leaves web view
579+ drag_data = None
580+
576581 def on_touch_down (self , touch , * kwargs ):
577582 # Mouse scrolling
578583 if "button" in touch .profile :
@@ -598,14 +603,10 @@ def on_touch_down(self, touch, *kwargs):
598603 mouseUp = True , clickCount = 1
599604 )
600605 else :
601- print ("~~ DragTargetDragEnter" )
602606 self .browser .SendMouseClickEvent (touch .x , y ,
603607 cefpython .MOUSEBUTTON_LEFT ,
604608 mouseUp = False , clickCount = 1 )
605- self .browser .DragTargetDragEnter (cefpython .DragData (), touch .x ,
606- y , cefpython .DRAG_OPERATION_EVERY )
607-
608-
609+ self .is_mouse_down = True
609610
610611
611612 def on_touch_up (self , touch , * kwargs ):
@@ -624,16 +625,33 @@ def on_touch_up(self, touch, *kwargs):
624625 y = self .height - touch .pos [1 ]
625626 self .browser .SendMouseClickEvent (touch .x , y , cefpython .MOUSEBUTTON_LEFT ,
626627 mouseUp = True , clickCount = 1 )
627-
628- print ("~~ DragTargetDrop" )
629- self .browser .DragTargetDrop (touch .x , y )
630-
631- print ("~~ DragSourceEndedAt" )
632- self .browser .DragSourceEndedAt (touch .x , y ,
633- cefpython .DRAG_OPERATION_MOVE )
634-
635- print ("~~ DragSourceSystemDragEnded" )
636- self .browser .DragSourceSystemDragEnded ()
628+ self .is_mouse_down = False
629+
630+ if self .is_drag :
631+ #print("on_touch_up=%s/%s" % (touch.x,y))
632+ if self .is_drag_leave or not self .is_inside_web_view (touch .x , y ):
633+ print ("~~ DragSourceEndedAt" )
634+ # See comment in is_inside_web_view() - x/y at borders
635+ # should be treated as outside of web view.
636+ x = touch .x
637+ if x == 0 :
638+ x = - 1
639+ if x == self .width - 1 :
640+ x = self .width
641+ if y == 0 :
642+ y = - 1
643+ if y == self .height - 1 :
644+ y = self .height
645+ self .browser .DragSourceEndedAt (x , y ,
646+ cefpython .DRAG_OPERATION_MOVE )
647+ self .drag_ended ()
648+ else :
649+ print ("~~ DragTargetDrop" )
650+ print ("~~ DragSourceEndedAt" )
651+ self .browser .DragTargetDrop (touch .x , y )
652+ self .browser .DragSourceEndedAt (touch .x , y ,
653+ cefpython .DRAG_OPERATION_MOVE )
654+ self .drag_ended ()
637655
638656 touch .ungrab (self )
639657
@@ -653,7 +671,10 @@ def on_mouse_move_emulate(self):
653671 y = int (mouse_pos [1 ]- self .height )
654672 if x >= 0 and y <= 0 :
655673 y = abs (y )
656- self .browser .SendMouseMoveEvent (x , y , mouseLeave = False )
674+ if not self .is_mouse_down and not self .is_drag :
675+ # When mouse is down on_touch_move will be called. Calling
676+ # mouse move event here caused issues with drag&drop.
677+ self .browser .SendMouseMoveEvent (x , y , mouseLeave = False )
657678
658679
659680 def on_touch_move (self , touch , * kwargs ):
@@ -665,13 +686,69 @@ def on_touch_move(self, touch, *kwargs):
665686 modifiers = cefpython .EVENTFLAG_LEFT_MOUSE_BUTTON
666687 self .browser .SendMouseMoveEvent (touch .x , y , mouseLeave = False ,
667688 modifiers = modifiers )
689+ if self .is_drag :
690+ #print("on_touch_move=%s/%s" % (touch.x, y))
691+ if self .is_inside_web_view (touch .x , y ):
692+ if self .is_drag_leave :
693+ print ("~~ DragTargetDragEnter" )
694+ self .browser .DragTargetDragEnter (
695+ self .drag_data , touch .x , y ,
696+ cefpython .DRAG_OPERATION_EVERY )
697+ self .is_drag_leave = False
698+ print ("~~ DragTargetDragOver" )
699+ self .browser .DragTargetDragOver (
700+ touch .x , y , cefpython .DRAG_OPERATION_MOVE )
701+ self .update_drag_icon (touch .x , y )
702+ else :
703+ if not self .is_drag_leave :
704+ self .is_drag_leave = True
705+ print ("~~ DragTargetDragLeave" )
706+ self .browser .DragTargetDragLeave ()
707+
708+
709+ def is_inside_web_view (self , x , y ):
710+ # When mouse is out of app window Kivy still generates move events
711+ # at the borders with x=0, x=width-1, y=0, y=height-1.
712+ if (x > 0 and x < self .width - 1 )\
713+ and (y > 0 and y < self .height - 1 ):
714+ return True
715+ return False
668716
669- print ("~~ DragTargetDragOver" )
670- self .browser .DragTargetDragOver (touch .x , y ,
671- cefpython .DRAG_OPERATION_MOVE )
672717
718+ def drag_ended (self ):
719+ # Either success or cancelled.
720+ self .is_drag = False
721+ self .is_drag_leave = False
722+ del self .drag_data
723+ self .update_drag_icon (None , None )
724+ print ("~~ DragSourceSystemDragEnded" )
725+ self .browser .DragSourceSystemDragEnded ()
726+
727+
728+ drag_icon = None
729+
730+ def update_drag_icon (self , x , y ):
731+ if self .drag_icon :
732+ self .canvas .remove (self .drag_icon )
733+ del self .drag_icon
734+ if self .is_drag :
735+ self .drag_icon = Rectangle (source = "kivy-dragdrop.png" ,
736+ pos = self .flip_pos_vertical (x ,y ),
737+ size = (40 ,40 ))
738+ self .canvas .add (self .drag_icon )
673739
674740
741+ def flip_pos_vertical (self , x , y ):
742+ half = self .height / 2
743+ if y > half :
744+ y = half - (y - half )
745+ elif y < half :
746+ y = half + (half - y )
747+ # Additionally position drag icon to the center of mouse cursor
748+ y = y - 20
749+ x = x - 20
750+ return (x , y )
751+
675752
676753class ClientHandler :
677754
@@ -791,7 +868,6 @@ def OnLoadingStateChange(self, browser, isLoading, canGoBack,
791868 print ("OnLoadingStateChange(): isLoading = %s" % isLoading )
792869 browserWidget = browser .GetUserData ("browserWidget" )
793870
794-
795871 def OnPaint (self , browser , paintElementType , dirtyRects , buffer , width ,
796872 height ):
797873 # print "OnPaint()"
@@ -805,6 +881,7 @@ def OnPaint(self, browser, paintElementType, dirtyRects, buffer, width,
805881 #update texture of canvas rectangle
806882 self .browserWidget .texture .blit_buffer (buffer , colorfmt = 'bgra' ,
807883 bufferfmt = 'ubyte' )
884+
808885 self .browserWidget ._update_rect ()
809886
810887 return True
@@ -862,16 +939,23 @@ def OnBeforeUnloadJavascriptDialog(self, browser, messageText, isReload,
862939
863940
864941 def StartDragging (self , browser , drag_data , allowed_ops , x , y ):
865- print ("!!!! StartDragging() " )
866- # TODO: succession of calls:
942+ print ("~~ StartDragging" )
943+ # Succession of d&d calls:
867944 # DragTargetDragEnter
868- # DragTargetDragOver
945+ # DragTargetDragOver - in touch move event
869946 # DragTargetDragLeave - optional
870947 # DragSourceSystemDragEnded - optional, to cancel dragging
871- # DragTargetDrop
872- # DragSourceEndedAt
873- # DragSourceSystemDragEnded
874- return False
948+ # DragTargetDrop - on mouse up
949+ # DragSourceEndedAt - on mouse up
950+ # DragSourceSystemDragEnded - on mouse up
951+ print ("~~ DragTargetDragEnter" )
952+ self .browserWidget .browser .DragTargetDragEnter (
953+ drag_data , x , y , cefpython .DRAG_OPERATION_EVERY )
954+ self .browserWidget .is_drag = True
955+ self .browserWidget .is_drag_leave = False
956+ self .browserWidget .drag_data = drag_data
957+ self .browserWidget .update_drag_icon (x , y )
958+ return True
875959
876960
877961 def UpdateDragCursor (self , browser , operation ):
0 commit comments