Implement separate inner and outer threshold sliders, and a custom threshold slider.

master
Glenn Maynard 5 years ago
parent 18475afbf8
commit d4c71941eb
  1. 11
      smx-config/App.config
  2. 11
      smx-config/ConfigPresets.cs
  3. 223
      smx-config/Helpers.cs
  4. 128
      smx-config/MainWindow.xaml
  5. 61
      smx-config/MainWindow.xaml.cs
  6. 42
      smx-config/Properties/Settings.Designer.cs
  7. 11
      smx-config/Properties/Settings.settings
  8. BIN
      smx-config/Resources/pad_cardinal.png
  9. BIN
      smx-config/Resources/pad_center.png
  10. BIN
      smx-config/Resources/pad_diagonal.png
  11. BIN
      smx-config/Resources/pad_down.png
  12. BIN
      smx-config/Resources/pad_down_left.png
  13. BIN
      smx-config/Resources/pad_down_right.png
  14. BIN
      smx-config/Resources/pad_left.png
  15. BIN
      smx-config/Resources/pad_right.png
  16. BIN
      smx-config/Resources/pad_up.png
  17. BIN
      smx-config/Resources/pad_up_left.png
  18. BIN
      smx-config/Resources/pad_up_right.png
  19. 23
      smx-config/SMXConfig.csproj
  20. 13
      smx-config/SetCustomSensors.xaml
  21. 33
      smx-config/SetCustomSensors.xaml.cs
  22. 248
      smx-config/Widgets.cs

@ -13,9 +13,18 @@
<setting name="LaunchOnStartup" serializeAs="String">
<value>False</value>
</setting>
<setting name="AuxSensors" serializeAs="String">
<setting name="CustomSensors" serializeAs="String">
<value />
</setting>
<setting name="UseInnerSensorThresholds" serializeAs="String">
<value>False</value>
</setting>
<setting name="UseOuterSensorThresholds" serializeAs="String">
<value>False</value>
</setting>
<setting name="AdvancedMode" serializeAs="String">
<value>False</value>
</setting>
</smx_config.Properties.Settings>
</userSettings>
</configuration>

@ -137,7 +137,7 @@ namespace smx_config
// and corners. Rev1 firmware uses those only. Copy cardinal directions (down) to the
// other cardinal directions (except for up, which already had its own setting) and corners
// to the other corners.
static public void SyncUnifiedThresholds(ref SMX.SMXConfig config)
static private void SyncUnifiedThresholds(ref SMX.SMXConfig config)
{
for(int fromPanel = 0; fromPanel < 9; ++fromPanel)
{
@ -155,14 +155,5 @@ namespace smx_config
}
}
}
// Return true if the panel thresholds are already synced, so SyncUnifiedThresholds would
// have no effect.
static public bool AreUnifiedThresholdsSynced(SMX.SMXConfig config)
{
SMX.SMXConfig config2 = Helpers.DeepClone(config);
SyncUnifiedThresholds(ref config2);
return SamePreset(config, config2);
}
}
}

