1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Drag 'n drop WIP

This commit is contained in:
SpoinkyNL 2016-05-23 10:48:25 +02:00
parent fdc18a1de0
commit cc10f46e63
8 changed files with 322 additions and 165 deletions

View File

@ -148,6 +148,10 @@
<HintPath>..\packages\CUE.NET.1.0.2.2\lib\net45\CUE.NET.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="GongSolutions.Wpf.DragDrop, Version=0.1.4.3, Culture=neutral, PublicKeyToken=d19974ea350ccea1, processorArchitecture=MSIL">
<HintPath>..\packages\gong-wpf-dragdrop.0.1.4.3\lib\net40\GongSolutions.Wpf.DragDrop.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Hardcodet.Wpf.TaskbarNotification, Version=1.0.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
<Private>True</Private>
@ -418,6 +422,8 @@
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Offsets.settings</DependentUpon>
</Compile>
<Compile Include="Styles\DropTargetAdorners\DropTargetMetroHighlightAdorner.cs" />
<Compile Include="Styles\DropTargetAdorners\DropTargetMetroInsertionAdorner.cs" />
<Compile Include="Utilities\ColorHelpers.cs" />
<Compile Include="Utilities\ExtensionMethods.cs" />
<Compile Include="Utilities\GameState\GameDataReceivedEventArgs.cs" />

View File

