예제 #1
0
 public RendererContext(BackgroundEffectRenderer ber, EffectConfigToken token, int threadNumber, int startOffset)
 {
     BackRenderer = ber;
     Token        = token;
     ThreadNumber = threadNumber;
     StartOffset  = startOffset;
 }
예제 #2
0
        protected sealed override void OnExecute()
        {
            for (int i = 0; i < this.iterations; ++i)
            {
                EffectConfigToken localToken;

                if (this.token == null)
                {
                    localToken = null;
                }
                else
                {
                    localToken = (EffectConfigToken)this.token.Clone();
                }

                RenderArgs srcArgs = new RenderArgs(image);
                RenderArgs dstArgs = new RenderArgs(dst);

                BackgroundEffectRenderer ber = new BackgroundEffectRenderer(effect, localToken, dstArgs, srcArgs, region,
                                                                            25 * Processor.LogicalCpuCount, Processor.LogicalCpuCount);

                ber.Start();
                ber.Join();

                ber.Dispose();
                ber = null;
            }
        }
예제 #3
0
        private void EffectConfigTokenChangedHandler(object sender, System.EventArgs e)
        {
            EffectConfigDialog       ecf = (EffectConfigDialog)sender;
            BackgroundEffectRenderer ber = (BackgroundEffectRenderer)ecf.Tag;

            if (ber != null)
            {
                AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBarAsync();
                ber.Start();
            }
        }
예제 #4
0
 private void RenderedTile(BackgroundEffectRenderer sender, int i, int tileCount)
 {
     if (IsCancelRequested)
     {
         sender.AbortAsync();
     }
     else if (dialog != null)
     {
         dialog.IncrementProgressBarValue(i, tileCount);
     }
 }
예제 #5
0
        protected sealed override void OnExecute()
        {
            for (int i = 0; i < this.Iterations; ++i)
            {
                EffectConfigToken localToken = Token == null ? null : (EffectConfigToken)Token.Clone();
                RenderArgs        srcArgs    = new RenderArgs(Image);
                RenderArgs        dstArgs    = new RenderArgs(Dest);

                using (BackgroundEffectRenderer ber = new BackgroundEffectRenderer(
                           Effect, localToken, dstArgs, srcArgs, Region,
                           25 * Processor.LogicalCpuCount, Processor.LogicalCpuCount))
                {
                    ber.Start();
                    ber.Join();
                }
            }
        }
