Skip to content

Commit

Permalink
Add basic UI for online library
Browse files Browse the repository at this point in the history
  • Loading branch information
visose committed Jan 21, 2022
1 parent 1b7281e commit 1cd99f0
Show file tree
Hide file tree
Showing 5 changed files with 306 additions and 29 deletions.
14 changes: 6 additions & 8 deletions .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@
**Robots** is a plugin for **[Rhino's](https://www.rhino3d.com/)** **Grasshopper** visual programming interface. It allows users to create and simulate robot programs for **ABB**, **KUKA**, **UR** and **Staubli** robots. It works in **Rhino 7** for **Windows** and **MacOS**.

## Install
1. Install in **Rhino 7** using the `_PackageManager` command, search for `Robots`.
> If you have an older version, delete `Robots.gha` and `Robots.dll` from the `Grasshopper Components` folder.
1. Download at least one pair of `XML` and `3DM` files from the [libraries folder](../libraries).
> You can install multiple libraries.
1. Place them inside a folder named `Robots` under the OS's `Documents` folder.
> In Windows the path will look like `C:\Users\userName\Documents\Robots\RobotLibrary.xml`.<br/>
> In Mac the path will look like `HD/Users/userName/Robots/RobotLibrary.xml`.

> If upgrading from an old version check [here](../../../wiki/home#Upgrading-from-an-older-version).
1. Install in **Rhino 7** using the `_PackageManager` command, search for `Robots`.
1. Restart **Rhino** and open **Grasshopper**. There should be a new tab in **Grasshopper** named `Robots`.
1. The robots from the library should appear in a **value list** when you place a `Load Robot System` component.
1. Install a robot library by clicking on the `Libraries` button of a `Load robot system` component.
> The robots from the library should appear in a **value list** connected to a `Load robot system` component.
1. Read the [docs](../../../wiki) for more info.
1. Check the [samples](../samples/).
> When opening a sample file, a dialog box might pop up with an assembly not found message. You can close this without fixing the path, it will automatically get fixed after the sample file is loaded.
4 changes: 3 additions & 1 deletion RELEASE
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
- version: 1.0.5
- version: 1.1.0
changes:
- Added UI to install robot libraries automatically inside Grasshopper.
- Added validation to names of target attributes and programs.
- Improved behavior of simulation playback controls.

- version: 1.0.4
changes:
Expand Down
255 changes: 249 additions & 6 deletions src/Robots.Grasshopper/RobotSystem/LibrariesForm.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,267 @@
using Eto.Drawing;
using System.Linq.Expressions;
using System.Diagnostics;
using Eto.Drawing;
using Eto.Forms;
using Rhino.Resources;
using static Robots.Grasshopper.LibrariesForm;
using EtoCommand = Eto.Forms.Command;

namespace Robots.Grasshopper;

class LibraryCell : StackLayout
{
public LibraryCell()
{
Padding = 5;
Spacing = 0;
Orientation = Orientation.Horizontal;
VerticalContentAlignment = VerticalAlignment.Center;

Items.Add(new StackLayoutItem(NewLabel(i => i.Name), true));
Items.Add(NewLabel(i => Icons(i), TextAlignment.Right));
}
}

class LibrariesForm : ComponentForm
{
public LibrariesForm()
// static

const string _helpUrl = "https://github.com/visose/Robots/wiki/Robot-libraries";

public static Label NewLabel(Expression<Func<LibraryItem, string>> bindText, TextAlignment align = TextAlignment.Left, Font? font = null)
{
Title = "Robot libraries";
var label = new Label
{
TextAlignment = align
};

if (font is not null)
label.Font = font;

label.TextBinding.BindDataContext(bindText);
return label;
}

public static string Icons(LibraryItem item)
{
if (item.IsLocal && item.IsDownloaded)
return "❕📁";

if (item.IsLocal)
return "📁";

if (item.IsDownloaded && item.IsUpdateAvailable)
return "⬆✔";

if (item.IsDownloaded)
return "✔";

if (item.IsOnline)
return "💾";

return "⚠";
}

static string Description(LibraryItem item)
{
if (item.IsLocal && item.IsDownloaded)
return "❕📁 Local override, installed";

if (item.IsLocal && item.IsOnline)
return "📁 Local, available online";

if (item.IsLocal)
return "📁 Local";

if (item.IsDownloaded && item.IsUpdateAvailable)
return "⬆✔ Installed, update available";

if (item.IsDownloaded && !item.IsOnline)
return "✔⚠ Installed, online missing";

if (item.IsDownloaded)
return "✔ Installed";

if (item.IsOnline)
return "💾 Available online";

return "⚠ Unknown error";
}

Padding = new Padding(5);
MinimumSize = new Size(200, 200);
// instance

readonly OnlineLibrary _library;
readonly GridView _grid;
readonly StackLayout _detailView;

public LibrariesForm()
{
_library = new OnlineLibrary();

Title = "Robot libraries";
BackgroundColor = Colors.White;
MinimumSize = new Size(600, 300);
Content = new StackLayout
{
Orientation = Orientation.Horizontal,
Spacing = 20,
Padding = 10,
Items =
{
ListView(_grid = Grid()),
new StackLayoutItem(_detailView = DetailView(), VerticalAlignment.Stretch, true)
}
};

_grid.SelectedRowsChanged += (s, e) => _detailView.DataContext = _grid.SelectedItem;
}

async Task UpdateAsync()
{
await _library.UpdateLibraryAsync();

var values = _library.Libraries.Values;
var ordered = values.OrderBy(i => i.Name);
_grid.DataStore = null;
_grid.DataStore = ordered;

if (values.Any())
_grid.SelectRow(0);
}

async Task DownloadAsync()
{
var item = (LibraryItem)_detailView.DataContext;

var success = item switch
{
{ IsUpdateAvailable: true } => await _library.TryDownloadLibraryAsync(item),
{ IsDownloaded: true } => _library.TryRemoveDownloadedLibrary(item),
_ => throw new ArgumentException("Invalid action")
};

if (!success)
MessageBox.Show(this, $"{ItemActions(item)} error on {item.Name}", MessageBoxType.Error);

_detailView.UpdateBindings(BindingUpdateMode.Destination);
_grid.ReloadData(_grid.SelectedRow);
}

string ItemActions(LibraryItem item) => item switch
{
{ IsDownloaded: true, IsUpdateAvailable: true } => "Update",
{ IsUpdateAvailable: true } => "Install",
{ IsDownloaded: true } => "Delete",
_ => ""
};

GridView Grid() => new()
{
Size = new Size(300, 300),
Border = BorderType.None,
GridLines = GridLines.Horizontal,
ShowHeader = false,
AllowMultipleSelection = false,
Columns =
{
new GridColumn
{
DataCell = CustomCell.Create<LibraryCell>(),
Expand = true
}
}
};

StackLayout ListView(GridView grid) => new()
{
Spacing = 10,
HorizontalContentAlignment = HorizontalAlignment.Stretch,
Items =
{
new StackLayoutItem(new Scrollable
{
Border = BorderType.Line,
ExpandContentWidth = true,
ExpandContentHeight = false,
Content = grid
}, true),
new StackLayout
{
Orientation = Orientation.Horizontal,
VerticalContentAlignment = VerticalAlignment.Bottom,
Items =
{
"Hello World!"
new StackLayoutItem(NewAsyncButton(UpdateAsync, label: "Refresh list", runOnce: true), true),
new LinkButton
{
Text = "Help",
Command = new EtoCommand((s, e) => Process.Start(_helpUrl))
}
}
}
}
};

StackLayout DetailView() => new()
{
Spacing = 10,
Items =
{
NewLabel(i => i.Name, font: EtoFonts.BoldHeadingFont),
NewLabel(i => Description(i), font: EtoFonts.NormalFont),
new StackLayoutItem(null, true),
NewDetailButton()
}
};

StackLayout NewDetailButton()
{
var detailButton = NewAsyncButton(DownloadAsync);
var button = (Button)detailButton.Items[0].Control;
button.TextBinding.BindDataContext((LibraryItem i) => ItemActions(i));
button.BindDataContext(s => s.Visible, (LibraryItem i) => ItemActions(i) != "");
return detailButton;
}

static StackLayout NewAsyncButton(Func<Task> actionAsync, string? label = null, bool runOnce = false)
{
Button button = new()
{
Text = label
};

Spinner spinner = new()
{
Size = new Size(22, 22),
Visible = false
};

button.Click += async (s, e) => await ClickAsync();

if (runOnce)
button.PerformClick();

return new StackLayout
{
Spacing = 5,
Orientation = Orientation.Horizontal,
VerticalContentAlignment = VerticalAlignment.Center,
Items =
{
button,
spinner
}
};

async Task ClickAsync()
{
button.Enabled = false;
spinner.Visible = true;

await actionAsync();

button.Enabled = true;
spinner.Visible = false;
}
}
}
2 changes: 1 addition & 1 deletion src/Robots/IO/FileIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ static IEnumerable<string> GetLibraries()
{
var name = Path.GetFileNameWithoutExtension(file);

if (!previous.Add(name))
if (!previous.Add(name.ToLowerInvariant()))
continue;

yield return file;
Expand Down
Loading

0 comments on commit 1cd99f0

Please sign in to comment.