BoltBait.com

Adding a User Interfact to Your Bitmap Plugin

Let's add a UI to the Dot at Center plugin


Imagine that we want to improve our "Dot at Center" plugin by adding a check box to it so that it can either draw the dot at center or draw a cross on the selection.


Open Paint.NET, make a selection, and run Effects > Advanced > CodeLab. Open the DotAtCenter.cs file we saved at the end of the previous lesson.


Dot At Center

Here is our "Dot at Center" code that we ended the last lesson with:

protected override void OnRender(IBitmapEffectOutput output)
{
    using IEffectInputBitmap<ColorBgra32> sourceBitmap = Environment.GetSourceBitmapBgra32();
    using IBitmapLock<ColorBgra32> sourceLock = Environment.GetSourceBitmapBgra32().Lock(new RectInt32(0, 0, sourceBitmap.Size));
    RegionPtr<ColorBgra32> sourceRegion = sourceLock.AsRegionPtr();

    RectInt32 outputBounds = output.Bounds;
    using IBitmapLock<ColorBgra32> outputLock = output.LockBgra32();
    RegionPtr<ColorBgra32> outputSubRegion = outputLock.AsRegionPtr();
    var outputRegion = outputSubRegion.OffsetView(-outputBounds.Location);

    int canvasCenterX = Environment.Document.Size.Width / 2;
    int canvasCenterY = Environment.Document.Size.Height / 2;
    var selection = Environment.Selection.RenderBounds;
    int selectionCenterX = (selection.Right - selection.Left) / 2 + selection.Left;
    int selectionCenterY = (selection.Bottom - selection.Top) / 2 + selection.Top;

    // Loop through the output canvas tile
    for (int y = outputBounds.Top; y < outputBounds.Bottom; ++y)
    {
        if (IsCancelRequested) return;

        for (int x = outputBounds.Left; x < outputBounds.Right; ++x)
        {
			// Get your source pixel
			ColorBgra32 sourcePixel = sourceRegion[x,y];

			if (y == selectionCenterY && x == selectionCenterX)
			{
				sourcePixel = SrgbColors.Black;
			}
			// Save your pixel to the output canvas
			outputRegion[x,y] = sourcePixel;
        }
    }
}

The first thing you need to do is press Ctrl+I to open the UI Designer and add a check box. Follow the instructions on the UI Designer page to add a check box with the name "Draw cross instead of dot" and a variable name of "Amount1".

Once you're done with the designer and have clicked OK to update your script, you should see the following lines at the top of your script:

#region UICode
CheckboxControl Amount1 = false; // Draw cross instead of dot
#endregion

If your code doesn't look exactly like that, just copy and paste it from here.

Now that we have a check box on the screen, we need to write the code in our script that will draw a cross when the check box is checked. It's not too hard.

Go look at the inner most part of your x and y loops. You'll see this code:

// Get your source pixel
ColorBgra32 sourcePixel = sourceRegion[x,y];

if (y == selectionCenterY && x == selectionCenterX)
{
	sourcePixel = SrgbColors.Black;
}
// Save your pixel to the output canvas
outputRegion[x,y] = sourcePixel;

This always turns the center pixel black. We need to put a condition around that code so that it only runs if our check box is not checked. In order to make that work, we now have a variable, "Amount1" that contains the state of the check box. It is a boolean variable that holds "false" for unchecked and "true" for checked.

// Get your source pixel
ColorBgra32 sourcePixel = sourceRegion[x,y];

if (!Amount1)
{
    if (y == selectionCenterY && x == selectionCenterX)
    {
	    sourcePixel = SrgbColors.Black;
    }
}
// Save your pixel to the output canvas
outputRegion[x,y] = sourcePixel;

You can press Ctrl+P to preview the effect:

If you check and uncheck the check box, you'll notice that it only renders the dot at center when the check box is not checked. If so, it's working perfectly.

Next up, we need to write the code that runs when the check box is checked.

The code to draw a cross instead of just a dot is very simple. We just need to change the condition in the "if" statement from "&&" meaning AND to "||" meaning OR.

    if (y == selectionCenterY || x == selectionCenterX)
    {
	    sourcePixel = SrgbColors.Black;
    }

