hello dear community.
unfortunately i haven´t found anything in the forum regarding this issue.
i wonder whether it is possible to add dynamically inputpins to a dynamic plugin, basically like we can do in the stallone node. and if yes, how can i call the fields?
thank you all
aiv
thats as simple as normal pins:
[Input("Input", IsPinGroup = true)] ISpread<ISpread<YourType>> FInput;
But what if you want to add & delete pins from within the plug-in and not through the user editing values with the Inspektor? Are there any examples or do we have to bang our heads against the plug-in specs to find out if there is a way?
For example I would like to create more convenient Cons nodes that auto-magically changes input pin count so there's always one empty NIL pin to the right so you can just connect stuff without trying to foresee how many inputs you'll need or constantly have to use the Inspektor to change the input count as your needs change.
to create pins like this have a look at
VVVV.Hosting.Pins.PinFactory.CreatePin(IPluginHost host, PinAttribute attribute)
where attributes is either an Input-, Output- or ConfigAttribute.
you delete those pins via their Dispose method.
mind you, when implementing your example you might run into two issues:
if you don't go the route via a config pin i fear connecting your node will fail.
i tried to write down a first draft, didn't test this code or anything, just to give you a clue how to address the whole thing. hope it helps!
using System; using System.Collections.Generic; using System.ComponentModel.Composition; using VVVV.Hosting.Pins; using VVVV.PluginInterfaces.V2; namespace VVVV.Nodes { public class AdvancedCons<T> : IPluginEvaluate, IPartImportsSatisfiedNotification { [Config("Input Count", DefaultValue = 2)] public IDiffSpread<int> FInputCountConfigPin; [Import] protected IPluginHost2 FPluginHost; private readonly List<Pin<T>> FInputPins = new List<Pin<T>>(); private Pin<T> FLastPin; public void OnImportsSatisfied() { FInputCountConfigPin.Changed += FInputCountConfigPing_Changed; // Not sure if Changed is raised here after, // otherwise you'll have to raise it yourself } private Pin<T> LastPin { get { return FLastPin; } set { if (FLastPin != null) { FLastPin.Connected -= HandleLastPinConnected; FLastPin.Disconnected -= HandleLastPinDisconnected; } FLastPin = value; if (FLastPin != null) { FLastPin.Connected += HandleLastPinConnected; FLastPin.Disconnected += HandleLastPinDisconnected; } } } void HandleInputCountConfigPinChanged(IDiffSpread<int> inputCountConfigPin) { // Create new pins and set LastPin accordingly for (int i = FInputPins.Count; i < inputCountConfigPin.SliceCount; i++) { Pin<T> pin = PinFactory.CreatePin<T>(FPluginHost, new InputAttribute(string.Format("Input {0}", i))); LastPin = pin; } // Delete old pins and set LastPin accordingly for (int i = FInputPins.Count - 1; i >= inputCountConfigPin.SliceCount; i--) { Pin<T> pin = FInputPins[i]; FInputPins.Remove(pin); LastPin = FInputPins[FInputPins.Count - 1]; pin.Dispose(); } } void HandleLastPinConnected(object sender, PinConnectionEventArgs args) { // This should trigger HandleInputCountConfigPinChanged FInputCountConfigPin[0]++; } void HandleLastPinDisconnected(object sender, PinConnectionEventArgs args) { // This should trigger HandleInputCountConfigPinChanged FInputCountConfigPin[0]--; } public void Evaluate(int SpreadMax) { throw new NotImplementedException(); } } }
thank you tonfilm.
um.. but i cannot do
ISpread<ISpread<ISpread<string>>> FMyFieldName;
right? In a way that autmatically for each FMyFieldName Pin a BinSize-Pin BinSize-Pin is created too?
at least i get exeptions..
right can't do that, thats not implemented.
i tried something similar, but i get weird exceptions. unfortunately the documentation is not really good for that kind of stuff.
what i eventually want to do is create input and output pins according to a configurable scheme.
can you point me in the right direction?
#region usings using System; using System.ComponentModel.Composition; using VVVV.PluginInterfaces.V1; using VVVV.PluginInterfaces.V2; using VVVV.Utils.VColor; using VVVV.Utils.VMath; using VVVV.Core.Logging; #endregion usings namespace VVVV.Nodes { #region PluginInfo [PluginInfo(Name = "Sender", Category = "Event", Help = "Basic template with one value in/out", Tags = "")] #endregion PluginInfo public class EventSenderNode : IPluginEvaluate { #region fields & pins [Input("Create", DefaultValue = 0.0)] ISpread<bool> FCreate; [Output("Output")] ISpread<double> FOutput; [Import()] ILogger FLogger; IPluginHost2 FHost; IPinFactory PinFactory; #endregion fields & pins //called when data for any output pin is requested public void Evaluate(int SpreadMax) { FOutput.SliceCount = SpreadMax; if (FCreate[0]) { InputAttribute att = new InputAttribute("test"); att.DefaultValue = 0; att.Name = "test"; Pin<double> pin = PinFactory.CreatePin<double>(att); } for (int i = 0; i < SpreadMax; i++) FOutput[i] = 2; //FLogger.Log(LogType.Debug, "hi tty!"); } } }
you have to remove the IPinFactory line, import IPluginHost or IPluginHost2 and then call the static class PinFactory.CreatePin(...).
i keep getting the same runtime exception if i use this instead:
edit: put in the recommended change
#region usings using System; using System.ComponentModel.Composition; using VVVV.PluginInterfaces.V1; using VVVV.PluginInterfaces.V2; using VVVV.Utils.VColor; using VVVV.Utils.VMath; using VVVV.Core.Logging; #endregion usings namespace VVVV.Nodes { #region PluginInfo [PluginInfo(Name = "Sender", Category = "Event", Help = "Basic template with one value in/out", Tags = "")] #endregion PluginInfo public class EventSenderNode : IPluginEvaluate { #region fields & pins [Input("Create", DefaultValue = 0.0)] ISpread<bool> FCreate; [Output("Output")] ISpread<double> FOutput; [Import()] ILogger FLogger; [Import()] IPluginHost2 FHost; #endregion fields & pins //called when data for any output pin is requested public EventSenderNode() { // IValueOut pin; // FHost.CreateValueOutput("config", 1, new string[] {"x"}, TSliceMode.Single, TPinVisibility.True, out pin); } public void Evaluate(int SpreadMax) { FOutput.SliceCount = SpreadMax; if (FCreate[0]) { IValueOut pin; FHost.CreateValueOutput("test", 1, new string[] {"x"}, TSliceMode.Dynamic, TPinVisibility.True, out pin); } for (int i = 0; i < SpreadMax; i++) FOutput[i] = 2; //FLogger.Log(LogType.Debug, "hi tty!"); } } }
don't you miss anImport above the IPluginHost2 FHost line?
yes, each field needs its own import attribute, i think thats the only thing you got wrong...
thanks, works nicely.
hi velcrome , it would be nice to see some of your working approaches .
proper documentation will follow, but as of yesterday a new development branch made it into develop where pin creation was refactored. if you use the sdk, pull in latest changes from upstream and have a look at the dynamic plugin Template (Value DynamicPins) to see how to create a stallone like node.
thanks
i found a little bit of time to continue working on it and quickly hit the next wall.
the current state of the plugin is still basic, it behaves pretty much like a decons but without the magic of PinGroup, because I want the output pins to be named dynamically.
the wall is when i reload the patch- the dynamically produced pins are gone and if i recreate them during the first evaluate, the corrupt links are long deleted. creating them in the constructor gives exceptions and the method SetPluginHost does not work with V2-plugs.
how would i go about this?
to use the host in the constructor, you need to use the ImportingConstructor and Import tag together with the constructor. search the forums, there are some examples.
i tried everything that was listed in a bunch of threads, but still the same exception :(
you need to import the host in the constructor as well.
oh, now i found another problem. you cannot read the pin values in the constructor. if you want to define pin names by a pin you have to consider a Config pin and do the pin creation in the config callback.
ok, thanks for the tip. the exception is gone at last.
but this plugin idea keeps on throwing problems at me. somehow it seems that the Config pins are buggy. They yield different results depending if they are used before the first frame or during later times. For example string-typed configs cannot be used correctly before first frame if they contain more than one slice.
found the time to work some more on the idea of dynamic data stream joining and splitting.
most of the functionality of creating pins has been done with the old plugin interface. creating the dynamic pins when loading the v4p was possible by storing all information in config pins.
the code is kinda messy, but as a prototype it serves well so far. unfortunately the spread-behavior of the config pins remains somewhat unstable, especially in boygrouped environments (try ctrl+b the MessageConfig) and restart the client to see what i mean).
anonymous user login
~5min ago
~45min ago
~56min ago
~2h ago
~3h ago
~3h ago
~5h ago
~5h ago
~8h ago