Simon Brown Posted July 3, 2011 Share Posted July 3, 2011 This tutorial shows you how to use rules in IndirectUI to selectively disable controls and create a "constrain sliders" option. I wrote this a while ago in response to a question by Cookies, but I decided I should publish it properly. View tutorial 2 Quote Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted July 3, 2011 Share Posted July 3, 2011 Very informative. Thanks Simon, this has gone a long way to improving my understanding of IndirectUI. Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
BoltBait Posted July 3, 2011 Share Posted July 3, 2011 This is good information. I considered supporting this in CodeLab, but I couldn't come up with an easy way to specify the rules. Quote Click to play: Download: BoltBait's Plugin Pack | CodeLab | and how about a Computer Dominos Game Link to comment Share on other sites More sharing options...
Rick Brewster Posted August 1, 2011 Share Posted August 1, 2011 Pinned. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
Red ochre Posted July 27, 2014 Share Posted July 27, 2014 Is it possible to link two sliders by their values using the IndirectU.I. prop rules?I would like to link Maximum and Minimum sliders so that Maximum can never be lower than Minimum and vice versa.Exactly the same behaviour as Pyrochild has used in his 'Random Shape Fill' effect.I cannot work out how to use the 'LinkValuesBasedOnBooleanRule' without including a named checkbox on the U.I.Is it possible to create two simple bool values based on the current values of the sliders and use these in the rules?eg.(psuedo-code)//bool linkMax2Min = false;//bool linkMin2Max = false;// if(Minimum > Maximum){linkMax2Min = true;}//if (Maximum < Minimum) {linkMin2Max = true;}// create two new LinkValuesBasedOnBooleanRules to use these instead of visible checkboxes identified by strings?Ideally I would like to use this for my 'AlphaThreshold' effect, butif this requires converting to the CustomU.I. template then it is probably not worth the effort.(In the current version I simply swap the values in the code to prevent crashes - just means the sliders are lying! )Any help/example code would be very useful and much appreciated. Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
Rick Brewster Posted July 27, 2014 Share Posted July 27, 2014 What if you override OnCreateConfigUI(), clone the property collection you're giving but omit the boolean property that controls the linking, then pass the property collection to CreateDefaultConfigUI(), and use that? Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
Red ochre Posted July 28, 2014 Share Posted July 28, 2014 Thanks Rick - that sort of answers my question, in that there is no simple way.I think I will leave this for the imminent pack update, but I will refer back to your advice when I have a better understanding of how all these methods and tokens interact. ( I can be very 'slow' )Many Thanks - and have an enjoyable vacation, after Pdn 4 you've earned it! Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
midora Posted July 28, 2014 Share Posted July 28, 2014 Is it possible to link two sliders by their values using the IndirectU.I. prop rules? I would like to link Maximum and Minimum sliders so that Maximum can never be lower than Minimum and vice versa. I guess you are looking to the wrong type of rule. Try the following: new SoftMutuallyBoundMinMaxRule<int, Int32Property>(PropertyNames.MinInt32Slider,PropertyNames.MaxInt32Slider), new SoftMutuallyBoundMinMaxRule<double, DoubleProperty>(PropertyNames.MinDoubleSlider,PropertyNames.MaxDoubleSlider), 2 Quote Link to comment Share on other sites More sharing options...
Red ochre Posted July 28, 2014 Share Posted July 28, 2014 Wow! - Thank you so much Midora - perfect. I am an amatuer. A 'simple' problem like this has had me perplexed for years! I did look at the definition of LinkValuesBasedOnBooleanRule and searched MSDN for clues. May I ask how you found that rule as intellisense does not suggest anything? For other inexperienced plugin writers here is the relevant code: //Example of Linked Maximum and Minimum integer sliders //Using the code example supplied by Midora protected override PropertyCollection OnCreatePropertyCollection() { List<Property> props = new List<Property>(); props.Add(new Int32Property(PropertyNames.Amount1, 63, 0, 255));//Minimum slider props.Add(new Int32Property(PropertyNames.Amount2, 191, 0, 255));//Maximum slider List<PropertyCollectionRule> propRules = new List<PropertyCollectionRule>(); propRules.Add(new SoftMutuallyBoundMinMaxRule<int, Int32Property>(PropertyNames.Amount1, PropertyNames.Amount2)); return new PropertyCollection(props, propRules); } //for double sliders use "new SoftMutuallyBoundMinMaxRule<double, DoubleProperty>(PropertyNames.Amount1,PropertyNames.Amount2)" Thanks again! Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
midora Posted July 28, 2014 Share Posted July 28, 2014 I am an amatuer. A 'simple' problem like this has had me perplexed for years! Come on. You have written some quite expressive plugins for the community. May I ask how you found that rule as intellisense does not suggest anything? OK, but don't tell it someone else ;-) if you know a rule then you also know the namespace where the rule is defined. It's PaintDotNet.PropertySystem. You should expect that other rules are implemented in the same namespace. So open the class view and search for PaintDotNet.PropertySystem. And Voila you get all the classes defining properties and rules. Luckily Paint.NET is using meaningful names. This helps a lot together with IntelliSense. As always. It's easy if you know it. 2 Quote Link to comment Share on other sites More sharing options...
Red ochre Posted July 28, 2014 Share Posted July 28, 2014 Thanks for the additional info Midora. Very useful... but I won't tell Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
toe_head2001 Posted February 26, 2015 Share Posted February 26, 2015 It looks like all the rules in PropertySystem are boolean based. Is that correct? I had wanted a property to become enabled when an option in a dropdown was selected. I just want verify that I can't do that. Let me know. Thank You. Quote My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
midora Posted February 26, 2015 Share Posted February 26, 2015 Rules may use static list properties. I.e. // Disable UnitDPI if ModeChoiceList.Print OR ModeChoiceList.Model3D OR UnitChoiceList.Pixel propRules.Add(new ReadOnlyBoundToNameValuesRule(PropertyNames.UnitDPI, false, new Pair<object, object>[] { new Pair<object, object>(PropertyNames.ModeChoice, ModeChoiceList.Output), new Pair<object, object>(PropertyNames.ModeChoice, ModeChoiceList.Visualization), new Pair<object, object>(PropertyNames.UnitChoice, UnitChoiceList.Pixel)})); 1 Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted February 26, 2015 Share Posted February 26, 2015 (edited) Thank you for the example code. When I compile, I get an error telling me that it's obsolete. 'PaintDotNet.PropertySystem.ReadOnlyBoundToNameValuesRule.ReadOnlyBoundToNameValuesRule(object, bool, params PaintDotNet.Pair<object,object>[])' is obsolete: 'Use the overload' c:\users\-----documents\visual studio 2013\Projects\-------\-------.cs Excuse my ignorance, but what is this overload that it speaks of? Is there a work around besides compiling against an older version of paint.net? Edited February 26, 2015 by toe_head2001 Quote My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
midora Posted February 26, 2015 Share Posted February 26, 2015 Your project may use .NET 3.5 and reference to the dlls of 3.5.11. Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted February 26, 2015 Share Posted February 26, 2015 (edited) Thanks, I got it setup correctly now. The control should only enable when option 4 is selected, however the control is enabled when the dialog loads (the rule is not recognizing that option 1 is selected until it clicked). I think I know why Rick disabled this rule in v4... Is there a way I can manually disable the control on dialog load? Edited February 26, 2015 by toe_head2001 Quote My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
midora Posted February 26, 2015 Share Posted February 26, 2015 As long as you are creating PropertyBasedEffects you are not able to access the controls. For this you have to create your own effects or OptionBasedEffects. Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted February 26, 2015 Share Posted February 26, 2015 Thanks for all your help. I'll proceed with plan B. Quote My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
MJW Posted October 28, 2015 Share Posted October 28, 2015 (edited) toe_head2001: It looks like all the rules in PropertySystem are boolean based. Is that correct? I had wanted a property to become enabled when an option in a dropdown was selected. I just want verify that I can't do that.. It can be done by using ReadOnlyBoundToValueRule. The following code is based on what was originally a CodeLab plugin (hence the Amount variables). I want to disable the second control if the first option of the first control isn't selected. (It could be simplified by using the inverse option, and the version of the call that takes a single value instead of an array, but I wanted to show the more general case.) // Standard stuff. public enum Amount1Options { Amount1Option1, Amount1Option2, Amount1Option3 } protected override PropertyCollection OnCreatePropertyCollection() { // Standard stuff. List<Property> props = new List<Property>(); props.Add(StaticListChoiceProperty.CreateForEnum<Amount1Options>(PropertyNames.Amount1, 0, false)); props.Add(new Int32Property(PropertyNames.Amount2, ColorBgra.ToOpaqueInt32(ColorBgra.FromBgra(EnvironmentParameters.PrimaryColor.B,EnvironmentParameters.PrimaryColor.G,EnvironmentParameters.PrimaryColor.R,255)), 0, 0xffffff)); // Enable or disable the second control based on the first control, which is a drop-down list. // If either the second or third list item is selected, the second control is disabled. List<PropertyCollectionRule> propRules = new List<PropertyCollectionRule>(); propRules.Add(new ReadOnlyBoundToValueRule<object, StaticListChoiceProperty>(PropertyNames.Amount2, PropertyNames.Amount1, new object[] { Amount1Options.Amount1Option2, Amount1Options.Amount1Option3 }, false)); // Standard, except a second argument is added to the PropertyCollection call for the rules. return new PropertyCollection(props, propRules); } The call has the basic form: ReadOnlyBoundToValueRule<TValue, TProperty> The various versions of the call are: ReadOnlyBoundToValueRule(Property targetProperty, TProperty sourceProperty, TValue valueForReadOnly, bool inverse); ReadOnlyBoundToValueRule(Property targetProperty, TProperty sourceProperty, TValue[] valuesForReadOnly, bool inverse); ReadOnlyBoundToValueRule(object targetPropertyName, object sourcePropertyName, TValue valueForReadOnly, bool inverse); ReadOnlyBoundToValueRule(object targetPropertyName, object sourcePropertyName, TValue[] valuesForReadOnly, bool inverse); Edited October 28, 2015 by MJW 2 Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted January 1, 2016 Share Posted January 1, 2016 (edited) It can be done by using ReadOnlyBoundToValueRule. Thanks, I finally got around to using this. It also works well for disabling a control when a Slider is set at zero. propRules.Add(new ReadOnlyBoundToValueRule<int, Int32Property>(PropertyNames.Amount2, PropertyNames.Amount1, 0, false)); Edited January 1, 2016 by toe_head2001 Quote My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
MJW Posted October 2, 2021 Share Posted October 2, 2021 It is often desirable to have a control enabled and disabled by the state of more than one other control. For instance, a group of controls may be enabled when a checkbox is checked, and one of those controls may be disabled when a specific choice is selected in a dropdown list within that group. The obvious solution is to use ReadOnlyBoundToBooleanRule for the checkbox and ReadOnlyBoundToValueRule for the dropdown list. Unfortunately, that simple approach doesn't work. Each of the rules will act independently, so the control will be enabled and disabled according to whichever of the checkbox or list is last changed. Fortunately, there is a solution, which is discussed in more detail in another thread. In Rick's word, "There is an overload of the ReadOnlyBoundToValueRule constructor which takes an array of values." The array consists of pairs of controls and values for the control. If for any of the pairs, the control is equal to the value, the dependent control will be disabled, unless the second (invert) argument is true, in which case it will be enabled. (The "dependent control" is the control to be enabled and disabled depending on the state of other controls.) For instance (code adapted from BoltBait): propRules.Add(new ReadOnlyBoundToNameValuesRule(PropertyNames.DependentControl, false, new TupleStruct<object, object>[] { new TupleStruct<object, object>(PropertyNames.CheckBoxControl, false), new TupleStruct<object, object>(PropertyNames.ListControl, ValueThatDisablesDependentControl) })); The dependent control will disabled if either the checkbox is false or the list is set to the specific disabling value. One thing to be careful about is that if the default states of the other controls would result in the dependent control being disabled, it must be disabled at initialization [EDIT: Rick Brewster has indicated that this problem will no longer exist in PDN 4.3.2.] (code adapted from Null54): new Int32Property(PropertyNames.DependentControl, defaultValue, minValue, maxValue, true); Note: While this approach handles many common cases, I believe there are situations where there is no way to construct a rule that properly enables and disables a control for the desired combinations of controls and values. In other cases, it might be somewhat cumbersome. For example, if I wanted to disable the dependent control unless a specific list selection was made, I'd have to individually include in the array an entry pair for all but that specific value. EDIT: A nice feature would be to also allow an array of three-tuples consisting of two objects (the control and value) and a boolean. If the boolean were true, the condition would hold if the control matched the value; if the boolean were false, the condition would hold if the control didn't match the value. 1 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.