Jump to content

Suggested "How to" topic: Non-PropertyBased controls


MJW
 Share

Recommended Posts

I wish someone who understands the subject would write a tutorial on using regular Visual Studio controls (non-PropertyBased controls) in plugins. I have some vague notion how it's done from looking at the code for Red ochre's Scribble plugin, but I'm not sure I understand exactly how the pieces fit together.

 

(I'd also like to encourage anyone who understands some matter of general interest to write a tutorial, the way BoltBait has done for CodeLab. I intend to try to do so.)

Edited by MJW
Link to comment
Share on other sites

I know how to create a regular VS Form, and if I didn't, I could find dozens of books and articles telling me how to do it. What I'd very much appreciate more details on, and which as far as I know isn't currently documented anywhere, is how to use the controls within the PDN plugin environment. As you mention, hooking up the UI controls to the Effect Tokens, and things like that. I'm not sure in what way declaring a WinForm to be an EffectConfigDialog makes it different from a standard WinForm class library project, but if it is different, I'd like to know about it. Most of the stuff I'd like to know, and which I think others might benefit from knowing, concerns how the token figures in to maintaining the control state and initiating traversals.

Edited by MJW
Link to comment
Share on other sites

I've made a simplified code example here. Not exactly a "How to" or a tutorial, but I hope my comments are sufficient.

This is your xyzConfigDialog.cs file. It acts as a WinForm file. See first code comment.

namespace xyzEffect
{
    // Notice it doesn't say " : Form", but rather " : EffectConfigDialog<xyzEffectPlugin, xyzConfigToken>"
    // Another option is simply " : EffectConfigDialog", but I don't like that option
    internal partial class xyzConfigDialog : EffectConfigDialog<xyzEffectPlugin, xyzConfigToken>
    {
        // Standard stuff here. No need to explain.
        public xyzConfigDialog()
        {
            InitializeComponent();
        }

        //When the checkbox is toggled it tells the Tokens to update
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            FinishTokenUpdate();
        }

        //When the numberBox is toggled it tells the Tokens to update
        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            FinishTokenUpdate();
        }


        // Initailized the Tokens from your xyzConfigToken.cs file
        protected override xyzConfigToken CreateInitialToken()
        {
            return new xyzConfigToken();
        }

        // Sets the UI control values from the stored token values
        protected override void InitDialogFromToken(xyzConfigToken fromToken)
        {
            checkBox1.Checked = fromToken.UseColor;
            numericUpDown1.Value = fromToken.Width;
        }

        //Sets the token values from the UI control values
        protected override void LoadIntoTokenFromDialog(xyzConfigToken toToken)
        {
            toToken.UseColor = checkBox1.Checked;
            toToken.Width = numericUpDown1.Value;
        }
    }
}
 

This is your xyzConfigToken.cs file

namespace xyzEffect
{
    // Notice the " : EffectConfigToken"
    class xyzConfigToken : EffectConfigToken
    {
        private bool t_useColor;
        private int t_width;

        // Initializes the configuration token
        public xyzConfigToken() : base()
        {
            t_useColor = true;
            t_width = 20;
        }

        private xyzConfigToken(bool useColor, int width)
        {
            t_useColor = useColor;
            t_width = width;
        }

        public override object Clone()
        {
            return new xyzConfigToken(t_useColor, t_width);
        }

        // These are the public functions that can be referrence from other classes
        public bool UseColor
        {
            get
            {
                return t_useColor;
            }
            set
            {
                t_useColor = value;
            }
        }
        public int Width
        {
            get
            {
                return t_width;
            }
            set
            {
                t_width = value;
            }
        }
    }
}
This is your xyzEffect.cs file

namespace xyzEffect
{
    // Notice the " : Effect<xyzConfigToken>", rather than " : PropertyBasedEffect"
    // Another option is simply " : Effect". Again, I don't like that option.
    internal class xyzEffectPlugin : Effect<xyzConfigToken>
    {

        ...

        bool useColor;
        int width; 

        // Inside OnSetRender, grab the saved Tokens so that your cool script can use their values.
        protected override void OnSetRenderInfo(xyzConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs)
        {
            useColor = newToken.UseColor;
            width = newToken.Width;
        }

        ...

        // The rest is standard stuff...

Edited by toe_head2001
  • Upvote 2
Link to comment
Share on other sites

MJW some of the Dwarves collaborated on such a guide. I will send you a PM and a link.

  • Upvote 3
Link to comment
Share on other sites

I would like to see a tutorial (including links to resources) on how to use the OptionBased library.

 

Once I play with it and learn the ins-and-outs, I wonder if I could add support for it in CodeLab...

 

Who is the developer/maintainer of the OptionBased library?