예제 #6
0
        private bool DoEffect(Effect effect, EffectConfigToken token, PdnRegion selectedRegion,
                              PdnRegion regionToRender, Surface originalSurface)
        {
            bool oldDirtyValue   = AppWorkspace.ActiveDocumentWorkspace.Document.Dirty;
            bool resetDirtyValue = false;

            bool returnVal = false;

            AppWorkspace.ActiveDocumentWorkspace.EnableOutlineAnimation = false;

            try
            {
                using (ProgressDialog aed = new ProgressDialog())
                {
                    if (effect.Image != null)
                    {
                        aed.Icon = Utility.ImageToIcon(effect.Image, Utility.TransparentKey);
                    }

                    aed.Opacity     = 0.9;
                    aed.Value       = 0;
                    aed.Text        = effect.Name;
                    aed.Description = string.Format(PdnResources.GetString("Effects.ApplyingDialog.Description"), effect.Name);

                    invalidateTimer.Enabled = true;

                    using (new WaitCursorChanger(AppWorkspace))
                    {
                        HistoryMemento ha     = null;
                        DialogResult   result = DialogResult.None;

                        AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBar();
                        AppWorkspace.Widgets.LayerControl.SuspendLayerPreviewUpdates();

                        try
                        {
                            ManualResetEvent     saveEvent = new ManualResetEvent(false);
                            BitmapHistoryMemento bha       = null;

                            // perf bug #1445: save this data in a background thread
                            PdnRegion selectedRegionCopy = selectedRegion.Clone();
                            PaintDotNet.Threading.ThreadPool.Global.QueueUserWorkItem(
                                delegate(object context)
                            {
                                try
                                {
                                    ImageResource image;

                                    if (effect.Image == null)
                                    {
                                        image = null;
                                    }
                                    else
                                    {
                                        image = ImageResource.FromImage(effect.Image);
                                    }

                                    bha = new BitmapHistoryMemento(effect.Name, image, this.AppWorkspace.ActiveDocumentWorkspace,
                                                                   this.AppWorkspace.ActiveDocumentWorkspace.ActiveLayerIndex, selectedRegionCopy, originalSurface);
                                }

                                finally
                                {
                                    saveEvent.Set();
                                    selectedRegionCopy.Dispose();
                                    selectedRegionCopy = null;
                                }
                            });

                            BackgroundEffectRenderer ber = new BackgroundEffectRenderer(
                                effect,
                                token,
                                new RenderArgs(((BitmapLayer)AppWorkspace.ActiveDocumentWorkspace.ActiveLayer).Surface),
                                new RenderArgs(originalSurface),
                                regionToRender,
                                tilesPerCpu * renderingThreadCount,
                                renderingThreadCount);

                            aed.Tag                = ber;
                            ber.RenderedTile      += new RenderedTileEventHandler(aed.RenderedTileHandler);
                            ber.RenderedTile      += new RenderedTileEventHandler(RenderedTileHandler);
                            ber.StartingRendering += new EventHandler(StartingRenderingHandler);
                            ber.FinishedRendering += new EventHandler(aed.FinishedRenderingHandler);
                            ber.FinishedRendering += new EventHandler(FinishedRenderingHandler);
                            ber.Start();

                            result = Utility.ShowDialog(aed, AppWorkspace);

                            if (result == DialogResult.Cancel)
                            {
                                resetDirtyValue = true;

                                using (new WaitCursorChanger(AppWorkspace))
                                {
                                    ber.Abort();
                                    ber.Join();
                                    ((BitmapLayer)AppWorkspace.ActiveDocumentWorkspace.ActiveLayer).Surface.CopySurface(originalSurface);
                                }
                            }

                            invalidateTimer.Enabled = false;

                            ber.Join();
                            ber.Dispose();

                            saveEvent.WaitOne();
                            saveEvent.Close();
                            saveEvent = null;

                            ha = bha;
                        }

                        catch
                        {
                            using (new WaitCursorChanger(AppWorkspace))
                            {
                                ((BitmapLayer)AppWorkspace.ActiveDocumentWorkspace.ActiveLayer).Surface.CopySurface(originalSurface);
                                ha = null;
                            }
                        }

                        finally
                        {
                            AppWorkspace.Widgets.LayerControl.ResumeLayerPreviewUpdates();
                        }

                        using (PdnRegion simplifiedRenderRegion = Utility.SimplifyAndInflateRegion(selectedRegion))
                        {
                            using (new WaitCursorChanger(AppWorkspace))
                            {
                                AppWorkspace.ActiveDocumentWorkspace.ActiveLayer.Invalidate(simplifiedRenderRegion);
                            }
                        }

                        using (new WaitCursorChanger(AppWorkspace))
                        {
                            if (result == DialogResult.OK)
                            {
                                if (ha != null)
                                {
                                    AppWorkspace.ActiveDocumentWorkspace.History.PushNewMemento(ha);
                                }

                                AppWorkspace.Update();
                                returnVal = true;
                            }
                            else
                            {
                                Utility.GCFullCollect();
                            }
                        }
                    } // using
                }     // using
            }

            finally
            {
                AppWorkspace.ActiveDocumentWorkspace.EnableOutlineAnimation = true;

                if (resetDirtyValue)
                {
                    AppWorkspace.ActiveDocumentWorkspace.Document.Dirty = oldDirtyValue;
                }
            }

            AppWorkspace.Widgets.StatusBarProgress.EraseProgressStatusBarAsync();
            return(returnVal);
        }
