Plugin Cafe Homepage
Forum Home Forum Home > Plugin Cafe > PYTHON Development
  New Posts New Posts
  FAQ FAQ  Forum Search

[SOLVED]Start Drag from GeUserArea

Author
Message
  Topic Search Topic Search
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Topic: [SOLVED]Start Drag from GeUserArea
    Posted: 2017 Jun 06 at 11:21am
I would like to know if it's possible to start a drag and drop event from a GeUserArea?

I successfully get drag event from other part of c4d but not from my GeUserArea.
Quick info it will be only aviable from my GeUserArea to my GeUserArea

According the C++ doc it can be done by HandleMouseDrag or MouseDragStart but I don't see this function aviable in python.
So I guess my best bet is to do my custom drag event with a timer. But is there any method for detect simple mouse click and drag click? If no I think I delayed all click with a timer of something like 30ms then check if click is still activate.
If no do the normal click else do drag.

Anyway thanks in advance ! :)



Edited by gr4ph0s - 2017 Jun 08 at 10:58am
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2017 Jun 07 at 3:03am
Hi,

Do you want to drag and drop inside the same or another instance of your GeUserArea?

GeUserArea.MouseDragStart()/MouseDrag()/MouseDragEnd() are available in the Python API but aren't documented currently. These functions allows dragging inside a GeUserArea.

GeUserArea.HandleMouseDrag() is missing in the Python API. The C++ API function allows starting a drag and drop to other places in Cinema (including the same GeUserArea the drag got started from).

You can try to implement your own dragging mechanism but this is tricky and may not work the way you want.
See Input Events page in the Python SDK documentation and Continuous polling



MAXON
Developer Support
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2017 Jun 07 at 3:08am
Thanks for the reply. 

Yes first case ;) Drag/Drop from the same GeUserArea.
So MouseDragStart/MouseDrag/MouseDragEnd are everything what I need ! :)

Does theses functions work as same as the one inside EditorWindows or the C++ one from GeUserArea? And Did they get the same flag than the C++ one or some are not handled?


Edited by gr4ph0s - 2017 Jun 07 at 3:09am
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2017 Jun 07 at 3:15am
Originally posted by gr4ph0s

Does theses functions work as same as the one inside EditorWindows or the C++ one from GeUserArea? And Did they get the same flag than the C++ one or some are not handled?
Exactly. These functions take the same parameters/return the same data as the one in EditorWindow.
And there's no difference between C++ and Python for the supported mouse drag flags.



MAXON
Developer Support
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2017 Jun 07 at 3:19am
Gonna do some test but I guess I can mark the thread as solved.

Thanks you alot.
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2017 Jun 07 at 1:57pm
I don't success to get it to work properly. The main issue is I don't know when to start drag event. Same for end it. So for exemple it didn't make the difference beetween a simple click and a drag event.

Moreover kills event doesn't seem to work.
Here is an exemple
import c4d

class Area(c4d.gui.GeUserArea):

    xValue = 0
    yValue = 0
   
    def DrawMsg(self, x1, y1, x2, y2, msg): 

        self.DrawSetPen(c4d.Vector(.2))
        self.DrawRectangle(x1, y1, x2, y2)
        
        
    def drag_message(self, msg, result):
        bc_click = c4d.BaseContainer()
        self.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, bc_click)
        mousex = bc_click.GetLong(c4d.BFM_INPUT_X)
        mousey = bc_click.GetLong(c4d.BFM_INPUT_X)

        self.MouseDragStart(c4d.KEY_MLEFT, mousex, mousey, c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE | c4d.MOUSEDRAGFLAGS_NOMOVE)
    
        mx = mousex
        my = mousey
        drag_result, dx, dy, channels = self.MouseDrag()
        first = True
        drag = False
        while drag_result == c4d.MOUSEDRAGRESULT_CONTINUE:
            drag = True
            if first:
                print 'Start'
                first = False
            mx += dx
            my += dy
            if dx==0.0 and dy==0.0:
                drag_result, dx, dy, channels = self.MouseDrag()
                continue
            self.KillEvents() #Don't work

            drag_result, dx, dy, channel = self.MouseDrag()
            print "Mouse Dragging at position [%f,%f]" % (mx, my)

        if self.MouseDragEnd() == c4d.MOUSEDRAGRESULT_FINISHED and drag:
            print "Mouse Dragging Ended: ", self.MouseDragEnd()

        return
        
    def Message(self, msg, result):
        self.drag_message(msg, result)
        if msg.GetId() == c4d.BFM_INPUT:
            print 'clicked'
        return c4d.gui.GeUserArea.Message(self, msg, result)
        

