-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19 from malware-dev/mockup-ui-presentation
Initial presentation UI implementation.
- Loading branch information
Showing
39 changed files
with
576 additions
and
537 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
Here is an example template for decorating a mocked ingame block. | ||
|
||
```cs | ||
using System.Collections.Generic; | ||
using System.ComponentModel; | ||
using System.ComponentModel.DataAnnotations; | ||
using System.Linq; | ||
using System.Text; | ||
using IngameScript.Mockups.Base; | ||
using Sandbox.ModAPI.Interfaces; | ||
using SpaceEngineers.Game.ModAPI.Ingame; | ||
|
||
namespace IngameScript.Mockups.Blocks | ||
{ | ||
#if !MOCKUP_DEBUG | ||
[System.Diagnostics.DebuggerNonUserCode] | ||
#endif | ||
// Decorate the class with a DisplayName attribute to have it visible in the block picker. | ||
[DisplayName("Air Vent")] | ||
public partial class MockAirVent : MockFunctionalBlock, IMyAirVent | ||
{ | ||
// Decorate a property with a DisplayName attribute to have it visible in the block details screen. | ||
// Add Range and ReadOnly attributes when appropriate to control how the property is rendered. | ||
[DisplayName("Oxygen Level"), Range(0, 1)] | ||
public virtual float OxygenLevel { get; set; } = 0; | ||
|
||
[DisplayName("Can Pressurize")] | ||
public virtual bool CanPressurize { get; set; } = true; | ||
|
||
[DisplayName("Is Depressurizing"), ReadOnly(true)] | ||
public virtual bool IsDepressurizing => Enabled && (Status == VentStatus.Depressurizing || Status == VentStatus.Depressurized); | ||
|
||
[DisplayName("De-pressurize")] | ||
public virtual bool Depressurize { get; set; } = false; | ||
|
||
[DisplayName("Status")] | ||
public virtual VentStatus Status { get; set; } | ||
|
||
public virtual bool PressurizationEnabled { get; } = true; | ||
|
||
protected override IEnumerable<ITerminalProperty> CreateTerminalProperties() | ||
{ | ||
return base.CreateTerminalProperties().Concat(new[] | ||
{ | ||
new MockTerminalProperty<IMyAirVent, bool>("Depressurize", b => b.Depressurize, (b, v) => b.Depressurize = v) | ||
}); | ||
} | ||
|
||
// Decorate methods with a DisplayName attribute to add them to the list of actions in the block details screen. | ||
[DisplayName("Get Oxygen Level")] | ||
public virtual float GetOxygenLevel() => OxygenLevel; | ||
|
||
public virtual bool IsPressurized() => PressurizationEnabled && (Status == VentStatus.Pressurized || Status == VentStatus.Pressurizing); | ||
} | ||
} | ||
``` | ||
|
||
Additional things to consider: | ||
* Space Engineers only supports C# 6.0, do not use any language features from higher versions (the TestScript will help confirm this). | ||
* Do not create `private` properties unless they are only required for your specific implementation, these classes should be easily extendable. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
using System; | ||
using System.ComponentModel; | ||
using System.ComponentModel.DataAnnotations; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Windows; | ||
using System.Windows.Controls; | ||
using System.Windows.Controls.Primitives; | ||
using System.Windows.Data; | ||
using MDK_UI.TemplateConverters; | ||
using Xceed.Wpf.Toolkit; | ||
using MessageBox = System.Windows.MessageBox; | ||
|
||
namespace MDK_UI.Extensions | ||
{ | ||
static class ReflectionBindingExtensions | ||
{ | ||
public static UIElement ToUiElement(this PropertyInfo prop, object target, PropertyInfo parent = null) | ||
{ | ||
switch (prop.GetDataType()) | ||
{ | ||
case DataType.MultilineText: | ||
var textArea = new TextBox() | ||
{ | ||
Height = 200, | ||
VerticalScrollBarVisibility = ScrollBarVisibility.Auto, | ||
AcceptsReturn = true, | ||
IsReadOnly = prop.IsReadOnly() | ||
}; | ||
|
||
textArea.SetBinding(TextBox.TextProperty, prop.GetBinding(target)); | ||
return textArea; | ||
default: | ||
var type = parent?.PropertyType ?? prop.PropertyType; | ||
|
||
if (type == typeof(bool)) | ||
{ | ||
var checkBox = new CheckBox | ||
{ | ||
IsEnabled = !prop.IsReadOnly(), | ||
VerticalAlignment = VerticalAlignment.Center | ||
}; | ||
|
||
checkBox.SetBinding(ToggleButton.IsCheckedProperty, prop.GetBinding(target)); | ||
return checkBox; | ||
} | ||
else if (type == typeof(int) || type == typeof(float)) | ||
{ | ||
if (prop.HasAttribute<RangeAttribute>()) | ||
{ | ||
var values = prop.GetCustomAttribute<RangeAttribute>(); | ||
var range = new Slider | ||
{ | ||
Minimum = (double)values.Minimum, | ||
Maximum = (double)values.Maximum, | ||
IsEnabled = !prop.IsReadOnly(), | ||
VerticalAlignment = VerticalAlignment.Center | ||
}; | ||
|
||
if (type == typeof(int)) | ||
{ | ||
range.TickFrequency = 1; | ||
} | ||
else | ||
{ | ||
range.TickFrequency = 0.01; | ||
} | ||
|
||
range.SetBinding(RangeBase.ValueProperty, prop.GetBinding(target)); | ||
return range; | ||
} | ||
else | ||
{ | ||
var range = new SingleUpDown | ||
{ | ||
IsReadOnly = !prop.IsReadOnly(), | ||
VerticalAlignment = VerticalAlignment.Center | ||
}; | ||
|
||
if (type == typeof(int)) | ||
{ | ||
range.Increment = 1; | ||
} | ||
else | ||
{ | ||
range.Increment = 0.01f; | ||
} | ||
|
||
range.SetBinding(SingleUpDown.ValueProperty, prop.GetBinding(target)); | ||
return range; | ||
} | ||
} | ||
else if (type == typeof(VRageMath.Color)) | ||
{ | ||
var colorPicker = new ColorPicker | ||
{ | ||
VerticalAlignment = VerticalAlignment.Center | ||
}; | ||
|
||
var binder = prop.GetBinding(target); | ||
binder.Converter = new ColorConverter(); | ||
|
||
colorPicker.SetBinding(ColorPicker.SelectedColorProperty, binder); | ||
return colorPicker; | ||
} | ||
else if (type == typeof(string)) | ||
{ | ||
var textBox = new TextBox | ||
{ | ||
AcceptsReturn = false, | ||
IsReadOnly = prop.IsReadOnly() | ||
}; | ||
|
||
textBox.SetBinding(TextBox.TextProperty, prop.GetBinding(target)); | ||
|
||
return textBox; | ||
} | ||
else if (type.IsEnum) | ||
{ | ||
var comboBox = new ComboBox | ||
{ | ||
IsReadOnly = prop.IsReadOnly(), | ||
IsEnabled = !prop.IsReadOnly() | ||
}; | ||
|
||
foreach (var value in Enum.GetValues(type)) | ||
{ | ||
comboBox.Items.Add(value); | ||
} | ||
|
||
var binding = prop.GetBinding(target); | ||
//binding.Converter = new DisplayNameConverter(); | ||
|
||
comboBox.SetBinding(Selector.SelectedItemProperty, binding); | ||
return comboBox; | ||
} | ||
else | ||
{ | ||
return new TextBlock() | ||
{ | ||
Text = $"Unsupported property type {type.Name}." | ||
}; | ||
} | ||
} | ||
} | ||
|
||
public static UIElement ToUIElement(this MethodInfo method, object target, MethodInfo parent = null) | ||
{ | ||
var name = method.GetCustomAttribute<DisplayNameAttribute>().DisplayName; | ||
var element = new Button | ||
{ | ||
Content = name | ||
}; | ||
|
||
method = parent ?? method; | ||
if (method.GetParameters().Any()) | ||
{ | ||
element.Click += UnsupportedMethod; | ||
} | ||
else | ||
{ | ||
element.Click += (sender, args) => | ||
{ | ||
var result = method.Invoke(target, new object[] { }); | ||
|
||
if (method.ReturnType != typeof(void)) | ||
element.InvokeMessageBox($"{name} returned:\n{result}", "Action Result", MessageBoxButton.OK, MessageBoxImage.Information); | ||
}; | ||
} | ||
|
||
return element; | ||
} | ||
|
||
private static void InvokeMessageBox(this UIElement element, string message, string caption, MessageBoxButton button, MessageBoxImage icon) | ||
{ | ||
element.Dispatcher.Invoke(() => MessageBox.Show(message, caption, button, icon)); | ||
} | ||
|
||
private static RoutedEventHandler UnsupportedMethod { get; } = (sender, args) => | ||
{ | ||
(sender as UIElement).InvokeMessageBox("Executing actions with parameters is not yet supported.", "Not Supported", MessageBoxButton.OK, MessageBoxImage.Exclamation); | ||
}; | ||
|
||
private static bool IsReadOnly(this PropertyInfo prop) | ||
=> !prop.CanWrite || (prop.GetCustomAttribute<ReadOnlyAttribute>()?.IsReadOnly ?? false); | ||
|
||
private static DataType GetDataType(this PropertyInfo prop) | ||
=> prop.GetCustomAttribute<DataTypeAttribute>()?.DataType ?? DataType.Text; | ||
|
||
private static Binding GetBinding(this PropertyInfo prop, object target) | ||
=> new Binding(prop.Name) | ||
{ | ||
Mode = prop.IsReadOnly() ? BindingMode.OneWay : BindingMode.Default, | ||
Source = target | ||
}; | ||
} | ||
} |
Oops, something went wrong.