Skip to content

Commit

Permalink
Fix locked tooltips so they reposition when window is resized. Shorte…
Browse files Browse the repository at this point in the history
…n some of the px4 tooltips. Add "clear all" adornments. Fix initial positioning of locked tooltips.
  • Loading branch information
lovettchris committed Mar 25, 2017
1 parent cbc828e commit b4cccbd
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 46 deletions.
7 changes: 4 additions & 3 deletions LogViewer/LogViewer/Controls/SimpleLineChart.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@

<Grid x:Name="RootContent" ClipToBounds="True" Background="Transparent">
<Grid.ContextMenu>
<ContextMenu x:Name="ContextMenu">
<ContextMenu x:Name="myContextMenu">
<MenuItem x:Name="ScaleIndependentMenuItem" Header="Scale independendently" Click="OnScaleIndependently"/>
<MenuItem x:Name="LockTooltipMenuItem" Header="Lock Tooltip" Click="OnLockTooltip" IsEnabled="False"/>
<MenuItem x:Name="AddTrendLineMenuItem" Header="Add Trend Line" Click="OnAddTrendLine" IsEnabled="False"/>
<Separator/>
<MenuItem Header="Clear Adornments" Click="OnClearAdornments"/>
<MenuItem Header="Clear All Adornments" Click="OnClearAllAdornments"/>
</ContextMenu>
</Grid.ContextMenu>
<Grid.RowDefinitions>
Expand All @@ -28,10 +29,10 @@
<Path x:Name="Graph" StrokeThickness="5" VerticalAlignment="Top" SnapsToDevicePixels="True" StrokeLineJoin="Bevel">
</Path>
<Path x:Name="Pointer" Fill="{StaticResource TooltipForeground}" Data="M0,-5 L 5,0 0,5 -5 0z" Visibility="Collapsed"/>
<Border x:Name="PointerBorder" Visibility="Collapsed" Padding="2" HorizontalAlignment="Left" VerticalAlignment="Top" BorderThickness="1"
<local:PointerBorder x:Name="PointerBorder" Visibility="Collapsed" Padding="2" HorizontalAlignment="Left" VerticalAlignment="Top" BorderThickness="1"
CornerRadius="3" BorderBrush="{StaticResource TooltipForeground}" Background="#80303030">
<TextBlock x:Name="PointerLabel" Foreground="{StaticResource TooltipForeground}"/>
</Border>
</local:PointerBorder>
<Canvas x:Name="AdornerCanvas">

</Canvas>
Expand Down
111 changes: 100 additions & 11 deletions LogViewer/LogViewer/Controls/SimpleLineChart.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public sealed partial class SimpleLineChart : UserControl
DataValue currentValue;
bool liveScrolling;
double liveScrollingXScale = 1;
bool contextMenuOpen;

/// <summary>
/// Set this property to add the chart to a group of charts. The group will share the same "scale" information across the
Expand All @@ -72,6 +73,23 @@ public SimpleLineChart()
this.InitializeComponent();
this.Background = new SolidColorBrush(Colors.Transparent); // ensure we get manipulation events no matter where user presses.
this.SizeChanged += SimpleLineChart_SizeChanged;

this.ContextMenuOpening += ContextMenu_ContextMenuOpening;
this.ContextMenuClosing += ContextMenu_ContextMenuClosing;
}

private void ContextMenu_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
contextMenuOpen = true;
}

private void ContextMenu_ContextMenuClosing(object sender, ContextMenuEventArgs e)
{
// tooltips are too quick to restart and lock tooltip picks up the new location before it can lock the original.
_delayedUpdates.StartDelayedAction("SlowRestoreTooltips", () =>
{
contextMenuOpen = false;
}, TimeSpan.FromSeconds(1));
}

void SimpleLineChart_SizeChanged(object sender, SizeChangedEventArgs e)
Expand Down Expand Up @@ -200,13 +218,13 @@ internal void ZoomTo(double x, double width)
var info = ComputeScaleSelf(0);
ApplyScale(info);

UpdateChart();
InvalidateArrange();
}

internal void ResetZoom()
{
zoomTransform = new MatrixTransform();
UpdateChart();
InvalidateArrange();
}

public void SetData(DataSeries series)
Expand Down Expand Up @@ -538,20 +556,28 @@ private void CloseBoxClick(object sender, RoutedEventArgs e)

internal void HandleMouseMove(MouseEventArgs e)
{
lastMousePosition = e.GetPosition(this);
UpdatePointer(lastMousePosition);
if (!contextMenuOpen)
{
lastMousePosition = e.GetPosition(this);
UpdatePointer(lastMousePosition);
}
}

