More Examples for GeUserArea?
-
Hi,
Are there other examples of the GeUserArea?
In threads on the forum, theMemoryViewer example
is often referred. But it's far off from my usage.
The API documentation doesn't also present a quickstart example.Like the previous threads, I am aiming for
- Transparent background. I was thinking of adding background to the GeUserArea but a .PNG transparent one.
- Just a column of modified buttons with corresponding commands
As confirmed here, transparency is not possible with GeDialog.
As confirmed here, its not possible to format/highlight buttons with GeDialogUltimately, I wanted something like in Blender functionality of pop-up as you can see here:
https://www.dropbox.com/s/8dhs505yz34lap3/c4d140_modified_popup_menu.mp4?dl=0Its my understanding that I could achieve this with GeUserArea.
Is this correct? If so, how?
Thank you for looking at my problem.
-
Hi,
a
GeUserArea
is just a customGeDialog
gadget. And no, you cannot achieve alpha blending with aGeUserArea
, as the underlying dialog will always be opaque. At least not alpha blending in the way you want it. You can totally draw an item with a non-rectangular shape, but you cannot have other elements shine through your gadget like shown in your video. You also cannot and stack dialog gadgets within a dialog (draw one on top of another).If you want some sort of semi-transparent menu in an editor view, which is letting the scene geometry shine through, your only option is to draw directly into a
BaseDraw
. But I am not really sure if you could achieve there something like in your video. You would definitely have to prerender some stuff into bitmaps and then blend these bitmaps.What are the parts of
GeUserArea
you don`t understand \ need an example for? I could provide some code, but mine is probably not better than what Maxon offers.Cheers
zipit -
Hi @bentraje there is no way at the moment to make a transparency background. But I've forward the idea to our development team.
Regarding List of icon and command, you can do it with a GeDialog, a group with multiple columns of BitmapButtonCustomGui.
Regarding more examples of GeUserArea: Take a look in the GitHub repository, especially geuserarea_basic_r13.py.
But if you have an idea about example, feel free to create an issue with the IDEA tag or even to contribute.
Cheers,
Maxime. -
@zipit
Thanks for the answerRE: a GeUserArea is just a custom GeDialog gadget.
Thanks for the clarification. I thought they were separated based on the documentation.RE: What are the parts of GeUserArea you dont understand \ need an example for?
It's just a list of text with their commands (i.e. they are clickable).
In the GeDialog, there isAddButton
but there seems to be no equivalent with GeUserArea.@m_adam
Thanks for the answer.RE: cinema4d_py_sdk_extended
Is this new? Huh. Indeed there is some GeUserArea examples. I was looking at thecinema4d_py_sdk
because I got it bookmarked but it seems like this is already old (deprecated).RE: GuiDialog
Yes, I was able to create one with the help of the forum. But I was having a problem with the highlighting when you hover. And the "button" looking like buttons. I just want them to be a text that I can click.
You can see an illustration here:
https://www.dropbox.com/s/dvk3mghn2s2ox8t/c4d141_highlight_hovered_button.mp4?dl=0RE: BitmapButtonCustomGui.
Thanks for pointing it out. But may I ask how do I implement it?
I couldn't see an example in the scripts directory.The closest reference I have in the forum is this thread
But its only a snippet. I'm not sure how to add it to the actual code. -
Hi,
you have to invoke
AddUserArea
and then attach an instance of your implemented type to it. Something like this:my_user_area = MyUserAreaType() self.AddUserArea(1000,*other_arguments) self.AttachUserArea(my_user_area, 1000)
I have attached an example which does some things you are trying to do (rows of things, highlighting stuff, etc.). The gadget is meant to display a list of boolean values and the code is over five years old. I had a rather funny idea of what good Python should look like then and my attempts of documentation were also rather questionable. I just wrapped the gadget into a quick example dialog you could run as a script. I did not maintain the code, so there might be newer and better ways to do things now.
Also a warning: GUI stuff is usually a lot of work and very little reward IMHO.
Cheers
zipitimport c4d import math import random from c4d import gui # Pattern Gadget IDC_SELECTLOOP_CELLSIZE = [32, 32] IDC_SELECTLOOP_GADGET_MINW = 400 IDC_SELECTLOOP_GADGET_MINH = 32 class ExampleDialog(gui.GeDialog): """ """ def CreateLayout(self): """ """ self.Pattern = c4d.BaseContainer() for i in range(10): self.Pattern[i] = random.choice([True, False]) self.PatternSize = len(self.Pattern) self.gadget = Patterngadget(host=self) self.AddUserArea(1000, c4d.BFH_FIT, 400, 32) self.AttachUserArea(self.gadget, 1000) return True class Patterngadget(gui.GeUserArea): """ A gui gadget to modify and display boolean patterns. """ def __init__(self, host): """ :param host: The hosting BaseToolData instance """ self.Host = host self.BorderWidth = None self.CellPerColumn = None self.CellWidht = IDC_SELECTLOOP_CELLSIZE[0] self.CellHeight = IDC_SELECTLOOP_CELLSIZE[1] self.Columns = None self.Height = None self.Width = None self.MinHeight = IDC_SELECTLOOP_GADGET_MINH self.MinWidht = IDC_SELECTLOOP_GADGET_MINW self.MouseX = None self.MouseY = None """------------------------------------------------------------------------ Overridden methods --------------------------------------------------------------------""" def Init(self): """ Init the gadget. :return : Bool """ self._get_colors() return True def GetMinSize(self): """ Resize the gadget :return : int, int """ return int(self.MinWidht), int(self.MinHeight) def Sized(self, w, h): """ Get the gadgets height and width """ self.Height, self.Width = int(h), int(w) self._fit_gadget() def Message(self, msg, result): """ Fetch and store mouse over events :return : bool """ if msg.GetId() == c4d.BFM_GETCURSORINFO: base = self.Local2Screen() if base: self.MouseX = msg.GetLong(c4d.BFM_DRAG_SCREENX) - base['x'] self.MouseY = msg.GetLong(c4d.BFM_DRAG_SCREENY) - base['y'] self.Redraw() self.SetTimer(1000) return gui.GeUserArea.Message(self, msg, result) def InputEvent(self, msg): """ Fetch and store mouse clicks :return : bool """ if not isinstance(msg, c4d.BaseContainer): return True if msg.GetLong(c4d.BFM_INPUT_DEVICE) == c4d.BFM_INPUT_MOUSE: if msg.GetLong(c4d.BFM_INPUT_CHANNEL) == c4d.BFM_INPUT_MOUSELEFT: base = self.Local2Global() if base: x = msg.GetLong(c4d.BFM_INPUT_X) - base['x'] y = msg.GetLong(c4d.BFM_INPUT_Y) - base['y'] pid = self._get_id(x, y) if pid <= self.Host.PatternSize: self.Host.Pattern[pid] = not self.Host.Pattern[pid] self.Redraw() return True def Timer(self, msg): """ Timer loop to catch OnMouseExit """ base = self.Local2Global() bc = c4d.BaseContainer() res = gui.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, bc) mx = bc.GetLong(c4d.BFM_INPUT_X) - base['x'] my = bc.GetLong(c4d.BFM_INPUT_Y) - base['y'] if res: if not (mx >= 0 and mx <= self.Width and my >= 0 and my <= self.Height): self.SetTimer(0) self.Redraw() def DrawMsg(self, x1, y1, x2, y2, msg): """ Draws the gadget """ # double buffering self.OffScreenOn(x1, y1, x2, y2) # background & border self.DrawSetPen(self.ColBackground) self.DrawRectangle(x1, y1, x2, y2) if self.BorderWidth: self.DrawBorder(c4d.BORDER_THIN_IN, x1, y1, self.BorderWidth + 2, y2 - 1) # draw pattern for pid, state in self.Host.Pattern: x, y = self._get_rect(pid) self._draw_cell(x, y, state, self._is_focus(x, y)) """------------------------------------------------------------------------ Public methods --------------------------------------------------------------------""" def Update(self, cid=None): """ Update the gadget. :param cid: A pattern id to toggle. """ if cid and cid < self.Host.PatternSize: self.Host.Pattern[cid] = not self.Host.Pattern[cid] self._fit_gadget() self.Redraw() """------------------------------------------------------------------------ Private methods --------------------------------------------------------------------""" def _get_colors(self, force=False): """ Set the drawing colors. :return : Bool """ self.ColScale = 1.0 / 255.0 if self.IsEnabled() or force: self.ColBackground = self._get_color_vector(c4d.COLOR_BG) self.ColCellActive = c4d.GetViewColor( c4d.VIEWCOLOR_ACTIVEPOINT) * 0.9 self.ColCellFocus = self._get_color_vector(c4d.COLOR_BGFOCUS) self.ColCellInactive = self._get_color_vector(c4d.COLOR_BGEDIT) self.ColEdgeDark = self._get_color_vector(c4d.COLOR_EDGEDK) self.ColEdgeLight = self._get_color_vector(c4d.COLOR_EDGELT) else: self.ColBackground = self._get_color_vector(c4d.COLOR_BG) self.ColCellActive = self._get_color_vector(c4d.COLOR_BG) self.ColCellFocus = self._get_color_vector(c4d.COLOR_BG) self.ColCellInactive = self._get_color_vector(c4d.COLOR_BG) self.ColEdgeDark = self._get_color_vector(c4d.COLOR_EDGEDK) self.ColEdgeLight = self._get_color_vector(c4d.COLOR_EDGELT) return True def _get_cell_pen(self, state, _is_focus): """ Get the color for cell depending on its state. :param state : The state :param _is_focus : If the cell is hoovered. :return : c4d.Vector() """ if state: pen = self.ColCellActive else: pen = self.ColCellInactive if self.IsEnabled() and _is_focus: return (pen + c4d.Vector(2)) * 1/3 else: return pen def _draw_cell(self, x, y, state, _is_focus): """ Draws a gadget cell. :param x: local x :param y: local y :param state: On/Off :param _is_focus: MouseOver state """ # left and top bright border self.DrawSetPen(self.ColEdgeLight) self.DrawLine(x, y, x + self.CellWidht, y) self.DrawLine(x, y, x, y + self.CellHeight) # bottom and right dark border self.DrawSetPen(self.ColEdgeDark) self.DrawLine(x, y + self.CellHeight - 1, x + self.CellWidht - 1, y + self.CellHeight - 1) self.DrawLine(x + self.CellWidht - 1, y, x + self.CellWidht - 1, y + self.CellHeight - 1) # cell content self.DrawSetPen(self._get_cell_pen(state, _is_focus)) self.DrawRectangle(x + 1, y + 1, x + self.CellWidht - 2, y + self.CellHeight - 2) def _get_rect(self, pid, offset=1): """ Get the drawing rect for an array id. :param pid : the pattern id :param offset : the pixel border offset :return : int, int """ pid = int(pid) col = pid / self.CellPerColumn head = pid % self.CellPerColumn return self.CellWidht * head + offset, self.CellHeight * col + offset def _get_id(self, x, y): """ Get the array id for a coord within the gadget. :param x : local x :param y : local y :return : int """ col = (y - 1) / self.CellHeight head = (x - 1) / self.CellWidht return col * self.CellPerColumn + head def _is_focus(self, x, y): """ Test if the cell coords are under the cursor. :param x : local x :param y : local y :return : bool """ if (self.MouseX >= x and self.MouseX <= x + self.CellWidht and self.MouseY >= y and self.MouseY <= y + self.CellHeight): self.MouseX = c4d.NOTOK self.MouseY = c4d.NOTOK return True else: return False def _fit_gadget(self): """ Fit the gadget size to the the array """ oldHeight = self.MinHeight self.CellPerColumn = int((self.Width - 2) / self.CellWidht) self.Columns = math.ceil( self.Host.PatternSize / self.CellPerColumn) + 1 self.MinHeight = int(IDC_SELECTLOOP_GADGET_MINH * self.Columns) + 3 self.MinWidht = int(IDC_SELECTLOOP_GADGET_MINW) self.BorderWidth = self.CellWidht * self.CellPerColumn if oldHeight != self.MinHeight: self.LayoutChanged() def _get_color_vector(self, cid): """ Get a color vector from a color ID. :param cid : The color ID :return : c4d.Vector() """ dic = self.GetColorRGB(cid) if dic: return c4d.Vector(float(dic['r']) * self.ColScale, float(dic['g']) * self.ColScale, float(dic['b']) * self.ColScale) else: return c4d.Vector() if __name__ == "__main__": dlg = ExampleDialog() dlg.Open(c4d.DLG_TYPE_ASYNC, defaultw=400, defaulth=400)
-
Hi @zipit
Apologies for the late response.
Your code sample looks interesting. And yep, close to what I was looking for. Stacking columns of clickable images/text
I keep looking back at it every now and then but I have to admit, it's beyond me at the moment really beyond me at the moment.Maybe I was just a bit spoiled with other GUI interface such as tkinter or PyQT, where it is relatively easy to implement.
Just copy some code and modify some parts. Or maybe there are just more available examples in tkinter and PyQT that fits my need.Will get back to this topic when I have the necessary skillset.
Sorry for the trouble and thanks again.