Can a plugin install a Window Layout? (rhw file)?

Good Morning,

Our users are CNC machine operators, they are often new to CAD and Rhino looks SCARY.
You and I know that it is not.

However to lessen the visual complexity we often strip out a lot of the Rhino toolbars initially.
We save this as a Rhino Window Layout *.rhw file.
I have distributed this file with our plugin within the .yak file.

However what I’d like to do is to make this .rhw Window layout appear in the Window Layout List - and ideally prompt users if they want to change when the plugin is first installed.

Where are the .rhw files stored on disk? can I add to them? Are there any methods in RhinoCommon to install or activate a window layout?

any other tips to avoid scaring new-to-cad users?

Thanks

The WindowLayout command can be run headlessly -WindowLayout which allows for importing a layout and restoring a layout, a user will however have to say Yes/No when changing to the layout.

Thanks @CallumSykes

I think I’m close but am getting a Rhino crash

RhinoApp.SendKeystrokes("! _WindowLayout Import D:\\Test.rhw",true);

Object name: 'Rhino.UI.Internal.TabPanels.Controls.TabPanelModalDialog'.
   at Eto.Widget.get_Handler() in D:\BuildAgent\work\dujour\src4\DotNetSDK\Eto\src\Eto\Widget.cs:line 88
   at Eto.Forms.Control.get_Handler() in D:\BuildAgent\work\dujour\src4\DotNetSDK\Eto\src\Eto\Forms\Controls\Control.cs:line 22
   at Eto.Forms.Dialog.get_Handler() in D:\BuildAgent\work\dujour\src4\DotNetSDK\Eto\src\Eto\Forms\Dialog.cs:line 126
   at Eto.Forms.Dialog.set_AbortButton(Button value) in D:\BuildAgent\work\dujour\src4\DotNetSDK\Eto\src\Eto\Forms\Dialog.cs:line 148
   at Rhino.UI.Internal.TabPanels.Controls.WindowLayoutsDialog.<>c__DisplayClass0_0.<Show>b__0(Object s, EventArgs e)
   at Eto.PropertyStore.TriggerEvent[T](Object key, Object sender, T args) in D:\BuildAgent\work\dujour\src4\DotNetSDK\Eto\src\Eto\PropertyStore.cs:line 233
   at Eto.Forms.Control.OnShown(EventArgs e) in D:\BuildAgent\work\dujour\src4\DotNetSDK\Eto\src\Eto\Forms\Controls\Control.cs:line 466
   at Eto.Forms.Control.Callback.OnShown(Control widget, EventArgs e) in D:\BuildAgent\work\dujour\src4\DotNetSDK\Eto\src\Eto\Forms\Controls\Control.cs:line 1674
   at Eto.Wpf.Forms.WpfWindow`3.<AttachEvent>b__41_6() in D:\BuildAgent\work\dujour\src4\DotNetSDK\Eto\src\Eto.Wpf\Forms\WpfWindow.cs:line 256
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
[END ERROR]

When our plugin opens I’d like to get a list of all window layouts, and if our layout is not installed to install it.

Use runscript instead?
And make sure the calling command has script runner attribute

https://developer.rhino3d.com/api/rhinocommon/rhino.rhinoapp/runscript

1 Like

Any reason not to use RhinoApp.RunScript? I’ve never used SendKeystrokes before.

Something like this should work.

using System;
using System.Linq;

using Rhino;

bool LayoutExists(string name)
{
    RhinoApp.CommandWindowCaptureEnabled = true;

    RhinoApp.RunScript("-WindowLayout L _Enter", true);

    string[] strings = RhinoApp.CapturedCommandWindowStrings(false);
    RhinoApp.CommandWindowCaptureEnabled = false;

    bool layoutExists = strings.Any(s => s.Contains(name));
    return layoutExists;
}


string myLayoutName = "myLayout";
if (!LayoutExists(myLayoutName))
{
    var path = "<path>/<name>.rhw";
    RhinoApp.RunScript($"-WindowLayout I {path} _Enter", true);

    if (!LayoutExists(myLayoutName))
    {
        RhinoApp.WriteLine("Failed to load Window Layout!");
        return;
    }

    RhinoApp.RunScript($"-WindowLayout {myLayoutName} _Enter", true);
    
    RhinoApp.WriteLine("Loaded Window Layout!");
}

Disclaimer : CommandWindowCaptureEnabled apparently doesn’t work on mac, so this only works on Windows. Ticket

2 Likes

Thank you @CallumSykes That’s super helpful & works well on windows.
Had a little trouble clearing the captured command history but the below works.

Any way to delete a window layout?

    private void InstallWindowLayout(string layoutName, string path, bool load) {
		if (!LayoutExists(layoutName)) {
			RhinoApp.RunScript($"-WindowLayout I {path} _Enter", true);

			if (!LayoutExists(layoutName)) {
				RhinoApp.WriteLine("Failed to load Window Layout!");
				return;
			}

			RhinoApp.WriteLine("Installed Window Layout!");
		}

		if (load) {
			RhinoApp.RunScript($"-WindowLayout {layoutName} _Enter", true);
			RhinoApp.WriteLine("Loaded Window Layout!");
		}
	}

	private bool LayoutExists(string name) {
		RhinoApp.ClearCommandHistoryWindow();
		RhinoApp.CapturedCommandWindowStrings(true);// clear captured strings
		RhinoApp.CommandWindowCaptureEnabled = true;

		RhinoApp.RunScript("-WindowLayout L _Enter", true);

		string[] strings = RhinoApp.CapturedCommandWindowStrings(true);
		RhinoApp.CommandWindowCaptureEnabled = false;

		bool layoutExists = strings.Any(s => s.Contains(name));
		return layoutExists;
	}```

I can’t see an automatic way. Might be worth including a version number in the name of the layout in this case as any imported layout does not overwrite.

That’s a good idea, will do

thanks