class MyDialog(c4d.gui.GeDialog):

    def __init__(self, area):
        self.area = area

    def CreateLayout(self):
        self.SetTitle("My UserArea")

        self.AddUserArea(1000, c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT)
        self.AttachUserArea(self.area, 1000)
        self.GroupEnd()
        return True

def main():
    area = Area()
    dialog = None

    dialog = MyDialog(area)
    dialog.Open(dlgtype=c4d.DLG_TYPE_MODAL_RESIZEABLE, defaultw=500, defaulth=500)

if __name__=='__main__':
    main()

As you could see if you click its also print you drag. Hope you understand my problem ^^'. Who is Get the start of a drag event and get the end of a drag event. Like that in the Message function I can do if START_OF_DRAG : self.drag_message, and if END_OF_DRAG : print 'end'
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2017 Jun 08 at 3:25am
To check for a drag event the solution is to simply use MouseDragStart()/MouseDrag()/MouseDragEnd().
Instead of Message(), move the mouse dragging into InputEvent().
Then to check if the started drag processing was just a click add this condition at the beginning of the while dragging loop:
if bc_click[c4d.BFM_INPUT_VALUE] == 0:
    break
This condition exits the loop whenever the mouse left button is released. Then check if the mouse was really moved or if it was just a mouse click. 

Finally, I don't think KillEvents() is useful here if it's called inside the while dragging loop.



MAXON
Developer Support
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2017 Jun 08 at 4:40am
Thanks you sadly I didnt succes to get the click evaluated properly.
import c4d

class Area(c4d.gui.GeUserArea):
  
    def DrawMsg(self, x1, y1, x2, y2, msg): 
        self.DrawSetPen(c4d.Vector(.2))
        self.DrawRectangle(x1, y1, x2, y2)
        
        
    def InputEvent(self, msg):
        mousex = msg[c4d.BFM_INPUT_X]
        mousey = msg[c4d.BFM_INPUT_Y]
        
        self.MouseDragStart(c4d.KEY_MLEFT, mousex, mousey, c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE | c4d.MOUSEDRAGFLAGS_NOMOVE)
        
        mx = mousex
        my = mousey
        while True:
            if msg[c4d.BFM_INPUT_VALUE] == 0:
                break
            
            result, dx, dy, channels = self.MouseDrag()
            if result!=c4d.MOUSEDRAGRESULT_CONTINUE: break
            
            #If we don't move that mean we clicked'
            if not dx or not dy:
                print 'clicked'
            else:
                mx += dx
                my += dy
                
                print "Mouse Dragging at position [%f,%f]" % (mx, my)
            

        
        end_state = self.MouseDragEnd()
        if end_state == c4d.MOUSEDRAGRESULT_ESCAPE:
            print "Escaped"
        elif end_state == c4d.MOUSEDRAGRESULT_FINISHED:
            print 'Mouse Drag End'             
        
            
        return True        

class MyDialog(c4d.gui.GeDialog):
    def CreateLayout(self):
        self.area = Area()
        
        self.AddUserArea(1000, c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT)
        self.AttachUserArea(self.area, 1000)
        return True

def main():
    dialog = MyDialog()
    dialog.Open(dlgtype=c4d.DLG_TYPE_MODAL_RESIZEABLE, defaultw=500, defaulth=500)

if __name__=='__main__':
    main()
As you could see, the first tick is always drag (dx and dy are not equal to 0) even if you don't move the mouse.

Moreover I would like to ask is there a way for changing mouse icon? For exemple I would like to change it when she is outside of my GeUserArea.


Edited by gr4ph0s - 2017 Jun 08 at 5:44am
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2017 Jun 08 at 8:14am
Sorry my first post was missing information.
MouseDrag() has to be called first in the loop for each drag event. Then the current input state for the mouse left button has to be retrieved before checking c4d.BFM_INPUT_VALUE.
So the dragging loop would be:
mx = mousex
my = mousey
state = c4d.BaseContainer()
while True:

    result, dx, dy, channels = self.MouseDrag()
    if result == c4d.MOUSEDRAGRESULT_ESCAPE:
      break

    if not self.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, state):
        break

    if state[c4d.BFM_INPUT_VALUE] == 0:
        print "Released Left Mouse"
        break

    if dx == 0 and dy == 0:
        continue

    mx += dx
    my += dy
    print "Mouse Dragging at position [%f,%f]" % (mx, my)