In order to trigger that code to run, we will put it just after our previous if statement and separate them with the "else" keyword:

// Get your source pixel
ColorBgra32 sourcePixel = sourceRegion[x,y];

if (!Amount1)
{
    if (y == selectionCenterY && x == selectionCenterX)
    {
	    sourcePixel = SrgbColors.Black;
    }
}
else
{
    if (y == selectionCenterY || x == selectionCenterX)
    {
	    sourcePixel = SrgbColors.Black;
    }
}
// Save your pixel to the output canvas
outputRegion[x,y] = sourcePixel;

You can preview your script again and play with the check box. Notice how the image changes when you change the check box? Exciting, right? That feeling is what keeps us programmers going!

Your full script should look like this now:

#region UICode
CheckboxControl Amount1 = false; // Draw cross instead of dot
#endregion

protected override void OnRender(IBitmapEffectOutput output)
{
    using IEffectInputBitmap<ColorBgra32> sourceBitmap = Environment.GetSourceBitmapBgra32();
    using IBitmapLock<ColorBgra32> sourceLock = Environment.GetSourceBitmapBgra32().Lock(new RectInt32(0, 0, sourceBitmap.Size));
        RegionPtr<ColorBgra32> sourceRegion = sourceLock.AsRegionPtr();

    RectInt32 outputBounds = output.Bounds;
    using IBitmapLock<ColorBgra32> outputLock = output.LockBgra32();
        RegionPtr<ColorBgra32> outputSubRegion = outputLock.AsRegionPtr();
    var outputRegion = outputSubRegion.OffsetView(-outputBounds.Location);

    int canvasCenterX = Environment.Document.Size.Width / 2;
    int canvasCenterY = Environment.Document.Size.Height / 2;
    var selection = Environment.Selection.RenderBounds;
    int selectionCenterX = (selection.Right - selection.Left) / 2 + selection.Left;
    int selectionCenterY = (selection.Bottom - selection.Top) / 2 + selection.Top;

    // Loop through the output canvas tile
    for (int y = outputBounds.Top; y < outputBounds.Bottom; ++y)
    {
        if (IsCancelRequested) return;

        for (int x = outputBounds.Left; x < outputBounds.Right; ++x)
        {
            // Get your source pixel
            ColorBgra32 sourcePixel = sourceRegion[x,y];

            if (!Amount1)
            {
                if (y == selectionCenterY && x == selectionCenterX)
                {
                    sourcePixel = SrgbColors.Black;
                }
            } 
            else 
            {
                if (y == selectionCenterY || x == selectionCenterX)
                {
                    sourcePixel = SrgbColors.Black;
                }
            }

            // Save your pixel to the output canvas
            outputRegion[x,y] = sourcePixel;
        }
    }
}								


Finishing Up

Once you've got that working, remember to save your script! I wouldn't want you to lose any of your hard work.

"File > Save" your DotAtCenter.cs file.

If you'd like to make that plugin a permanent part of your Paint.NET installation, read:

How to Build a DLL from a CodeLab script
How to install a DLL into Paint.NET


What's Next?

Now that you know a bit about the UI design, let's dig a little deeper and add another control to our UI!

So far, the effect looks good and it useful, but what if we're working on a completely black canvas? Drawing a black dot or cross on that wouldn't do much. Let's add a color wheel control to the UI so that we can change the color of the dot or cross.

The first thing you need to do is press Ctrl+I to open the UI Designer and add a color wheel control to the bottom of our list. Follow the instructions on the UI Designer page to add a color wheel with the name "Select a color", a variable name of "Amount2", and a default color of Black.

Once you're done with the designer and have clicked OK to update your script, you should see the following lines at the top of your script:

#region UICode
CheckboxControl Amount1 = false; // Draw cross instead of dot
ColorWheelControl Amount2 = ColorBgra.FromBgr(0, 0, 0); // [Black] Select a color
#endregion

If your code doesn't look exactly like that, just copy and paste it from here.

Now that we have a color wheel on the screen, we need to write the code in our script that will draw a cross in our selected color. It's not too hard.

Go look at the inner most part of your x and y loops. You'll see this code:

