Collapsing/Foldable Groups in Python?



  • On 17/11/2013 at 18:53, xxxxxxxx wrote:

    I seem to remember being told this wasn't possible in Python, but now I'm wanting to double check this.

    When doing User Data, if you put something in a new group, that group can be foldable/collapsable.

    Is there any way to do this in a GeDialog in Python?

    To see what I mean create a cube, look in the Coords tab. The Freeze Transformation can be collapses. I'm looking to be able to do that in my GeDialog plugin.



  • On 18/11/2013 at 04:05, xxxxxxxx wrote:

    Hi Bret,

    unfortunately the groupflag which makes the group foldable is broken. It is however possible by using a
    button/userarea widget and the GeDialog.HideElement() function.

    Here's a quick example:

     

    >
    > import c4d
    > import weakref
    >
    > class FoldUa(c4d.gui.GeUserArea) :
    >
    > def __init__(self, dlg, wid, parent_id, state_1=None, state_2=None) :
    > super(FoldUa, self).__init__()
    > self.dlg = weakref.ref(dlg)
    > self.wid = wid
    > self.parent_id = parent_id
    > self.hidden = False
    >
    > if not state_1: state_1 = c4d.RESOURCEIMAGE_PLUS
    > if not state_2: state_2 = c4d.RESOURCEIMAGE_SUBGROUP
    > self.state_1 = state_1
    > self.state_2 = state_2
    > print self.state_1, self.state_2
    >
    > def Toggle(self, notify=True) :
    > self.hidden = not self.hidden
    > self.SetState(self.hidden, notify)
    >
    > def SetState(self, hidden, notify=True) :
    > self.hidden = bool(hidden)
    > self.dlg().HideElement(self.wid, self.hidden)
    > if notify:
    > self.LayoutChanged()
    > self.dlg().LayoutChanged(self.parent_id)
    >
    > def GetStateIcon(self) :
    > if self.hidden:
    > icon = self.state_1
    > else:
    > icon = self.state_2
    >
    > if isinstance(icon, int) :
    > icon = c4d.gui.GetIcon(icon)
    > elif isinstance(icon, dict) :
    > pass
    > elif isinstance(icon, c4d.bitmaps.BaseBitmap) :
    > w, h = icon.GetSize()
    > icon = {'x': 0, 'y': 0, 'w': w, 'h': h, 'bmp': icon}
    > elif not icon:
    > pass
    > else:
    > raise TypeError('Expected int, dict or BaseBitmap for state field.')
    >
    > return icon
    >
    > def DrawMsg(self, x1, y1, x2, y2, msg) :
    > self.DrawSetPen(c4d.COLOR_BG)
    > self.DrawRectangle(x1, y1, x2 - 1, y2 - 1)
    >
    > icon = self.GetStateIcon()
    > if not icon: return
    > self.DrawBitmap(icon['bmp'], 0, 0, icon['w'], icon['h'],
    > icon['x'], icon['y'], icon['w'], icon['h'],
    > c4d.BMP_ALLOWALPHA)
    >
    > def InputEvent(self, msg) :
    > 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_MOUSELEFT:
    > self.Toggle()
    > return True
    >
    > def GetMinSize(self) :
    > icon = self.GetStateIcon()
    > if icon:
    > return (icon['w'], icon['h'])
    > else:
    > return (0, 0)
    >
    > class Dialog(c4d.gui.GeDialog) :
    >
    > GRP_FOLDABLE = 1000
    > EDT_SOMEFIELD = 1001
    >
    > def __init__(self) :
    > super(Dialog, self).__init__()
    > self.__foldindex = 10000
    > self.__folduas = {}
    >
    > def GroupBeginFoldable(self, id, flags, *args, **kwargs) :
    > self.GroupBegin(self.__foldindex, flags, 0, 1)
    > ua = FoldUa(self, id, self.__foldindex)
    > self.__foldindex += 1
    >
    > self.AddUserArea(self.__foldindex, 0)
    > self.AttachUserArea(ua, self.__foldindex)
    > self.__folduas[self.__foldindex] = ua
    > self.__foldindex += 1
    >
    > return self.GroupBegin(id, flags, *args, **kwargs)
    >
    > def GroupEndFoldable(self) :
    > self.GroupEnd()
    > self.GroupEnd()
    >
    > # c4d.gui.GeDialog
    >
    > def CreateLayout(self) :
    > if self.GroupBeginFoldable(self.GRP_FOLDABLE, c4d.BFH_SCALEFIT, 0, 1) :
    > self.AddStaticText(0, 0, name="Field")
    > self.AddEditSlider(self.EDT_SOMEFIELD, c4d.BFH_SCALEFIT)
    > self.GroupEndFoldable()
    >
    > self.AddDlgGroup(c4d.DLG_CANCEL)
    > return True
    >
    > def Command(self, wid, msg) :
    > if wid == c4d.DLG_CANCEL:
    > self.Close()
    > return True
    >
    > dlg = Dialog()
    > dlg.Open(c4d.DLG_TYPE_MODAL_RESIZEABLE)

    Best,
    -Niklas



  • On 18/11/2013 at 07:30, xxxxxxxx wrote:

    Is there a way though to make it so it will display the group name still?



  • On 18/11/2013 at 11:17, xxxxxxxx wrote:

    Requires a bit more hacky approach using a 2-level group call.

    import c4d
    import weakref
      
    class FoldUa(c4d.gui.GeUserArea) :
      
        minsize = (10, 10)
      
        def __init__(self, dlg, wid, parent_id, state_1=None, state_2=None) :
            super(FoldUa, self).__init__()
            self.dlg = weakref.ref(dlg)
            self.wid = wid
            self.parent_id = parent_id
            self.hidden = False
      
            if not state_1: state_1 = c4d.RESOURCEIMAGE_PLUS
            if not state_2: state_2 = c4d.RESOURCEIMAGE_SUBGROUP
            self.state_1 = state_1
            self.state_2 = state_2
      
        def Toggle(self, notify=True) :
            self.hidden = not self.hidden
            self.SetState(self.hidden, notify)
      
        def SetState(self, hidden, notify=True) :
            self.hidden = bool(hidden)
            self.dlg().HideElement(self.wid, self.hidden)
            if notify:
                self.LayoutChanged()
                self.dlg().LayoutChanged(self.parent_id)
      
        def GetStateIcon(self) :
            if self.hidden:
                icon = self.state_1
            else:
                icon = self.state_2
      
            if isinstance(icon, int) :
                icon = c4d.gui.GetIcon(icon)
            elif isinstance(icon, dict) :
                pass
            elif isinstance(icon, c4d.bitmaps.BaseBitmap) :
                w, h = icon.GetSize()
                icon = {'x': 0, 'y': 0, 'w': w, 'h': h, 'bmp': icon}
            elif not icon:
                pass
            else:
                raise TypeError('Expected int, dict or BaseBitmap for state field.')
      
            return icon
      
        def DrawMsg(self, x1, y1, x2, y2, msg) :
            self.DrawSetPen(c4d.COLOR_BGFOCUS)
            self.DrawRectangle(x1, y1, x2 - 1, y2 - 1)
      
            icon = self.GetStateIcon()
            if not icon: return
      
            x = (self.GetWidth() - icon['w']) / 2
            y = (self.GetHeight() - icon['h']) / 2
            self.DrawBitmap(icon['bmp'], x, x, icon['w'], icon['h'],
                            icon['x'], icon['y'], icon['w'], icon['h'],
                            c4d.BMP_ALLOWALPHA)
      
        def InputEvent(self, msg) :
            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_MOUSELEFT:
                self.Toggle()
            return True
      
        def GetMinSize(self) :
            icon = self.GetStateIcon()
            if icon:
                return tuple(map(max, zip(self.minsize, (icon['w'], icon['h']))))
            else:
                return tuple(self.minsize)
      
    class Dialog(c4d.gui.GeDialog) :
      
        GRP_FOLDABLE = 1000
        EDT_SOMEFIELD = 1001
      
        def __init__(self) :
            super(Dialog, self).__init__()
            self.__foldindex = 10000
            self.__folduas = {}
      
        def GroupBeginFoldable(self, id, flags, rows=0, cols=0, title="",
                    groupflags=0, initw=0, inith=0) :
            id_ua = self.__foldindex
            id_group = self.__foldindex + 1
            self.__foldindex += 2
      
            self.GroupBegin(id, flags, 2, 0, title, groupflags, initw, inith)
            self.__continue_data = (id, flags, rows, cols, title, groupflags,
                    initw, inith, id_ua, id_group)
      
            return True
      
        def GroupContinueFoldable(self) :
            if not self.__continue_data:
                raise RuntimeError('No foldable group opened.')
      
            (id, flags, rows, cols, title, groupflags,
                    initw, inith, id_ua, id_group) = self.__continue_data
            self.__continue_data = None
      
            # Column 1: User Area
            ua = FoldUa(self, wid=id_group, parent_id=id)
            self.__folduas[id_ua] = ua
            self.AddUserArea(id_ua, 0)
            self.AttachUserArea(ua, id_ua)
      
            # Column 2: The inner group.
            self.GroupBegin(id_group, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT,
                    rows, cols, title, groupflags, initw, inith)
      
            return True
      
        def GroupEndFoldable(self) :
            self.GroupEnd()
            self.GroupEnd()
      
        # c4d.gui.GeDialog
      
        def CreateLayout(self) :
            if self.GroupBeginFoldable(self.GRP_FOLDABLE, c4d.BFH_SCALEFIT, 0, 1,
                                       title="Foldable Group") :
                self.GroupBorder(c4d.BORDER_GROUP_TOP | c4d.BORDER_WITH_TITLE)
                self.GroupContinueFoldable()
      
                self.AddStaticText(0, 0, name="Field")
                self.AddEditSlider(self.EDT_SOMEFIELD, c4d.BFH_SCALEFIT)
                self.GroupEndFoldable()
      
            self.AddDlgGroup(c4d.DLG_CANCEL)
            return True
      
        def Command(self, wid, msg) :
            if wid == c4d.DLG_CANCEL:
                self.Close()
            return True
      
    dlg = Dialog()
    dlg.Open(c4d.DLG_TYPE_MODAL_RESIZEABLE)
    


  • On 19/11/2013 at 02:20, xxxxxxxx wrote:

    I think one thing worth mentioning in that context is also, that GeDialog.LoadDialogRessource 
    does not overwrite the dialogs ressources, but appends the IDs content to the dialog.


Log in to reply