private void AvailableControls_MouseMove(object sender, MouseEventArgs e)
        {
            Point  mousePos = e.GetPosition(null);
            Vector motion   = controlDragStartPoint - mousePos;

            if (e.LeftButton == MouseButtonState.Pressed &&
                (Math.Abs(motion.X) > SystemParameters.MinimumHorizontalDragDistance ||
                 Math.Abs(motion.Y) > SystemParameters.MinimumVerticalDragDistance))
            {
                Border source = ((DependencyObject)e.OriginalSource).FindAncestor <Border>();
                if (source == null)
                {
                    return;
                }

                StackPanel p = source.Child as StackPanel;
                //the first child is the label, the second is a separator, and the third is the tilegrid
                TileGrid tileGrid = p.Children.Cast <UIElement>().Last() as TileGrid;
                //the tilegrid's only child is the control!
                SourcedControl c = tileGrid.Children.Cast <UIElement>().Last() as SourcedControl;
                //get the source control type info to pass to the dragdrop
                Type       controlType = c.GetType();
                DataObject dragInfo    = new DataObject(NetworkDataFormats.SourcedControl, controlType);
                DragDrop.DoDragDrop(source, dragInfo, DragDropEffects.Copy | DragDropEffects.Move);
                tray.Show();
            }
        }
 private void DashboardRoot_Drop(object sender, DragEventArgs e)
 {
     if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey) &&
         e.Data.GetDataPresent(NetworkDataFormats.NetworkElement))
     {
         //offer to create the bound control here
         NetworkElement dataSource = (NetworkElement)e.Data.GetData(NetworkDataFormats.NetworkElement);
         //all available types
         IEnumerable <Type> controlTypes = PluginLoader.GetControls();
         IEnumerable <Type> allowedControls;
         //check whether this is a primitive or complex data and filter the controls appropriately
         if (dataSource.Type == typeof(NetworkTree))
         {
             //get the expected type of the element
             NetworkTable table    = NetworkTable.GetTable(dataSource.FullPath);
             string       dataType = table.GetString("type", null);
             allowedControls = controlTypes
                               .Where((t) => SourcedControl.GetAllowedComplexTypes(t).Contains(dataType));
         }
         else
         {
             allowedControls = controlTypes
                               .Where((t) => SourcedControl.GetAllowedPrimitiveTypes(t).Contains(dataSource.Type));
         }
         if (allowedControls.Count() != 0)
         {
             ControlPreviewDialog previewDialog = new ControlPreviewDialog();
             PopulateControlPreviewWrapPanel(previewDialog.availableControls, allowedControls);
             if (previewDialog.ShowDialog() == true)
             {
                 Type controlType = previewDialog.SelectedType;
                 if (controlType != null)
                 {
                     SourcedControl c = (SourcedControl)controlType.GetConstructor(Type.EmptyTypes).Invoke(null);
                     PlaceAtDropPoint(c, e);
                     dashboardRoot.Children.Add(c);
                     c.Source = dataSource.FullPath.Replace("/SmartDashboard/", "");
                 }
             }
         }
         else
         {
             MessageBox.Show("There are no controls that can display this entry!", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
         }
     }
     else if (e.Data.GetDataPresent(NetworkDataFormats.SourcedControl))
     {
         //create the control here
         Type           controlType = (Type)e.Data.GetData(NetworkDataFormats.SourcedControl);
         SourcedControl c           = (SourcedControl)controlType.GetConstructor(Type.EmptyTypes).Invoke(null);
         PlaceAtDropPoint(c, e);
         dashboardRoot.Children.Add(c);
     }
     e.Handled = true;
 }
 private void PopulateControlPreviewWrapPanel(WrapPanel wp, IEnumerable <Type> controlTypes)
 {
     wp.Children.Clear();
     foreach (Type controlType in controlTypes)
     {
         //do some fancy arranging. what we need:
         //size-to-fit border (plus some extra space) with transparent background to register the hits.
         //label the extra space with the name of the control
         SourcedControl c = (SourcedControl)controlType.GetConstructor(Type.EmptyTypes).Invoke(null);
         c.IsEnabled = false;
         double   expectedWidth  = TileGrid.GetColumnSpan(c) * 50;
         double   expectedHeight = TileGrid.GetRowSpan(c) * 50;
         TileGrid container      = new TileGrid()
         {
             ShowGridlines  = false,
             IsEditable     = false,
             TileSizingMode = TileSizingMode.Uniform,
             Width          = expectedWidth,
             Height         = expectedHeight,
             Background     = new SolidColorBrush(Colors.Transparent)
         };
         container.Children.Add(c);
         Border outline = new Border()
         {
             Background      = new SolidColorBrush(Colors.Transparent),
             BorderBrush     = new SolidColorBrush(Colors.Black),
             BorderThickness = new Thickness(1),
             Margin          = new Thickness(5)
         };
         StackPanel p = new StackPanel();
         outline.Child = p;
         TextBlock label = new TextBlock()
         {
             Text   = Util.ToTitleCase(controlType.Name),
             Margin = new Thickness(2)
         };
         p.Children.Add(label);
         p.Children.Add(new Separator());
         p.Children.Add(container);
         wp.Children.Add(outline);
     }
 }
        private void PlaceAtDropPoint(SourcedControl c, DragEventArgs e)
        {
            Point dropPoint = e.GetPosition(dashboardRoot);
            //centering. goal: if there span is even, we want to center on nearest line,
            //if span is odd, center the nearest full tile
            //for even, rounding works because the division causes the control to tend towards the left
            int    colSpan    = TileGrid.GetColumnSpan(c);
            int    rowSpan    = TileGrid.GetRowSpan(c);
            double preciseCol = dropPoint.X / dashboardRoot.GetColumnWidth();
            double preciseRow = dropPoint.Y / dashboardRoot.GetRowHeight();
            int    col        = colSpan % 2 == 0 ? (int)Math.Round(preciseCol) : (int)Math.Floor(preciseCol);
            int    row        = rowSpan % 2 == 0 ? (int)Math.Round(preciseRow) : (int)Math.Floor(preciseRow);
            int    colOffset  = colSpan / 2;
            int    rowOffset  = rowSpan / 2;

            col = Math.Max(col - colOffset, 0);
            row = Math.Max(row - rowOffset, 0);
            TileGrid.SetColumn(c, col);
            TileGrid.SetRow(c, row);
        }