@ferdinand That was so simple, thank you!
How would I call the Base/Super Implementation in this case? Do you mean something like this?
def InputEvent(self, msg):
# override code goes here
return super().InputEvent(msg)
@ferdinand That was so simple, thank you!
How would I call the Base/Super Implementation in this case? Do you mean something like this?
def InputEvent(self, msg):
# override code goes here
return super().InputEvent(msg)
@mp5gosu Sorry, I missed it! That works! In case other devs have a solution, I'll mark yours as the right answer. Thank you!
@ferdinand Thank you, Ferdinand for the thorough answer and ideas for workarounds. I don't quite have my head around how to use threading in Cinema 4D yet but you've inspired me to look into it. Thank you!
Hello,
Please excuse my multiple posts about the GeUserArea in a Scrollgroup, but I was unable to find any information about the following in the documentation or the forum.
By default, the GeUserArea in a ScrollGroup in this script can be grabbed by middle-mouse button clicking and dragging.
In my plugin however, I need to override the GeUserArea:InputEvent method. This seems to be where the grabbing functionality exists. How can I add the middle-mouse grab to my InputEvent override? Thank you!
import c4d
import random
from c4d import gui
GADGET_ID_GEUSERAREA = 10000
SCROLL_ID = 10001
SLIDER_ID = 10002
class ExampleGeUserArea(c4d.gui.GeUserArea):
width = 400
height = 500
bmp_cache = None
def GetBitmap(self):
bmp = c4d.bitmaps.BaseBitmap()
bmp.Init(self.width, self.height)
for h in range(self.height):
for w in range(self.width):
r = random.randint(0, 70)
bmp.SetPixel(w, h, r, r, r)
return bmp
def DrawMsg(self, x1, y1, x2, y2, msg):
self.OffScreenOn()
self.SetClippingRegion(x1, y1, x2, y2)
self.DrawSetPen(c4d.Vector(1, 0, 0))
self.DrawRectangle(x1, y1, x2, y2)
if self.bmp_cache == None:
self.bmp_cache = self.GetBitmap()
self.DrawBitmap(self.bmp_cache, x1, y1, x2, y2, 0, 0,
w=self.bmp_cache.GetBw(),
h=self.bmp_cache.GetBh(),
mode=c4d.BMP_NORMAL)
"""
def InputEvent(self, msg):
#This stops the grab functionality
device = msg.GetLong(c4d.BFM_INPUT_DEVICE)
channel = msg.GetLong(c4d.BFM_INPUT_CHANNEL)
if device == c4d.BFM_INPUT_MOUSE and channel == c4d.BFM_INPUT_MOUSEMIDDLE:
print (device,channel)
return True
"""
def Message(self, msg, result):
# Catch the draw message to cancel it (return True)
# and call ourself the DrawMsg with the dimension we expect
if msg.GetId() == c4d.BFM_DRAW:
self.DrawMsg(0, 0, self.width, self.height, c4d.BaseContainer())
return True
return c4d.gui.GeUserArea.Message(self, msg, result)
def GetMinSize(self):
return self.width, self.height
class ExampleDialog(c4d.gui.GeDialog):
geUserArea = ExampleGeUserArea()
def _centerAlignScrollGroup(self):
_, _, sgw, sgh = self.GetItemDim(SCROLL_ID).values()
_, _, uaw, uah = self.GetItemDim(GADGET_ID_GEUSERAREA).values()
sax1, say1, sax2, say2 = self.GetVisibleArea(SCROLL_ID).values()
dx, dy = sgw - (sax2 - sax1), sgh - (say2 - say1) # 16, 15
sgw -= dx
sgh -= dy
x, y = int((uaw - sgw) * .5), int((uah - sgh) * .5)
self.SetVisibleArea(SCROLL_ID, x, y, x + sgw, y + sgh)
def DrawUA(self, scale):
self.geUserArea.width = int(400*scale)
self.geUserArea.height = int(500*scale)
self.LayoutChanged(SCROLL_ID)
def CreateLayout(self):
self.SetTitle("GeUserArea")
if self.ScrollGroupBegin(SCROLL_ID, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, c4d.SCROLLGROUP_HORIZ | c4d.SCROLLGROUP_VERT):
self.AddUserArea(GADGET_ID_GEUSERAREA, c4d.BFH_CENTER | c4d.BFH_SCALE |
c4d.BFV_CENTER | c4d.BFV_SCALE, initw=gui.SizePix(400), inith=gui.SizePix(500))
self.AttachUserArea(self.geUserArea, GADGET_ID_GEUSERAREA)
self.GroupEnd()
self.AddEditSlider(SLIDER_ID, c4d.BFH_SCALEFIT | c4d.BFV_CENTER)
return True
def InitValues(self):
self.SetFloat(SLIDER_ID, 1.0, min=0.01, max=2, step=0.01)
self._centerAlignScrollGroup()
return True
def Command(self, id, msg):
if id == SLIDER_ID:
self.DrawUA(msg[c4d.BFM_ACTION_VALUE])
self._centerAlignScrollGroup()
return True
def main():
global dlg
dlg = ExampleDialog()
dlg.Open(c4d.DLG_TYPE_ASYNC, pluginid=1234567, defaultw=300, defaulth=300)
if __name__ == "__main__":
main()
@ferdinand You are an absolute genius. Thank you so so much, Ferdinand. Incredible!!
@m_magalhaes Hi Manuel, thank you and @mp5gosu for the replies.
I'm trying to create a keyboard shortcut for my plugin so unfortunately ERERERERERERERERERERER isn't a workaround that I can use. Please let me know what the devs say. Thanks!
@ferdinand Thank you for the workaround. I'll wait to close this until you've found if it is a bug.
Hello,
I am having an issue getting a consistent result with the GeDialog.Message and BFM_INPUT_KEYBOARD.
In the code below, I'm listening to BFM_INPUT_CHANNEL
69 (the 'E' key) and printing to the Console. The Message will only work once or twice and then lose functionality until I interact with the GeDialog in some way. Sometimes it takes a few interactions to get it started again. In the screencast below, every time the menu icon and window title are flashing is when I am pressing the 'E' key.
Is there a way to make this interaction more consistent, please?
import c4d, random
from c4d import gui
GADGET_ID_GEUSERAREA = 10000
SCROLL_ID = 10001
SLIDER_ID = 10002
class ExampleGeUserArea(c4d.gui.GeUserArea):
width = 400
height = 500
bmp_cache = None
def GetBitmap(self):
bmp = c4d.bitmaps.BaseBitmap()
bmp.Init(self.width,self.height)
for h in range(self.height):
for w in range(self.width):
r = random.randint(0, 70)
bmp.SetPixel(w, h, r, r, r)
return bmp
def DrawMsg(self, x1, y1, x2, y2, msg):
self.OffScreenOn()
self.SetClippingRegion(x1, y1, x2, y2)
self.DrawSetPen(c4d.Vector(1,0,0))
self.DrawRectangle(x1, y1, x2, y2)
if self.bmp_cache == None:
self.bmp_cache = self.GetBitmap()
self.DrawBitmap(self.bmp_cache, x1, y1, x2, y2, 0, 0,
w=self.bmp_cache.GetBw(),
h=self.bmp_cache.GetBh(),
mode=c4d.BMP_NORMAL)
def Message(self, msg, result):
# Catch the draw message to cancel it (return True)
# and call ourself the DrawMsg with the dimension we expect
if msg.GetId() == c4d.BFM_DRAW:
self.DrawMsg(0, 0, self.width, self.height, c4d.BaseContainer())
return True
return c4d.gui.GeUserArea.Message(self, msg, result)
def GetMinSize(self):
return self.width,self.height
class ExampleDialog(c4d.gui.GeDialog):
geUserArea = ExampleGeUserArea()
def DrawUA(self,scale):
self.geUserArea.width = int(400*scale)
self.geUserArea.height = int(500*scale)
self.LayoutChanged(SCROLL_ID)
def CreateLayout(self):
self.SetTitle("GeUserArea")
if self.ScrollGroupBegin(SCROLL_ID, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, c4d.SCROLLGROUP_HORIZ | c4d.SCROLLGROUP_VERT):
self.AddUserArea(GADGET_ID_GEUSERAREA, c4d.BFH_CENTER | c4d.BFH_SCALE | c4d.BFV_CENTER | c4d.BFV_SCALE, initw=gui.SizePix(400), inith=gui.SizePix(500))
self.AttachUserArea(self.geUserArea, GADGET_ID_GEUSERAREA)
self.GroupEnd()
return True
def Message(self, msg, result):
device = msg.GetLong(c4d.BFM_INPUT_DEVICE)
channel = msg.GetLong(c4d.BFM_INPUT_CHANNEL)
if device == c4d.BFM_INPUT_KEYBOARD:
if channel==69:
#E
print("E pressed.")
return c4d.gui.GeDialog.Message(self, msg, result)
def main():
global dlg
dlg = ExampleDialog()
dlg.Open(c4d.DLG_TYPE_ASYNC, pluginid=1234567, defaultw=300, defaulth=300)
if __name__ == "__main__":
main()
Thank you.
Hello!
I'm rendering an image in my plugin with documents.RenderDocument() and using StatusSetSpin().
With the code below, I'm using RenderDocument()'s prog
parameter function to update the Status progress bar. Currently this code shows the spinner, but the render progress isn't given until after the rendering has completed which is unexpected. With the progress_type
RENDERPROGRESSTYPE_DURINGRENDERING
, I'd expect the function to execute during rendering rather than afterwards. Perhaps it is, but the UI gets frozen during rendering. With longer renders (like with the Zombie - Toon Rig scene from the Content Browser), the StatusBar doesn't get cleared with the code I have below. Here are my questions:
import c4d
from c4d import documents
def updateProgressBar(p, progress_type):
if progress_type == c4d.RENDERPROGRESSTYPE_BEFORERENDERING:
print("Before Rendering")
c4d.StatusSetText('Initializing render...')
c4d.StatusSetSpin()
elif progress_type == c4d.RENDERPROGRESSTYPE_DURINGRENDERING:
print(p)
c4d.StatusSetText('Rendering...')
c4d.StatusSetSpin()
elif progress_type == c4d.RENDERPROGRESSTYPE_AFTERRENDERING:
print("After Rendering")
c4d.StatusClear()
c4d.EventAdd()
def main(doc):
rd = doc.GetActiveRenderData().GetData()
bmp = c4d.bitmaps.BaseBitmap()
bmp.Init(int(rd[c4d.RDATA_XRES]), int(rd[c4d.RDATA_YRES]), 24)
documents.RenderDocument(doc, rd, bmp, c4d.RENDERFLAGS_EXTERNAL, prog=updateProgressBar)
c4d.StatusClear()
c4d.StatusSetText('Render complete.')
c4d.EventAdd()
if __name__=='__main__':
main(doc)
Thank you!
Hello,
I'm having an issue where, when I release my mouse click outside of my font chooser, the text disappears until a new font is chosen. The Command function is still receiving a FontData BaseContainer message even when nothing is showing in the FontChooser.
How can I prevent this disappearance from happening?
import c4d, random
from c4d import gui
GADGET_ID_GEUSERAREA = 10000
FONT_CHOOSER = 10001
SLIDER_ID = 10002
class ExampleDialog(c4d.gui.GeDialog):
fontChooser = None
def CreateLayout(self):
self.SetTitle("Font Chooser")
self.GroupBorderSpace(50,50,50,50)
self.fontChooser = self.AddCustomGui(FONT_CHOOSER, c4d.CUSTOMGUI_FONTCHOOSER, "Bitmap Button", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 0, 0)
return True
def InitValues(self):
defaultFont = c4d.bitmaps.GeClipMap.GetDefaultFont(c4d.GE_FONT_DEFAULT_SYSTEM)
defaultFontName = c4d.bitmaps.GeClipMap.GetFontName(defaultFont, c4d.GE_FONT_NAME_POSTSCRIPT)
defaultFontBC = c4d.bitmaps.GeClipMap.GetFontDescription(defaultFontName, c4d.GE_FONT_NAME_POSTSCRIPT)
self.fontChooser.SetFont(defaultFontBC)
return True
def Command(self,id,msg):
print(id)
for cid,val in msg:
print(cid,val)
return True
def main():
global dlg
dlg = ExampleDialog()
dlg.Open(c4d.DLG_TYPE_ASYNC, pluginid=1234567, xpos=-2, ypos=-2, defaultw=600, defaulth=300)
if __name__ == "__main__":
main()
Thank you!