@ -379,7 +379,7 @@ namespace smx_config
// The threshold sliders in the advanced tab affect different panels and sensors depending
// on the user's settings. This handles managing which sensors each slider controls.
static class ThresholdSettings
static public class ThresholdSettings
{
[Serializable]
public struct PanelAndSensor
@ -393,6 +393,17 @@ namespace smx_config
public int sensor;
};
public static List<string> thresholdSliderNames = new List<string>()
{
"up-left", "up", "up-right",
"left", "center", "right",
"down-left", "down", "down-right",
"cardinal", "corner",
"inner-sensors",
"outer-sensors",
"custom-sensors",
};
// These correspond with ThresholdSlider.Type.
static Dictionary<string, int> panelNameToIndex = new Dictionary<string, int>() {
{ "up-left", 0 },
@ -409,15 +420,12 @@ namespace smx_config
// are then synced to the other panels.
{ "cardinal", 7 },
{ "corner", 2 },
// The aux threshold allows giving a list of specific sensors different thresholds.
{ "aux", -1 },
};
// Save and load the list of aux sensors to settings. These aren't saved to the pad, we just
// keep them in application settings.
static List<PanelAndSensor> cachedAuxSensors;
static public void SetAuxSensors(List<PanelAndSensor> panelAndSensors)
// Save and load the list of custom threshold sensors to settings. These aren't saved to the pad, we
// just keep them in application settings.
static List<PanelAndSensor> cachedCustomSensors;
static public void SetCustomSensors(List<PanelAndSensor> panelAndSensors)
{
List<object> result = new List<object>();
foreach(PanelAndSensor panelAndSensor in panelAndSensors)
@ -426,31 +434,38 @@ namespace smx_config
result.Add(panelAndSensorArray);
}
Properties.Settings.Default.AuxSensors = SerializeJSON.Serialize(result);
SetCustomSensorsJSON(result);
}
// Set CustomSensors from a [[1,1],[2,2]] array. This is what we save to settings and
// export to JSON.
static public void SetCustomSensorsJSON(List<object> panelAndSensors)
{
Properties.Settings.Default.CustomSensors = SerializeJSON.Serialize(panelAndSensors);
Properties.Settings.Default.Save();
// Clear the cache. Set it to null instead of assigning panelAndSensors to it to force
// it to re-parse at least once, to catch problems early.
cachedAuxSensors = null;
cachedCustomSensors = null;
}
// Return the sensors that are controlled by the aux threshold slider. The other
// Return the sensors that are controlled by the custom-sensors slider. The other
// threshold sliders will leave these alone.
static public List<PanelAndSensor> GetAuxSensors()
static public List<PanelAndSensor> GetCustomSensors()
{
// Properties.Settings.Default.AuxSensors = "[[0,0], [1,0]]";
// This is only ever changed with calls to SetSavedAuxSensors.
if(cachedAuxSensors != null)
return Helpers.DeepClone(cachedAuxSensors);
// Properties.Settings.Default.CustomSensors = "[[0,0], [1,0]]";
// This is only ever changed with calls to SetCustomSensors.
if(cachedCustomSensors != null)
return Helpers.DeepClone(cachedCustomSensors);
List<PanelAndSensor> result = new List<PanelAndSensor>();
if(Properties.Settings.Default.AuxSensors == "")
if(Properties.Settings.Default.CustomSensors == "")
return result;
try {
// This is a list of [panel,sensor] arrays:
// [[0,0], [0,1], [1,0]]
List<object> sensors = SMXJSON.ParseJSON.Parse<List<object>>(Properties.Settings.Default.AuxSensors);
List<object> sensors = GetCustomSensorsJSON();
foreach(object panelAndSensorObj in sensors)
{
List<object> panelAndSensor = (List<object>) panelAndSensorObj;
@ -465,18 +480,104 @@ namespace smx_config
return result;
}
cachedAuxSensors = result;
// SetAuxSensors(result); // XXX
cachedCustomSensors = result;
return Helpers.DeepClone(cachedCustomSensors);
}
static public List<object> GetCustomSensorsJSON()
{
return SMXJSON.ParseJSON.Parse<List<object>>(Properties.Settings.Default.CustomSensors);
}
// SetSavedAuxSensors(result);
return Helpers.DeepClone(cachedAuxSensors);
const int SensorLeft = 0;
const int SensorRight = 1;
const int SensorUp = 2;
const int SensorDown = 3;
static public List<PanelAndSensor> GetInnerSensors()
{
return new List<PanelAndSensor>()
{
new PanelAndSensor(1,SensorDown), // up panel, bottom sensor
new PanelAndSensor(3,SensorRight), // left panel, right sensor
new PanelAndSensor(5,SensorLeft), // right panel, left sensor
new PanelAndSensor(7,SensorUp), // down panel, top sensor
};
}
static public List<PanelAndSensor> GetControlledSensorsForSliderType(string Type, bool advancedMode)
static public List<PanelAndSensor> GetOuterSensors()
{
return new List<PanelAndSensor>()
{
new PanelAndSensor(1,SensorUp), // up panel, top sensor
new PanelAndSensor(3,SensorLeft), // left panel, left sensor
new PanelAndSensor(5,SensorRight), // right panel, right sensor
new PanelAndSensor(7,SensorDown), // down panel, bottom sensor
};
}
// Return the sensors controlled by the given slider. Most of the work is done
// in GetControlledSensorsForSliderTypeInternal. This just handles removing overlapping
// sensors. If inner-sensors is enabled, the inner sensors are removed from the normal
// thresholds.
//
// This is really inefficient: it calls GetControlledSensorsForSliderTypeInternal a lot,
// and the filtering is a linear search, but it doesn't matter.
//
// If includeOverridden is true, include sensors that would be controlled by this slider
// by default, but which have been overridden by a higher priority slider, or which are
// disabled by checkboxes. This is used for the UI.
static public List<PanelAndSensor> GetControlledSensorsForSliderType(string Type, bool advancedMode, bool includeOverridden)
{
// The aux threshold slider always controls the aux sensors.
if(Type == "aux")
return GetAuxSensors();
List<PanelAndSensor> result = GetControlledSensorsForSliderTypeInternal(Type, advancedMode, includeOverridden);
if(!includeOverridden)
{
// inner-sensors, outer-sensors and custom thresholds overlap each other and the standard
// sliders. inner-sensors and outer-sensors take over the equivalent sensors in the standard
// sliders, and custom thresholds take priority over everything else.
//
// We always pass false to includeOverridden here, since we need to know the real state of the
// sliders we're removing.
if(Type == "inner-sensors" || Type == "outer-sensors")
{
// Remove any sensors controlled by the custom threshold.
RemoveFromSensorList(result, GetControlledSensorsForSliderTypeInternal("custom-sensors", advancedMode, false));
}
else if(Type != "custom-sensors")
{
// This is a regular slider. Remove any sensors controlled by inner-sensors, outer-sensors
// or custom-sensors.
RemoveFromSensorList(result, GetControlledSensorsForSliderTypeInternal("inner-sensors", advancedMode, false));
RemoveFromSensorList(result, GetControlledSensorsForSliderTypeInternal("outer-sensors", advancedMode, false));
RemoveFromSensorList(result, GetControlledSensorsForSliderTypeInternal("custom-sensors", advancedMode, false));
}
}
return result;
}
static private void RemoveFromSensorList(List<PanelAndSensor> target, List<PanelAndSensor> sensorsToRemove)
{
foreach(PanelAndSensor panelAndSensor in sensorsToRemove)
target.Remove(panelAndSensor);
}
static private List<PanelAndSensor> GetControlledSensorsForSliderTypeInternal(string Type, bool advancedMode, bool includeOverridden)
{
// inner-sensors and outer-sensors do nothing if their checkbox is disabled. We do this here because we
// need to skip this for the RemoveFromSensorList logic above.
if(!includeOverridden)
{
if(Type == "inner-sensors" && !Properties.Settings.Default.UseInnerSensorThresholds)
return new List<PanelAndSensor>();
if(Type == "outer-sensors" && !Properties.Settings.Default.UseOuterSensorThresholds)
return new List<PanelAndSensor>();
}
// Special sliders:
if(Type == "custom-sensors") return GetCustomSensors();
if(Type == "inner-sensors") return GetInnerSensors();
if(Type == "outer-sensors") return GetOuterSensors();
List<PanelAndSensor> result = new List<PanelAndSensor>();
@ -498,7 +599,6 @@ namespace smx_config
// If advanced mode is disabled, save to all panels this slider affects. The down arrow controls
// all four cardinal panels. (If advanced mode is enabled we'll never be a different cardinal
// direction, since those widgets won't exist.) If it's disabled, just write to our own panel.
List<PanelAndSensor> auxSensors = GetAuxSensors();
List<int> saveToPanels = new List<int>();
int ourPanelIdx = panelNameToIndex[Type];
saveToPanels.Add(ourPanelIdx);
@ -508,17 +608,59 @@ namespace smx_config
foreach(int panelIdx in saveToPanels)
{
for(int sensor = 0; sensor < 4; ++sensor)
{
// Ignore sensors controlled by the aux threshold.
PanelAndSensor panelAndSensor = new PanelAndSensor(panelIdx, sensor);
if(auxSensors.Contains(panelAndSensor))
continue;
result.Add(new PanelAndSensor(panelIdx, sensor));
}
return result;
}
// If the user disables inner-sensors after setting a value and control of those thresholds
// goes back to other sliders, the old inner-sensors thresholds will still be set in config
// until the user changes them, which is confusing. Make sure the value of each slider is
// actually set to config, even if the user doesn't change them.
//
// This isn't perfect. If the user assigns the first up sensor to custom and then removes it,
// so that sensor goes back to the normal up slider, this will sync the custom value to up.
// That's because we don't know which thresholds were actually being controlled by the up slider
// before it was changed. This is tricky to fix and not a big problem.
private static void SyncSliderThresholdsForConfig(ref SMX.SMXConfig config)
{
if(!config.fsr())
return;
result.Add(panelAndSensor);
bool AdvancedModeEnabled = Properties.Settings.Default.AdvancedMode;
foreach(string sliderName in thresholdSliderNames)
{
List<PanelAndSensor> controlledSensors = GetControlledSensorsForSliderType(sliderName, AdvancedModeEnabled, false);
if(controlledSensors.Count == 0)
continue;
PanelAndSensor firstSensor = controlledSensors[0];
foreach(PanelAndSensor panelAndSensor in controlledSensors)
{
config.panelSettings[panelAndSensor.panel].fsrLowThreshold[panelAndSensor.sensor] =
config.panelSettings[firstSensor.panel].fsrLowThreshold[firstSensor.sensor];
config.panelSettings[panelAndSensor.panel].fsrHighThreshold[panelAndSensor.sensor] =
config.panelSettings[firstSensor.panel].fsrHighThreshold[firstSensor.sensor];
}
}
}
return result;
public static void SyncSliderThresholds()
{
foreach(Tuple<int,SMX.SMXConfig> activePad in ActivePad.ActivePads())
{
SMX.SMXConfig config = activePad.Item2;
SyncSliderThresholdsForConfig(ref config);
SMX.SMX.SetConfig(activePad.Item1, config);
}
CurrentSMXDevice.singleton.FireConfigurationChanged(null);
}
public static bool IsAdvancedModeRequired()
{
return false;
}
}
@ -735,6 +877,11 @@ namespace smx_config
}
dict.Add("panelColors", panelColors);
dict.Add("advancedMode", Properties.Settings.Default.AdvancedMode);
dict.Add("useOuterSensorThresholds", Properties.Settings.Default.UseOuterSensorThresholds);
dict.Add("useInnerSensorThresholds", Properties.Settings.Default.UseInnerSensorThresholds);
dict.Add("customSensors", ThresholdSettings.GetCustomSensorsJSON());
return SMXJSON.SerializeJSON.Serialize(dict);
}
@ -798,6 +945,14 @@ namespace smx_config
config.stepColor[PanelIndex*3+2] = color.B;
}
}
// Older exported settings don't have advancedMode. Set it to true if it's missing.
Properties.Settings.Default.AdvancedMode = dict.Get<bool>("advancedMode", true);
Properties.Settings.Default.UseOuterSensorThresholds = dict.Get<bool>("useOuterSensorThresholds", false);
Properties.Settings.Default.UseInnerSensorThresholds = dict.Get<bool>("useInnerSensorThresholds", false);
List<object> customSensors = dict.Get<List<object>>("customSensors", null);
if(customSensors != null)
ThresholdSettings.SetCustomSensorsJSON(customSensors);
}
};
}