예제 #7
0
        public void RunEffect(Type effectType)
        {
            bool oldDirtyValue   = AppWorkspace.ActiveDocumentWorkspace.Document.Dirty;
            bool resetDirtyValue = false;

            AppWorkspace.Update(); // make sure the window is done 'closing'
            AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBar();
            DocumentWorkspace activeDW = AppWorkspace.ActiveDocumentWorkspace;

            PdnRegion selectedRegion;

            if (activeDW.Selection.IsEmpty)
            {
                selectedRegion = new PdnRegion(activeDW.Document.Bounds);
            }
            else
            {
                selectedRegion = activeDW.Selection.CreateRegion();
            }

            BitmapLayer layer = (BitmapLayer)activeDW.ActiveLayer;

            using (new PushNullToolMode(activeDW))
            {
                try
                {
                    Effect effect = (Effect)Activator.CreateInstance(effectType);

                    EffectEnvironmentParameters eep = new EffectEnvironmentParameters(
                        AppWorkspace.AppEnvironment.PrimaryColor,
                        AppWorkspace.AppEnvironment.SecondaryColor,
                        AppWorkspace.AppEnvironment.PenInfo.Width,
                        selectedRegion);

                    string            name         = effect.Name;
                    EffectConfigToken newLastToken = null;
                    effect.EnvironmentParameters = eep;

                    if (!(effect.IsConfigurable))
                    {
                        Surface copy = activeDW.BorrowScratchSurface(this.GetType() + ".RunEffect() using scratch surface for non-configurable rendering");

                        try
                        {
                            using (new WaitCursorChanger(AppWorkspace))
                            {
                                copy.CopySurface(layer.Surface);
                            }

                            DoEffect(effect, null, selectedRegion, selectedRegion, copy);
                        }

                        finally
                        {
                            activeDW.ReturnScratchSurface(copy);
                        }
                    }
                    else
                    {
                        PdnRegion previewRegion = (PdnRegion)selectedRegion.Clone();
                        previewRegion.Intersect(RectangleF.Inflate(activeDW.VisibleDocumentRectangleF, 1, 1));

                        Surface originalSurface = activeDW.BorrowScratchSurface(this.GetType() + ".RunEffect() using scratch surface for rendering during configuration");

                        try
                        {
                            using (new WaitCursorChanger(AppWorkspace))
                            {
                                originalSurface.CopySurface(layer.Surface);
                            }

                            //
                            AppWorkspace.SuspendThumbnailUpdates();
                            //

                            using (EffectConfigDialog configDialog = effect.CreateConfigDialog())
                            {
                                configDialog.Opacity             = 0.9;
                                configDialog.Effect              = effect;
                                configDialog.EffectSourceSurface = originalSurface;
                                configDialog.Selection           = selectedRegion;

                                EventHandler eh = new EventHandler(EffectConfigTokenChangedHandler);
                                configDialog.EffectTokenChanged += eh;

                                if (this.effectTokens.ContainsKey(effectType))
                                {
                                    EffectConfigToken oldToken = (EffectConfigToken)effectTokens[effectType].Clone();
                                    configDialog.EffectToken = oldToken;
                                }

                                BackgroundEffectRenderer ber = new BackgroundEffectRenderer(
                                    effect,
                                    configDialog.EffectToken,
                                    new RenderArgs(layer.Surface),
                                    new RenderArgs(originalSurface),
                                    previewRegion,
                                    tilesPerCpu * renderingThreadCount,
                                    renderingThreadCount);

                                ber.RenderedTile      += new RenderedTileEventHandler(RenderedTileHandler);
                                ber.StartingRendering += new EventHandler(StartingRenderingHandler);
                                ber.FinishedRendering += new EventHandler(FinishedRenderingHandler);
                                configDialog.Tag       = ber;

                                invalidateTimer.Enabled = true;
                                DialogResult dr = Utility.ShowDialog(configDialog, AppWorkspace);
                                invalidateTimer.Enabled = false;

                                this.InvalidateTimer_Tick(invalidateTimer, EventArgs.Empty);

                                if (dr == DialogResult.OK)
                                {
                                    this.effectTokens[effectType] = (EffectConfigToken)configDialog.EffectToken.Clone();
                                }

                                using (new WaitCursorChanger(AppWorkspace))
                                {
                                    ber.Abort();
                                    ber.Join();
                                    ber.Dispose();
                                    ber = null;

                                    if (dr != DialogResult.OK)
                                    {
                                        ((BitmapLayer)activeDW.ActiveLayer).Surface.CopySurface(originalSurface);
                                        activeDW.ActiveLayer.Invalidate();
                                    }

                                    configDialog.EffectTokenChanged -= eh;
                                    configDialog.Hide();
                                    AppWorkspace.Update();
                                    previewRegion.Dispose();
                                }

                                //
                                AppWorkspace.ResumeThumbnailUpdates();
                                //

                                if (dr == DialogResult.OK)
                                {
                                    PdnRegion remainingToRender = selectedRegion.Clone();
                                    PdnRegion alreadyRendered   = PdnRegion.CreateEmpty();

                                    for (int i = 0; i < this.progressRegions.Length; ++i)
                                    {
                                        if (this.progressRegions[i] == null)
                                        {
                                            break;
                                        }
                                        else
                                        {
                                            remainingToRender.Exclude(this.progressRegions[i]);
                                            alreadyRendered.Union(this.progressRegions[i]);
                                        }
                                    }

                                    activeDW.ActiveLayer.Invalidate(alreadyRendered);
                                    newLastToken = (EffectConfigToken)configDialog.EffectToken.Clone();
                                    AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBar();
                                    DoEffect(effect, newLastToken, selectedRegion, remainingToRender, originalSurface);
                                }
                                else // if (dr == DialogResult.Cancel)
                                {
                                    using (new WaitCursorChanger(AppWorkspace))
                                    {
                                        activeDW.ActiveLayer.Invalidate();
                                        Utility.GCFullCollect();
                                    }

                                    resetDirtyValue = true;
                                    return;
                                }
                            }
                        }

                        finally
                        {
                            activeDW.ReturnScratchSurface(originalSurface);
                        }
                    }

                    // if it was from the Effects menu, save it as the "Repeat ...." item
                    if (effect.Category == EffectCategory.Effect)
                    {
                        this.lastEffect = effect;

                        if (newLastToken == null)
                        {
                            this.lastEffectToken = null;
                        }
                        else
                        {
                            this.lastEffectToken = (EffectConfigToken)newLastToken.Clone();
                        }

                        PopulateMenu(true);
                    }
                }

                finally
                {
                    selectedRegion.Dispose();
                    AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBar();
                    AppWorkspace.Widgets.StatusBarProgress.EraseProgressStatusBar();
                    AppWorkspace.ActiveDocumentWorkspace.EnableOutlineAnimation = true;

                    for (int i = 0; i < this.progressRegions.Length; ++i)
                    {
                        if (this.progressRegions[i] != null)
                        {
                            this.progressRegions[i].Dispose();
                            this.progressRegions[i] = null;
                        }
                    }

                    if (resetDirtyValue)
                    {
                        AppWorkspace.ActiveDocumentWorkspace.Document.Dirty = oldDirtyValue;
                    }
                }
            }
        }
