/// <summary> /// Updates site controls UI position in parent Grid panel based on the /// location of data bound widget data object within its parent widget container. /// </summary> /// <remarks> /// Widget data model consists of widget data objects which represent individual widgets /// and widget container objects which represent a 2D matrix of widgets. On the UI side /// widget containers are bound to source properties of WidgetMatrix controls which in /// turn create children WidgetSiteControl controls whose source is then bound to /// corresponding widget data objects. /// /// If parent widget container is resized, locations of widgets in the UI may need to /// be updated. The purpose of this method is to perform such an update to ensure the UI /// remains consistent with its underlying data model. /// </remarks> public void UpdateGridPosition() { MatrixLoc gridPosition = ParentContainer.Source.Bounds.ToIndex(_location); SetValue(Grid.RowProperty, gridPosition.Row); SetValue(Grid.ColumnProperty, gridPosition.Column); }
/// <summary> /// Initializing constructor /// </summary> /// <param name="action">Specifies if a widget was added, removed or replaced</param> /// <param name="location">Location of the changed widget</param> /// <param name="oldWidget">Reference to the original widget, or null if there wasn't any</param> /// <param name="newWidget">Reference to the new widget, or null if there isn't any</param> public WidgetContainerChangedEventArgs( NotifyCollectionChangedAction action, MatrixLoc location, WidgetData oldWidget, WidgetData newWidget ) { _location = location; _action = action; _oldWidget = oldWidget; _newWidget = newWidget; }
private void UpdateMatrixUI(MatrixLoc insertLoc, WidgetSiteDragDropData data) { List <SiteShiftInfo> relocatedSites; relocatedSites = CalculateWhichSitesToShift(insertLoc, data); var sitesToMove = relocatedSites.Except(_prevRelocatedSites, SiteShiftInfoComparer.Comparer).ToList(); var sitesToReverse = _prevRelocatedSites.Except(relocatedSites, SiteShiftInfoComparer.Comparer).ToList(); foreach (var s in sitesToMove) { AnimateSiteTranslate(s.site, s.translateX, s.translateY); } foreach (var s in sitesToReverse) { AnimateSiteTranslate(s.site, 0.0, 0.0); } _prevRelocatedSites = relocatedSites; }
private WidgetSiteControl CreateWidgetSite(MatrixLoc location, bool withAnimation, ref TimeSpan animationTime) { var site = new WidgetSiteControl(); var transform = new TransformGroup(); transform.Children.Add(withAnimation ? new ScaleTransform(0, 0) : new ScaleTransform(1, 1)); transform.Children.Add(new TranslateTransform()); site.RenderTransform = transform; site.RenderTransformOrigin = new Point(0.5, 0.5); if (withAnimation) { AnimateSiteScaleTransform(site, ref animationTime, 0, 1, null); } matrixPanel.Children.Add(site); site.Location = location; return(site); }
private bool ProcessDataObject(DragEventArgs eventArgs, ProcessDataObjectDelegate callback) { WidgetSiteDragDropData data = eventArgs.Data.GetData("Droppy.WidgetSiteDragDropData") as WidgetSiteDragDropData; if (data == null) { eventArgs.Effects = DragDropEffects.None; return(false); } Point pt = eventArgs.GetPosition(this.Target) - new Vector(data.DraggableOffset.X, data.DraggableOffset.Y); Rect dragRect = new Rect(pt, new Size(data.Site.ActualWidth + data.Site.Margin.Width(), data.Site.ActualHeight + data.Site.Margin.Height())); Point dragCenter = new Point(dragRect.X + dragRect.Width / 2, dragRect.Y + dragRect.Height / 2); MatrixLoc insertIndex = new MatrixLoc( (int)((dragCenter.Y + dragRect.Height) / dragRect.Height) - 1, (int)((dragCenter.X + dragRect.Width) / dragRect.Width) - 1); MatrixLoc insertLoc = _controlData.Source.Bounds.ToLocation(insertIndex); if (_controlData.Source.Bounds.Contains(insertLoc)) { eventArgs.Effects = DragDropEffects.Move; callback(insertLoc, data); } else { eventArgs.Effects = DragDropEffects.None; } return(true); }
private void CommitMove(MatrixLoc insertLoc, WidgetSiteDragDropData data) { List <SiteShiftInfo> relocatedSites; relocatedSites = CalculateWhichSitesToShift(insertLoc, data); if (relocatedSites.Count > 0) { foreach (var s in relocatedSites) { _controlData.Source[s.newLocation] = s.widget; AnimateTranslate(s.site, TranslateTransform.XProperty, null); AnimateTranslate(s.site, TranslateTransform.YProperty, null); } _controlData.Source[insertLoc] = data.Widget; } // If there are any controls left out of original position, return them now. _prevRelocatedSites = _prevRelocatedSites.Except(relocatedSites, SiteShiftInfoComparer.Comparer).ToList(); CancelMove(); }
/// <summary> /// Sets parent container information on the current widget /// </summary> /// <param name="parent">Reference to the parent widget container</param> /// <param name="location">Location of the widget within the parent container</param> public void SetOwner( WidgetContainerData parent, MatrixLoc location ) { _location = location; _parent = parent; }
/// <summary> /// Removes any association between the widget and its parent /// </summary> public void ClearOwner() { _parent = null; _location = new MatrixLoc(); }
private void SetWidget( MatrixLoc location, WidgetData widget ) { WidgetData removedWidget = null; Validate(); // the same widget is being inserted at the same spot where it is already located, // let not do anything and just exit if( widget != null && widget.Parent == this && widget.Location == location ) return; MatrixRect neededBounds = _containerBounds.GrowTo( location ); // If the cell being modified within the bounds of the current array, let's make sure // the existing cell is empty. Otherwise, we need to reallocate the array before // we can assign the widget to it. if( neededBounds.Size == _containerBounds.Size ) { removedWidget = ClearWidget( location ); } else if( widget != null ) { WidgetContainerResizeJustify resizeJustify = ( _containerBounds.Row == neededBounds.Row ? WidgetContainerResizeJustify.Top : WidgetContainerResizeJustify.Bottom ) | ( _containerBounds.Column == neededBounds.Column ? WidgetContainerResizeJustify.Left : WidgetContainerResizeJustify.Right ); Resize( neededBounds.Size, resizeJustify ); } Validate(); if( widget != null ) { if( widget.HasOwner ) { widget.Parent.Remove( widget ); } _widgetArray[ _containerBounds.ToIndex( location ) ] = widget; widget.SetOwner( this, location ); widget.IsDirtyChanged += OnChildIsDirtyChanged; if( removedWidget != null ) { OnWidgetReplaced( location, removedWidget, widget ); removedWidget = null; } else { OnWidgetAdded( location, widget ); } } if( removedWidget != null ) { OnWidgetRemoved( location, removedWidget ); } Validate(); IsDirty = true; }
private WidgetData ClearWidget( MatrixLoc loc ) { MatrixLoc arrayIndex = _containerBounds.ToIndex( loc ); WidgetData widget = _widgetArray[ arrayIndex ]; _widgetArray[ arrayIndex ] = null; if( widget != null ) { widget.ClearOwner(); widget.IsDirtyChanged -= OnChildIsDirtyChanged; } return widget; }
/// <summary> /// This method is invoked whenever a widget is replaced /// </summary> /// <param name="location">Location where a widget was replaced</param> /// <param name="oldWidget">Reference to an old widget that was replaced</param> /// <param name="newWidget">Reference to a new widget that is being inserted</param> protected virtual void OnWidgetReplaced( MatrixLoc location, WidgetData oldWidget, WidgetData newWidget ) { if( _containerChangedEvent != null ) { _containerChangedEvent( this, new WidgetContainerChangedEventArgs( NotifyCollectionChangedAction.Replace, location, oldWidget, newWidget ) ); } }
/// <summary> /// This method is invoked whenever a widget is added /// </summary> /// <param name="location">Location where new widget was added</param> /// <param name="widget">Reference to a widget that was added</param> protected virtual void OnWidgetAdded( MatrixLoc location, WidgetData widget ) { if( _containerChangedEvent != null ) { _containerChangedEvent( this, new WidgetContainerChangedEventArgs( NotifyCollectionChangedAction.Add, location, null, widget ) ); } }
/// <summary> /// Gets/sets a widget at a specified location in the container /// </summary> /// <param name="location">Location to access/modify</param> public WidgetData this[MatrixLoc location] { get { return _widgetArray[ _containerBounds.ToIndex( location ) ]; } set { SetWidget( location, value ); } }
private List <SiteShiftInfo> CalculateWhichSitesToShift(MatrixLoc insertLoc, WidgetSiteDragDropData data) { MatrixLoc sourceLoc = data.Site.Location; List <SiteShiftInfo> relocatedSites; int i, step; double translateBy; // preallocate enough so we don't need to worry about reallocations relocatedSites = new List <SiteShiftInfo>(_controlData.Source.Bounds.RowCount + _controlData.Source.Bounds.ColumnCount + 10); if (insertLoc.Column != sourceLoc.Column) { translateBy = data.Site.ActualWidth + data.Site.Margin.Width(); if (insertLoc.Column < sourceLoc.Column) { step = 1; } else { step = -1; translateBy = -translateBy; } for (i = insertLoc.Column; i != sourceLoc.Column; i += step) { MatrixLoc arrayIndex = _controlData.Source.Bounds.ToIndex(new MatrixLoc(sourceLoc.Row, i)); WidgetSiteControl ctrl = _controlData.SiteGrid[arrayIndex]; relocatedSites.Add(new SiteShiftInfo() { site = ctrl, widget = (Data.WidgetData)ctrl.Content, translateX = translateBy, translateY = 0.0, newLocation = new MatrixLoc(sourceLoc.Row, i + step) }); } } if (insertLoc.Row != sourceLoc.Row) { translateBy = data.Site.ActualHeight + data.Site.Margin.Height(); if (insertLoc.Row < sourceLoc.Row) { step = 1; } else { step = -1; translateBy = -translateBy; } for (i = insertLoc.Row; i != sourceLoc.Row; i += step) { MatrixLoc arrayIndex = _controlData.Source.Bounds.ToIndex(new MatrixLoc(i, insertLoc.Column)); WidgetSiteControl ctrl = _controlData.SiteGrid[arrayIndex]; relocatedSites.Add(new SiteShiftInfo() { site = ctrl, widget = (Data.WidgetData)ctrl.Content, translateY = translateBy, translateX = 0.0, newLocation = new MatrixLoc(i + step, insertLoc.Column) }); } } return(relocatedSites); }
private void UpdateGrid(bool withAnimation) { TimeSpan animationTime = new TimeSpan(); List <WidgetSiteControl> sitesToRemove = new List <WidgetSiteControl>(256); int rowCount = _controlData.Source.Bounds.RowCount; int columnCount = _controlData.Source.Bounds.ColumnCount; ResizeRowOrColumn(matrixPanel.RowDefinitions, rowCount); ResizeRowOrColumn(matrixPanel.ColumnDefinitions, columnCount); _controlData.SiteGrid = new Array2D <WidgetSiteControl>(rowCount, columnCount); foreach (var child in matrixPanel.Children) { WidgetSiteControl site = child as WidgetSiteControl; if (site == null) { continue; } if (!_controlData.Source.Bounds.Contains(site.Location)) { if (withAnimation) { MatrixSize siteDistance = _controlData.Source.Bounds.Distance(site.Location); TranslateTransform transform = (TranslateTransform)((TransformGroup)site.RenderTransform).Children[1]; transform.Y = site.HeightWithMargin * siteDistance.RowCount; transform.X = site.WidthWithMargin * siteDistance.ColumnCount; AnimateSiteScaleTransform(site, ref animationTime, 1, 0, new EventHandler((o, e) => { matrixPanel.Children.Remove(site); })); } else { sitesToRemove.Add(site); } } else { MatrixLoc arrayIndex = _controlData.Source.Bounds.ToIndex(site.Location); _controlData.SiteGrid[arrayIndex] = site; site.UpdateGridPosition(); } } foreach (var site in sitesToRemove) { matrixPanel.Children.Remove(site); } foreach (MatrixLoc loc in _controlData.Source.Bounds) { MatrixLoc arrayIndex = _controlData.Source.Bounds.ToIndex(loc); if (_controlData.SiteGrid[arrayIndex] == null) { var site = CreateWidgetSite(loc, withAnimation, ref animationTime); _controlData.SiteGrid[arrayIndex] = site; } _controlData.SiteGrid[arrayIndex].Content = _controlData.Source[loc]; } }