diff --git a/App.config b/App.config
index 98282d404..e8470174a 100644
--- a/App.config
+++ b/App.config
@@ -1,21 +1,29 @@
-
+
-
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
-
+
-
+
diff --git a/MatterControl.csproj b/MatterControl.csproj
index 30655aad3..cce467a21 100644
--- a/MatterControl.csproj
+++ b/MatterControl.csproj
@@ -155,6 +155,7 @@
+
Form
@@ -452,9 +453,25 @@
+
+ packages\System.Reactive.Core.3.1.1\lib\net46\System.Reactive.Core.dll
+
+
+ packages\System.Reactive.Interfaces.3.1.1\lib\net45\System.Reactive.Interfaces.dll
+
+
+ packages\System.Reactive.Linq.3.1.1\lib\net46\System.Reactive.Linq.dll
+
+
+ packages\System.Reactive.PlatformServices.3.1.1\lib\net46\System.Reactive.PlatformServices.dll
+
+
+ packages\System.Reactive.Windows.Threading.3.1.1\lib\net45\System.Reactive.Windows.Threading.dll
+
packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll
+
@@ -465,6 +482,10 @@
+
+
+ packages\Zeroconf.2.9.0\lib\net45\Zeroconf.dll
+
diff --git a/SlicerConfiguration/Settings/SettingsHelpers.cs b/SlicerConfiguration/Settings/SettingsHelpers.cs
index 7d6845a18..ee0032145 100644
--- a/SlicerConfiguration/Settings/SettingsHelpers.cs
+++ b/SlicerConfiguration/Settings/SettingsHelpers.cs
@@ -87,6 +87,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
public const string has_sd_card_reader = nameof(has_sd_card_reader);
public const string heat_extruder_before_homing = nameof(heat_extruder_before_homing);
public const string include_firmware_updater = nameof(include_firmware_updater);
+ public const string selector_ip_address = nameof(selector_ip_address);
public const string ip_address = nameof(ip_address);
public const string ip_port = nameof(ip_port);
public const string layer_gcode = nameof(layer_gcode);
diff --git a/SlicerConfiguration/SliceSettingsOrganizer.cs b/SlicerConfiguration/SliceSettingsOrganizer.cs
index 608ffa482..43818e092 100644
--- a/SlicerConfiguration/SliceSettingsOrganizer.cs
+++ b/SlicerConfiguration/SliceSettingsOrganizer.cs
@@ -46,7 +46,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
public class SliceSettingData
{
[JsonConverter(typeof(StringEnumConverter))]
- public enum DataEditTypes { STRING, INT, INT_OR_MM, DOUBLE, POSITIVE_DOUBLE, OFFSET, DOUBLE_OR_PERCENT, VECTOR2, OFFSET2, CHECK_BOX, LIST, MULTI_LINE_TEXT, HARDWARE_PRESENT, COM_PORT };
+ public enum DataEditTypes { STRING, INT, INT_OR_MM, DOUBLE, POSITIVE_DOUBLE, OFFSET, DOUBLE_OR_PERCENT, VECTOR2, OFFSET2, CHECK_BOX, LIST, MULTI_LINE_TEXT, HARDWARE_PRESENT, COM_PORT, IP_LIST };
public string SlicerConfigName { get; set; }
diff --git a/SlicerConfiguration/SliceSettingsWidget.cs b/SlicerConfiguration/SliceSettingsWidget.cs
index c990485eb..2403f197b 100644
--- a/SlicerConfiguration/SliceSettingsWidget.cs
+++ b/SlicerConfiguration/SliceSettingsWidget.cs
@@ -606,6 +606,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
uiField = new ExtruderOffsetField(settingsContext, settingData.SlicerConfigName);
break;
+ case SliceSettingData.DataEditTypes.IP_LIST:
+ uiField = new IpAddessField(printer);
+ break;
default:
// Missing Setting
settingsRow.AddContent(new TextWidget(String.Format("Missing the setting for '{0}'.", settingData.DataEditType.ToString()))
diff --git a/SlicerConfiguration/SlicerMapping/EngineMappingMatterSlice.cs b/SlicerConfiguration/SlicerMapping/EngineMappingMatterSlice.cs
index 7396c69f0..593ec866f 100644
--- a/SlicerConfiguration/SlicerMapping/EngineMappingMatterSlice.cs
+++ b/SlicerConfiguration/SlicerMapping/EngineMappingMatterSlice.cs
@@ -136,6 +136,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
new VisibleButNotMappedToEngine("solid_shell"),
new VisibleButNotMappedToEngine(SettingsKey.laser_speed_025),
new VisibleButNotMappedToEngine(SettingsKey.laser_speed_100),
+ new VisibleButNotMappedToEngine("selector_ip_address"),
};
matterSliceSettingNames = new HashSet(mappedSettings.Select(m => m.CanonicalSettingsName));
diff --git a/SlicerConfiguration/UIFields/IpAddessField.cs b/SlicerConfiguration/UIFields/IpAddessField.cs
new file mode 100644
index 000000000..d54875a75
--- /dev/null
+++ b/SlicerConfiguration/UIFields/IpAddessField.cs
@@ -0,0 +1,127 @@
+using MatterHackers.Agg;
+using MatterHackers.Agg.UI;
+using MatterHackers.Localizations;
+using MatterHackers.MatterControl.PrinterCommunication;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MatterHackers.SerialPortCommunication.FrostedSerial;
+using Zeroconf;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ class IpAddessField : UIField
+ {
+ private DropDownList dropdownList;
+
+ private PrinterConfig printer;
+
+ public IpAddessField(PrinterConfig printer)
+ {
+ this.printer = printer;
+ }
+
+ public override void Initialize(int tabIndex)
+ {
+ EventHandler unregisterEvents = null;
+
+ base.Initialize(tabIndex);
+ bool canChangeComPort = !printer.Connection.PrinterIsConnected && printer.Connection.CommunicationState != CommunicationStates.AttemptingToConnect;
+ dropdownList = new DropDownList("Manual".Localize(), maxHeight: 200)
+ {
+ ToolTipText = HelpText,
+ Margin = new BorderDouble(),
+ TabIndex = tabIndex,
+
+ Enabled = canChangeComPort,
+ TextColor = canChangeComPort ? ActiveTheme.Instance.PrimaryTextColor : new Color(ActiveTheme.Instance.PrimaryTextColor, 150),
+ BorderColor = canChangeComPort ? ActiveTheme.Instance.SecondaryTextColor : new Color(ActiveTheme.Instance.SecondaryTextColor, 150),
+
+
+ };
+
+ dropdownList.Click += (s, e) =>
+ {
+ //this blows up without runonidle
+ //RebuildMenuItems();
+ };
+
+ RebuildMenuItems();
+
+ // Prevent droplist interaction when connected
+ printer.Connection.CommunicationStateChanged.RegisterEvent((s, e) =>
+ {
+ canChangeComPort = !printer.Connection.PrinterIsConnected && printer.Connection.CommunicationState != CommunicationStates.AttemptingToConnect;
+ dropdownList.Enabled = canChangeComPort;
+ dropdownList.TextColor = canChangeComPort ? ActiveTheme.Instance.PrimaryTextColor : new Color(ActiveTheme.Instance.PrimaryTextColor, 150);
+ dropdownList.BorderColor = canChangeComPort ? ActiveTheme.Instance.SecondaryTextColor : new Color(ActiveTheme.Instance.SecondaryTextColor, 150);
+ }, ref unregisterEvents);
+
+ // Release event listener on close
+ dropdownList.Closed += (s, e) =>
+ {
+ unregisterEvents?.Invoke(null, null);
+ };
+
+ this.Content = dropdownList;
+ }
+
+ protected override void OnValueChanged(FieldChangedEventArgs fieldChangedEventArgs)
+ {
+ dropdownList.SelectedLabel = this.Value;
+ base.OnValueChanged(fieldChangedEventArgs);
+ }
+
+ private void RebuildMenuItems()
+ {
+ IReadOnlyList possibleHosts = ProbeForNetworkedTelenetConnections().Result;
+ dropdownList.MenuItems.Clear();
+ MenuItem defaultOption = dropdownList.AddItem("Manual", "127.0.0.1:23");
+ defaultOption.Selected += (sender, e) =>
+ {
+ printer.Settings.SetValue(SettingsKey.selector_ip_address,defaultOption.Text);
+ };
+ foreach (Zeroconf.IZeroconfHost host in possibleHosts)
+ {
+ // Add each found telnet host to the dropdown list
+ IService service;
+ bool exists = host.Services.TryGetValue("_telnet._tcp.local.", out service);
+ int port = exists ? service.Port:23;
+ MenuItem newItem = dropdownList.AddItem(host.DisplayName, $"{host.IPAddress}:{port}"); //The port may be unnecessary
+ // When the given menu item is selected, save its value back into settings
+ newItem.Selected += (sender, e) =>
+ {
+ if (sender is MenuItem menuItem)
+ {
+ //this.SetValue(
+ // menuItem.Text,
+ // userInitiated: true);
+ string[] ipAndPort = menuItem.Value.Split(':');
+ printer.Settings.SetValue(SettingsKey.ip_address, ipAndPort[0]);
+ printer.Settings.SetValue(SettingsKey.ip_port, ipAndPort[1]);
+ printer.Settings.SetValue(SettingsKey.selector_ip_address, menuItem.Text);
+ }
+ };
+ }
+
+ }
+
+ private void DefaultOption_Selected(object sender, EventArgs e)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static async Task> ProbeForNetworkedTelenetConnections()
+ {
+ return await ZeroconfResolver.ResolveAsync("_telnet._tcp.local.");
+ }
+
+ public static async Task> EnumerateAllServicesFromAllHosts()
+ {
+ ILookup domains = await ZeroconfResolver.BrowseDomainsAsync();
+ return await ZeroconfResolver.ResolveAsync(domains.Select(g => g.Key));
+ }
+ }
+}
diff --git a/StaticData/SliceSettings/Layouts.txt b/StaticData/SliceSettings/Layouts.txt
index fc43f4441..440574a8d 100644
--- a/StaticData/SliceSettings/Layouts.txt
+++ b/StaticData/SliceSettings/Layouts.txt
@@ -15,6 +15,7 @@ Simple
auto_connect
baud_rate
com_port
+ selector_ip_address
ip_address
ip_port
Intermediate
@@ -81,6 +82,7 @@ Intermediate
auto_connect
baud_rate
com_port
+ selector_ip_address
ip_address
ip_port
Advanced
@@ -266,6 +268,7 @@ Advanced
auto_connect
baud_rate
com_port
+ selector_ip_address
ip_address
ip_port
Print Area
diff --git a/StaticData/SliceSettings/Properties.json b/StaticData/SliceSettings/Properties.json
index 0ad9f2c48..e71255ee9 100644
--- a/StaticData/SliceSettings/Properties.json
+++ b/StaticData/SliceSettings/Properties.json
@@ -1826,6 +1826,17 @@
"RebuildGCodeOnChange": false,
"ReloadUiWhenChanged": true
},
+ {
+ "SlicerConfigName": "selector_ip_address",
+ "PresentationName": "IP Finder",
+ "HelpText": "List of IP's discovered on the network",
+ "DataEditType": "IP_LIST",
+ "ShowAsOverride": false,
+ "ShowIfSet": "enable_network_printing",
+ "DefaultValue": "Manual",
+ "RebuildGCodeOnChange": false,
+ "ReloadUiWhenChanged": true
+ },
{
"SlicerConfigName": "ip_address",
"PresentationName": "IP Address",
@@ -1833,6 +1844,7 @@
"DataEditType": "STRING",
"ShowAsOverride": false,
"ShowIfSet": "enable_network_printing",
+ "EnableIfSet": "selector_ip_address=Manual",
"DefaultValue": "127.0.0.1",
"RebuildGCodeOnChange": false
},
@@ -1843,6 +1855,7 @@
"DataEditType": "INT",
"ShowAsOverride": false,
"ShowIfSet": "enable_network_printing",
+ "EnableIfSet": "selector_ip_address=Manual",
"DefaultValue": "23",
"RebuildGCodeOnChange": false
},
diff --git a/packages.config b/packages.config
index d01982fbb..1679dbf39 100644
--- a/packages.config
+++ b/packages.config
@@ -2,5 +2,12 @@
+
+
+
+
+
+
+
\ No newline at end of file