예제 #8
0
        public override void Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length)
        {
            ConfigToken token     = (ConfigToken)parameters;
            PdnRegion   selection = EnvironmentParameters.GetSelection(srcArgs.Bounds);

            if (changed)
            {
                changed = false;

                if (dialog != null)
                {
                    dialog.SetProgressBarMaximum(token.effects.Count, tilesPerCpu * renderingThreadCount);
                    dialog.EnableOKButton(false);
                }
                using (Surface scratch = new Surface(srcArgs.Size))
                {
                    scratch.CopySurface(srcArgs.Surface);

                    for (int i = 0; i < token.effects.Count; ++i)
                    {
                        ScriptStep step = token.effects[i];
                        Type       type = step.EffectType;

                        if (type == null)
                        {
                            if (dialog != null)
                            {
                                dialog.IncrementProgressBarValue(i, 1);
                            }
                        }
                        else
                        {
                            Effect effect = (Effect)(type.GetConstructor(Type.EmptyTypes).Invoke(new object[0]));
                            effect.Services = Services;
                            effect.EnvironmentParameters = new EffectEnvironmentParameters(
                                step.PrimaryColor,
                                step.SecondaryColor,
                                EnvironmentParameters.BrushWidth,
                                selection,
                                EnvironmentParameters.SourceSurface);

                            BackgroundEffectRenderer ber = new BackgroundEffectRenderer(effect, step.Token, dstArgs, new RenderArgs(scratch), selection, null, tilesPerCpu * renderingThreadCount, renderingThreadCount);
                            ber.RenderedTile += (sender, e) => RenderedTile((BackgroundEffectRenderer)sender, i, e.TileCount);
                            ber.Start();
                            ber.Join();

                            scratch.CopySurface(dstArgs.Surface);
                        }

                        if (IsCancelRequested)
                        {
                            return;
                        }
                    }
                    if (dialog != null)
                    {
                        dialog.ClearProgressBars();
                        dialog.EnableOKButton(true);
                    }
                }
            }
        }
예제 #9
0
 public RendererContext(BackgroundEffectRenderer ber, EffectConfigToken token, int threadNumber)
     : this(ber, token, threadNumber, 0)
 {
 }
