Modeless Dialog - Lock Rhino?


#1

Hi
I have a plugin (c#) that uses a modeless dialog which generates lots of objects from the window. During this time, you can work in rhino while it’s generating objects, but I’d like to make so that the user can’t do any modeling work while the plugin is generating objects. Is this possible without going to a modal dialog? Can you lock the Rhino UI or something? So far there doesn’t seem to be any adverse effects from being able to work in rhino, but I see a lot of potential for weirdness (user tries to close Rhino, etc) that I would like to prevent.

Any advice appreciated
thanks,
tom


#2

What happens if the user is in the middle of a command when your script puts the objects in?


#3

It works. You can start the Line command (pick first point), execute the plugin, plugin generates lines, then finish the Line command (second point), no fuss, no problems, but still seems like bad practice - especially when the plugin can take a few minutes to do all it’s work.


(Steve Baer) #4

The best way to work with modeless dialogs is to

  • create a command in your plug-in that creates all the objects inside the command named something like “CreateTheStuff”
  • clicking on a button on your dialog the “does the work” will call RhinoApp.RunScript("!_CreateTheStuff", true)

This will also have the benefit of making your code properly support undo


#5

Thanks Steve,
I’ll have to mull this over - it’s a bit of an architectural shift… At first thought I’m not sure how to make that happen with my current setup. Progress bars in the modeless dialog etc…

On another note: I can turn off redraws with:
RhinoDoc.ActiveDoc.Views.RedrawEnabled = false;
I’m assuming this is safe to use in commands as long as you turn it back on after the command is run? (Hoping to speed things up a bit by using that code)

thanks,
tom


(Steve Baer) #6

It is just going to work better using the approach that I am suggesting. You can make your dialog available to your command which will let your command get at whatever values are being set on the dialog and the command can tell the dialog that it needs to update progress bars.

You won’t need to set RedrawEnabled = false in your command. Rhino doesn’t normally redraw unless your command tells it to. You will want to call doc.Views.Redraw(); at the end of your command’s execution.


#7

Thanks again Steve,
I’ll find a way to make that model happen - it’ll just take a bit work out…
Good to know about the redraw() situation.

Appreciate the help!
tom


#8

@stevebaer Would the attached be good practice? I also realized that currently I am creating geometry on a new thread. Would creating the geometry on a new thread started from command2 be ok? Would the command still be in the undo queue or would that break things?..

thanks,
tom


(Steve Baer) #9

That looks like a good workflow. Creating geometry on separate threads is fine, but make sure to only add geometry to the document on the main thread since the document is not thread safe.


#10

Cool - Thanks for the guidance!
cheers
tom


#11

I’ve restructured things, but I’m having a little trouble getting cancel to work (undos work nicely though). Previously, cancel was executed through the progress display panel and was nice and crisp. I’ve tried to hook up a an EventHandler for Escape keys, but I can’t get it to work running on the same thread. I have tried everything I could think of (event hook code is below in case I’m doing something horribly wrong), but the only way I got escape to work was to start a new thread from inside the Rhino command (Command2) and use a Thread.Join(), which wreaked some havoc on the progress display…
I tried detaching the listener (GUI updates) too, but that didn’t seem to help either…

Appreciate any ideas on this,
thanks,
tom

protected override Result RunCommand(RhinoDoc doc, RunMode mode) {

	//...code...

            EventHandler evh = new EventHandler(RhinoApp_EscapeKeyPressed);
            RhinoApp.EscapeKeyPressed += evh;

            executeSystem(system_name);

            RhinoApp.EscapeKeyPressed -= evh;

            return Rhino.Commands.Result.Success;

} 



    private void RhinoApp_EscapeKeyPressed(Object sender, System.EventArgs args) {

    //have trouble getting this far...
        Rhino.RhinoApp.WriteLine("Cancelling execution...");
        //grab a ref to the Engine
        EvaluationEngine engine = MYPlugIn.Instance.Engine;

        if (engine != null) {
            //execute the system
            engine.CancelExecution();

        } else {
            Rhino.RhinoApp.WriteLine("Failed to send cancel to Engine from Plugin.");
        }

    }

(Steve Baer) #12

I would recommend using a GetString with a message “Press esc to cancel” on your main thread instead of the EscapeKeyPress event. This will put Rhino in a modal state where other operations can’t occur until the user presses a key.


#13

Sorry - I think I confused the issue. Just to clarify, I have taken all the threading out of this now (I am NOT using the weird experiment with Thread.Join() - that was just a test to see if I could somewhere with the event). I am trying to follow your advice and make this as Rhino safe/friendly as I can, so currently, this is running on the thread that creates it. I think your last suggestion would work with a threaded form of “executeSystem(name)”, but I’m not sure it applies without a second thread if I’m understanding this properly…
I was playing around with a modal dialog last night (non-Threaded), but still no joy with the escape key event…


#14

Face palm moment…

//call periodically in execution

System.Windows.Forms.Application.DoEvents;

That was the only thing holding this up.
Progress display, cancel, modeless dialog, undos, all working great and thread safe under the new setup per diagram…
Happy and relieved to have it playing nicely.
tom


(Steve Baer) #15

Great! RhinoApp.Wait() should have the same effect since it lets the message queue get processed