state[c4d.BFM_INPUT_VALUE] gives the mouse left button clicked state. So this allows to check when the mouse button has been released.
If the mouse position hasn't changed then no dragging should be processed.


You can change the mouse icon with gui.SetMousePointer().



MAXON
Developer Support
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2017 Jun 08 at 9:38am
Thanks you. Tested and solved ! :)
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2017 Jun 09 at 12:54am
Sorry to bump this thread but is there a way for start drag from a GeUserArea and recieve drop message from TreeViewCustomGui? Or at least is it possible to send message to this TreeViewCustomGui? Or a timer? 
Just tell me yes or no ;) 

Cause I think I must do the following thing but I prefer ask if there is no other way before ^^
Make my timer function into my GeDialog who call a custom timer function inside my TreeView :)


Edited by gr4ph0s - 2017 Jun 09 at 1:20am
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2017 Jun 09 at 2:29am
GeUserArea.HandleMouseDrag() is missing in the Python API so it would be really difficult and hacky to send drag and drop data to other gadgets.


MAXON
Developer Support
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2017 Jun 09 at 2:46am
Ok thanks for confirming ! :)
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2017 Jun 09 at 1:53pm
Sorry again to bump this thread, but I don't udnerstand the output code while the mouse is not moving, delta y is always -22 while it should be 0
    def InputEvent(self, msg):
        mousex = msg[c4d.BFM_INPUT_X]
        mousey = msg[c4d.BFM_INPUT_Y]

        self.MouseDragStart(c4d.KEY_MLEFT, mousex, mousey, c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE | c4d.MOUSEDRAGFLAGS_NOMOVE)

        start_x = mousex
        start_y = mousey

        mx = mousex
        my = mousey
        state = c4d.BaseContainer()
        while True:

            result, dx, dy, channels = self.MouseDrag()
            if result == c4d.MOUSEDRAGRESULT_ESCAPE:
                break

            if not self.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, state):
                break

            if state[c4d.BFM_INPUT_VALUE] == 0:
                print "Released Left Mouse"
                break

            if dx == 0 and dy == 0: #dy != 0 while not moving
                continue

            mx += dx
            my += dy

           #Should not be display if not moving
           print 'drag'

        print start_x - mx
        print start_y - my #-22 if not moving

        return True


Edited by gr4ph0s - 2017 Jun 09 at 2:26pm
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2017 Jun 12 at 7:06am
Originally posted by gr4ph0s

Sorry again to bump this thread, but I don't understand the output code while the mouse is not moving, delta y is always -22 while it should be 0
If the mouse doesn't move dx and dy are 0. The final mouse delta X and Y values depends on how you calculate the current mouse position.
It's better to subtract the mouse drag delta values:
mx -= dx
my -= dy
Then the final delta value can be calculated:
print mx - mousex
print my - mousey

If you don't want MouseDrag() to return when the mouse doesn't move, don't pass MOUSEDRAGFLAGS_NOMOVE to MouseDragStart().



MAXON
Developer Support
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2017 Jun 13 at 4:52am
Ok I get why it's wrong... The corect loop initialization is:
        mousex = msg[c4d.BFM_INPUT_X]
        mousey = msg[c4d.BFM_INPUT_Y]
        
        self.MouseDragStart(c4d.KEY_MLEFT, mousex, mousey, c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE | c4d.MOUSEDRAGFLAGS_NOMOVE)
        
        while self.MouseDrag()[0] == c4d.MOUSEDRAGRESULT_CONTINUE:
            if msg[c4d.BFM_INPUT_VALUE] == 0:
                break
            
            result, dx, dy, channels = self.MouseDrag()
            print "dx {} - dy {}".format(dx, dy)

While in the documention of https://developers.maxon.net/docs/Cinema4DPythonSDK/html/modules/c4d.gui/EditorWindow/index.html#EditorWindow.MouseDragStart the main drag loop is done with While true, which give you a wrong value for dx/dy for the first packet of the drag input.

