Can REAL MIN / MAX value be changed on Init?
-
Hello @mocoloco,
Thank you for reaching out to us. To change values in a description, or to add or remove elements from it, you must modify the c4d.Description of the node instance by overwriting c4d.NodeData.GetDDescription.
This is the only way to do this as the description returned by
c4d.C4DAtom.GetDescription
is a copy and changes to it will not be reflected by the node. One therefore can only modify the description of nodes for which one has access to their implementation (with the exception of the special description sub container for user data, i.e.,ID_USERDATA
). There are multiple GetDDescription examples to be found in our GitHub code examples, I also have provided a short example for your exact case below. The makeup of the description data container is documented on the c4d.Description page.Cheers,
FerdinandResult:
Description Resource:
// The description defintion of the tag Tmmover. CONTAINER Tmmover { NAME Tmmover; INCLUDE Texpression; // The main "Tag" tab of the tag. GROUP ID_TAGPROPERTIES { // ... GROUP { // The parameter to modify the MAX values dynamically for. REAL ID_OFF_X { MIN 0.0; MAX 100.0; UNIT METER; STEP 0.001; CUSTOMGUI REALSLIDER; } // Used to determine if ID_OFF_X.MAX and ID_OFF_X.MAXLSIDER should be 10. or 100. BOOL ID_OFF_X_SHORT {} } } }
Code:
def GetDDescription(self, node: c4d.GeListNode, description: c4d.Description, flags: int) -> typing.Union[bool, tuple[bool, int]]: """Called by Cinema 4D when the description of a node is being evaluated to let the node dynamically modify its own description. """ # Bail when the description cannot be/is not fully loaded. if not description.LoadDescription(node.GetType()): return False, flags # The parameter we want to modify and the parameter which is currently queued to be # evaluated by the description. offxParamId: c4d.DescID = c4d.DescID(c4d.DescLevel(c4d.ID_OFF_X, c4d.DTYPE_REAL, 0)) singleId: c4d.DescID = description.GetSingleDescID() print (f"{singleId = }") # Bail when there is a to be evaluated parameter and our parameter is not part off or equal # to the to be evaluated parameter. We could also do our modifications without this check but it # ensures that the modification is only done once per cycle and therefore much more # performant. if singleId and not offxParamId.IsPartOf(singleId): return True, flags # Get the description data container instance (GetParameter>I<) for the parameter we want to # modify. All changes made to the container will be directly reflected on the node. offxDesc: c4d.BaseContainer = description.GetParameterI(offxParamId) if offxDesc is None: return True, flags # Write the MAX and MAXSLIDER values based on the state of "off.x.short" checkbox state. offxDesc[c4d.DESC_MAX] = 10. if node[c4d.ID_OFF_X_SHORT] else 100. offxDesc[c4d.DESC_MAXSLIDER] = 10. if node[c4d.ID_OFF_X_SHORT] else 100. return True, flags | c4d.DESCFLAGS_DESC_LOADED
-
Hello @ferdinand, Thanks a lot for all the informations. So there is a way to get it work, glad to hear and read all of this!
I'm going to have a look on this deeper now I have a lead, and see how I can manage this. As I'm going to change those values only once at first run once some UserDatas are loaded, I think the impact on performance will be really limited.
Have a good day and thanks for the tips!
Cheers,Christophe
-
Hey @mocoloco,
I think the impact on performance will be really limited.
I am not quite sure how you mean that, but when my code comments about performance were the cause, you should not be worried. Cinema 4D evaluates the description of nodes quite often. When the description of a node must be evaluated, Cinema 4D will call
GetDDescription
multiple times, usually at least once per parameter a node has, but often also many times more.The minimal node has at least ten parameters as the description base and things like groups also do count. So, when you click on something on a node, this will then result in at least ten, but more likely something like fifteen
GetDDescription
calls for such minimal node. For substantial nodes, for example materials, you can easily end up with hundreds of calls for every interaction. The idea I line out in the code above, is then to avoid setting for exampleDESC_MAX
for every one of these calls (and trigger all sorts of things by doing so), but only for the one call where the description signals viaGetSingleDescID
that it this parameter's turn to be modified.Even when you do everything wrong and you write data multiple times, nothing would get really slow, as for one plugin the impact will always be negligible. It would only become a problem when every plugin would do that. But when you follow the pattern from above, you should be good to go.
Cheers,
Ferdinand -
Hi @ferdinand,
Thanks for clarifying, and I indeed noticed by the past when looking for bugs and printing some values in console that indeed
GetDDescription
are called multiple time. In my case, the change of the slider values will only occurs once.The scene loaded contains some UserData that will be used to set sliders MIN/MAX. Once done, they will be no change needed.
So in my case theGetDDescription
call will still multiple but the changed will be skipped once done. But it is good to indeed clarify this point.Cheers,
Christophe -
Hi @ferdinand,
For an unknown reason, that does not work. I do not get any errors, but anyways, the sliders MIN/MAX values remains identical to the value sets in Resource file.
I sat up almost the same code, and so I was wondering if there is a way to reach the
c4d.DESC_MIN
parameters by correctly setting up thedescID
of the sliders and use instead thedescription.SetParameters(descID, param, groupID)
. I just didn't find the right declaration to get is work.For a correct understanding, here the Resource .res,
// The description defintion of the tag Tmmover. CONTAINER Tmmover { NAME Tmmover; INCLUDE Texpression; // The main "Tag" tab of the tag. GROUP ID_TAGPROPERTIES { // ... GROUP { REAL ID_X { MIN -100.0; MAX 100.0; UNIT DEGREE; STEP 0.005; CUSTOMGUI REALSLIDER; } REAL ID_Y { MIN -50.0; MAX 50.0; UNIT DEGREE; STEP 0.005; CUSTOMGUI REALSLIDER; } } } }
Code,
global Parameters Parameters = dict() Parameters['Xmin'] = -25.0 Parameters['Xmax'] = 25.0 def GetDDescription(self, node, description, flags): global Parameters if not description.LoadDescription(node.GetType()): return False # Change Slider limits accordingly to the UserData loaded into the global dict() named Parameters # Sliders to modify: ID_X, ID_Y ## AXIS X paramID_X: c4d.DescID = c4d.DescID(c4d.DescLevel(c4d.ID_X, c4d.DTYPE_REAL, 0)) singleId: c4d.DescID = description.GetSingleDescID() print (f"{singleId = }") # Bail when there is a to be evaluated parameter and our parameter is not part off or equal # to the to be evaluated parameter. if singleId and not paramID_X.IsPartOf(singleId): return True, flags # Get the description data container instance (GetParameter>I<) for the parameter we want to modify desc_X c4d.BaseContainer = description.GetParameterI(paramID_X) if desc_X is None: return True, flags # Write the MAX and MAXSLIDER values based on Parameters values print(f"min { Parameters['Xmin'] } / max {Parameters['Xmax']}" ) desc_X[c4d.DESC_MIN] = Parameters["Xmin"] desc_X[c4d.DESC_MINSLIDER] = Parameters["Xmin"] desc_X[c4d.DESC_MAX] = Parameters["Xmax"] desc_X[c4d.DESC_MAXSLIDER] = Parameters["Xmax"] # Not Working, no errors, but something should be wrong here # How to define SetParameter with the new correct values that are set into the Parameter dictionary? # description.SetParameter(singleId, desc_X, paramID_X) return (True, flags | c4d.DESCFLAGS_DESC_LOADED)
Help would be appreciated as I do not understand why it is not working while your example is...
Cheers,
Christophe -
Hello @mocoloco,
Since I provided an example which does the exact same thing above, I am fairly certain that my code does work ;). Notice that I show in the GIF-screencast both the slider and edit field range changing. Does your code hit the statement
print(f"min { Parameters['Xmin'] } / max {Parameters['Xmax']}" )
and what does that print? Have you tried overwriting something likeDESC_NAME
andDESC_SHORT_NAME
to be sure that things are indeed 'not working, no errors'?Also: The double
global
keyword for the module attributeParameters
is a bit weird. One never does require the keywordglobal
in a module scope (outside of function, method, or class definitions). And you only need it in a local scope (e.g., a method) when you want to write to an object that lives in a module scope. So, you do not needglobal
here at all. But that should not break anything in this case (I think), but still a bit odd to do.[...] and use instead the description.SetParameters(descID, param, groupID). I just didn't find the right declaration to get is work [..]
There is no
Description.SetParameters
, I assume you mean.SetParameter
. But doing that would not change much. You must still retrieve the data container with.GetParameter
. When you use.GetParameterI
as I did, you rid yourself of the necessity of writing the container back, as you retrieve the actual container object and not a copy of it.When you are determined on using
.SetParameter
, you must be able to address the group the parameter is contained in. You cannot do this here directly, since the group you two parameters are in is anonymous (the group insideID_TAGPROPERTIES
). So, you would have to look intoDESC_PARENTGROUP
in the description data of your parameter to get the ID of the group the parameter is parented to. Then you can define the groupDescID
asgroupDescId = c4d.DescID(idFromFileOrDescriptionData, c4d.DTYPE_GROUP, 0)
.Cheers,
Ferdinand -
Hello @ferdinand,
Thanks for your reply. To answer you to all your question in order,
Yes, my code hit the statement
print(f"min { Parameters['Xmin'] } / max {Parameters['Xmax']}" )
and I'm getting in console the followingsingleId = (1551, 0, 0) min -25.0 / max 25.0
I was a bit afraid about what you confirmed me, that,
.SetParameter()
wouldn't change anything about writing the values. So there should be something else...I'm going to test this part of the code independently with this only assignment and see if it works or not.
About
global
, I read the both in Python doc and it wasn't that clear if the global need to be specified inside the method's class or not asParameters
is defined as global, and outside of the class. What I noticed, is if I do not mention the global inGetDDescription()
methods I'm getting error in console saying thatParameters
is use prior being assigned, which means somehow Python do not see and look for the global var namedParameters
. That error never occurred once global is specified inGetDDescription()
, but yes, it is weird.I'm keeping you in touch about the next tests.
Cheers,
Christophe -
I found the problem. For a reason I can't explain, going through the new assignment once on the first call of
GetDDescription()
isn't enough. I thought that I could do the change once on first plugin TAG load/use, then avoid to going through this change each timeGetDDescription()
is called. But that's isn't the case. It seems that the change need to be perpetual and need to be parsed and evaluated constantly to be seen and changed in the interface ( honestly I found this weird and not really optimised in terms of coding ).So, by getting rid of the flag
FIRST_INIT
(which wasn't in the code above), the code does work as expected.Maybe could you explain me why this repetitive reassignment is needed?
Thanks a lot for your prompt support and all detailed explanation you are providing, it does help a lot.
Cheers,Christophe
-
There is something weird going on. I intend to change several sliders accordingly to
Parameters
,ID_X
andID_Y
.
I adapted the code accordingly, but it seems that onlyDESC_MAXSLIDER
andDESC_MINSLIDER
are took into account whileDESC_MIN
andDESC_MAX
stick to previous values. Could that be a bug?I let in remarks the code that improve a bit better the result and allows
ID_X
to be fully set (MIN/MAX as well as MINSLIDER/MAXSLIDER), but the problems remains onID_Y
.Here the whole code of
GetDDescription()
,global Parameters Parameters = dict() Parameters['Xmin'] = -360.0 Parameters['Xmax'] = 360.0 Parameters['Ymin'] = -25.0 Parameters['Ymax'] = 25.0 def GetDDescription(self, node, description, flags): if not description.LoadDescription(node.GetType()): return False # Change Slider limits accordingly to Parameters values # Sliders to modifiy ID_X, ID_Y ## SLIDER ID_X if len(Parameters) > 0: paramID_X: c4d.DescID = c4d.DescID(c4d.DescLevel(ID_X, c4d.DTYPE_REAL, 0)) single_X: c4d.DescID = description.GetSingleDescID() # Bail when there is a to be evaluated parameter and our parameter is not part off or equal to the to be evaluated parameter. if single_X and not paramID_X.IsPartOf(single_X): return True, flags # if singleId[0] == mAXIS_X: print (f"singleID found: {singleId} ") # Get the description data container instance (GetParameter>I<) for the parameter we want to modify desc_X: c4d.BaseContainer = description.GetParameterI(paramID_X) if desc_X is None: return True, flags # if single_X and paramID_X.IsPartOf(single_X): # if paramID_A1.IsPartOf(single_X)[0]: # Write the MAX and MAXSLIDER values based on UserDatas desc_X[c4d.DESC_MIN] = c4d.utils.DegToRad(Parameters["Xmin"]) desc_X[c4d.DESC_MINSLIDER] = c4d.utils.DegToRad(Parameters["Xmin"]) desc_X[c4d.DESC_MAX] = c4d.utils.DegToRad(Parameters["Xmax"]) desc_X[c4d.DESC_MAXSLIDER] = c4d.utils.DegToRad(Parameters["Xmax"]) # if single_X and paramID_X.IsPartOf(single_X): # if paramID_X.IsPartOf(single_X)[0]: # print (f"Found X: {paramID_X.IsPartOf(single_X)[0]} ") # return (True, flags | c4d.DESCFLAGS_DESC_LOADED) ## SLIDER ID_Y paramID_Y: c4d.DescID = c4d.DescID(c4d.DescLevel(mAXIS_Y, c4d.DTYPE_REAL, 0)) single_Y: c4d.DescID = description.GetSingleDescID() # Bail when there is a to be evaluated parameter and our parameter is not part off or equal to the to be evaluated parameter. if single_Y and not paramID_Y.IsPartOf(single_Y): return True, flags # Get the description data container instance (GetParameter>I<) for the parameter we want to modify desc_Y: c4d.BaseContainer = description.GetParameterI(paramID_Y) if desc_Y is None: return True, flags # Write the MAX and MAXSLIDER values based on UserDatas desc_Y[c4d.DESC_MIN] = c4d.utils.DegToRad(Parameters["Ymin"]) desc_Y[c4d.DESC_MINSLIDER] = c4d.utils.DegToRad(Parameters["Ymin"]) desc_Y[c4d.DESC_MAX] = c4d.utils.DegToRad(Parameters["Ymax"]) desc_Y[c4d.DESC_MAXSLIDER] = c4d.utils.DegToRad(Parameters["Ymax"]) # if single_Y and paramID_A2.IsPartOf(single_Y): # if paramID_Y.IsPartOf(single_Y)[0]: # print (f"Found Y: {paramID_Y.IsPartOf(single_Y)[0]} ") # return (True, flags | c4d.DESCFLAGS_DESC_LOADED) return (True, flags | c4d.DESCFLAGS_DESC_LOADED)
Does this trick to change REALSLIDER MIN/MAX values intend to be associated to only on change, and not on several UI object?
Thanks in advance,
Cheers,Christophe
-
You can add the following code to see the values before and after new assignment. You will see that the values are correctly changed, but the change does not reach the interface for unknown reason.
for k,v in desc_Y: print(f"Y New, Key {k} / Val {v}")
-
Hey @mocoloco,
So, I gave it a spin and the root of your problems is that you defined your parameters as
UNIT DEGREE
where you and I usedMETER
in the first examples. When you do so, you must define your values in radians, not degree when you write into the raw data.But there are also some weird things going on with
DEGREE
. First of all, min-max slider values are always set tonull\None
in the description container, no matter how often you write the values, and the general min/max values seem to be used instead. One could sort of make sense of that, but what is really weird how the first parameter in a group does behave.
Fig. I - Unit Degree: We set the min-max range and name for both parameters. Setting the name works on both, but the first parameter adopts a clamped range which is a weird mix of its old and new value. The second parameter works fine.Running the same code but using
METER
as a unit works without any issues.
Fig. II - Unit Meter: Here both parameters work flawlessly.There is either a bug in the degree description handling, or you must jump through some hoops and set up the data in a specific way. I will not have the time to test this in more detail before next week. To help yourself, I would suggest defining either via user-data or a resource file a
REAL DEGREE
parameter and then reading out all its description values, looking for anything special that might be going on.Cheers,
FerdinandCode:
"""Implements a tag which drives the position of a host object procedurally or via tracks. """ import c4d import typing class DynamicDescriptionTagData(c4d.plugins.TagData): """Implements a tag which drives the position of a host object procedurally or via tracks. """ # The plugin ID. ID_PLUGIN: int = 1060463 # What you dubbed "user data", a dictionary holding some description data to be injected at # runtime. I just changed things a bit up and include/identify things over their ID instead # of made-up strings, but nothing would prevent you from having both, it would just be a bit # more complicated to parse such data: # # INTERFACE_DATA = [ # { # "label": "Foo", # "id": c4d.DescId(...), # "data": [ # {"label": "Name", "id": c4d.DESC_NAME, "value": "Bar"}, # ... # ] # }, # ... # ] INTERFACE_DATA: list[tuple[c4d.DescID, dict[int, typing.Any]]] = [ (c4d.DescID(c4d.DescLevel(c4d.ID_OFF_X, c4d.DTYPE_REAL, 0)), { c4d.DESC_NAME: "foo.x", c4d.DESC_SHORT_NAME: "foo.x", c4d.DESC_MIN: c4d.utils.DegToRad(-360.), c4d.DESC_MAX: c4d.utils.DegToRad(360.), }), (c4d.DescID(c4d.DescLevel(c4d.ID_OFF_Y, c4d.DTYPE_REAL, 0)), { c4d.DESC_NAME: "bar.y", c4d.DESC_SHORT_NAME: "bar.y", c4d.DESC_MIN: c4d.utils.DegToRad(-45.), c4d.DESC_MAX: c4d.utils.DegToRad(45.), }), ] DID_PARENT_GROUP: c4d.DescID = c4d.DescID(c4d.DescLevel(c4d.ID_GRP_STUFF, c4d.DTYPE_GROUP, 0)) def Init(self, node: c4d.GeListNode) -> bool: """Called to initialize a DynDescription tag instance. Args: node: The BaseTag instance representing this plugin object. """ self.InitAttr(node, float, c4d.ID_OFF_X) self.InitAttr(node, float, c4d.ID_OFF_Y) node[c4d.ID_OFF_X] = 0. node[c4d.ID_OFF_Y] = 0. return True def Execute(self, tag: c4d.BaseTag, doc: c4d.documents.BaseDocument, op: c4d.BaseObject, bt: c4d.threading.BaseThread, priority: int, flags: int) -> int: """Called when expressions are evaluated to let a tag modify a scene. Does nothing in this example. """ return c4d.EXECUTIONRESULT_OK def GetDDescription(self, node: c4d.GeListNode, description: c4d.Description, flags: int) -> typing.Union[bool, tuple[bool, int]]: """Called by Cinema 4D when the description of a node is being evaluated to let the node dynamically modify its own description. """ # Bail when the description cannot/is not fully loaded. if not description.LoadDescription(node.GetType()): return False, flags singleId: c4d.DescID = description.GetSingleDescID() for paramId, dataDictionary in DynamicDescriptionTagData.INTERFACE_DATA: if (singleId and not paramId.IsPartOf(singleId)): return True, flags data: c4d.BaseContainer = description.GetParameterI(paramId) if data is None: return True, flags for key, value in dataDictionary.items(): data[key] = value print (f"{data[key]} ({key})") return True, flags | c4d.DESCFLAGS_DESC_LOADED def RegisterPlugins() -> None: """Registers the plugins contained in this file. """ if not c4d.plugins.RegisterTagPlugin( id=DynamicDescriptionTagData.ID_PLUGIN, str="DynDescription Tag", info=c4d.TAG_EXPRESSION | c4d.TAG_VISIBLE, g=DynamicDescriptionTagData, description="tdyndescription", icon=c4d.bitmaps.InitResourceBitmap(c4d.ID_MODELING_MOVE)): print("Warning: Failed to register 'DynDescription' tag plugin.") if __name__ == "__main__": RegisterPlugins()
Resource
// The description defintion of the tag Tdyndescription. CONTAINER Tdyndescription { NAME Tdyndescription; INCLUDE Texpression; // The main "Tag" tab of the tag. GROUP ID_TAGPROPERTIES { // A subcontainer, just to keep the example the same. GROUP ID_GRP_STUFF { // Your two parameters, we will drive their min, max, and name valumes // dynamically. REAL ID_OFF_X { MIN -90.0; MAX 90.0; UNIT METER; STEP 0.005; CUSTOMGUI REALSLIDER; } REAL ID_OFF_Y { MIN -90.0; MAX 90.0; UNIT METER; STEP 0.005; CUSTOMGUI REALSLIDER; } } } }
#ifndef _TDYNDESCRIPTION_H_ #define _TDYNDESCRIPTION_H_ enum { ID_GRP_STUFF = 2000, ID_OFF_X = 1000, ID_OFF_Y, } #endif // _TDYNDESCRIPTION_H_
STRINGTABLE Tdyndescription { Tdyndescription "DynDescription"; ID_OFF_X "off.x"; ID_OFF_Y "off.y"; }
-
Hi @ferdinand,
Thanks a lot for your time on this and sorry for the wrong unit on the first example I submitted with
METERS
instead ofDEGREES
- at the sometime it seems that it raised some kind of bug link to this ^^.Like you wrote, I did convert the value in Radian for all the Parameters and so, but anyway the problem seems linked to the simultaneous use of
UNIT DEGREES; CUSTOMGUI REALSLIDER
in the resource file.I ran a couple of tests and I noticed the following:
• When only usingREAL
withoutCUSTOMGUI REALSLIDER;
in the resource file, the field behaves as it should and limits changes works as expected
• When usingCUSTOMGUI REALSLIDER;
withUNIT METERS;
it does work as well as expected
• When usingUNIT PERCENT;
withMIN -100.0; MAX 100.0
and assigning the values by multiplying the slider value byParameters[--max]
, printing and assigning the result to aSTATICTEXT
it displays the right value in degree or rad depending on the final conversion made prior display.
• When assigningUNIT DEGREES;
withCUSTOMGUI REALSLIDER
, I'm getting weird behaviour like said previously and like you noticed.I haven't had the time to ran test today with
INTERFACE_DATA
like you suggested. I will try to do that tomorrow and I will keep you in touch about this.Cheers,
Christophe -
Hey @mocoloco,
No need to be sorry. For
UNIT PERCENT
you will have to write values as decimal values, i.e.,100%
is1.0
.The root problem is the weird behavior of
MINSLIDERS
andMAXSLIDERS
not being written when messing with the description when the unit is percent. The best way to check for possible "tricks", would be to inspect a valid existing description for aREAL, UNIT DEGREE
parameter to see what is what.And as stated in my last posting, I unfortunately will not have the time to debug this this week, but I will give it a spin next week.
Cheers,
Ferdinand -
Hi @ferdinand,
I was quite sure indeed that
UNIT PERCENT
will work, but I give a try to see. What I do not understand is, when I'm printing all the values existing indesc_X
ordesc_Y
, they looks good, the value is correct, but not took completely into account on the drawing side forCUSTOMGUI REALSLIDER
.Like I said, if I remove the
CUSTOMGUI REALSLIDER;
option in the resource file and using REAL as a standard input field, whatever theUNIT
I'm using, everything behaves correctly.MIN/MAX
values are correctly assigned even though there is multipleREAL
that need to be change. That let me lead like you to a bug linked toCUSTOMGUI REALSLIDER
when only usingUNIT DEGREE
.No problem to have a look on this next week. I can deal with that for the moment using
PERCENT
, as is produce slightly the same result. It is just not really convenient to guess a percentage for an angle, but that's OK.Many thanks,
Cheers,Christophe
-
Hey @mocoloco,
I had time to revisit this today with less time pressure than I had before. I made some mistakes in my prior answer:
MINSLIDER
andMAXSLIDER
are being written even when the unit isDEGREE
- Being the first item or not in a group is irrelevant for the problem, the determining factor is if the new range is larger or smaller than the old one.
- When one overwrites an edit and slider range with a range that is larger than the old one, and the unit is degree:
- Both the edit and slider range remain the old value for the user when interacting with the GUI,
- But the position of the slider know on the slider bar reflects the new value, with the side effect that the user cannot drag the knob all the way, as the range is still clamped to the old values.
- And the description data that are stored reflect the new value.
- For any other unit other than
DEGREE
this does not happen.
You can see here the effect for the same plugin I used in my prior posting, where both parameters are initialized as
[-90°, 90°]
. The first one is then changed to[-45°, 45°]
and the second one to[-180°, 180°]
. The first parameter works fine, while the second one exhibits the effects described above with both the value and slider clamp range being unchanged while the slider position reflects the new value.
Fig. I: When the unit isDEGREE
, increasing the value and slider range will fail. Also shown here, I compare the description of our modifiedbar.y
parameter with a user data parameter of the same date type, unit, and range. The values are identical.I also talked with one of our GUI developers and he does not see any problems with the code we use either. This is very likely a bug, since the data in the description is the same (
bar.y
anddata.x
in the example screen cast above and the print out below), but treated differently, when and only when the unit isDEGREE
. I have filed an issue for that in our bug tracker.I currently also do not see any good workaround for this for you. You will have to wait for a fix or the dev untangling the core issue and telling us how you can work around this. I have for now classified the issue as low priority, which means it might take some time before we get to it.
Cheers,
FerdinandThe script to print out the description of the active tag I used in the example:
import c4d import typing DESC_MAP: dict[int: str] = { c4d.DESC_NAME: "DESC_NAME", c4d.DESC_SHORT_NAME: "DESC_SHORT_NAME", c4d.DESC_VERSION: "DESC_VERSION", c4d.DESC_CHILDREN: "DESC_CHILDREN", c4d.DESC_MIN: "DESC_MIN", c4d.DESC_MAX: "DESC_MAX", c4d.DESC_MINEX: "DESC_MINEX", c4d.DESC_MIN: "DESC_MIN", c4d.DESC_MAXEX: "DESC_MAXEX", c4d.DESC_MAX: "DESC_MAX", c4d.DESC_STEP: "DESC_STEP", c4d.DESC_ANIMATE: "DESC_ANIMATE", c4d.DESC_ANIMATE_MIX: "DESC_ANIMATE_MIX", c4d.DESC_ASKOBJECT: "DESC_ASKOBJECT", c4d.DESC_UNIT: "DESC_UNIT", c4d.DESC_PARENTGROUP: "DESC_PARENTGROUP", c4d.DESC_CYCLE: "DESC_CYCLE", c4d.DESC_HIDE: "DESC_HIDE", c4d.DESC_DEFAULT: "DESC_DEFAULT", c4d.DESC_ACCEPT: "DESC_ACCEPT", c4d.DESC_SEPARATORLINE: "DESC_SEPARATORLINE", c4d.DESC_REFUSE: "DESC_REFUSE", c4d.DESC_PARENTID: "DESC_PARENTID", c4d.DESC_CUSTOMGUI: "DESC_CUSTOMGUI", c4d.DESC_COLUMNS: "DESC_COLUMNS", c4d.DESC_LAYOUTGROUP: "DESC_LAYOUTGROUP", c4d.DESC_REMOVEABLE: "DESC_REMOVEABLE", c4d.DESC_GUIOPEN: "DESC_GUIOPEN", c4d.DESC_EDITABLE: "DESC_EDITABLE", c4d.DESC_MINSLIDER: "DESC_MINSLIDER", c4d.DESC_MAXSLIDER: "DESC_MAXSLIDER", c4d.DESC_GROUPSCALEV: "DESC_GROUPSCALEV", c4d.DESC_SCALEH: "DESC_SCALEH", c4d.DESC_LAYOUTVERSION: "DESC_LAYOUTVERSION", c4d.DESC_ALIGNLEFT: "DESC_ALIGNLEFT", c4d.DESC_FITH: "DESC_FITH", c4d.DESC_NEWLINE: "DESC_NEWLINE", c4d.DESC_TITLEBAR: "DESC_TITLEBAR", c4d.DESC_CYCLEICONS: "DESC_CYCLEICONS", c4d.DESC_CYCLESYMBOLS: "DESC_CYCLESYMBOLS", c4d.DESC_PARENT_COLLAPSE: "DESC_PARENT_COLLAPSE", c4d.DESC_FORBID_INLINE_FOLDING: "DESC_FORBID_INLINE_FOLDING", c4d.DESC_FORBID_SCALING: "DESC_FORBID_SCALING", c4d.DESC_UNIT_METER: "DESC_UNIT_METER", c4d.DESC_ANGULAR_XYZ: "DESC_ANGULAR_XYZ", c4d.DESC_INPORT: "DESC_INPORT", c4d.DESC_OUTPORT: "DESC_OUTPORT", c4d.DESC_STATICPORT: "DESC_STATICPORT", c4d.DESC_NEEDCONNECTION: "DESC_NEEDCONNECTION", c4d.DESC_MULTIPLE: "DESC_MULTIPLE", c4d.DESC_PORTONLY: "DESC_PORTONLY", c4d.DESC_CREATEPORT: "DESC_CREATEPORT", c4d.DESC_PORTSMIN: "DESC_PORTSMIN", c4d.DESC_PORTSMAX: "DESC_PORTSMAX", c4d.DESC_NOTMOVABLE: "DESC_NOTMOVABLE", c4d.DESC_EDITPORT: "DESC_EDITPORT", c4d.DESC_ITERATOR: "DESC_ITERATOR", c4d.DESC_PARENTMSG: "DESC_PARENTMSG", c4d.DESC_MATEDNOTEXT: "DESC_MATEDNOTEXT", c4d.DESC_COLUMNSMATED: "DESC_COLUMNSMATED", c4d.DESC_SHADERLINKFLAG: "DESC_SHADERLINKFLAG", c4d.DESC_NOGUISWITCH: "DESC_NOGUISWITCH", c4d.DESC_COLORALWAYSLINEAR: "DESC_COLORALWAYSLINEAR", c4d.DESC_HIDE_WHEN_INLINE: "DESC_HIDE_WHEN_INLINE", c4d.DESC_MATERIALEDITOR_LEFTSIDE: "DESC_MATERIALEDITOR_LEFTSIDE", c4d.DESC_CHANGED: "DESC_CHANGED", c4d.DESC_HIDEINFIELDS: "DESC_HIDEINFIELDS", c4d.DESC_SHOWINFIELDS: "DESC_SHOWINFIELDS", c4d.DESC_FIELDCOLORCHANNEL: "DESC_FIELDCOLORCHANNEL", c4d.DESC_FIELDDIRECTIONCHANNEL: "DESC_FIELDDIRECTIONCHANNEL", c4d.DESC_FIELDVALUECHANNEL: "DESC_FIELDVALUECHANNEL", c4d.DESC_FIELDROTATIONCHANNEL: "DESC_FIELDROTATIONCHANNEL", c4d.DESC_NODEPORT: "DESC_NODEPORT", c4d.DESC_REPLACECOMPLEXUI: "DESC_REPLACECOMPLEXUI", c4d.DESC_REPLACE_HIDE: "DESC_REPLACE_HIDE", c4d.DESC_RESOURCEPATH: "DESC_RESOURCEPATH", c4d.DESC_RESOURCELINE: "DESC_RESOURCELINE", c4d.DESC_TEMPDESCID: "DESC_TEMPDESCID", c4d.DESC_IDENT: "DESC_IDENT", c4d.DESC_IDENT_ORIGIN: "DESC_IDENT_ORIGIN", c4d.DESC_DISABLELAYOUTSWITCH: "DESC_DISABLELAYOUTSWITCH", c4d.DESC_UNIMPORTANTFORDEFAULTS: "DESC_UNIMPORTANTFORDEFAULTS", } op: c4d.BaseObject # The active object. doc: c4d.documents.BaseDocument # The active document. def main(): """ """ tag: c4d.BaseTag = doc.GetActiveTag() if tag is None: return c4d.CallCommand(13957) line: str = "{} = {}" data: c4d.BaseContainer for data, _, _ in tag.GetDescription(c4d.DESCFLAGS_DESC_NONE): print ("\n" + ("-" * 100) + "\n") for did, label in DESC_MAP.items(): value: typing.Any = data[did] if value is None: continue if isinstance(value, c4d.BaseContainer): print(line.format(label, "")) for k, v in value: print(f"\t{k}: {v}") else: print(line.format(label, value)) if __name__ == "__main__": main()
Output:
[...] ---------------------------------------------------------------------------------------------------- DESC_NAME = foo.x DESC_ANIMATE_MIX = foo.x DESC_VERSION = 3 DESC_MIN = -0.7853981633974483 DESC_MAX = 0.7853981633974483 DESC_MINEX = 0 DESC_MAXEX = 0 DESC_STEP = 8.726646259971648e-05 DESC_ANIMATE = 1 DESC_UNIT = 1717856114 DESC_CUSTOMGUI = 1000489 DESC_MINSLIDER = -0.7853981633974483 DESC_MAXSLIDER = 0.7853981633974483 DESC_IDENT = ID_OFF_X ---------------------------------------------------------------------------------------------------- DESC_NAME = bar.y DESC_ANIMATE_MIX = bar.y DESC_VERSION = 3 DESC_MIN = -3.141592653589793 DESC_MAX = 3.141592653589793 DESC_MINEX = 0 DESC_MAXEX = 0 DESC_STEP = 8.726646259971648e-05 DESC_ANIMATE = 1 DESC_UNIT = 1717856114 DESC_CUSTOMGUI = 1000489 DESC_MINSLIDER = -3.141592653589793 DESC_MAXSLIDER = 3.141592653589793 DESC_IDENT = ID_OFF_Y ---------------------------------------------------------------------------------------------------- DESC_NAME = User Data DESC_ANIMATE_MIX = User Data DESC_DEFAULT = 1 DESC_IDENT = ID_USERDATA ---------------------------------------------------------------------------------------------------- DESC_NAME = data.x DESC_ANIMATE_MIX = data.x DESC_VERSION = 3 DESC_MIN = -3.141592653589793 DESC_MAX = 3.141592653589793 DESC_MINEX = 0 DESC_MAXEX = 0 DESC_STEP = 8.726646259971648e-05 DESC_ANIMATE = 1 DESC_UNIT = 1717856114 DESC_PARENTGROUP = (700, 5, 0) DESC_CUSTOMGUI = 1000489 DESC_REMOVEABLE = 1 DESC_EDITABLE = 1 DESC_MINSLIDER = -3.141592653589793 DESC_MAXSLIDER = 3.141592653589793
-
Good morning @ferdinand,
Thanks a lot for taking time going though this. That's exactly what I noticed last week. Changed are took into account but they are not reflected on the GUI. The only workaround that seems possible at this moment is to set
MIN/MAX
sliders values beyond the possible values that could be set on UserData. Doing so GUI should behave correctly.Could you please let this thread unsolved for the moment, the time we get a fix on this?
Have a great day,
Cheers, -
@mocoloco said in Can REAL MIN / MAX value be changed on Init?:
Could you please let this thread unsolved for the moment, the time we get a fix on this?
Typically, we track to be fixed issues with the to fix tag which I have also added to your thread here. With that we know where to look once we fixed the issue to announce the fix. What would be the advantage of letting this topic unsolved for you? Youl will also get notified when there is a new reply in a solved topic, e.g., us announcing that we fixed something.
Cheers,
Ferdinand -
Oh, I didn't know about the to fix tag. Keeping unsolved was much more for the community
I the meantime I setup the resource file as discussed, and indeed, having higher values prior setting them solve the GUI problem / which is a good fix for me.Thanks a lot,
Cheers,Christophe
-
-
Hi there,
Was the issue fixed on R2023 or R2024?Thanks,
Christophe