internal void HandleMouseLeave()
{
if (!ContextMenu.IsVisible)
if (!contextMenuOpen)
{
HidePointer();
}
}

protected override void OnMouseMove(MouseEventArgs e)
{
if (contextMenuOpen)
{
// don't move tooltip while user is interacting with the menu.
return;
}
HandleMouseMove(e);
base.OnMouseMove(e);
}
Expand Down Expand Up @@ -657,7 +683,7 @@ void UpdatePointer(Point pos)
double offset = Canvas.GetLeft(Graph);
double x = scaled.X + offset;
double y = availableHeight - scaled.Y;
ShowTip(series.Name + " = " + (!string.IsNullOrEmpty(found.Label) ? found.Label : found.Y.ToString()), new Point(x, y));
ShowTip(series.Name + " = " + (!string.IsNullOrEmpty(found.Label) ? found.Label : found.Y.ToString()), new Point(x, y), found);
}
else
{
Expand Down Expand Up @@ -694,7 +720,7 @@ void HidePointer()
LockTooltipMenuItem.IsEnabled = false;
}

void ShowTip(string label, Point pos)
void ShowTip(string label, Point pos, DataValue data = null)
{
PointerLabel.Text = label;
PointerBorder.UpdateLayout();
Expand All @@ -712,6 +738,7 @@ void ShowTip(string label, Point pos)
}
PointerBorder.Margin = new Thickness(tipPositionX, tipPositionY, 0, 0);
PointerBorder.Visibility = System.Windows.Visibility.Visible;
PointerBorder.Data = data;

Point pointerPosition = pos;
Pointer.RenderTransform = new TranslateTransform(pointerPosition.X, pointerPosition.Y);
Expand All @@ -720,14 +747,54 @@ void ShowTip(string label, Point pos)
LockTooltipMenuItem.IsEnabled = true;
}

void RepositionTip(PointerBorder pointer)
{
DataValue data = pointer.Data;

double availableHeight = this.ActualHeight;
double value = data.Y;
Point scaled = scaleTransform.Transform(new Point(data.X, data.Y));
scaled = zoomTransform.Transform(scaled);
double offset = Canvas.GetLeft(Graph);
double x = scaled.X + offset;
double y = availableHeight - scaled.Y;
double tipPositionX = x;
if (tipPositionX + PointerBorder.ActualWidth > this.ActualWidth)
{
tipPositionX = this.ActualWidth - PointerBorder.ActualWidth;
}
double tipPositionY = y - PointerLabel.ActualHeight - 4;
if (tipPositionY < 0)
{
tipPositionY = 0;
}
pointer.Margin = new Thickness(tipPositionX, tipPositionY, 0, 0);

pointer.Pointer.RenderTransform = new TranslateTransform(x, y);
}


protected override Size ArrangeOverride(Size arrangeBounds)
{
this.dirty = true;
DelayedUpdate();
HidePointer();
_delayedUpdates.StartDelayedAction("RepositionTips", () => { RepositionTips(); }, TimeSpan.FromMilliseconds(30));
return base.ArrangeOverride(arrangeBounds);
}

private void RepositionTips()
{
foreach (UIElement child in AdornerCanvas.Children)
{
PointerBorder pointer = child as PointerBorder;
if (pointer != null)
{
RepositionTip(pointer);
}
}
}

private void OnLockTooltip(object sender, RoutedEventArgs e)
{
// we lock the tooltip by cloning the existing tooltip objects.
Expand All @@ -742,7 +809,7 @@ private void OnLockTooltip(object sender, RoutedEventArgs e)
Fill = Pointer.Fill, Data = Pointer.Data.Clone(), RenderTransform = Pointer.RenderTransform.Clone() };
AdornerCanvas.Children.Add(ptr);

Border ptrBorder = new Border()
PointerBorder ptrBorder = new PointerBorder()
{
Padding = PointerBorder.Padding,
HorizontalAlignment = PointerBorder.HorizontalAlignment,
Expand All @@ -751,7 +818,9 @@ private void OnLockTooltip(object sender, RoutedEventArgs e)
CornerRadius = PointerBorder.CornerRadius,
BorderBrush = PointerBorder.BorderBrush,
Background = PointerBorder.Background,
Margin = PointerBorder.Margin
Margin = PointerBorder.Margin,
Data = PointerBorder.Data,
Pointer = ptr,
};
ptrBorder.Child = new TextBlock() { Foreground = PointerLabel.Foreground, Text = PointerLabel.Text };
AdornerCanvas.Children.Add(ptrBorder);
Expand Down Expand Up @@ -812,14 +881,28 @@ private void OnAddTrendLine(object sender, RoutedEventArgs e)
};

