I found a solution in other posts, and this is an video example:
example code:
import c4d
from c4d import bitmaps,gui
class DraggingArea(c4d.gui.GeUserArea):
def __init__(self):
self.startx = 0
self.starty = 0
def DrawMsg(self, x1, y1, x2, y2, msg):
# Initializes draw region
self.OffScreenOn()
self.SetClippingRegion(x1, y1, x2, y2)
icon_bmp = bitmaps.InitResourceBitmap(5159)
icon_clip = bitmaps.GeClipMap()
icon_clip.InitWithBitmap(icon_bmp,icon_bmp.GetInternalChannel())
clip = bitmaps.GeClipMap()
w,h = self.GetWidth(),self.GetHeight()
clip.Init(w,h)
clip.BeginDraw()
clip.SetColor(0,0,180)
clip.FillRect(0,0,w,int(h*0.4))
clip.SetColor(180,0,0)
clip.FillRect(0,int(h*0.4),w,h)
clip.SetDrawMode(c4d.GE_CM_DRAWMODE_BLEND,255)
clip.Blit(self.startx,self.starty,icon_clip,0,0,icon_clip.GetBw(),icon_clip.GetBh(),c4d.GE_CM_BLIT_COL)
clip.EndDraw()
# Get default Background color
bmp = clip.GetBitmap()
self.DrawBitmap(bmp,0,0,w,h,0,0,w,h,c4d.BMP_NORMAL)
def InputEvent(self, msg):
"""
Called by Cinema 4D, when there is a user interaction (click) on the GeUserArea.
This is the place to catch and handle drag interaction.
:param msg: The event container.
:type msg: c4d.BaseContainer
:return: True if the event was handled, otherwise False.
:rtype: bool
"""
# Do nothing if its not a left mouse click event
if msg[c4d.BFM_INPUT_DEVICE] != c4d.BFM_INPUT_MOUSE and msg[c4d.BFM_INPUT_CHANNEL] != c4d.BFM_INPUT_MOUSELEFT:
return True
# Retrieves the initial position of the click
mouseX = msg[c4d.BFM_INPUT_X]
mouseY = msg[c4d.BFM_INPUT_Y]
mouse_pos_dict = self.Global2Local()
x, y = mouse_pos_dict['x'] + msg.GetInt32(c4d.BFM_INPUT_X), mouse_pos_dict['y'] + msg.GetInt32(
c4d.BFM_INPUT_Y)
self.startx = x
self.starty = y
# Initializes the start of the dragging process (needs to be initialized with the original mouseX, mouseY).
self.MouseDragStart(c4d.KEY_MLEFT, mouseX, mouseY, c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE | c4d.MOUSEDRAGFLAGS_NOMOVE)
isFirstTick = True
# MouseDrag needs to be called all time to update information about the current drag process.
# This allow to catch when the mouse is released and leave the infinite loop.
while True:
# Updates the current mouse information
result, deltaX, deltaY, channels = self.MouseDrag()
if result != c4d.MOUSEDRAGRESULT_CONTINUE:
break
# The first tick is ignored as deltaX/Y include the mouse clicking behavior with a deltaX/Y always equal to 4.0.
# However it can be useful to do some initialization or even trigger single click event
if isFirstTick:
isFirstTick = False
continue
# If the mouse didn't move, don't need to do anything
if deltaX == 0.0 and deltaY == 0.0:
continue
# Updates mouse position with the updated delta
mouseX -= deltaX
mouseY -= deltaY
x -= deltaX
y -= deltaY
self.startx = int(x)
self.starty = int(y)
# Redraw the GeUserArea (it will call DrawMsg)
self.Redraw()
# Asks why we leave the while loop
endState = self.MouseDragEnd()
return True
class MyDialog(c4d.gui.GeDialog):
"""
Creates a Dialog with only a GeUserArea within.
"""
def __init__(self):
# It's important to stores our Python implementation instance of the GeUserArea in class variable,
# This way we are sure the GeUserArea instance live as long as the GeDialog.
self.area = DraggingArea()
def CreateLayout(self):
"""
This method is called automatically when Cinema 4D Create the Layout (display) of the Dialog.
"""
self.AddUserArea(1000, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT)
self.AttachUserArea(self.area, 1000)
return True
def main():
# Creates a new dialog
dialog = MyDialog()
# Opens it
dialog.Open(dlgtype=c4d.DLG_TYPE_MODAL_RESIZEABLE, defaultw=500, defaulth=500)
if __name__ == '__main__':
main()