if (!Amount1)
{
	if (y == selectionCenterY && x == selectionCenterX)
	{
		sourcePixel = SrgbColors.Black;
	}
} 
else 
{
	if (y == selectionCenterY || x == selectionCenterX)
	{
		sourcePixel = SrgbColors.Black;
	}
}

Instead of using "SrgbColors.Black" just replace that with the variable "Amount2", like so:

if (!Amount1)
{
	if (y == selectionCenterY && x == selectionCenterX)
	{
		sourcePixel = Amount2;
	}
} 
else 
{
	if (y == selectionCenterY || x == selectionCenterX)
	{
		sourcePixel = Amount2;
	}
}

Be sure you changed it in both places! And, that's all there is to it!

If you've been following along, your final script should look like this:

#region UICode
CheckboxControl Amount1 = false; // Draw cross instead of dot
ColorWheelControl Amount2 = ColorBgra.FromBgr(0, 0, 0); // [Black] Select a color
#endregion

protected override void OnRender(IBitmapEffectOutput output)
{
    using IEffectInputBitmap<ColorBgra32> sourceBitmap = Environment.GetSourceBitmapBgra32();
    using IBitmapLock<ColorBgra32> sourceLock = Environment.GetSourceBitmapBgra32().Lock(new RectInt32(0, 0, sourceBitmap.Size));
        RegionPtr<ColorBgra32> sourceRegion = sourceLock.AsRegionPtr();

    RectInt32 outputBounds = output.Bounds;
    using IBitmapLock<ColorBgra32> outputLock = output.LockBgra32();
        RegionPtr<ColorBgra32> outputSubRegion = outputLock.AsRegionPtr();
    var outputRegion = outputSubRegion.OffsetView(-outputBounds.Location);

    int canvasCenterX = Environment.Document.Size.Width / 2;
    int canvasCenterY = Environment.Document.Size.Height / 2;
    var selection = Environment.Selection.RenderBounds;
    int selectionCenterX = (selection.Right - selection.Left) / 2 + selection.Left;
    int selectionCenterY = (selection.Bottom - selection.Top) / 2 + selection.Top;

    // Loop through the output canvas tile
    for (int y = outputBounds.Top; y < outputBounds.Bottom; ++y)
    {
        if (IsCancelRequested) return;

        for (int x = outputBounds.Left; x < outputBounds.Right; ++x)
        {
            // Get your source pixel
            ColorBgra32 sourcePixel = sourceRegion[x,y];

            if (!Amount1) // Draw single dot
            {
                if (y == selectionCenterY && x == selectionCenterX)
                {
                    sourcePixel = Amount2;
                }
            } 
            else // Draw cross instead
            {
                if (y == selectionCenterY || x == selectionCenterX)
                {
                    sourcePixel = Amount2;
                }
            }

            // Save your pixel to the output canvas
            outputRegion[x,y] = sourcePixel;
        }
    }
}

Go ahead and press Ctrl+P to preview your effect. It should look something like this:



Finishing Up

Once you've got that working, remember to save your script! I wouldn't want you to lose any of your hard work.

"File > Save" your DotAtCenter.cs file.

If you'd like to make that plugin a permanent part of your Paint.NET installation, read:

How to Build a DLL from a CodeLab script
How to install a DLL into Paint.NET


What's Next?

Head back to the Tutorial Index to learn something else



Donate

The best way to say "Thanks" for teaching you something here, is to fill out this form. It uses PayPal to process your donation. You don't need a PayPal account, just a credit/debit card will do. If PayPal doesn't work for you, no need to worry--just enjoy the tutorials for free!

$
Thank you for your donation. I don't get many, so you can be sure I really appreciate yours!



 

 
 

News



CodeLab 6.12 Released
(February 11, 2024)
This latest release of CodeLab for Paint.NET includes the ability to write GPU accelerated plugins.
More...

Double-Six Dominoes 3.1
(May 10, 2021)
This long-awaited refresh of the most popular dominoes game on Download.com is now available!
More...

HTML Editor 1.5 Released
(March 31, 2016)
This latest release is a complete rewrite adding a wysiwyg editor mode and a much improved UI.
More...