Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    More Examples for GeUserArea?

    Cinema 4D SDK
    r21 python
    4
    7
    1.2k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B
      bentraje
      last edited by

      Hi,

      Are there other examples of the GeUserArea?
      In threads on the forum, the MemoryViewer 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

      1. Transparent background. I was thinking of adding background to the GeUserArea but a .PNG transparent one.
      2. 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 GeDialog

      Ultimately, 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=0

      Its my understanding that I could achieve this with GeUserArea.

      Is this correct? If so, how?

      Thank you for looking at my problem.

      1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand
        last edited by ferdinand

        Hi,

        a GeUserArea is just a custom GeDialog gadget. And no, you cannot achieve alpha blending with a GeUserArea, 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

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 2
        • M
          m_adam
          last edited by

          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.

          MAXON SDK Specialist

          Development Blog, MAXON Registered Developer

          1 Reply Last reply Reply Quote 1
          • B
            bentraje
            last edited by

            @zipit
            Thanks for the answer

            RE: 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 is AddButton 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 the cinema4d_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=0

            RE: 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.

            1 Reply Last reply Reply Quote 0
            • ferdinandF
              ferdinand
              last edited by ferdinand

              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
              zipit

              import 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)
              

              MAXON SDK Specialist
              developers.maxon.net

              1 Reply Last reply Reply Quote 3
              • B
                bentraje
                last edited by

                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.

                1 Reply Last reply Reply Quote 0
                • JH23J
                  JH23
                  last edited by

                  This post is deleted!
                  1 Reply Last reply Reply Quote 0
                  • First post
                    Last post