AdornerCanvas.Children.Add(endlabel);

}

private void OnClearAdornments(object sender, RoutedEventArgs e)
{
AdornerCanvas.Children.Clear();
}

public void ClearAdornments()
{
AdornerCanvas.Children.Clear();
}

public event EventHandler ClearAllAdornments;

private void OnClearAllAdornments(object sender, RoutedEventArgs e)
{
if (ClearAllAdornments != null)
{
ClearAllAdornments(this, EventArgs.Empty);
}
}

private void OnScaleIndependently(object sender, RoutedEventArgs e)
{
bool value = !ScaleIndependentMenuItem.IsChecked;
Expand Down Expand Up @@ -849,6 +932,12 @@ public bool ScaleIndependently
}
}
}

}

class PointerBorder : Border
{
public DataValue Data { get; set; }
public Path Pointer { get; set; }
}
}
2 changes: 1 addition & 1 deletion LogViewer/LogViewer/LogViewer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<SuiteName>PX4 Log Viewer</SuiteName>
<CreateWebPageOnPublish>true</CreateWebPageOnPublish>
<WebPage>publish.htm</WebPage>
<ApplicationRevision>29</ApplicationRevision>
<ApplicationRevision>31</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
Expand Down
9 changes: 9 additions & 0 deletions LogViewer/LogViewer/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,7 @@ private void GraphItem(LogItemSchema schema)
ChartStack.Visibility = Visibility.Visible;
ChartStack.UpdateLayout();
SimpleLineChart chart = new SimpleLineChart();
chart.ClearAllAdornments += OnClearAllAdornments;
chart.Margin = defaultChartMargin;
chart.Focusable = false;
chart.Closed += OnChartClosed;
Expand Down Expand Up @@ -897,6 +898,14 @@ private void GraphItem(LogItemSchema schema)
SystemConsole.Show();
}
}

private void OnClearAllAdornments(object sender, EventArgs e)
{
foreach (var chart in ChartStack.FindCharts())
{
chart.ClearAdornments();
}
}

private void InitializeChartData(LogItemSchema schema, SimpleLineChart chart, List<DataValue> values)
{
Expand Down
66 changes: 35 additions & 31 deletions LogViewer/LogViewer/Model/MavlinkLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ internal DataValue GetDataValue(LogItemSchema schema, Message msg)

StringBuilder textBuilder = new StringBuilder();
var row = msg.TypedValue;
if (row != null && row.GetType().Name == rowSchema.Name)
if (row != null && row.GetType().Name == rowSchema.Type)
{
// get a time value for this message.
FieldInfo fi = row.GetType().GetField(columnSchema.Name, BindingFlags.Public | BindingFlags.Instance);
Expand Down Expand Up @@ -191,12 +191,6 @@ private string GetLabel(object row, string fieldName)
}
return null;
}

private string GetLandedStateNames(byte landed_state)
{
throw new NotImplementedException();
}

public IEnumerable<DataValue> LiveQuery(LogItemSchema schema, CancellationToken token)
{
return new MavlinkQuery(this, schema, token);
Expand Down Expand Up @@ -651,7 +645,17 @@ private void CreateSchema(object message)
return;
}

LogItemSchema item = new LogItemSchema() { Name = t.Name, Type = t.Name, ChildItems = new List<LogItemSchema>(), Parent = this.schema };
string name = t.Name;
if (name.StartsWith("mavlink_"))
{
name = name.Substring(8);
}
else if (name.StartsWith("mavlink"))
{
name = name.Substring(7);
}

LogItemSchema item = new LogItemSchema() { Name = name, Type = t.Name, ChildItems = new List<LogItemSchema>(), Parent = this.schema };

foreach (FieldInfo fi in t.GetFields(BindingFlags.Public | BindingFlags.Instance))
{
Expand Down Expand Up @@ -706,14 +710,14 @@ static string GetSystemStateName(int value)
}

static string[] MavSystemStateNames = {
"MAV_STATE_UNINIT - Uninitialized system, state is unknown.",
"MAV_STATE_BOOT - System is booting up.",
"MAV_STATE_CALIBRATING - System is calibrating and not flight-ready.",
"MAV_STATE_STANDBY - System is grounded and on standby. It can be launched any time.",
"MAV_STATE_ACTIVE - System is active and might be already airborne. Motors are engaged.",
"MAV_STATE_CRITICAL - System is in a non-normal flight mode. It can however still navigate.",
"MAV_STATE_EMERGENCY - System is in a non-normal flight mode. It lost control over parts or over the whole airframe. It is in mayday and going down.",
"MAV_STATE_POWEROFF - System just initialized its power-down sequence, will shut down now."
"MAV_STATE_UNINIT",
"MAV_STATE_BOOT",
"MAV_STATE_CALIBRATING",
"MAV_STATE_STANDBY",
"MAV_STATE_ACTIVE",
"MAV_STATE_CRITICAL",
"MAV_STATE_EMERGENCY",
"MAV_STATE_POWEROFF"
};