@ -135,15 +135,15 @@ Use if the platform is too sensitive.</clr:String>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:ThresholdSlider}">
<Grid Margin="0,0,0,0" Width="400" HorizontalAlignment="Center" VerticalAlignment="Center">
<Image
<Grid Margin="0,0,0,0" Width="500" HorizontalAlignment="Center" VerticalAlignment="Center">
<controls:PlatformSensorDisplay
x:Name="PlatformSensorDisplay"
Margin="-370,0,0,0"
Height="28" Width="28"
VerticalAlignment="Top"
Source="{TemplateBinding Icon}"
/>
<Label Margin="-300,0,0,0" x:Name="LowerValue" Content="0" Width="30" HorizontalContentAlignment="Right"
VerticalAlignment="Top"
Visibility="{Binding Path=SliderActive, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
<Image x:Name="ThresholdWarning"
Source="Resources/threshold_warning.png" Width="9" Height="28"
@ -158,10 +158,28 @@ Use if the platform is too sensitive.</clr:String>
Width="240"
Focusable="False"
Style="{DynamicResource DoubleSlider}"
IsEnabled="{Binding Path=SliderActive, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
/>
<Label Margin="360,0,0,0" x:Name="UpperValue" Content="0" Width="40" HorizontalContentAlignment="Center"
VerticalAlignment="Top"
VerticalAlignment="Top"
Visibility="{Binding Path=SliderActive, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
<!-- This is only shown for inner-sensors and outer-sensors. It's always hidden and
checked for other sliders. -->
<controls:ThresholdEnabledButton
x:Name="EnabledCheckbox"
controls:Type="{Binding Path=Type, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="-450,0,0,0"
IsChecked="{Binding Path=ThresholdEnabled, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
/>
<Button
x:Name="EditCustomSensorsButton"
Visibility="Hidden"
Content="Edit" Width="35" Height="30" Margin="-450 0 0 0" Padding="0 0" />
</Grid>
</ControlTemplate>
</Setter.Value>
@ -333,7 +351,7 @@ Use if the platform is too sensitive.</clr:String>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:PanelColorButton}"
BasedOn="{StaticResource {x:Type controls:ColorButton}}">
@ -601,7 +619,7 @@ Use if the platform is too sensitive.</clr:String>
Text="Some sensors on this panel aren't responding correctly."
/>
</DockPanel>
<DockPanel
x:Name="BadSensorDIPSwitches"
Width="200"
@ -702,7 +720,7 @@ Use if the platform is too sensitive.</clr:String>
</Setter.Value>
</Setter>
</Style>
<!-- P1, P2 labels in the top right: -->
<Style x:Key="EnabledIcon" TargetType="Label">
<Style.Triggers>
@ -715,6 +733,76 @@ Use if the platform is too sensitive.</clr:String>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type controls:PlatformSensorDisplay}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:PlatformSensorDisplay}">
<Grid Width="34" Height="34">
<controls:PanelIconWithSensors x:Name="Panel0" Margin="-22,-22,0,0" />
<controls:PanelIconWithSensors x:Name="Panel1" Margin=" 0,-22,0,0" />
<controls:PanelIconWithSensors x:Name="Panel2" Margin="+22,-22,0,0" />
<controls:PanelIconWithSensors x:Name="Panel3" Margin="-22, 0,0,0" />
<controls:PanelIconWithSensors x:Name="Panel4" Margin=" 0, 0,0,0" />
<controls:PanelIconWithSensors x:Name="Panel5" Margin="+22, 0,0,0" />
<controls:PanelIconWithSensors x:Name="Panel6" Margin="-22,+22,0,0" />
<controls:PanelIconWithSensors x:Name="Panel7" Margin=" 0,+22,0,0" />
<controls:PanelIconWithSensors x:Name="Panel8" Margin="+22,+22,0,0" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- An icon that highlights sensors for a panel. -->
<Style TargetType="{x:Type controls:PanelIconWithSensors}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:PanelIconWithSensors}">
<Border Padding="1">
<Grid Width="10" Height="10" Background="Black">
<controls:PanelIconWithSensorsSensor x:Name="Sensor0"
Width="2" Height="4" HorizontalAlignment="Left" Margin="1,0,0,0" />
<controls:PanelIconWithSensorsSensor x:Name="Sensor1"
Width="2" Height="4" HorizontalAlignment="Right" Margin="0,0,1,0" />
<controls:PanelIconWithSensorsSensor x:Name="Sensor2"
Width="4" Height="2" VerticalAlignment="Top" Margin="0,1,0,0" />
<controls:PanelIconWithSensorsSensor x:Name="Sensor3"
Width="4" Height="2" VerticalAlignment="Bottom" Margin="0,0,0,1"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:PanelIconWithSensorsSensor}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:PanelIconWithSensorsSensor}">
<Border x:Name="border" BorderBrush="#000000" BorderThickness="0" SnapsToDevicePixels="true">
<ContentPresenter
SnapsToDevicePixels="true"
Focusable="False"
HorizontalAlignment="Center" VerticalAlignment="Center"
/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Highlight" Value="0">
<Setter Property="Background" TargetName="border" Value="#00000000"/>
</Trigger>
<Trigger Property="Highlight" Value="1">
<Setter Property="Background" TargetName="border" Value="#FFA0A0A0"/>
</Trigger>
<Trigger Property="Highlight" Value="2">
<Setter Property="Background" TargetName="border" Value="#FFFFFFFF"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Background="#DDD">
@ -729,7 +817,12 @@ Use if the platform is too sensitive.</clr:String>
SelectionChanged="MainTab_Selected">
<TabItem Header="Settings">
<Grid Background="#FFE5E5E5" RenderTransformOrigin="0.5,0.5">
<StackPanel Margin="0,0,0,0" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*"/>
<ColumnDefinition Width="17*"/>
<ColumnDefinition Width="416*"/>
</Grid.ColumnDefinitions>
<StackPanel Margin="0,0,0,0" VerticalAlignment="Top" Grid.ColumnSpan="3">
<TextBlock HorizontalAlignment="Center" Margin="0,15,0,10" VerticalAlignment="Top"
TextAlignment="Center"
xml:space="preserve" FontSize="16">Panel sensitivity</TextBlock>
@ -769,7 +862,7 @@ Use if the platform is too sensitive.</clr:String>
Leave this application running to play animations.
</TextBlock>
</StackPanel>
<StackPanel
Visibility="Visible"
Name="ColorPickerGroup" HorizontalAlignment="Center" Orientation="Vertical">
@ -795,7 +888,7 @@ Use if the platform is too sensitive.</clr:String>
</Grid>
<controls:FloorColorButton x:Name="P1_Floor" Pad="0" Content="=" Margin="0,0,0,0" />
</StackPanel>
<StackPanel x:Name="PanelColorP2" Orientation="Vertical">
<Grid Width="100" Height="100">
<controls:PanelColorButton x:Name="P2_0" Panel="9" Content="↖" Margin="-60,-50,0,0" />
@ -827,7 +920,7 @@ Use if the platform is too sensitive.</clr:String>
shifts it by a couple pixels, which makes it fidget around when we connect
and disconnect. -->
<Label x:Name="Version2" Content="Version"
HorizontalAlignment="Center" VerticalAlignment="Bottom" FontSize="15" Margin="0 0 0 7" />
HorizontalAlignment="Center" VerticalAlignment="Bottom" FontSize="15" Margin="130,0,227,7" Grid.Column="2" />
</Grid>
</TabItem>
@ -849,7 +942,7 @@ Use if the platform is too sensitive.</clr:String>
<DockPanel Margin="0,0,0,0" VerticalAlignment="Top" x:Name="ThresholdSliderContainer">
<!-- CreateThresholdSliders adds ThresholdSliders here. The slider below is only
for the UI preview, and is removed on refresh. -->
<controls:ThresholdSlider DockPanel.Dock="Top" controls:ThresholdSlider.Type="up-left" controls:ThresholdSlider.Icon="Resources/pad_up_left.png" Margin="0,8,0,0" />
<controls:ThresholdSlider DockPanel.Dock="Top" controls:ThresholdSlider.Type="up-left" Margin="0,8,0,0" />
</DockPanel>
</ScrollViewer>
<TextBlock DockPanel.Dock="Top" HorizontalAlignment="Center" Margin="0,25,0,0" VerticalAlignment="Top"
@ -933,11 +1026,6 @@ instead of only panels with sensors.</TextBlock>
<Button Content="Import" Width="50" Padding="5,2" Margin="5,10" Click="ImportSettings" />
</StackPanel>
<Separator Margin="0,10,0,10" />
<TextBlock HorizontalAlignment="Center"
xml:space="preserve" FontSize="16">Aux sensors</TextBlock>
<Button Content="Set auxilliary sensors" Width="140" Margin="0 10 0 0" Padding="0 4" Click="SetAuxSensors_Click"/>
<Separator Margin="0,10,0,10" />
<TextBlock HorizontalAlignment="Center"
xml:space="preserve" FontSize="16">Reset all settings</TextBlock>
@ -950,7 +1038,7 @@ instead of only panels with sensors.</TextBlock>
</StackPanel>
</TabItem>
</TabControl>
<!-- A list of which pads are connected, overlapping the tab bar in the top right. -->
<StackPanel x:Name="ConnectedPads" VerticalAlignment="Top" HorizontalAlignment="Right" Orientation="Horizontal">
<Label Content="Connected:" FontSize="10"/>

