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.