  • Upvote 1

Click to play:
j.pngs.pngd.pnga.pngp.png
Download: BoltBait's Plugin Pack | CodeLab | and how about a Computer Dominos Game

Link to comment
Share on other sites

Thank you, Ego Eram Reputo! I'm eager to read it. Perhaps it could be published in the Developer's Forum as a How-to.

 

 

I think the publication of this material could stimulate the developers of effects plugins.

 

It started out as my own reference tool. It's grown over time, but is still far from ready for a public release.

Link to comment
Share on other sites

It may take a little while, but I hope by combining what I learn from Red ochre's Scribble plugin, toe_head2001's comment, and Ego Eram Reputo's guide, I'll understand it well enough to write a How-to post. I intend to concentrate on the subject of binding controls to data that can be used by PDN. Other Visual Studio plugin issue can be dealt with separately (and some already are in "Help needed: Using Visual Studio instead of CodeLab for developing" and BoltBait's "Beyond CodeLab" tutorial).

Edited by MJW
Link to comment
Share on other sites

In addition to using the built-in Windows Forms controls many of the Indirect UI controls can be replicated.

I ported Red Ochre's FurBlur plugin to use Windows Forms to allow XML presets to be used, a screenshot of the resulting UI is here.

 

The source code in this post has been replaced by the attachment in post #20

 

 

  • Upvote 3

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

null54, that's very interesting because my primary reason for asking about non-PropertyBased effects was I had the idea that I might make an Open Source-type library of IndirectUI lookalike controls. It looks like you've already gone quite a ways in that direction.

Link to comment
Share on other sites

null54, that's very interesting because my primary reason for asking about non-PropertyBased effects was I had the idea that I might make an Open Source-type library of IndirectUI lookalike controls. It looks like you've already gone quite a ways in that direction.

 

If you look at the Paint.NET code with ILSpy you can see that many of the IndirectUI controls use the native Windows Forms controls while handling all the layout and databinding.

The PaintDotNet folder in the FurBlur source code contains the custom controls from the Paint.NET 3.36 source code that are used to recreate the feel of IndirectUI, the rest are standard WinForms controls.

  • Upvote 1

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

Thanks for the link to the disassembler, null54. I didn't have a disassembler and have been meaning to install one if I could find a decent free one.

 

I had assumed from their appearance that many IndirectUI controls were pretty much standard WinForm controls, usually with the addition of the (very useful) reset button. Making custom controls which are combinations of other controls is pretty easy, as I recall, so those would probably be relatively simple to implement. I'm not too concerned about the lay-out issue. IndirectUI's auto-positioning is convenient, if inflexible, but positioning controls isn't too difficult in VS, so I think that could be left to the plugin programmer. The hard part would be devising a data-binding scheme that's as transparent and easy to use as possible. I think that the more that could be built into the controls the better, but because they all share the token class, that seems to me to be difficult to achieve. (Given my current incomplete understanding of how it all works, the previous sentence may be completely confused and off base.)

 

EDIT: Now that I've had the chance to look at the code and the guide a little more carefully, I see that the controls are not that closely tied to the token system, which is good. From what I gather, there are really just a few fairly simple things that need to be done:

 

InitialInitToken must create a token with the default values.

InitDialogFromToken must assign the token's values to the controls.

InitTokenFromDialog must save the control values in the token.

FinishTokenUpdate initiates a new traversal (and causes InitTokenFromDialog to be called).

 

As far as I know, the only special thing the controls need to do is, when their values are changed, call a routine which (normally) calls FinishTokenUpdate.

 

(For those who don't already know, the token is a class that pretty much just contains the same things as the CodeLab Amount variables. The values in the token are copied over to local variables in OnSetRenderInfo.)

 

EDIT 2: I'm sure I could figure it out for myself (pretty sure, at least), but I don't see in the FurBlur or Scribble code where the reset-arrow buttons are added or processed, though I can see from running the plugins that they are. Perhaps someone more familiar with the code can explain how that works.

Edited by MJW
Link to comment
Share on other sites

EDIT 2: I'm sure I could figure it out for myself (pretty sure, at least), but I don't see in the FurBlur or Scribble code where the reset-arrow buttons are added or processed, though I can see from running the plugins that they are. Perhaps someone more familiar with the code can explain how that works.

 

The Windows Forms version of FurBlur does not have reset buttons, mainly because I have not found a good way to store the defaults.

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

I'm glad I didn't spend a lot of time looking! I have some ideas on how to do it.

 

I ended up adding a new class to store the original values.

The attached source code now has reset buttons, and the UI was updated to match Red Ochre's latest version.

 

FurBlurWinFormsSource.zip

  • Upvote 1

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

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.

 Share

×
×
  • Create New...