Strange behavior of UserArea docked with Timeline
-
Hi,
I am trying to use UserArea to draw a simple 4x4 grid in a dialog, and docking it with the Timeline.
The issue is when I click around the UserArea and the Timeline(which is built-in UserArea??), top and bottom edges of the UserArea behave strangely.
And when I tweak the size of the dialog to redraw the UserArea, it returns to normal.video:
https://drive.google.com/file/d/1arqRD-4y52WJfyI3QnlgN3oBpsuvfxcj/view?usp=sharing.pyp:
import c4d import os PLUGIN_ID = 9366042 # Random Number ID_UA = 1000 class TestUserArea(c4d.gui.GeUserArea): def DrawMsg(self, x1, y1, x2, y2, msg): self.OffScreenOn() self.SetClippingRegion(x1, y1, x2, y2) # Draw Background black = c4d.Vector(0) self.DrawSetPen(black) self.DrawRectangle(x1, y1, x2, y2) # Draw Grid white = c4d.Vector(1) self.DrawSetPen(white) w = self.GetWidth() h = self.GetHeight() for i in range(5): xpos = int(i*0.25*w) self.DrawLine(xpos, y1, xpos, y2) ypos = int(i*0.25*h) self.DrawLine(x1, ypos, x2, ypos) class TestDialog(c4d.gui.GeDialog): def CreateLayout(self): self.ua = TestUserArea() self.AddUserArea(ID_UA, c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT) self.AttachUserArea(self.ua, ID_UA) return True class TestData(c4d.plugins.CommandData): dialog = None def Execute(self, doc): if self.dialog is None: self.dialog = TestDialog() return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID) def RestoreLayout(self, sec_ref): if self.dialog is None: self.dialog = TestDialog() return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref) if __name__ == "__main__": path, file = os.path.split(__file__) bmp = c4d.bitmaps.BaseBitmap() bmp.InitWith(os.path.join(path, "res", "icon.tif")) c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID, str="TestUserArea", info=0, help="", dat=TestData(), icon=bmp)
The same issue can be seen with the official plugin sample Py-MemoryViewer.
In this one, Redraw() is called frequently, so it returns to normal display immediately.
https://drive.google.com/file/d/1vGgoPJ3ierUFBNdD92hUl7UuaKjkcE--/view?usp=sharingI know that this issue is not that critical, but is there any solution? Thank you.
-
Hi,
i tested your code with S24 and was unable to reproduce the behavior. Wath is the version that you are using?
Cheers,
Manuel -
@m_magalhaes
The versions I have checked are R21.207 and S24.037 on Windows.
I also checked with S24 on Mac and there was no problem.The problem shows up when it is docked next to the timeline, especially in the lower left corner of the animation layout like this.
-
hi,
I was able to reproduce it, after asking to @m_adam it's not a bug it's an optimisation.
The screen redraw happens from top left to bottom right. So, the coordinates sent to the UserArea will only contain what really need to be redraw. In our example, we don't take that into account.
As you can see in this screenshot, the UserArea is sliced in two but align with the attribut manager menu. (because I've clicked there)
The Draw function is called twice, one for the top part and one for the bottom part. That's why the grid is different and the memory appears various times.To fix that you can simply not redraw if the size sent to the DrawMsg function are not correct. To know if they are correct you can simply use the Sized function to retrieve the size of the UserArea and store it locally.
def Sized(self, w, h): self.h = h self.w = w def DrawMsg(self, x1, y1, x2, y2, msg_ref): """This Method is called automatically when Cinema 4D Draw the Gadget. Args: x1 (int): The upper left x coordinate. y1 (int): The upper left y coordinate. x2 (int): The lower right x coordinate. y2 (int): The lower right y coordinate. msg_ref (c4d.BaseContainer): The original mesage container. """ if x2-x1 < self.w: return if y2-y1 < self.h: return
Or you can use the same technique than @m_adam in this thread
Catch the draw message and call yourself the DrawMsg with the maximum size. (redraw everything)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)
Cheers,
Manuel -
Hi,
It looks like the problem got solved by Sized function.
Thanks a lot @m_magalhaes and @m_adam !!