Jump to content

Tutorial: How to use IndirectUI rules


Recommended Posts

Very informative. Thanks Simon, this has gone a long way to improving my understanding of IndirectUI.

Link to comment
Share on other sites

  • 4 weeks later...
  • 2 years later...

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, but
if 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!   :lol: )

Any help/example code would be very useful and much appreciated.
 

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

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?

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

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'  :roll: )

Many Thanks - and have an enjoyable vacation, after Pdn 4 you've earned it! ;)

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

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),

  • Upvote 2

midoras signature.gif

Link to comment
Share on other sites

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!

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

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.

  • Upvote 2

midoras signature.gif

Link to comment
Share on other sites

  • 6 months later...

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.

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

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)}));
  • Upvote 1

midoras signature.gif

Link to comment
Share on other sites

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 by toe_head2001

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

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 by toe_head2001

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

  • 8 months later...

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 by MJW
  • Upvote 2
Link to comment
Share on other sites

  • 2 months later...

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 by toe_head2001

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

  • 5 years later...

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.

  • Thanks 1
  • Upvote 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...