So doing it like in the C++ exemple
    win->MouseDragStart(button, mouseX, mouseY, MOUSEDRAGFLAGS_DONTHIDEMOUSE | MOUSEDRAGFLAGS_NOMOVE);
    while (win->MouseDrag(&dx, &dy, &device) == MOUSEDRAGRESULT_CONTINUE)

give us in python
        self.MouseDragStart(c4d.KEY_MLEFT, mousex, mousey, c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE | c4d.MOUSEDRAGFLAGS_NOMOVE)
        
        while self.MouseDrag()[0] == c4d.MOUSEDRAGRESULT_CONTINUE:

Anyway thanks for your support ! :)


Edited by gr4ph0s - 2017 Jun 13 at 4:53am
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2017 Jun 13 at 8:18am
I can't confirm that because the delta values returned from the call to MouseDrag()[0] aren't processed for each while loop:
while self.MouseDrag()[0] == c4d.MOUSEDRAGRESULT_CONTINUE: # dx, dy and channels not retrieved and processed

There should be only one MouseDrag() call for each while loop.



MAXON
Developer Support
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2017 Jun 13 at 8:28am
Juste copy paste thoses two codes and do a normal click without dragging. Just a simple click (no move, nothing just a click), So result should be 0 and 0 for dx/dy in all case (in all packet of the drag pool)
The first one give correct result for dx , dy
import c4d

class Area(c4d.gui.GeUserArea):
  
    def InputEvent(self, msg):
        mousex = msg[c4d.BFM_INPUT_X]
        mousey = msg[c4d.BFM_INPUT_Y]
        
        self.MouseDragStart(c4d.KEY_MLEFT, mousex, mousey, c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE | c4d.MOUSEDRAGFLAGS_NOMOVE)
        
        while self.MouseDrag()[0]:
            if msg[c4d.BFM_INPUT_VALUE] == 0:
                break
            
            result, dx, dy, channels = self.MouseDrag()
            if result!=c4d.MOUSEDRAGRESULT_CONTINUE: break
            
            print "dx {} - dy {}".format(dx, dy)
                        
        return True

class MyDialog(c4d.gui.GeDialog):
    def CreateLayout(self):
        self.area = Area()
        
        self.AddUserArea(1000, c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT)
        self.AttachUserArea(self.area, 1000)
        return True

def main():
    dialog = MyDialog()
    dialog.Open(dlgtype=c4d.DLG_TYPE_MODAL_RESIZEABLE, defaultw=500, defaulth=500)

if __name__=='__main__':
    main()

While the sdk code(using While True) give wrong result for dx, dy in the first packet (dx 4 and dy 4)
import c4d

class Area(c4d.gui.GeUserArea):
  
    def InputEvent(self, msg):
        mousex = msg[c4d.BFM_INPUT_X]
        mousey = msg[c4d.BFM_INPUT_Y]
        
        self.MouseDragStart(c4d.KEY_MLEFT, mousex, mousey, c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE | c4d.MOUSEDRAGFLAGS_NOMOVE)
        
        while True:
            if msg[c4d.BFM_INPUT_VALUE] == 0:
                break
            
            result, dx, dy, channels = self.MouseDrag()
            if result!=c4d.MOUSEDRAGRESULT_CONTINUE: break
            
            print "dx {} - dy {}".format(dx, dy)
                        
        return True

class MyDialog(c4d.gui.GeDialog):
    def CreateLayout(self):
        self.area = Area()
        
        self.AddUserArea(1000, c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT)
        self.AttachUserArea(self.area, 1000)
        return True

def main():
    dialog = MyDialog()
    dialog.Open(dlgtype=c4d.DLG_TYPE_MODAL_RESIZEABLE, defaultw=500, defaulth=500)

if __name__=='__main__':
    main()


Edited by gr4ph0s - 2017 Jun 13 at 8:43am
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2017 Jun 14 at 3:17am
You're not retrieving and printing the delta values dx and dy from the self.MouseDrag()[0] calls in the first script. The delta values are 4.0 for the first mouse drag there too.

The limitation with MouseDrag() in Python is the language doesn't support assignments in expressions.



MAXON
Developer Support
Back to Top

Forum Jump Forum Permissions View Drop Down

Bulletin Board Software by Web Wiz Forums® version 9.61 [Free Express Edition]
Copyright ©2001-2009 Web Wiz

This page was generated in 0.109 seconds.