@ -149,91 +149,7 @@ namespace Artemis.Models.Profiles
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor())
};
}
public void Reorder(LayerModel selectedLayer, bool moveUp)
{
// Fix the sorting just in case
FixOrder();
// Possibly remove selectedLayer from a folder
if (selectedLayer.Parent?.LayerType == LayerType.Folder)
{
var parent = selectedLayer.Parent;
var siblings = parent.Children;
if ((selectedLayer == siblings.FirstOrDefault() && moveUp) ||
(selectedLayer == siblings.LastOrDefault() && !moveUp))
{
// If selectedLayer is on the edge of a folder and moved off of it, remove it from the folder
parent.Children.Remove(selectedLayer);
if (parent.Parent != null)
parent.Parent.Children.Add(selectedLayer);
else
parent.Profile.Layers.Add(selectedLayer);
if (moveUp)
selectedLayer.Order = parent.Order - 1;
else
selectedLayer.Order = parent.Order + 1;
return;
}
}
int newOrder;
if (moveUp)
newOrder = selectedLayer.Order - 1;
else
newOrder = selectedLayer.Order + 1;
var target = Children.FirstOrDefault(l => l.Order == newOrder);
if (target == null)
return;
ApplyReorder(selectedLayer, target, newOrder, moveUp);
}
public static void ApplyReorder(LayerModel selectedLayer, LayerModel target, int newOrder, bool moveUp)
{
if (target.LayerType == LayerType.Folder)
{
if (selectedLayer.Parent == null)
selectedLayer.Profile.Layers.Remove(selectedLayer);
else
selectedLayer.Parent.Children.Remove(selectedLayer);
target.Children.Add(selectedLayer);
selectedLayer.Parent = target;
if (moveUp)
{
var parentTarget = target.Children.OrderBy(c => c.Order).LastOrDefault();
if (parentTarget != null)
{
parentTarget.Order--;
selectedLayer.Order = parentTarget.Order + 1;
}
else
selectedLayer.Order = 1;
}
else
{
var parentTarget = target.Children.OrderBy(c => c.Order).FirstOrDefault();
if (parentTarget != null)
{
parentTarget.Order++;
selectedLayer.Order = parentTarget.Order - 1;
}
else
selectedLayer.Order = 1;
}
target.FixOrder();
return;
}
target.Order = selectedLayer.Order;
selectedLayer.Order = newOrder;
}
public void FixOrder()
{
Children.Sort(l => l.Order);

View File

@ -86,23 +86,6 @@ namespace Artemis.Models.Profiles
return layer;
}
public void Reorder(LayerModel selectedLayer, bool moveUp)
{
FixOrder();
int newOrder;
if (moveUp)
newOrder = selectedLayer.Order - 1;
else
newOrder = selectedLayer.Order + 1;
var target = Layers.FirstOrDefault(l => l.Order == newOrder);
if (target == null)
return;
LayerModel.ApplyReorder(selectedLayer, target, newOrder, moveUp);
}
public void FixOrder()
{
Layers.Sort(l => l.Order);

View File

@ -0,0 +1,75 @@
// Direct copy-paste from GongSolutions.WPF.DragDrop - https://github.com/punker76/gong-wpf-dragdrop
// All credit goes to their awesome library, I merely copied this in order to change the highlight color.
// BSD 3-Clause License
//
// Copyright (c) 2015, Jan Karger (Steven Kirk)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of gong-wpf-dragdrop nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using GongSolutions.Wpf.DragDrop;
using MahApps.Metro;
namespace Artemis.Styles.DropTargetAdorners
{
public class DropTargetMetroHighlightAdorner : DropTargetAdorner
{
public DropTargetMetroHighlightAdorner(UIElement adornedElement)
: base(adornedElement)
{
}
protected override void OnRender(DrawingContext drawingContext)
{
var visualTargetItem = DropInfo.VisualTargetItem;
if (visualTargetItem != null)
{
var rect = Rect.Empty;
var tvItem = visualTargetItem as TreeViewItem;
if (tvItem != null && VisualTreeHelper.GetChildrenCount(tvItem) > 0)
{
var descendant = VisualTreeHelper.GetDescendantBounds(tvItem);
var translatePoint = tvItem.TranslatePoint(new Point(), AdornedElement);
var itemRect = new Rect(translatePoint, tvItem.RenderSize);
descendant.Union(itemRect);
rect = new Rect(translatePoint, new Size(descendant.Width - translatePoint.X, tvItem.ActualHeight));
}
if (rect.IsEmpty)
{
rect = new Rect(visualTargetItem.TranslatePoint(new Point(), AdornedElement),
VisualTreeHelper.GetDescendantBounds(visualTargetItem).Size);
}
var color = (Color) ThemeManager.DetectAppStyle(Application.Current).Item2.Resources["AccentColor"];
drawingContext.DrawRoundedRectangle(null, new Pen(new SolidColorBrush(color), 2), rect, 2, 2);
}
}
}
}

View File

@ -0,0 +1,169 @@
// Direct copy-paste from GongSolutions.WPF.DragDrop - https://github.com/punker76/gong-wpf-dragdrop
// All credit goes to their awesome library, I merely copied this in order to change the highlight color.
// BSD 3-Clause License
//
// Copyright (c) 2015, Jan Karger (Steven Kirk)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of gong-wpf-dragdrop nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using GongSolutions.Wpf.DragDrop;
using MahApps.Metro;
namespace Artemis.Styles.DropTargetAdorners
{
public class DropTargetMetroInsertionAdorner : DropTargetAdorner
{
private static readonly Pen m_Pen;
private static readonly PathGeometry m_Triangle;
static DropTargetMetroInsertionAdorner()
{
// Create the pen and triangle in a static constructor and freeze them to improve performance.
const int triangleSize = 5;
var color = (Color)ThemeManager.DetectAppStyle(Application.Current).Item2.Resources["AccentColor"];
m_Pen = new Pen(new SolidColorBrush(color), 2);
m_Pen.Freeze();
var firstLine = new LineSegment(new Point(0, -triangleSize), false);
firstLine.Freeze();
var secondLine = new LineSegment(new Point(0, triangleSize), false);
secondLine.Freeze();
var figure = new PathFigure { StartPoint = new Point(triangleSize, 0) };
figure.Segments.Add(firstLine);
figure.Segments.Add(secondLine);
figure.Freeze();
m_Triangle = new PathGeometry();
m_Triangle.Figures.Add(figure);
m_Triangle.Freeze();
}
public DropTargetMetroInsertionAdorner(UIElement adornedElement)
: base(adornedElement)
{
}
protected override void OnRender(DrawingContext drawingContext)
{
var itemsControl = DropInfo.VisualTarget as ItemsControl;
if (itemsControl != null)
{
// Get the position of the item at the insertion index. If the insertion point is
// to be after the last item, then get the position of the last item and add an
// offset later to draw it at the end of the list.
ItemsControl itemParent;
if (DropInfo.VisualTargetItem != null)
{
itemParent = ItemsControl.ItemsControlFromItemContainer(DropInfo.VisualTargetItem);
}
else
{
itemParent = itemsControl;
}
var index = Math.Min(DropInfo.InsertIndex, itemParent.Items.Count - 1);
var lastItemInGroup = false;
var targetGroup = DropInfo.TargetGroup;
if (targetGroup != null && targetGroup.IsBottomLevel &&
DropInfo.InsertPosition.HasFlag(RelativeInsertPosition.AfterTargetItem))
{
var indexOf = targetGroup.Items.IndexOf(DropInfo.TargetItem);
lastItemInGroup = indexOf == targetGroup.ItemCount - 1;
if (lastItemInGroup && DropInfo.InsertIndex != itemParent.Items.Count)
{
index--;
}
}
var itemContainer = (UIElement)itemParent.ItemContainerGenerator.ContainerFromIndex(index);
if (itemContainer != null)
{
var itemRect = new Rect(itemContainer.TranslatePoint(new Point(), AdornedElement),
itemContainer.RenderSize);
Point point1, point2;
double rotation = 0;
if (DropInfo.VisualTargetOrientation == Orientation.Vertical)
{
if (DropInfo.InsertIndex == itemParent.Items.Count || lastItemInGroup)
{
itemRect.Y += itemContainer.RenderSize.Height;
}
point1 = new Point(itemRect.X, itemRect.Y);
point2 = new Point(itemRect.Right, itemRect.Y);
}
else
{
var itemRectX = itemRect.X;
if (DropInfo.VisualTargetFlowDirection == FlowDirection.LeftToRight &&
DropInfo.InsertIndex == itemParent.Items.Count)
{
itemRectX += itemContainer.RenderSize.Width;
}
else if (DropInfo.VisualTargetFlowDirection == FlowDirection.RightToLeft &&
DropInfo.InsertIndex != itemParent.Items.Count)
{
itemRectX += itemContainer.RenderSize.Width;
}
point1 = new Point(itemRectX, itemRect.Y);
point2 = new Point(itemRectX, itemRect.Bottom);
rotation = 90;
}
drawingContext.DrawLine(m_Pen, point1, point2);
DrawTriangle(drawingContext, point1, rotation);
DrawTriangle(drawingContext, point2, 180 + rotation);
}
}
}
private void DrawTriangle(DrawingContext drawingContext, Point origin, double rotation)
{
drawingContext.PushTransform(new TranslateTransform(origin.X, origin.Y));
drawingContext.PushTransform(new RotateTransform(rotation));
drawingContext.DrawGeometry(m_Pen.Brush, null, m_Triangle);
drawingContext.Pop();
drawingContext.Pop();
}
}
}

View File

@ -18,16 +18,18 @@ using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Models.Profiles.Properties;
using Artemis.Services;
using Artemis.Styles.DropTargetAdorners;
using Artemis.Utilities;
using Artemis.ViewModels.LayerEditor;
using Caliburn.Micro;
using GongSolutions.Wpf.DragDrop;
using MahApps.Metro;
using Ninject;
using Timer = System.Timers.Timer;
namespace Artemis.ViewModels
{
public sealed class ProfileEditorViewModel : Screen, IHandle<ActiveKeyboardChanged>
public sealed class ProfileEditorViewModel : Screen, IHandle<ActiveKeyboardChanged>, IDropTarget
{
private readonly GameModel _gameModel;
private readonly MainManager _mainManager;
@ -150,6 +152,66 @@ namespace Artemis.ViewModels
private KeyboardProvider ActiveKeyboard { get; set; }
public void DragOver(IDropInfo dropInfo)
{
var sourceItem = dropInfo.Data as LayerModel;
var targetItem = dropInfo.TargetItem as LayerModel;
if (sourceItem == null || targetItem == null)
return;
if (dropInfo.InsertPosition == RelativeInsertPosition.TargetItemCenter &&
targetItem.LayerType == LayerType.Folder)
{
dropInfo.DropTargetAdorner = typeof(DropTargetMetroHighlightAdorner);
dropInfo.Effects = DragDropEffects.Copy;
}
else
{
dropInfo.DropTargetAdorner = typeof(DropTargetMetroInsertionAdorner);
dropInfo.Effects = DragDropEffects.Move;
}
}
public void Drop(IDropInfo dropInfo)
{
var sourceItem = dropInfo.Data as LayerModel;
var targetItem = dropInfo.TargetItem as LayerModel;
if (sourceItem == null || targetItem == null || sourceItem == targetItem)
return;
if (dropInfo.InsertPosition == RelativeInsertPosition.TargetItemCenter &&
targetItem.LayerType == LayerType.Folder)
{
// Insert into folder
return;
}
// Remove the source from it's old profile/parent
if (sourceItem.Parent == null)
sourceItem.Profile.Layers.Remove(sourceItem);
else
sourceItem.Parent.Children.Remove(sourceItem);
// Insert the source into it's new profile/parent and update the order
if (dropInfo.InsertPosition == RelativeInsertPosition.AfterTargetItem)
sourceItem.Order = targetItem.Order + 1;
else
sourceItem.Order = targetItem.Order - 1;
if (targetItem.Parent == null)
{
targetItem.Profile.Layers.Add(sourceItem);
targetItem.Profile.FixOrder();
}
else
{
targetItem.Parent.Children.Add(sourceItem);
targetItem.Parent.FixOrder();
}
UpdateLayerList(sourceItem);
}
/// <summary>
/// Handles chaning the active keyboard, updating the preview image and profiles collection
/// </summary>
@ -318,41 +380,6 @@ namespace Artemis.ViewModels
SelectedProfile.FixOrder();
}
/// <summary>
/// Moves the currently selected layer up in the profile's layer tree
/// </summary>
public void LayerUp()
{
MoveLayer(true);
}
/// <summary>
/// Moves the currently selected layer down in the profile's layer tree
/// </summary>
public void LayerDown()
{
MoveLayer(false);
}
/// <summary>
/// Moves the currently selected layer up or down in the profile's layer tree
/// </summary>
/// <param name="moveUp"></param>
private void MoveLayer(bool moveUp)
{
if (SelectedLayer == null)
return;
var reorderLayer = SelectedLayer;
if (SelectedLayer.Parent != null)
SelectedLayer.Parent.Reorder(SelectedLayer, moveUp);
else
SelectedLayer.Profile.Reorder(SelectedLayer, moveUp);
UpdateLayerList(reorderLayer);
}
private void UpdateLayerList(LayerModel selectModel)
{
// Update the UI
@ -421,7 +448,7 @@ namespace Artemis.ViewModels
var hoverLayer = SelectedProfile.GetEnabledLayers()
.Where(l => l.MustDraw())
.FirstOrDefault(l => ((KeyboardPropertiesModel) l.Properties)
.GetRect(1).Contains(x, y));
.GetRect(1).Contains(x, y));
HandleDragging(e, x, y, hoverLayer);

View File

@ -7,6 +7,7 @@
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:itemBehaviours="clr-namespace:Artemis.ItemBehaviours"
xmlns:utilities="clr-namespace:Artemis.Utilities"
xmlns:dragDrop="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop"
mc:Ignorable="d"
d:DesignHeight="473" Width="1055">
<UserControl.Resources>
@ -16,7 +17,6 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@ -27,7 +27,7 @@
<!-- Preview -->
<Label Grid.Column="0" Grid.Row="0" FontSize="20" HorizontalAlignment="Left" Content="Preview" />
<Border Grid.Column="0" Grid.Row="1" Background="#FF232323" BorderBrush="{DynamicResource HighlightBrush}"
BorderThickness="3" Width="750" Height="400">
BorderThickness="3" Width="800" Height="400">
<Border>
<Border.Effect>
<!-- TODO: Pulse 10-20 -->
@ -64,6 +64,9 @@
<Border Grid.Column="1" Grid.Row="1" Background="#FF232323" BorderBrush="{DynamicResource HighlightBrush}"
BorderThickness="3" Margin="10,0,0,0" Height="400" Width="233">
<TreeView x:Name="ProfileTree"
dragDrop:DragDrop.IsDragSource="True"
dragDrop:DragDrop.IsDropTarget="True"
dragDrop:DragDrop.DropHandler="{Binding}"
ItemsSource="{Binding Path=Layers, Converter={StaticResource LayerOrderConverter}, ConverterParameter=Order}">
<i:Interaction.Behaviors>
<itemBehaviours:BindableSelectedItemBehavior SelectedItem="{Binding SelectedLayer, Mode=TwoWay}" />
@ -113,29 +116,6 @@
<!-- Layer movement -->
<StackPanel Grid.Column="2" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="10,0,0,0">
<Button x:Name="LayerUp" Width="40" Height="40" Style="{DynamicResource MetroCircleButtonStyle}">
<Button.Content>
<Rectangle
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
Width="16" Height="16">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource appbar_arrow_up}" Stretch="Fill" />
</Rectangle.OpacityMask>
</Rectangle>
</Button.Content>
</Button>
<Button x:Name="LayerDown" Width="40" Height="40" Style="{DynamicResource MetroCircleButtonStyle}">
<Button.Content>
<Rectangle
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
Width="16" Height="16">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource appbar_arrow_down}" Stretch="Fill" />
</Rectangle.OpacityMask>
</Rectangle>
</Button.Content>
</Button>
</StackPanel>
Margin="10,0,0,0"/>
</Grid>
</UserControl>

View File

@ -6,6 +6,7 @@
<package id="Colore" version="4.0.0" targetFramework="net452" />
<package id="CUE.NET" version="1.0.2.2" targetFramework="net452" />
<package id="Extended.Wpf.Toolkit" version="2.7" targetFramework="net452" />
<package id="gong-wpf-dragdrop" version="0.1.4.3" targetFramework="net452" />
<package id="Hardcodet.NotifyIcon.Wpf" version="1.0.8" targetFramework="net452" />
<package id="ImageLibrary" version="2.0.5" targetFramework="net452" />
<package id="log4net" version="2.0.5" targetFramework="net452" />