public void AddToSelection(SkinnableControl control)
        {
            var tmp = this.selectedControls.ToList();

            tmp.Add(control);
            SelectMultiple(new Collection <SkinnableControl>(tmp));
        }
 public void Deselect(SkinnableControl control)
 {
     if (control != null)
     {
         var tmp = this.selectedControls.ToList();
         tmp.Remove(control);
         SelectMultiple(new Collection <SkinnableControl>(tmp));
     }
 }
 public bool ToggleSelection(SkinnableControl control)
 {
     if (this.selectedControls.Contains(control))
     {
         Deselect(control);
         return(false);
     }
     else
     {
         AddToSelection(control);
         return(true);
     }
 }
 public void Select(SkinnableControl control)
 {
     if (control == null)
     {
         SelectMultiple(null);
     }
     else
     {
         var tmp = new Collection <SkinnableControl>();
         tmp.Add(control);
         SelectMultiple(tmp);
     }
 }
        /// <summary>
        /// Event handler che viene chiamato quando è necessario ridisegnare i metacontrolli
        /// (ad esempio, i resize handle).
        /// Viene chiamato quando il controllo selezionato viene ridimensionato o spostato, o al
        /// MouseUp dopo un ridimensionamento (per nascondere i righelli).
        /// </summary>
        /// <param name="sender">Il controllo i cui metacontrolli devono essere ridisegnati.</param>
        /// <param name="e"></param>
        void selectedControl_MetaControlsNeedRepaint(object sender, EventArgs e)
        {
            if (!(sender is SkinnableControl))
            {
                return;
            }

            SkinnableControl control = (SkinnableControl)sender;


            // Handles per il resize

            MetaControls.MetaResizeHandles resizeHandles = new MetaControls.MetaResizeHandles(this);
            resizeHandles.Control              = control;
            resizeHandles.IsWindow             = this.containerControl == resizeHandles.Control;
            resizeHandles.ClipRectanglePadding = CONTROL_CLIP_RECTANGLE_PADDING;

            selectionResizeHandles.Remove(control);
            selectionResizeHandles.Add(control, resizeHandles);
            resizeHandles.InvalidateView();


            // Handle per il drag dei Container

            MetaControls.MetaDragContainer dragContainer = new MetaControls.MetaDragContainer(this);
            dragContainer.Control  = control;
            dragContainer.IsWindow = this.containerControl == dragContainer.Control;

            dragContainerHandles.Remove(control);
            dragContainerHandles.Add(control, dragContainer);
            dragContainer.InvalidateView();


            // FIXME Il clipping funziona, ma non considera i righelli (che vengono tagliati fuori)...
            // questa è una mancanza (da fixare) di getMetaControlsOuterRectangle() in InvalidateView().
            // Per ora risolviamo invalidando tutto, correggere non ne vale la pena (bisognerebbe
            // effettuare misurazioni del testo, calcolare rotazioni, ecc). Il problema comunque non
            // è grave visto che è limitato al designer, e al momento non causa problemi di performance.

            if (DebugShowRuler)
            {
                MetaControls.MetaMeasure measure = new MetaControls.MetaMeasure(this);
                measure.Control          = control;
                measure.Font             = this.Font;
                measure.MeasureDirection = MetaControls.MetaMeasure.ResizeDirectionToMeasureDirection(this.resizingDirection);

                resizeMeasure.Remove(control);
                resizeMeasure.Add(control, measure);
                measure.InvalidateView();
            }
        }
        private Tuple <float, float, SkinnableControl> RecursiveHitTest(int x, int y)
        {
            if (this.containerControl.HitTest(new PointF(x, y)) == false)
            {
                return(null);
            }

            var closerContainer = this.containerControl;
            SkinnableControl finalHit = this.containerControl;
            float            absX = closerContainer.Left, absY = closerContainer.Top;

            do
            {
                var shiftedLocation = new PointF(x - absX, y - absY);
                var tmp             = closerContainer.Controls.FirstOrDefault(k => k.HitTest(shiftedLocation));
                if (tmp == null)
                {
                    break;
                }
                else
                {
                    absX    += tmp.Left;
                    absY    += tmp.Top;
                    finalHit = tmp;
                    if (tmp is SkinnableControls.Container)
                    {
                        closerContainer = (SkinnableControls.Container)tmp;
                    }
                    else
                    {
                        finalHit = tmp;
                        break;
                    }
                }
            } while (true);

            return(new Tuple <float, float, SkinnableControl>(absX, absY, finalHit));
        }
        protected override void OnQueryContinueDrag(QueryContinueDragEventArgs e)
        {
            base.OnQueryContinueDrag(e);

            var leftPressed           = (e.KeyState & 1) == 1;
            var rightPressed          = (e.KeyState & 2) == 2;
            var middlePressed         = (e.KeyState & 16) == 16;
            var noMouseButtonsPressed = !(leftPressed || rightPressed || middlePressed);

            if (e.EscapePressed || noMouseButtonsPressed)
            {
                if (draggingControl != null)
                {
                    // Stavamo facendo il dragging di un nostro controllo
                    // Rimettiamo il controllo al suo posto
                    this.draggingControlOriginalContainer.Controls.Add(draggingControl);
                    this.Select(draggingControl);
                    this.draggingControl = null;
                }
            }

            // ATTENZIONE!! Non tocchiamo e.Action: vogliamo il comportamento predefinito (cancel se e solo se viene premuto ESC).
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (this.dragStarting && this.draggingControl == null && this.selectedControls.Count > 0)
            {
                // Prima di far partire il drag controlliamo se il pulsante premuto è il sinistro e se abbiamo superato il delta di distanza
                var delta = SystemInformation.DragSize;
                if (e.Button == System.Windows.Forms.MouseButtons.Left &&
                    (Math.Abs(this.dragStartPosition.X - e.X) >= delta.Width || Math.Abs(this.dragStartPosition.Y - e.Y) >= delta.Height))
                {
                    this.dragStarting = false;

                    // FIXME Fare il drag di tutti i controlli selezionati invece che solo dell'ultimo!
                    var lastctl = this.selectedControls.Last();
                    this.draggingControl = lastctl;
                    this.draggingControlOriginalContainer = draggingControl.Parent;
                    this.draggingBitmap = lastctl.ToBitmap();
                    this.draggingControl.Parent.Controls.Remove(this.draggingControl);
                    this.Select(null);

                    //this.DoDragDrop(GetDataObject(CLIPBOARD_PLAYERCONTROL_FORMAT, this.draggingControl), DragDropEffects.Move | DragDropEffects.Scroll);
                    this.DoDragDrop(new DataObject(typeof(SkinnableControl).FullName, this.draggingControl), DragDropEffects.Move | DragDropEffects.Scroll);
                }
            }

            if (selectingWithMouse)
            {
                this.selectionEndPoint = e.Location;
                this.Invalidate();
            }

            if (draggingControl == null && resizingControl == null && selectingWithMouse == false)
            {
                // Non stiamo né draggando né ridimensionando.

                // Controlliamo se siamo sopra a un drag handle di un Container
                bool trovato = false;
                foreach (var ctl in selectedControls)
                {
                    if (ctl != this.containerControl)
                    {
                        var rect = dragContainerHandles[ctl].GetHandleRectangle();
                        if (rect.Contains(e.Location))
                        {
                            trovato     = true;
                            this.Cursor = Cursors.SizeAll;
                            break;
                        }
                    }
                }

                if (!trovato)
                {
                    // Controlliamo se siamo sopra a un resize handle
                    bool actionSet = false;
                    foreach (var ctl in selectedControls)
                    {
                        var       topctn    = ctl == this.containerControl;
                        Direction resizeDir = selectionResizeHandles[ctl].WhatResizeHandle(e.Location);
                        actionSet = true;
                        if ((resizeDir == Direction.Left && !topctn) || resizeDir == Direction.Right)
                        {
                            this.Cursor = Cursors.SizeWE;
                        }
                        else if ((resizeDir == Direction.Up && !topctn) || resizeDir == Direction.Down)
                        {
                            this.Cursor = Cursors.SizeNS;
                        }
                        else if ((resizeDir == (Direction.Up | Direction.Right) && !topctn) || (resizeDir == (Direction.Down | Direction.Left) && !topctn))
                        {
                            this.Cursor = Cursors.SizeNESW;
                        }
                        else if ((resizeDir == (Direction.Up | Direction.Left) && !topctn) || resizeDir == (Direction.Down | Direction.Right))
                        {
                            this.Cursor = Cursors.SizeNWSE;
                        }
                        else
                        {
                            actionSet = false;
                        }

                        if (actionSet)
                        {
                            break;
                        }
                    }

                    if (!actionSet)
                    {
                        this.Cursor = Cursors.Default;
                    }
                }
            }

            if (resizingControl != null)
            {
                const int minWidth = 11, minHeight = 11;
                var       resizingCtrlPos = resizingControl.GetAbsoluteLocation();

                if ((resizingDirection & Direction.Down) == Direction.Down)
                {
                    float heightIncr = (e.Y - resizingCtrlPos.Y) - resizingControl.Size.Height;
                    selectedControls.ForEach(c => c.Size = new SizeF(c.Size.Width, Math.Max(c.Size.Height + heightIncr, minHeight)));
                }
                if ((resizingDirection & Direction.Right) == Direction.Right)
                {
                    float widthIncr = (e.X - resizingCtrlPos.X) - resizingControl.Size.Width;
                    selectedControls.ForEach(c => c.Size = new SizeF(Math.Max(c.Size.Width + widthIncr, minWidth), c.Size.Height));
                }
                if ((resizingDirection & Direction.Up) == Direction.Up)
                {
                    float height = resizingControl.Size.Height + (resizingCtrlPos.Y - e.Y);
                    if (height >= minHeight)
                    {
                        float heightIncr = height - resizingControl.Size.Height;
                        float topIncr    = e.Y - resizingCtrlPos.Y;
                        selectedControls.ForEach(c => { c.Top += topIncr; c.Size = new SizeF(c.Size.Width, c.Size.Height + heightIncr); });
                    }
                }
                if ((resizingDirection & Direction.Left) == Direction.Left)
                {
                    float width = resizingControl.Size.Width + (resizingCtrlPos.X - e.X);
                    if (width >= minWidth)
                    {
                        float widthIncr = width - resizingControl.Size.Width;
                        float leftIncr  = e.X - resizingCtrlPos.X;
                        selectedControls.ForEach(c => { c.Left += leftIncr; c.Size = new SizeF(c.Size.Width + widthIncr, c.Size.Height); });
                    }
                }

                resizingControl.OnResize(new EventArgs());
            }
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                // Gestione handle di spostamento Container
                foreach (var ctl in selectedControls)
                {
                    if (ctl != this.containerControl)
                    {
                        var rect = dragContainerHandles[ctl].GetHandleRectangle();
                        if (rect.Contains(e.Location))
                        {
                            var absLoc = ctl.GetAbsoluteLocation();

                            this.dragStarting      = true;
                            this.dragStartPosition = e.Location;
                            this.draggingOffset.X  = e.X - absLoc.X;
                            this.draggingOffset.Y  = e.Y - absLoc.Y;
                            break;
                        }
                    }
                }
            }

            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                // Gestione resize handle (se non sta partendo il drag)
                if (!dragStarting)
                {
                    foreach (var ctl in selectedControls)
                    {
                        var       resizeHandles = selectionResizeHandles[ctl];
                        Direction resizeDir     = resizeHandles.WhatResizeHandle(e.Location);
                        if (resizeDir != Direction.None)
                        {
                            if (ctl != this.containerControl ||
                                ((resizeDir & Direction.Left) != Direction.Left && // containerControl non può ridimensionarsi a sx
                                 (resizeDir & Direction.Up) != Direction.Up))   // containerControl non può ridimensionarsi in alto
                            {
                                this.resizingControl   = ctl;
                                this.resizingDirection = resizeDir;
                            }
                        }
                    }
                }
            }

            // Gestione selezione e dragging (se non è stato cliccato un resize handle e se non sta partendo un drag)
            if (resizingControl == null && !dragStarting)
            {
                if (DrawWindowDecorations && getWindowDecorationsPath().IsVisible(e.Location))
                {
                    // E' stata cliccata la decorazione della finestra
                    if (ModifierKeys == Keys.Control)
                    {
                        this.ToggleSelection(this.containerControl);
                    }
                    else
                    {
                        this.Select(this.containerControl);
                    }
                }
                else
                {
                    bool startDrag = false;

                    var hitInfo = RecursiveHitTest(e.X, e.Y);
                    if (hitInfo != null && hitInfo.Item3 != this.containerControl)
                    {
                        SkinnableControl ctl = hitInfo.Item3;
                        if (ModifierKeys == Keys.Control)
                        {
                            this.ToggleSelection(ctl);
                        }
                        else if (e.Button == System.Windows.Forms.MouseButtons.Right)
                        {
                            this.AddToSelection(ctl);
                        }
                        else
                        {
                            this.Select(ctl);
                        }

                        startDrag = true;
                    }
                    else if (hitInfo != null && hitInfo.Item3 == this.containerControl)
                    {
                        if (ModifierKeys == Keys.Control)
                        {
                            this.ToggleSelection(this.containerControl);
                        }
                        else if (e.Button == System.Windows.Forms.MouseButtons.Right)
                        {
                            this.AddToSelection(this.containerControl);
                        }
                        else
                        {
                            this.Select(this.containerControl);
                        }
                    }

                    if (e.Button == System.Windows.Forms.MouseButtons.Left)
                    {
                        if (hitInfo != null && hitInfo.Item3 is SkinnableControls.Container)
                        {
                            // Fa partire la selezione col mouse
                            this.selectingWithMouse      = true;
                            this.selectionStartPoint     = e.Location;
                            this.selectionEndPoint       = e.Location;
                            this.selectionStartContainer = (Container)hitInfo.Item3;
                            this.Invalidate();
                        }
                        else
                        {
                            if (startDrag)
                            {
                                StartingControlDrag(e.Location, e.X - hitInfo.Item1, e.Y - hitInfo.Item2);
                            }
                        }
                    }
                }
            }
        }
        protected override void OnDragDrop(DragEventArgs e)
        {
            base.OnDragDrop(e);

            if (e.Data.GetDataPresent(typeof(SkinnableControls.SkinnableControl.SemanticType)))
            {
                // Drop dalla toolbox

                var dropInfo = ControlDropAllowed(this.PointToClient(new Point(e.X, e.Y)), true);
                if (dropInfo != null)
                {
                    SkinnableControls.SkinnableControl.SemanticType ctype =
                        (SkinnableControls.SkinnableControl.SemanticType)e.Data.GetData(typeof(SkinnableControls.SkinnableControl.SemanticType));

                    SkinnableControls.SkinnableControl.SemanticTypeMeta info =
                        SkinnableControls.SkinnableControl.GetPlayerControlInstanceInfo(ctype);

                    e.Effect = DragDropEffects.Copy;

                    // Istanziamo un nuovo oggetto del tipo draggato, e lo aggiungiamo al playerView
                    SkinnableControls.SkinnableControl c = (SkinnableControls.SkinnableControl)Activator.CreateInstance(info.InstanceType, new object[] { ctype });

                    // Inizializiamo qualche proprietà per i controlli standard
                    if (c is SkinnableControls.Button)
                    {
                        ((SkinnableControls.Button)c).Text = info.Title;
                    }
                    else if (c is SkinnableControls.ToggleButton)
                    {
                        ((SkinnableControls.ToggleButton)c).Text        = info.Title;
                        ((SkinnableControls.ToggleButton)c).CheckedText = info.Title;
                    }
                    else if (c is SkinnableControls.Label)
                    {
                        ((SkinnableControls.Label)c).Text = info.Title;
                    }

                    dropInfo.Item3.Controls.AddFirst(c);
                    var location = this.PointToClient(new Point(e.X, e.Y));
                    // Non posizioniamo sotto al mouse le coordinate (0,0) del controllo: lo spostiamo un pochino in alto e a sinistra.
                    const float mouseOffsetX = 7, mouseOffsetY = 7;
                    c.Location = new PointF(Math.Max(0, location.X - dropInfo.Item1 - mouseOffsetX), Math.Max(0, location.Y - dropInfo.Item2 - mouseOffsetY));

                    if (DesignerControlsTreeChanged != null)
                    {
                        DesignerControlsTreeChanged(this, new EventArgs());
                    }
                    this.Select(c);

                    this.Focus();
                }
            }
            else if (e.Data.GetDataPresent(typeof(SkinnableControl).FullName))
            {
                // Drop di un controllo
                var c = (SkinnableControl)e.Data.GetData(typeof(SkinnableControl).FullName);

                if (c.Parent != null)
                {
                    // Qualcuno lo ha già riaggiunto alla View prima di noi (probabilmente OnQueryContinueDrag che
                    // credeva che il dragging fosse stato annullato).
                    // Togliamolo così più sotto lo reinseriamo al posto giusto.
                    c.Parent = null;
                    this.Select(null);
                }

                var dropInfo = ControlDropAllowed(this.PointToClient(new Point(e.X, e.Y)), false);
                if (dropInfo != null)
                {
                    var newParent = dropInfo.Item3;
                    if (newParent != c)
                    {
                        newParent.Controls.AddFirst(c);
                    }
                    var location = this.PointToClient(new Point(e.X, e.Y));
                    c.Location           = new PointF(location.X - this.draggingOffset.X - dropInfo.Item1, location.Y - this.draggingOffset.Y - dropInfo.Item2);
                    this.draggingControl = null;
                    if (DesignerControlsTreeChanged != null)
                    {
                        DesignerControlsTreeChanged(this, new EventArgs());
                    }
                    this.Select(c);
                    if (SelectedObjectPropertyChanged != null)
                    {
                        SelectedObjectPropertyChanged(this, new EventArgs());
                    }
                }
            }
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            this.dragStarting = false;

            if (this.selectingWithMouse)
            {
                this.selectingWithMouse = false;

                if (this.selectionStartPoint != this.selectionEndPoint)
                {
                    // Cerchiamo i controlli che cadono nel rettangolo di selezione
                    RectangleF selRect = new RectangleF(
                        Math.Min(selectionStartPoint.X, selectionEndPoint.X),
                        Math.Min(selectionStartPoint.Y, selectionEndPoint.Y),
                        Math.Abs(selectionStartPoint.X - selectionEndPoint.X),
                        Math.Abs(selectionStartPoint.Y - selectionEndPoint.Y));

                    bool foundSome = false;
                    foreach (var ctl in this.selectionStartContainer.Controls)
                    {
                        RectangleF ctlRect = new RectangleF(ctl.GetAbsoluteLocation(), ctl.Size);
                        if (selRect.IntersectsWith(ctlRect))
                        {
                            if (ModifierKeys == Keys.Control)
                            {
                                foundSome |= this.ToggleSelection(ctl);
                            }
                            else
                            {
                                this.AddToSelection(ctl);
                                foundSome = true;
                            }
                        }
                    }

                    // Decidiamo se deselezionare il contenitore oppure no
                    // in base al fatto che sia stato selezionato almeno un figlio
                    // (n.b. questa logica potrebbe benissimo essere migliorata)
                    if (foundSome)
                    {
                        this.Deselect(this.selectionStartContainer);
                    }
                }

                this.Invalidate();
            }

            if (resizingControl != null)
            {
                resizingControl = null;

                foreach (var ctl in selectedControls)
                {
                    selectedControl_MetaControlsNeedRepaint(ctl, new EventArgs());
                }

                if (SelectedObjectPropertyChanged != null)
                {
                    SelectedObjectPropertyChanged(this, new EventArgs());
                }
            }

            //if (ContextMenuRequested != null) ContextMenuRequested(this, new EventArgs());
        }