예제 #10
0
        public void RunEffect(Type effectType)
        {
            bool oldDirtyValue   = AppWorkspace.ActiveDocumentWorkspace.Document.Dirty;
            bool resetDirtyValue = false;

            AppWorkspace.Update(); // make sure the window is done 'closing'
            AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBar();
            DocumentWorkspace activeDW = AppWorkspace.ActiveDocumentWorkspace;

            PdnRegion selectedRegion;

            if (activeDW.Selection.IsEmpty)
            {
                selectedRegion = new PdnRegion(activeDW.Document.Bounds);
            }
            else
            {
                selectedRegion = activeDW.Selection.CreateRegion();
            }

            Exception   exception = null;
            Effect      effect    = null;
            BitmapLayer layer     = (BitmapLayer)activeDW.ActiveLayer;

            using (new PushNullToolMode(activeDW))
            {
                try
                {
                    effect = (Effect)Activator.CreateInstance(effectType);

                    string            name         = effect.Name;
                    EffectConfigToken newLastToken = null;

                    if (!(effect.CheckForEffectFlags(EffectFlags.Configurable)))
                    {
                        Surface copy = activeDW.BorrowScratchSurface(GetType() +
                                                                     ".RunEffect() using scratch surface for non-configurable rendering");

                        try
                        {
                            using (new WaitCursorChanger(AppWorkspace))
                            {
                                copy.CopySurface(layer.Surface);
                            }

                            EffectEnvironmentParameters eep = new EffectEnvironmentParameters(
                                AppWorkspace.AppEnvironment.PrimaryColor,
                                AppWorkspace.AppEnvironment.SecondaryColor,
                                AppWorkspace.AppEnvironment.PenInfo.Width,
                                selectedRegion,
                                copy);

                            effect.EnvironmentParameters = eep;

                            DoEffect(effect, null, selectedRegion, selectedRegion, copy, out exception);
                        }

                        finally
                        {
                            activeDW.ReturnScratchSurface(copy);
                        }
                    }
                    else
                    {
                        PdnRegion previewRegion = (PdnRegion)selectedRegion.Clone();
                        previewRegion.Intersect(RectangleF.Inflate(activeDW.VisibleDocumentRectangleF, 1, 1));

                        Surface originalSurface = activeDW.BorrowScratchSurface(GetType() +
                                                                                ".RunEffect() using scratch surface for rendering during configuration");

                        try
                        {
                            using (new WaitCursorChanger(AppWorkspace))
                            {
                                originalSurface.CopySurface(layer.Surface);
                            }

                            EffectEnvironmentParameters eep = new EffectEnvironmentParameters(
                                AppWorkspace.AppEnvironment.PrimaryColor,
                                AppWorkspace.AppEnvironment.SecondaryColor,
                                AppWorkspace.AppEnvironment.PenInfo.Width,
                                selectedRegion,
                                originalSurface);

                            effect.EnvironmentParameters = eep;

                            //
                            IDisposable resumeTUFn = AppWorkspace.SuspendThumbnailUpdates();
                            //

                            using (EffectConfigDialog configDialog = effect.CreateConfigDialog())
                            {
                                configDialog.Opacity             = 0.9;
                                configDialog.Effect              = effect;
                                configDialog.EffectSourceSurface = originalSurface;
                                configDialog.Selection           = selectedRegion;

                                BackgroundEffectRenderer ber = null;

                                void OnEffectTokenChanged(object sender, EventArgs e)
                                {
                                    EffectConfigDialog ecf = (EffectConfigDialog)sender;

                                    if (ber != null)
                                    {
                                        AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBarAsync();

                                        try
                                        {
                                            ber.Start();
                                        }

                                        catch (Exception ex)
                                        {
                                            exception = ex;
                                            ecf.Close();
                                        }
                                    }
                                }

                                configDialog.EffectTokenChanged += OnEffectTokenChanged;

                                if (EffectTokens.ContainsKey(effectType))
                                {
                                    EffectConfigToken oldToken = (EffectConfigToken)EffectTokens[effectType].Clone();
                                    configDialog.EffectToken = oldToken;
                                }

                                int pixelCount  = layer.Surface.Height;
                                int threadCount = effect.CheckForEffectFlags(EffectFlags.SingleThreaded) ? 1 : RenderingThreadCount;
                                int maxTiles    = TilesPerCpu * threadCount;
                                int tileCount   = Math.Min(maxTiles, pixelCount);
                                ber = new BackgroundEffectRenderer(
                                    effect,
                                    configDialog.EffectToken,
                                    new RenderArgs(layer.Surface),
                                    new RenderArgs(originalSurface),
                                    previewRegion,
                                    tileCount,
                                    threadCount);

                                ber.RenderedTile      += new RenderedTileEventHandler(RenderedTileHandler);
                                ber.StartingRendering += new EventHandler(StartingRenderingHandler);
                                ber.FinishedRendering += new EventHandler(FinishedRenderingHandler);

                                InvalidateTimer.Enabled = true;

                                DialogResult dr;

                                try
                                {
                                    dr = Utility.ShowDialog(configDialog, AppWorkspace);
                                }

                                catch (Exception ex)
                                {
                                    dr        = DialogResult.None;
                                    exception = ex;
                                }

                                InvalidateTimer.Enabled = false;

                                InvalidateTimer_Tick(InvalidateTimer, EventArgs.Empty);

                                if (dr == DialogResult.OK)
                                {
                                    EffectTokens[effectType] = (EffectConfigToken)configDialog.EffectToken.Clone();
                                }

                                using (new WaitCursorChanger(AppWorkspace))
                                {
                                    try
                                    {
                                        ber.Abort();
                                        ber.Join();
                                    }

                                    catch (Exception ex)
                                    {
                                        exception = ex;
                                    }

                                    ber.Dispose();
                                    ber = null;

                                    if (dr != DialogResult.OK)
                                    {
                                        ((BitmapLayer)activeDW.ActiveLayer).Surface.CopySurface(originalSurface);
                                        activeDW.ActiveLayer.Invalidate();
                                    }

                                    configDialog.EffectTokenChanged -= OnEffectTokenChanged;
                                    configDialog.Hide();
                                    AppWorkspace.Update();
                                    previewRegion.Dispose();
                                }

                                //
                                resumeTUFn.Dispose();
                                resumeTUFn = null;
                                //

                                if (dr == DialogResult.OK)
                                {
                                    PdnRegion remainingToRender = selectedRegion.Clone();
                                    PdnRegion alreadyRendered   = PdnRegion.CreateEmpty();

                                    for (int i = 0; i < ProgressRegions.Length; ++i)
                                    {
                                        if (ProgressRegions[i] == null)
                                        {
                                            break;
                                        }
                                        else
                                        {
                                            remainingToRender.Exclude(ProgressRegions[i]);
                                            alreadyRendered.Union(ProgressRegions[i]);
                                        }
                                    }

                                    activeDW.ActiveLayer.Invalidate(alreadyRendered);
                                    newLastToken = (EffectConfigToken)configDialog.EffectToken.Clone();
                                    AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBar();
                                    DoEffect(effect, newLastToken, selectedRegion, remainingToRender, originalSurface, out exception);
                                }
                                else // if (dr == DialogResult.Cancel)
                                {
                                    using (new WaitCursorChanger(AppWorkspace))
                                    {
                                        activeDW.ActiveLayer.Invalidate();
                                        Utility.GCFullCollect();
                                    }

                                    resetDirtyValue = true;
                                    return;
                                }
                            }
                        }

                        catch (Exception ex)
                        {
                            exception = ex;
                        }

                        finally
                        {
                            activeDW.ReturnScratchSurface(originalSurface);
                        }
                    }

                    // if it was from the Effects menu, save it as the "Repeat ...." item
                    if (effect.Category == EffectCategory.Effect)
                    {
                        LastEffect = effect;

                        LastEffectToken = newLastToken == null ? null :
                                          (EffectConfigToken)newLastToken.Clone();

                        PopulateMenu(true);
                    }
                }

                catch (Exception ex)
                {
                    exception = ex;
                }

                finally
                {
                    selectedRegion.Dispose();
                    AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBar();
                    AppWorkspace.Widgets.StatusBarProgress.EraseProgressStatusBar();
                    AppWorkspace.ActiveDocumentWorkspace.EnableOutlineAnimation = true;

                    if (ProgressRegions != null)
                    {
                        for (int i = 0; i < ProgressRegions.Length; ++i)
                        {
                            ProgressRegions[i]?.Dispose();
                            ProgressRegions[i] = null;
                        }
                    }

                    if (resetDirtyValue)
                    {
                        AppWorkspace.ActiveDocumentWorkspace.Document.Dirty = oldDirtyValue;
                    }

                    if (exception != null)
                    {
                        HandleEffectException(AppWorkspace, effect, exception);
                    }
                }
            }
        }