enum PX4_CUSTOM_MAIN_MODE
Expand Down Expand Up @@ -754,9 +758,9 @@ enum MAV_LANDED_STATE
};

static string[] MavLandedStateNames = {
"MAV_LANDED_STATE_UNDEFINED - state is unknown.",
"MAV_LANDED_STATE_ON_GROUND - MAV is landed (on ground).",
"MAV_LANDED_STATE_IN_AIR - MAV is in air."
"MAV_LANDED_STATE_UNDEFINED",
"MAV_LANDED_STATE_ON_GROUND",
"MAV_LANDED_STATE_IN_AIR"
};

static string GetLandedStateName(int value)
Expand All @@ -771,11 +775,11 @@ static string GetLandedStateName(int value)
// Enumeration of VTOL states
static string[] MavVTOLStateNames =
{
"MAV_VTOL_STATE_UNDEFINED (0) - MAV is not configured as VTOL",
"MAV_VTOL_STATE_TRANSITION_TO_FW (1) - VTOL is in transition from multicopter to fixed-wing",
"MAV_VTOL_STATE_TRANSITION_TO_MC (2) - VTOL is in transition from fixed-wing to multicopter",
"MAV_VTOL_STATE_MC (3) - VTOL is in multicopter state",
"MAV_VTOL_STATE_FW (4) - VTOL is in fixed-wing state"
"MAV_VTOL_STATE_UNDEFINED",
"MAV_VTOL_STATE_TRANSITION_TO_FW",
"MAV_VTOL_STATE_TRANSITION_TO_MC",
"MAV_VTOL_STATE_MC",
"MAV_VTOL_STATE_FW"
};

static string GetVTolStateName(int value)
Expand Down Expand Up @@ -835,13 +839,13 @@ static string GetModeFlags(uint value)
}

static FlagName[] ModeFlagNames = {
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.TEST_ENABLED, Name = "MAV_MODE_FLAG_TEST_ENABLED - system has a test mode enabled. This flag is intended for temporary system tests and should not be used for stable implementations." },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.AUTO_ENABLED, Name = "MAV_MODE_FLAG_AUTO_ENABLED - autonomous mode enabled, system finds its own goal positions. Guided flag can be set or not, depends on the actual implementation." },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.GUIDED_ENABLED, Name = "MAV_MODE_FLAG_GUIDED_ENABLED - guided mode enabled, system flies MISSIONs / mission items." },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.STABILIZE_ENABLED, Name = "MAV_MODE_FLAG_STABILIZE_ENABLED - system stabilizes electronically its attitude (and optionally position). It needs however further control inputs to move around." },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.HIL_ENABLED, Name = "MAV_MODE_FLAG_HIL_ENABLED - hardware in the loop simulation. All motors / actuators are blocked, but internal software is full operational." },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.MANUAL_INPUT_ENABLED, Name = "MAV_MODE_FLAG_MANUAL_INPUT_ENABLED - remote control input is enabled." },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.SAFETY_ARMED, Name = "MAV_MODE_FLAG_SAFETY_ARMED - MAV safety set to armed. Motors are enabled / running / can start. Ready to fly." }
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.TEST_ENABLED, Name = "MAV_MODE_FLAG_TEST_ENABLED" },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.AUTO_ENABLED, Name = "MAV_MODE_FLAG_AUTO_ENABLED" },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.GUIDED_ENABLED, Name = "MAV_MODE_FLAG_GUIDED_ENABLED" },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.STABILIZE_ENABLED, Name = "MAV_MODE_FLAG_STABILIZE_ENABLED" },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.HIL_ENABLED, Name = "MAV_MODE_FLAG_HIL_ENABLED" },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.MANUAL_INPUT_ENABLED, Name = "MAV_MODE_FLAG_MANUAL_INPUT_ENABLED" },
new FlagName() { Flag = (int)MAVLink.MAV_MODE_FLAG.SAFETY_ARMED, Name = "MAV_MODE_FLAG_SAFETY_ARMED" }
};

}
Expand Down

0 comments on commit b4cccbd

Please sign in to comment.