@ -69,39 +69,29 @@ namespace smx_config
};
}
List<string> thresholdSliderNames = new List<string>()
{
"up-left", "up", "up-right", "left", "center", "right", "down-left", "down", "down-right", "cardinal", "corner", "aux",
};
Dictionary<string, string> thresholdToIcon = new Dictionary<string, string>()
{
{ "up-left", "Resources/pad_up_left.png" },
{ "up", "Resources/pad_up.png" },
{ "up-right", "Resources/pad_up_right.png" },
{ "left", "Resources/pad_left.png" },
{ "center", "Resources/pad_center.png" },
{ "right", "Resources/pad_right.png" },
{ "down-left", "Resources/pad_down_left.png" },
{ "down", "Resources/pad_down.png" },
{ "down-right","Resources/pad_down_right.png" },
{ "cardinal", "Resources/pad_cardinal.png" },
{ "corner", "Resources/pad_diagonal.png" },
{ "aux", "Resources/pad_diagonal.png" },
};
bool IsThresholdSliderShown(string type)
{
bool AdvancedModeEnabled = (bool)AdvancedModeEnabledCheckbox.IsChecked;
bool AdvancedModeEnabled = Properties.Settings.Default.AdvancedMode;
SMX.SMXConfig config = ActivePad.GetFirstActivePadConfig();
bool[] enabledPanels = config.GetEnabledPanels();
// Check the list of sensors this slider controls. If the list is empty, don't show it.
// For example, if the user adds all four sensors on the up panel to aux, the up button
// has nothing left to control, so we'll hide it.
List<ThresholdSettings.PanelAndSensor> panelAndSensors = ThresholdSettings.GetControlledSensorsForSliderType(type, AdvancedModeEnabled);
if(panelAndSensors.Count == 0)
return false;
// For example, if the user adds all four sensors on the up panel to custom-sensors, the
// up button has nothing left to control, so we'll hide it.
//
// Don't do this for custom, inner-sensors or outer-sensors. Those are always shown in
// advanced mode.
List<ThresholdSettings.PanelAndSensor> panelAndSensors = ThresholdSettings.GetControlledSensorsForSliderType(type, AdvancedModeEnabled, false);
if(type == "custom-sensors" || type == "inner-sensors" || type == "outer-sensors")
{
if(!AdvancedModeEnabled || !config.fsr())
return false;
}
else
{
if(panelAndSensors.Count == 0)
return false;
}
// Hide thresholds that only affect panels that are disabled, so we don't show
// corner panel sliders in advanced mode if the corner panels are disabled. We
@ -131,24 +121,17 @@ namespace smx_config
{
ThresholdSlider slider = new ThresholdSlider();
slider.Type = type;
string iconPath = "pack://application:,,,/" + thresholdToIcon[type];
slider.Icon = (new ImageSourceConverter()).ConvertFromString(iconPath) as ImageSource;
return slider;
}
void CreateThresholdSliders()
{
SMX.SMXConfig config = ActivePad.GetFirstActivePadConfig();
bool[] enabledPanels = config.GetEnabledPanels();
// remove the threshold sliders from xaml, create them all here
//
// remove the AdvancedModeEnabled binding and ShouldBeDisplayed, handle that here
// by creating the ones we need
//
// then we can add custom sliders too
ThresholdSliderContainer.Children.Clear();
foreach(string sliderName in thresholdSliderNames)
foreach(string sliderName in ThresholdSettings.thresholdSliderNames)
{
if(!IsThresholdSliderShown(sliderName))
continue;
@ -158,6 +141,8 @@ namespace smx_config
slider.Margin = new Thickness(0, 8, 0, 0);
ThresholdSliderContainer.Children.Add(slider);
}
ThresholdSettings.SyncSliderThresholds();
}
public override void OnApplyTemplate()
@ -600,12 +585,6 @@ namespace smx_config
}
}
private void SetAuxSensors_Click(object sender, RoutedEventArgs e)
{
SetAuxSensors dialog = new SetAuxSensors();
dialog.ShowDialog();
}
private void UploadLatestGIF()
{
// Create a progress window. Center it on top of the main window.

@ -38,12 +38,48 @@ namespace smx_config.Properties {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string AuxSensors {
public string CustomSensors {
get {
return ((string)(this["AuxSensors"]));
return ((string)(this["CustomSensors"]));
}
set {
this["AuxSensors"] = value;
this["CustomSensors"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool UseInnerSensorThresholds {
get {
return ((bool)(this["UseInnerSensorThresholds"]));
}
set {
this["UseInnerSensorThresholds"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool UseOuterSensorThresholds {
get {
return ((bool)(this["UseOuterSensorThresholds"]));
}
set {
this["UseOuterSensorThresholds"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool AdvancedMode {
get {
return ((bool)(this["AdvancedMode"]));
}
set {
this["AdvancedMode"] = value;
}
}
}

@ -5,8 +5,17 @@
<Setting Name="LaunchOnStartup" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="AuxSensors" Type="System.String" Scope="User">
<Setting Name="CustomSensors" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="UseInnerSensorThresholds" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="UseOuterSensorThresholds" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="AdvancedMode" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings>
</SettingsFile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

@ -105,8 +105,8 @@
<Compile Include="DiagnosticsWidgets.cs" />
<Compile Include="DoubleSlider.cs" />
<Compile Include="Helpers.cs" />
<Compile Include="SetAuxSensors.xaml.cs">
<DependentUpon>SetAuxSensors.xaml</DependentUpon>
<Compile Include="SetCustomSensors.xaml.cs">
<DependentUpon>SetCustomSensors.xaml</DependentUpon>
</Compile>
<Compile Include="ProgressWindow.xaml.cs">
<DependentUpon>ProgressWindow.xaml</DependentUpon>
@ -126,7 +126,7 @@
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="SetAuxSensors.xaml">
<Page Include="SetCustomSensors.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
@ -174,14 +174,6 @@
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\pad_cardinal.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\pad_center.png" />
<Resource Include="Resources\pad_diagonal.png" />
<Resource Include="Resources\pad_up.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\window icon.png" />
</ItemGroup>
@ -191,15 +183,6 @@
<ItemGroup>
<Resource Include="window icon.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\pad_down.png" />
<Resource Include="Resources\pad_down_left.png" />
<Resource Include="Resources\pad_down_right.png" />
<Resource Include="Resources\pad_left.png" />
<Resource Include="Resources\pad_right.png" />
<Resource Include="Resources\pad_up_left.png" />
<Resource Include="Resources\pad_up_right.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\sdk\Windows\SMX.vcxproj">
<Project>{c5fc0823-9896-4b7c-bfe1-b60db671a462}</Project>

@ -1,4 +1,4 @@
<Window x:Class="smx_config.SetAuxSensors"
<Window x:Class="smx_config.SetCustomSensors"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@ -6,7 +6,7 @@
mc:Ignorable="d"
Icon="Resources/window icon.png"
Background="#DDD"
Height="418" Width="325" ResizeMode="NoResize"
Height="422" Width="325" ResizeMode="NoResize"
xmlns:controls="clr-namespace:smx_config"
x:Name="root"
Title="Select Auxilliary Sensors"
@ -52,15 +52,14 @@
<ControlTemplate TargetType="{x:Type controls:SensorSelector}">
<Border Padding="1">
<Grid Width="70" Height="70">
<!-- XXX: the order of these is wrong -->
<controls:SensorSelectionButton x:Name="Sensor0" Style="{StaticResource SensorSelectionButton}"
Width="40" Height="13" VerticalAlignment="Top" />
Width="13" Height="40" HorizontalAlignment="Left" />
<controls:SensorSelectionButton x:Name="Sensor1" Style="{StaticResource SensorSelectionButton}"
Width="40" Height="13" VerticalAlignment="Bottom" />
Width="13" Height="40" HorizontalAlignment="Right" />
<controls:SensorSelectionButton x:Name="Sensor2" Style="{StaticResource SensorSelectionButton}"
Width="13" Height="40" HorizontalAlignment="Left" />
Width="40" Height="13" VerticalAlignment="Top" />
<controls:SensorSelectionButton x:Name="Sensor3" Style="{StaticResource SensorSelectionButton}"
Width="13" Height="40" HorizontalAlignment="Right" />
Width="40" Height="13" VerticalAlignment="Bottom" />
</Grid>
</Border>
</ControlTemplate>

@ -50,22 +50,25 @@ namespace smx_config
{
// Toggle the clicked sensor.
Console.WriteLine("Clicked sensor " + sensor);
List<ThresholdSettings.PanelAndSensor> auxSensors = ThresholdSettings.GetAuxSensors();
bool enabled = !IsSensorEnabled(auxSensors, sensor);
List<ThresholdSettings.PanelAndSensor> customSensors = ThresholdSettings.GetCustomSensors();
bool enabled = !IsSensorEnabled(customSensors, sensor);
if(enabled)
auxSensors.Add(new ThresholdSettings.PanelAndSensor(Panel, sensor));
customSensors.Add(new ThresholdSettings.PanelAndSensor(Panel, sensor));
else
auxSensors.Remove(new ThresholdSettings.PanelAndSensor(Panel, sensor));
ThresholdSettings.SetAuxSensors(auxSensors);
customSensors.Remove(new ThresholdSettings.PanelAndSensor(Panel, sensor));
ThresholdSettings.SetCustomSensors(customSensors);
// Sync thresholds after changing custom sensors.
ThresholdSettings.SyncSliderThresholds();
CurrentSMXDevice.singleton.FireConfigurationChanged(this);
}
// Return true if the given sensor is marked as an aux sensor.
bool IsSensorEnabled(List<ThresholdSettings.PanelAndSensor> auxSensors, int sensor)
// Return true if the given sensor is included in custom-sensors.
bool IsSensorEnabled(List<ThresholdSettings.PanelAndSensor> customSensors, int sensor)
{
foreach(ThresholdSettings.PanelAndSensor panelAndSensor in auxSensors)
foreach(ThresholdSettings.PanelAndSensor panelAndSensor in customSensors)
{
if(panelAndSensor.panel == Panel && panelAndSensor.sensor == sensor)
return true;
@ -75,18 +78,18 @@ namespace smx_config
private void LoadUIFromConfig(LoadFromConfigDelegateArgs args)
{
// Check the selected aux sensors.
List<ThresholdSettings.PanelAndSensor> auxSensors = ThresholdSettings.GetAuxSensors();
// Check the selected custom-sensors.
List<ThresholdSettings.PanelAndSensor> customSensors = ThresholdSettings.GetCustomSensors();
for(int sensor = 0; sensor < 4; ++sensor)
SensorSelectionButtons[sensor].IsChecked = IsSensorEnabled(auxSensors, sensor);
SensorSelectionButtons[sensor].IsChecked = IsSensorEnabled(customSensors, sensor);
}
}
// This dialog sets which sensors are controlled by the auxilliary threshold. The actual
// work is done by SensorSelector above.
public partial class SetAuxSensors: Window
// This dialog sets which sensors are controlled by custom-sensors. The actual work is done
// by SensorSelector above.
public partial class SetCustomSensors: Window
{
public SetAuxSensors()
public SetCustomSensors()
{
InitializeComponent();
}

@ -12,11 +12,7 @@ using System.Collections.Generic;
namespace smx_config
{
// The checkbox to enable and disable the advanced per-panel sliders.
//
// This is always enabled if the thresholds in the configuration are set to different
// values. If the user enables us, we'll remember that we were forced on. If the user
// disables us, we'll sync the thresholds back up and turn the ForcedOn flag off.
// The checkbox to enable and disable the advanced per-panel sliders (Settings.Default.AdvancedMode).
public class AdvancedThresholdViewCheckbox: CheckBox
{
public static readonly DependencyProperty AdvancedModeEnabledProperty = DependencyProperty.Register("AdvancedModeEnabled",
@ -28,10 +24,6 @@ namespace smx_config
OnConfigChange onConfigChange;
// If true, the user enabled advanced view and we should display it even if
// the thresholds happen to be synced. If false, we'll only show the advanced
// view if we need to because the thresholds aren't synced.
bool ForcedOn;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
@ -48,38 +40,21 @@ namespace smx_config
bool SupportsAdvancedMode = config.masterVersion != 0xFF && config.masterVersion >= 2;
Visibility = SupportsAdvancedMode? Visibility.Visible:Visibility.Collapsed;
// If the thresholds are different, force the checkbox on. This way, if you load the application
// with a platform with per-panel thresholds, and change the thresholds to no longer be different,
// advanced mode stays forced on. It'll only turn off if you uncheck the box, or if you exit
// the application with synced thresholds and then restart it.
if(SupportsAdvancedMode && !ConfigPresets.AreUnifiedThresholdsSynced(config))
ForcedOn = true;
// If the controller doesn't support advanced mode, make sure advanced mode is disabled.
if(!SupportsAdvancedMode)
Properties.Settings.Default.AdvancedMode = false;
// Enable advanced mode if the master says it's supported, and either the user has checked the
// box to turn it on or the thresholds are different in the current configuration.
AdvancedModeEnabled = SupportsAdvancedMode && ForcedOn;
AdvancedModeEnabled = Properties.Settings.Default.AdvancedMode;
}
protected override void OnClick()
{
if(AdvancedModeEnabled)
Properties.Settings.Default.AdvancedMode = !Properties.Settings.Default.AdvancedMode;
if(!Properties.Settings.Default.AdvancedMode)
{
// Stop forcing advanced mode on, and sync the thresholds so we exit advanced mode.
ForcedOn = false;
foreach(Tuple<int,SMX.SMXConfig> activePad in ActivePad.ActivePads())
{
int pad = activePad.Item1;
SMX.SMXConfig config = activePad.Item2;
ConfigPresets.SyncUnifiedThresholds(ref config);
SMX.SMX.SetConfig(pad, config);
}
CurrentSMXDevice.singleton.FireConfigurationChanged(this);
}
else
{
// Enable advanced mode.
ForcedOn = true;
// Sync thresholds when we exit advanced mode. XXX: not needed since MainWindow is recreating
// sliders anyway
ThresholdSettings.SyncSliderThresholds();
}
// Refresh the UI.
@ -90,14 +65,6 @@ namespace smx_config
// This implements the threshold slider widget for changing an upper/lower threshold pair.
public class ThresholdSlider: Control
{
public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon",
typeof(ImageSource), typeof(ThresholdSlider), new FrameworkPropertyMetadata(null));
public ImageSource Icon {
get { return (ImageSource) GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type",
typeof(string), typeof(ThresholdSlider), new FrameworkPropertyMetadata(""));
@ -106,6 +73,27 @@ namespace smx_config
set { SetValue(TypeProperty, value); }
}
// If false, this threshold hasn't been enabled by the user. The slider will be greyed out. This
// is different from our own IsEnabled, since setting that to false would also disable EnabledCheckbox,
// preventing it from being turned back on.
public static readonly DependencyProperty ThresholdEnabledProperty = DependencyProperty.Register("ThresholdEnabled",
typeof(bool), typeof(ThresholdSlider), new FrameworkPropertyMetadata(true));
public bool ThresholdEnabled {
get { return (bool) GetValue(ThresholdEnabledProperty); }
set { SetValue(ThresholdEnabledProperty, value); }
}
// This is set to true if the slider is enabled and the low/high values are displayed. We set this to
// false when the slider is disabled (or has no selected sensors, for custom-sliders).
public static readonly DependencyProperty SliderActiveProperty = DependencyProperty.Register("SliderActive",
typeof(bool), typeof(ThresholdSlider), new FrameworkPropertyMetadata(true));
public bool SliderActive {
get { return (bool) GetValue(SliderActiveProperty); }
set { SetValue(SliderActiveProperty, value); }
}
public static readonly DependencyProperty AdvancedModeEnabledProperty = DependencyProperty.Register("AdvancedModeEnabled",
typeof(bool), typeof(ThresholdSlider), new FrameworkPropertyMetadata(false));
@ -117,6 +105,7 @@ namespace smx_config
DoubleSlider slider;
Label LowerLabel, UpperLabel;
Image ThresholdWarning;
PlatformSensorDisplay SensorDisplay;
OnConfigChange onConfigChange;
@ -128,27 +117,46 @@ namespace smx_config
LowerLabel = GetTemplateChild("LowerValue") as Label;
UpperLabel = GetTemplateChild("UpperValue") as Label;
ThresholdWarning = GetTemplateChild("ThresholdWarning") as Image;
SensorDisplay = GetTemplateChild("PlatformSensorDisplay") as PlatformSensorDisplay;
slider.ValueChanged += delegate(DoubleSlider slider) { SaveToConfig(); };
// Show the edit button for the custom-sensors slider.
Button EditCustomSensorsButton = GetTemplateChild("EditCustomSensorsButton") as Button;
EditCustomSensorsButton.Visibility = Type == "custom-sensors"? Visibility.Visible:Visibility.Hidden;
EditCustomSensorsButton.Click += delegate(object sender, RoutedEventArgs e)
{
SetCustomSensors dialog = new SetCustomSensors();
dialog.Owner = Window.GetWindow(this);
dialog.ShowDialog();
};
onConfigChange = new OnConfigChange(this, delegate (LoadFromConfigDelegateArgs args) {
LoadUIFromConfig(ActivePad.GetFirstActivePadConfig(args));
});
}
private void RefreshSliderActiveProperty()
{
if(Type == "custom-sensors")
SliderActive = ThresholdSettings.GetCustomSensors().Count > 0;
else
SliderActive = ThresholdEnabled;
}
// Return the panel/sensors this widget controls.
//
// This returns values for FSRs. We don't configure individual sensors with load cells,
// and the sensor value will be ignored.
private List<ThresholdSettings.PanelAndSensor> GetControlledSensors()
private List<ThresholdSettings.PanelAndSensor> GetControlledSensors(bool includeOverridden)
{
return ThresholdSettings.GetControlledSensorsForSliderType(Type, AdvancedModeEnabled);
return ThresholdSettings.GetControlledSensorsForSliderType(Type, AdvancedModeEnabled, includeOverridden);
}
private void SetValueToConfig(ref SMX.SMXConfig config)
{
List<ThresholdSettings.PanelAndSensor> panelAndSensors = GetControlledSensors();
List<ThresholdSettings.PanelAndSensor> panelAndSensors = GetControlledSensors(false);
foreach(ThresholdSettings.PanelAndSensor panelAndSensor in panelAndSensors)
{
if(!config.fsr())
@ -171,7 +179,7 @@ namespace smx_config
lower = upper = 0;
// Use the first controlled sensor. The rest should be the same.
foreach(ThresholdSettings.PanelAndSensor panelAndSensor in GetControlledSensors())
foreach(ThresholdSettings.PanelAndSensor panelAndSensor in GetControlledSensors(false))
{
if(!config.fsr())
{
@ -208,6 +216,8 @@ namespace smx_config
// Make sure SaveToConfig doesn't treat these as the user changing values.
UpdatingUI = true;
RefreshSliderActiveProperty();
// Set the range for the slider.
if(config.fsr())
{
@ -240,8 +250,9 @@ namespace smx_config
UpperLabel.Content = upper.ToString();
}
List<ThresholdSettings.PanelAndSensor> controlledSensors = GetControlledSensors(false);
bool ShowThresholdWarning = false;
foreach(ThresholdSettings.PanelAndSensor panelAndSensor in GetControlledSensors())
foreach(ThresholdSettings.PanelAndSensor panelAndSensor in controlledSensors)
{
if(config.ShowThresholdWarning(panelAndSensor.panel, panelAndSensor.sensor))
ShowThresholdWarning = true;
@ -249,10 +260,74 @@ namespace smx_config
ThresholdWarning.Visibility = ShowThresholdWarning? Visibility.Visible:Visibility.Hidden;
// SensorDisplay shows which sensors we control. If this sensor is enabled, show the
// sensors this sensor controls.
//
// If we're disabled, the icon will be empty. That looks
// weird, so in that case we show
// Set the icon next to the slider to show which sensors we control.
List<ThresholdSettings.PanelAndSensor> defaultControlledSensors = GetControlledSensors(true);
SensorDisplay.SetFromPanelAndSensors(controlledSensors, defaultControlledSensors);
UpdatingUI = false;
}
}
// The checkbox next to the threshold slider to turn it on or off. This is only used
// for inner-sensors and outer-sensors, and hides itself automatically for others.
public class ThresholdEnabledButton: CheckBox
{
// Which threshold slider this is for. This is bound to ThresholdSlider.Type above.
public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type",
typeof(string), typeof(ThresholdEnabledButton), new FrameworkPropertyMetadata(""));
public string Type {
get { return (string) GetValue(TypeProperty); }
set { SetValue(TypeProperty, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if(Type != "inner-sensors" && Type != "outer-sensors")
{
Visibility = Visibility.Hidden;
IsChecked = true;
return;
}
Checked += delegate(object sender, RoutedEventArgs e) { SaveToSettings(); };
Unchecked += delegate(object sender, RoutedEventArgs e) { SaveToSettings(); };
OnConfigChange onConfigChange;
onConfigChange = new OnConfigChange(this, delegate(LoadFromConfigDelegateArgs args) {
LoadFromSettings();
});
}
private void LoadFromSettings()
{
if(Type == "inner-sensors")
IsChecked = Properties.Settings.Default.UseInnerSensorThresholds;
else if(Type == "outer-sensors")
IsChecked = Properties.Settings.Default.UseOuterSensorThresholds;
}
private void SaveToSettings()
{
if(Type == "inner-sensors")
Properties.Settings.Default.UseInnerSensorThresholds = (bool) IsChecked;
else if(Type == "outer-sensors")
Properties.Settings.Default.UseOuterSensorThresholds = (bool) IsChecked;
Properties.Settings.Default.Save();
// Sync thresholds after enabling or disabling a slider.
ThresholdSettings.SyncSliderThresholds();
CurrentSMXDevice.singleton.FireConfigurationChanged(this);
}
}
// A button with a selectable highlight.
public class SelectableButton: Button
{
@ -1009,4 +1084,79 @@ namespace smx_config
CurrentSMXDevice.singleton.FireConfigurationChanged(this);
}
}
public class PanelIconWithSensorsSensor: Control
{
// 0: black
// 1: dim highlight
// 2: bright highlight
public static readonly DependencyProperty HighlightProperty = DependencyProperty.Register("Highlight",
typeof(int), typeof(PanelIconWithSensorsSensor), new FrameworkPropertyMetadata(0));
public int Highlight {
get { return (int) GetValue(HighlightProperty); }
set { SetValue(HighlightProperty, value); }
}
}
// A control with one button for each of four sensors:
class PanelIconWithSensors: Control
{
PanelIconWithSensorsSensor[] panelIconWithSensorsSensor;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
panelIconWithSensorsSensor = new PanelIconWithSensorsSensor[4];
for(int sensor = 0; sensor < 4; ++sensor)
panelIconWithSensorsSensor[sensor] = GetTemplateChild("Sensor" + sensor) as PanelIconWithSensorsSensor;
}
public PanelIconWithSensorsSensor GetSensorControl(int sensor)
{
return panelIconWithSensorsSensor[sensor];
}
}
public class PlatformSensorDisplay: Control
{
PanelIconWithSensors[] panelIconWithSensors;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
panelIconWithSensors = new PanelIconWithSensors[9];
for(int panel = 0; panel < 9; ++panel)
panelIconWithSensors[panel] = GetTemplateChild("Panel" + panel) as PanelIconWithSensors;
}
private PanelIconWithSensorsSensor GetSensor(int panel, int sensor)
{
return panelIconWithSensors[panel].GetSensorControl(sensor);
}
// Highlight the sensors included in panelAndSensors, and dimly highlight the sensors in
// disabledPanelAndSensors. If a sensor is in both lists, panelAndSensors takes priority.
public void SetFromPanelAndSensors(
List<ThresholdSettings.PanelAndSensor> panelAndSensors,
List<ThresholdSettings.PanelAndSensor> disabledPanelAndSensors)
{
UnhighlightAllSensors();
foreach(ThresholdSettings.PanelAndSensor panelAndSensor in disabledPanelAndSensors)
GetSensor(panelAndSensor.panel, panelAndSensor.sensor).Highlight = 1;
foreach(ThresholdSettings.PanelAndSensor panelAndSensor in panelAndSensors)
GetSensor(panelAndSensor.panel, panelAndSensor.sensor).Highlight = 2;
}
// Clear all sensor highlighting.
public void UnhighlightAllSensors()
{
for(int panel = 0; panel < 9; ++panel)
{
for(int sensor = 0; sensor < 4; ++sensor)
GetSensor(panel, sensor).Highlight = 0;
}
}
}
}

Loading…
Cancel
Save