Implemented editable themes / master themes

This commit is contained in:
Ben 2015-07-05 22:43:17 +01:00
parent 511f503e88
commit bfa2341ab8
20 changed files with 354 additions and 89 deletions

View File

@ -0,0 +1,30 @@
using System.Windows.Media;
using Filtration.ObjectModel.Enums;
using Filtration.ObjectModel.ThemeEditor;
using NUnit.Framework;
namespace Filtration.ObjectModel.Tests.ThemeEditor
{
[TestFixture]
public class TestThemeComponentCollection
{
[Test]
public void AddComponent_ReturnsFirstAddedComponent_WhenComponentAddedTwice()
{
// Arrange
var testInputTargetType = ThemeComponentType.TextColor;
var testInputComponentName = "testComponent";
var testInputColor = new Color();
var componentCollection = new ThemeComponentCollection();
// Act
var firstResult = componentCollection.AddComponent(testInputTargetType, testInputComponentName, testInputColor);
var secondResult = componentCollection.AddComponent(testInputTargetType, testInputComponentName, testInputColor);
// Assert
Assert.AreSame(firstResult, secondResult);
}
}
}

View File

@ -1,4 +1,4 @@
using System.ComponentModel; using System;
using System.Windows.Media; using System.Windows.Media;
using Filtration.ObjectModel.ThemeEditor; using Filtration.ObjectModel.ThemeEditor;
@ -38,6 +38,19 @@ namespace Filtration.ObjectModel.BlockItemBaseTypes
get { return _themeComponent; } get { return _themeComponent; }
set set
{ {
if (_themeComponent == value){ return;}
if (_themeComponent != null)
{
_themeComponent.ThemeComponentUpdated -= OnThemeComponentUpdated;
_themeComponent.ThemeComponentDeleted -= OnThemeComponentDeleted;
}
if (value != null)
{
value.ThemeComponentUpdated += OnThemeComponentUpdated;
value.ThemeComponentDeleted += OnThemeComponentDeleted;
}
_themeComponent = value; _themeComponent = value;
OnPropertyChanged(); OnPropertyChanged();
} }
@ -55,5 +68,15 @@ namespace Filtration.ObjectModel.BlockItemBaseTypes
OnPropertyChanged(); OnPropertyChanged();
} }
} }
private void OnThemeComponentUpdated(object sender, EventArgs e)
{
Color = ((ThemeComponent) sender).Color;
}
private void OnThemeComponentDeleted(object sender, EventArgs e)
{
ThemeComponent = null;
}
} }
} }

View File

@ -1,12 +1,17 @@
using System; using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Media; using System.Windows.Media;
using Filtration.ObjectModel.Annotations;
using Filtration.ObjectModel.Enums; using Filtration.ObjectModel.Enums;
namespace Filtration.ObjectModel.ThemeEditor namespace Filtration.ObjectModel.ThemeEditor
{ {
[Serializable] [Serializable]
public class ThemeComponent public class ThemeComponent : INotifyPropertyChanged
{ {
private Color _color;
public ThemeComponent() public ThemeComponent()
{ {
@ -24,8 +29,41 @@ namespace Filtration.ObjectModel.ThemeEditor
ComponentName = componentName; ComponentName = componentName;
} }
public event EventHandler ThemeComponentUpdated;
public event EventHandler ThemeComponentDeleted;
public string ComponentName { get; set; } public string ComponentName { get; set; }
public ThemeComponentType ComponentType{ get; set; } public ThemeComponentType ComponentType{ get; private set; }
public Color Color { get; set; }
public Color Color
{
get { return _color; }
set
{
_color = value;
OnPropertyChanged();
if (ThemeComponentUpdated != null)
{
ThemeComponentUpdated.Invoke(this, EventArgs.Empty);
}
}
}
public void TerminateComponent()
{
if (ThemeComponentDeleted != null)
{
ThemeComponentDeleted.Invoke(this, EventArgs.Empty);
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
} }
} }

View File

@ -5,7 +5,7 @@ using Filtration.ObjectModel.Enums;
namespace Filtration.ObjectModel.ThemeEditor namespace Filtration.ObjectModel.ThemeEditor
{ {
public class ThemeComponentCollection : Collection<ThemeComponent> public class ThemeComponentCollection : ObservableCollection<ThemeComponent>
{ {
public bool IsMasterCollection { get; set; } public bool IsMasterCollection { get; set; }

View File

@ -101,12 +101,12 @@
<Compile Include="Services\ThemeService.cs" /> <Compile Include="Services\ThemeService.cs" />
<Compile Include="ViewModels\IThemeViewModelFactory.cs" /> <Compile Include="ViewModels\IThemeViewModelFactory.cs" />
<Compile Include="ViewModels\ThemeComponentViewModel.cs" /> <Compile Include="ViewModels\ThemeComponentViewModel.cs" />
<Compile Include="ViewModels\ThemeViewModel.cs" /> <Compile Include="ViewModels\ThemeEditorViewModel.cs" />
<Compile Include="Views\ThemeComponentControl.xaml.cs"> <Compile Include="Views\ThemeComponentControl.xaml.cs">
<DependentUpon>ThemeComponentControl.xaml</DependentUpon> <DependentUpon>ThemeComponentControl.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\ThemeControl.xaml.cs"> <Compile Include="Views\ThemeEditorView.xaml.cs">
<DependentUpon>ThemeControl.xaml</DependentUpon> <DependentUpon>ThemeEditorView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="WindsorInstallers\ProvidersInstaller.cs" /> <Compile Include="WindsorInstallers\ProvidersInstaller.cs" />
<Compile Include="WindsorInstallers\ServicesInstaller.cs" /> <Compile Include="WindsorInstallers\ServicesInstaller.cs" />
@ -132,7 +132,7 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\ThemeControl.xaml"> <Page Include="Views\ThemeEditorView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>

View File

@ -1,4 +1,6 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using AutoMapper; using AutoMapper;
using Filtration.ObjectModel; using Filtration.ObjectModel;
using Filtration.ObjectModel.ThemeEditor; using Filtration.ObjectModel.ThemeEditor;
@ -9,10 +11,11 @@ namespace Filtration.ThemeEditor.Providers
{ {
public interface IThemeProvider public interface IThemeProvider
{ {
IThemeViewModel NewThemeForScript(ItemFilterScript script); IThemeEditorViewModel NewThemeForScript(ItemFilterScript script);
IThemeViewModel LoadThemeFromFile(string filePath); IThemeEditorViewModel MasterThemeForScript(ItemFilterScript script);
IThemeEditorViewModel LoadThemeFromFile(string filePath);
Theme LoadThemeModelFromFile(string filePath); Theme LoadThemeModelFromFile(string filePath);
void SaveTheme(IThemeViewModel themeViewModel, string filePath); void SaveTheme(IThemeEditorViewModel themeEditorViewModel, string filePath);
} }
internal class ThemeProvider : IThemeProvider internal class ThemeProvider : IThemeProvider
@ -26,20 +29,35 @@ namespace Filtration.ThemeEditor.Providers
_themePersistenceService = themePersistenceService; _themePersistenceService = themePersistenceService;
} }
public IThemeViewModel NewThemeForScript(ItemFilterScript script) public IThemeEditorViewModel NewThemeForScript(ItemFilterScript script)
{ {
var themeComponentViewModels = Mapper.Map<ObservableCollection<ThemeComponentViewModel>>(script.ThemeComponents); var themeComponentCollection = script.ThemeComponents.Aggregate(new ThemeComponentCollection(),
(c, component) =>
{
c.Add(new ThemeComponent(component.ComponentType, component.ComponentName, component.Color));
return c;
});
var themeViewModel = _themeViewModelFactory.Create(); var themeViewModel = _themeViewModelFactory.Create();
themeViewModel.Initialise(themeComponentViewModels, true); themeViewModel.Initialise(themeComponentCollection, true);
themeViewModel.FilePath = "Untitled.filtertheme"; themeViewModel.FilePath = "Untitled.filtertheme";
return themeViewModel; return themeViewModel;
} }
public IThemeViewModel LoadThemeFromFile(string filePath) public IThemeEditorViewModel MasterThemeForScript(ItemFilterScript script)
{
var themeViewModel = _themeViewModelFactory.Create();
themeViewModel.Initialise(script.ThemeComponents, true);
themeViewModel.FilePath = "<Master Theme> " + Path.GetFileName(script.FilePath);
return themeViewModel;
}
public IThemeEditorViewModel LoadThemeFromFile(string filePath)
{ {
var model = _themePersistenceService.LoadTheme(filePath); var model = _themePersistenceService.LoadTheme(filePath);
var viewModel = Mapper.Map<IThemeViewModel>(model); var viewModel = Mapper.Map<IThemeEditorViewModel>(model);
viewModel.FilePath = filePath; viewModel.FilePath = filePath;
return viewModel; return viewModel;
} }
@ -49,9 +67,9 @@ namespace Filtration.ThemeEditor.Providers
return _themePersistenceService.LoadTheme(filePath); return _themePersistenceService.LoadTheme(filePath);
} }
public void SaveTheme(IThemeViewModel themeViewModel, string filePath) public void SaveTheme(IThemeEditorViewModel themeEditorViewModel, string filePath)
{ {
var theme = Mapper.Map<Theme>(themeViewModel); var theme = Mapper.Map<Theme>(themeEditorViewModel);
_themePersistenceService.SaveTheme(theme, filePath); _themePersistenceService.SaveTheme(theme, filePath);
} }
} }

View File

@ -2,7 +2,7 @@
{ {
public interface IThemeViewModelFactory public interface IThemeViewModelFactory
{ {
IThemeViewModel Create(); IThemeEditorViewModel Create();
void Release(IThemeViewModel themeViewModel); void Release(IThemeEditorViewModel themeEditorViewModel);
} }
} }

View File

@ -1,29 +1,36 @@
using System; using System;
using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Windows; using System.Windows;
using System.Windows.Forms; using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Filtration.Common.Services; using Filtration.Common.Services;
using Filtration.Common.ViewModels; using Filtration.Common.ViewModels;
using Filtration.Interface; using Filtration.Interface;
using Filtration.ObjectModel.Enums;
using Filtration.ObjectModel.ThemeEditor;
using Filtration.ThemeEditor.Providers; using Filtration.ThemeEditor.Providers;
using GalaSoft.MvvmLight.CommandWpf;
using NLog; using NLog;
using MessageBox = System.Windows.MessageBox;
namespace Filtration.ThemeEditor.ViewModels namespace Filtration.ThemeEditor.ViewModels
{ {
public interface IThemeViewModel : IEditableDocument public interface IThemeEditorViewModel : IEditableDocument
{ {
void Initialise(ObservableCollection<ThemeComponentViewModel> themeComponentViewModels, bool newTheme); RelayCommand<ThemeComponentType> AddThemeComponentCommand { get; }
RelayCommand<ThemeComponent> DeleteThemeComponentCommand { get; }
void Initialise(ThemeComponentCollection themeComponentCollection, bool newTheme);
bool EditEnabled { get; }
string Title { get; } string Title { get; }
string FilePath { get; set; } string FilePath { get; set; }
string Filename { get; } string Filename { get; }
string Name { get; set; } string Name { get; set; }
ObservableCollection<ThemeComponentViewModel> Components { get; set; } ThemeComponentCollection Components { get; set; }
ThemeComponent SelectedThemeComponent { get; }
} }
public class ThemeViewModel : PaneViewModel, IThemeViewModel public class ThemeEditorViewModel : PaneViewModel, IThemeEditorViewModel
{ {
private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
@ -31,15 +38,17 @@ namespace Filtration.ThemeEditor.ViewModels
private readonly IMessageBoxService _messageBoxService; private readonly IMessageBoxService _messageBoxService;
private bool _filenameIsFake; private bool _filenameIsFake;
private string _filePath; private string _filePath;
private ThemeComponent _selectedThemeComponent;
public ThemeViewModel(IThemeProvider themeProvider, public ThemeEditorViewModel(IThemeProvider themeProvider,
IMessageBoxService messageBoxService) IMessageBoxService messageBoxService)
{ {
_themeProvider = themeProvider; _themeProvider = themeProvider;
_messageBoxService = messageBoxService; _messageBoxService = messageBoxService;
Components = new ObservableCollection<ThemeComponentViewModel>(); AddThemeComponentCommand = new RelayCommand<ThemeComponentType>(OnAddThemeComponentCommand, t => EditEnabled);
DeleteThemeComponentCommand = new RelayCommand<ThemeComponent>(OnDeleteThemeComponentCommand,
t => EditEnabled && SelectedThemeComponent != null);
var icon = new BitmapImage(); var icon = new BitmapImage();
icon.BeginInit(); icon.BeginInit();
@ -48,9 +57,17 @@ namespace Filtration.ThemeEditor.ViewModels
IconSource = icon; IconSource = icon;
} }
public void Initialise(ObservableCollection<ThemeComponentViewModel> themeComponentViewModels, bool newTheme) public RelayCommand<ThemeComponentType> AddThemeComponentCommand { get; private set; }
public RelayCommand<ThemeComponent> DeleteThemeComponentCommand { get; private set; }
public bool EditEnabled
{ {
Components = themeComponentViewModels; get { return Components.IsMasterCollection; }
}
public void Initialise(ThemeComponentCollection themeComponentCollection, bool newTheme)
{
Components = themeComponentCollection;
_filenameIsFake = newTheme; _filenameIsFake = newTheme;
} }
@ -70,12 +87,22 @@ namespace Filtration.ThemeEditor.ViewModels
public string Filename public string Filename
{ {
get { return Path.GetFileName(FilePath); } get { return _filenameIsFake ? FilePath : Path.GetFileName(FilePath); }
} }
public string Name { get; set; } public string Name { get; set; }
public ObservableCollection<ThemeComponentViewModel> Components { get; set; } public ThemeComponentCollection Components { get; set; }
public ThemeComponent SelectedThemeComponent
{
get { return _selectedThemeComponent; }
set
{
_selectedThemeComponent = value;
RaisePropertyChanged();
}
}
public void Save() public void Save()
{ {
@ -138,5 +165,19 @@ namespace Filtration.ThemeEditor.ViewModels
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
private void OnAddThemeComponentCommand(ThemeComponentType themeComponentType)
{
Components.Add(new ThemeComponent(themeComponentType, "Untitled Component",
new Color {A = 255, R = 255, G = 255, B = 255}));
}
private void OnDeleteThemeComponentCommand(ThemeComponent themeComponent)
{
if (themeComponent == null) return;
themeComponent.TerminateComponent();
Components.Remove(themeComponent);
}
} }
} }

View File

@ -3,11 +3,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:viewModels="clr-namespace:Filtration.ThemeEditor.ViewModels"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:converters="clr-namespace:Filtration.ThemeEditor.Converters" xmlns:converters="clr-namespace:Filtration.ThemeEditor.Converters"
xmlns:themeEditor="clr-namespace:Filtration.ObjectModel.ThemeEditor;assembly=Filtration.ObjectModel"
xmlns:views="clr-namespace:Filtration.ThemeEditor.Views"
mc:Ignorable="d" mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=viewModels:ThemeComponentViewModel}" d:DataContext="{d:DesignInstance Type=themeEditor:ThemeComponent}"
d:DesignHeight="40" d:DesignWidth="200"> d:DesignHeight="40" d:DesignWidth="200">
<UserControl.Resources> <UserControl.Resources>
<converters:ThemeComponentTypeToStringConverter x:Key="ThemeComponentTypeToStringConverter" /> <converters:ThemeComponentTypeToStringConverter x:Key="ThemeComponentTypeToStringConverter" />
@ -18,8 +19,30 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="25" /> <RowDefinition Height="25" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.Resources>
<DataTemplate x:Key="EditableComponentNameTemplate">
<TextBox Text="{Binding ComponentName}" />
</DataTemplate>
<DataTemplate x:Key="ViewOnlyComponentNameTemplate">
<TextBlock Text="{Binding ComponentName}" ToolTip="{Binding ComponentName}" />
</DataTemplate>
</Grid.Resources>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding ComponentType, Converter={StaticResource ThemeComponentTypeToStringConverter}}" Foreground="Red" FontSize="10" /> <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding ComponentType, Converter={StaticResource ThemeComponentTypeToStringConverter}}" Foreground="Red" FontSize="10" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding ComponentName}" ToolTip="{Binding ComponentName}" /> <ContentControl Grid.Row="1" Grid.Column="0" Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=DataContext.EditEnabled, RelativeSource={RelativeSource AncestorType={x:Type views:ThemeEditorView}}}" Value="true">
<Setter Property="ContentTemplate" Value="{StaticResource EditableComponentNameTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=DataContext.EditEnabled, RelativeSource={RelativeSource AncestorType={x:Type views:ThemeEditorView}}}" Value="false">
<Setter Property="ContentTemplate" Value="{StaticResource ViewOnlyComponentNameTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
<xctk:ColorPicker Grid.Row="2" Grid.Column="0" SelectedColor="{Binding Color}" /> <xctk:ColorPicker Grid.Row="2" Grid.Column="0" SelectedColor="{Binding Color}" />
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Filtration.ThemeEditor.Views
{
/// <summary>
/// Interaction logic for ThemeControl.xaml
/// </summary>
public partial class ThemeControl : UserControl
{
public ThemeControl()
{
InitializeComponent();
}
}
}

View File

@ -1,4 +1,4 @@
<UserControl x:Class="Filtration.ThemeEditor.Views.ThemeControl" <UserControl x:Class="Filtration.ThemeEditor.Views.ThemeEditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@ -7,7 +7,7 @@
xmlns:views="clr-namespace:Filtration.ThemeEditor.Views" xmlns:views="clr-namespace:Filtration.ThemeEditor.Views"
xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase" xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
mc:Ignorable="d" mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=viewModels:ThemeViewModel}" d:DataContext="{d:DesignInstance Type=viewModels:ThemeEditorViewModel}"
d:DesignHeight="300" d:DesignWidth="300"> d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources> <UserControl.Resources>
<CollectionViewSource Source="{Binding Components}" x:Key="ComponentsViewSource"> <CollectionViewSource Source="{Binding Components}" x:Key="ComponentsViewSource">
@ -21,13 +21,35 @@
</UserControl.Resources> </UserControl.Resources>
<Grid> <Grid>
<ScrollViewer HorizontalScrollBarVisibility="Disabled"> <ScrollViewer HorizontalScrollBarVisibility="Disabled">
<ItemsControl ItemsSource="{Binding Source={StaticResource ComponentsViewSource}}" Margin="10"> <ListView ItemsSource="{Binding Source={StaticResource ComponentsViewSource}}"
<ItemsControl.ItemsPanel> SelectedItem="{Binding SelectedThemeComponent}"
Margin="10"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border Name="Border" Padding="2" SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="Background" Value="#A9BDD8"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.Resources>
<ListView.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<WrapPanel /> <WrapPanel />
</ItemsPanelTemplate> </ItemsPanelTemplate>
</ItemsControl.ItemsPanel> </ListView.ItemsPanel>
<ItemsControl.GroupStyle> <ListView.GroupStyle>
<GroupStyle> <GroupStyle>
<GroupStyle.HeaderTemplate> <GroupStyle.HeaderTemplate>
<DataTemplate> <DataTemplate>
@ -35,13 +57,13 @@
</DataTemplate> </DataTemplate>
</GroupStyle.HeaderTemplate> </GroupStyle.HeaderTemplate>
</GroupStyle> </GroupStyle>
</ItemsControl.GroupStyle> </ListView.GroupStyle>
<ItemsControl.ItemTemplate> <ListView.ItemTemplate>
<DataTemplate> <DataTemplate>
<views:ThemeComponentControl DataContext="{Binding}" Margin="10,5,10,5" /> <views:ThemeComponentControl DataContext="{Binding}" Margin="10,5,10,5" />
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ListView.ItemTemplate>
</ItemsControl> </ListView>
</ScrollViewer> </ScrollViewer>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -0,0 +1,10 @@
namespace Filtration.ThemeEditor.Views
{
public partial class ThemeEditorView
{
public ThemeEditorView()
{
InitializeComponent();
}
}
}

View File

@ -11,8 +11,8 @@ namespace Filtration.ThemeEditor.WindsorInstallers
public void Install(IWindsorContainer container, IConfigurationStore store) public void Install(IWindsorContainer container, IConfigurationStore store)
{ {
container.Register( container.Register(
Component.For<IThemeViewModel>() Component.For<IThemeEditorViewModel>()
.ImplementedBy<ThemeViewModel>() .ImplementedBy<ThemeEditorViewModel>()
.LifeStyle.Transient); .LifeStyle.Transient);
container.Register( container.Register(

View File

@ -20,6 +20,7 @@
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.RadioButton.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.RadioButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.Scrollbars.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.Scrollbars.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.TextBox.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.TextBox.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.ListView.xaml" />
<ResourceDictionary Source="Views/CrossButton.xaml" /> <ResourceDictionary Source="Views/CrossButton.xaml" />
<ResourceDictionary Source="Views/IconsDictionary.xaml" /> <ResourceDictionary Source="Views/IconsDictionary.xaml" />

View File

@ -58,9 +58,9 @@ namespace Filtration
.ForMember(dest => dest.IsExpanded, .ForMember(dest => dest.IsExpanded,
opts => opts.UseValue(false)); opts => opts.UseValue(false));
Mapper.CreateMap<Theme, IThemeViewModel>().ConstructUsingServiceLocator(); Mapper.CreateMap<Theme, IThemeEditorViewModel>().ConstructUsingServiceLocator();
Mapper.CreateMap<ThemeComponent, ThemeComponentViewModel>().ReverseMap(); Mapper.CreateMap<ThemeComponent, ThemeComponentViewModel>().ReverseMap();
Mapper.CreateMap<IThemeViewModel, Theme>(); Mapper.CreateMap<IThemeEditorViewModel, Theme>();
Mapper.AssertConfigurationIsValid(); Mapper.AssertConfigurationIsValid();

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Filtration.Common.ViewModels; using Filtration.Common.ViewModels;
using Filtration.Interface; using Filtration.Interface;
using Filtration.ThemeEditor.ViewModels;
using Filtration.ViewModels.ToolPanes; using Filtration.ViewModels.ToolPanes;
using GalaSoft.MvvmLight.Messaging; using GalaSoft.MvvmLight.Messaging;
@ -14,6 +15,7 @@ namespace Filtration.ViewModels
IDocument ActiveDocument { get; set; } IDocument ActiveDocument { get; set; }
ReadOnlyObservableCollection<IDocument> OpenDocuments { get; } ReadOnlyObservableCollection<IDocument> OpenDocuments { get; }
IItemFilterScriptViewModel ActiveScriptViewModel { get; } IItemFilterScriptViewModel ActiveScriptViewModel { get; }
IThemeEditorViewModel ActiveThemeViewModel { get; }
ISectionBrowserViewModel SectionBrowserViewModel { get; } ISectionBrowserViewModel SectionBrowserViewModel { get; }
IBlockGroupBrowserViewModel BlockGroupBrowserViewModel { get; } IBlockGroupBrowserViewModel BlockGroupBrowserViewModel { get; }
IBlockOutputPreviewViewModel BlockOutputPreviewViewModel { get; } IBlockOutputPreviewViewModel BlockOutputPreviewViewModel { get; }
@ -30,6 +32,7 @@ namespace Filtration.ViewModels
private IDocument _activeDocument; private IDocument _activeDocument;
private IItemFilterScriptViewModel _activeScriptViewModel; private IItemFilterScriptViewModel _activeScriptViewModel;
private IThemeEditorViewModel _activeThemeViewModel;
private readonly ObservableCollection<IDocument> _openDocuments; private readonly ObservableCollection<IDocument> _openDocuments;
private readonly ReadOnlyObservableCollection<IDocument> _readOnlyOpenDocuments; private readonly ReadOnlyObservableCollection<IDocument> _readOnlyOpenDocuments;
@ -72,9 +75,14 @@ namespace Filtration.ViewModels
{ {
_activeScriptViewModel = (IItemFilterScriptViewModel) value; _activeScriptViewModel = (IItemFilterScriptViewModel) value;
} }
else if (value.IsTheme)
{
_activeThemeViewModel = (IThemeEditorViewModel) value;
}
else else
{ {
_activeScriptViewModel = null; _activeScriptViewModel = null;
_activeThemeViewModel = null;
} }
if (ActiveDocumentChanged != null) if (ActiveDocumentChanged != null)
@ -91,6 +99,11 @@ namespace Filtration.ViewModels
get { return _activeScriptViewModel; } get { return _activeScriptViewModel; }
} }
public IThemeEditorViewModel ActiveThemeViewModel
{
get { return _activeThemeViewModel; }
}
public IBlockGroupBrowserViewModel BlockGroupBrowserViewModel public IBlockGroupBrowserViewModel BlockGroupBrowserViewModel
{ {
get { return _blockGroupBrowserViewModel; } get { return _blockGroupBrowserViewModel; }
@ -108,6 +121,7 @@ namespace Filtration.ViewModels
private List<IToolViewModel> _tools; private List<IToolViewModel> _tools;
public IEnumerable<IToolViewModel> Tools public IEnumerable<IToolViewModel> Tools
{ {
get get
@ -127,6 +141,10 @@ namespace Filtration.ViewModels
{ {
_activeScriptViewModel = (IItemFilterScriptViewModel) document; _activeScriptViewModel = (IItemFilterScriptViewModel) document;
} }
else if (document.IsTheme)
{
_activeThemeViewModel = (IThemeEditorViewModel) document;
}
_openDocuments.Add(document); _openDocuments.Add(document);
ActiveDocument = document; ActiveDocument = document;

View File

@ -10,6 +10,7 @@ using Filtration.Common.Services;
using Filtration.Common.ViewModels; using Filtration.Common.ViewModels;
using Filtration.Interface; using Filtration.Interface;
using Filtration.Models; using Filtration.Models;
using Filtration.ObjectModel.Enums;
using Filtration.ObjectModel.ThemeEditor; using Filtration.ObjectModel.ThemeEditor;
using Filtration.Properties; using Filtration.Properties;
using Filtration.Repositories; using Filtration.Repositories;
@ -95,8 +96,18 @@ namespace Filtration.ViewModels
OpenAboutWindowCommand = new RelayCommand(OnOpenAboutWindowCommand); OpenAboutWindowCommand = new RelayCommand(OnOpenAboutWindowCommand);
ReplaceColorsCommand = new RelayCommand(OnReplaceColorsCommand, () => ActiveDocumentIsScript); ReplaceColorsCommand = new RelayCommand(OnReplaceColorsCommand, () => ActiveDocumentIsScript);
CreateThemeCommand = new RelayCommand(OnCreateThemeCommand, () => ActiveDocumentIsScript); CreateThemeCommand = new RelayCommand(OnCreateThemeCommand, () => ActiveDocumentIsScript);
ApplyThemeToScriptCommand = new RelayCommand(OnApplyThemeToScriptCommand, () => ActiveDocumentIsScript); ApplyThemeToScriptCommand = new RelayCommand(OnApplyThemeToScriptCommand, () => ActiveDocumentIsScript);
EditMasterThemeCommand = new RelayCommand(OnEditMasterThemeCommand, () => ActiveDocumentIsScript);
AddTextColorThemeComponentCommand = new RelayCommand(OnAddTextColorThemeComponentCommand, () => ActiveDocumentIsTheme && ActiveThemeIsEditable);
AddBackgroundColorThemeComponentCommand = new RelayCommand(OnAddBackgroundColorThemeComponentCommand, () => ActiveDocumentIsTheme && ActiveThemeIsEditable);
AddBorderColorThemeComponentCommand = new RelayCommand(OnAddBorderColorThemeComponentCommand, () => ActiveDocumentIsTheme && ActiveThemeIsEditable);
DeleteThemeComponentCommand = new RelayCommand(OnDeleteThemeComponentCommand,
() =>
ActiveDocumentIsTheme && ActiveDocumentIsTheme &&
_avalonDockWorkspaceViewModel.ActiveThemeViewModel.SelectedThemeComponent != null);
ExpandAllBlocksCommand = new RelayCommand(OnExpandAllBlocksCommand, () => ActiveDocumentIsScript); ExpandAllBlocksCommand = new RelayCommand(OnExpandAllBlocksCommand, () => ActiveDocumentIsScript);
CollapseAllBlocksCommand = new RelayCommand(OnCollapseAllBlocksCommand, () => ActiveDocumentIsScript); CollapseAllBlocksCommand = new RelayCommand(OnCollapseAllBlocksCommand, () => ActiveDocumentIsScript);
@ -129,6 +140,7 @@ namespace Filtration.ViewModels
PasteCommand.RaiseCanExecuteChanged(); PasteCommand.RaiseCanExecuteChanged();
ReplaceColorsCommand.RaiseCanExecuteChanged(); ReplaceColorsCommand.RaiseCanExecuteChanged();
ApplyThemeToScriptCommand.RaiseCanExecuteChanged(); ApplyThemeToScriptCommand.RaiseCanExecuteChanged();
EditMasterThemeCommand.RaiseCanExecuteChanged();
CreateThemeCommand.RaiseCanExecuteChanged(); CreateThemeCommand.RaiseCanExecuteChanged();
RaisePropertyChanged("ShowAdvancedStatus"); RaisePropertyChanged("ShowAdvancedStatus");
break; break;
@ -161,9 +173,16 @@ namespace Filtration.ViewModels
public RelayCommand CloseCommand { get; private set; } public RelayCommand CloseCommand { get; private set; }
public RelayCommand OpenAboutWindowCommand { get; private set; } public RelayCommand OpenAboutWindowCommand { get; private set; }
public RelayCommand ReplaceColorsCommand { get; private set; } public RelayCommand ReplaceColorsCommand { get; private set; }
public RelayCommand EditMasterThemeCommand { get; private set; }
public RelayCommand CreateThemeCommand { get; private set; } public RelayCommand CreateThemeCommand { get; private set; }
public RelayCommand ApplyThemeToScriptCommand { get; private set; } public RelayCommand ApplyThemeToScriptCommand { get; private set; }
public RelayCommand AddTextColorThemeComponentCommand { get; private set; }
public RelayCommand AddBackgroundColorThemeComponentCommand { get; private set; }
public RelayCommand AddBorderColorThemeComponentCommand { get; private set; }
public RelayCommand DeleteThemeComponentCommand { get; private set; }
public RelayCommand AddBlockCommand { get; private set; } public RelayCommand AddBlockCommand { get; private set; }
public RelayCommand AddSectionCommand { get; private set; } public RelayCommand AddSectionCommand { get; private set; }
public RelayCommand DeleteBlockCommand { get; private set; } public RelayCommand DeleteBlockCommand { get; private set; }
@ -262,7 +281,12 @@ namespace Filtration.ViewModels
public bool ActiveDocumentIsTheme public bool ActiveDocumentIsTheme
{ {
get { { return AvalonDockWorkspaceViewModel.ActiveDocument is ThemeViewModel; } } get { return AvalonDockWorkspaceViewModel.ActiveDocument is ThemeEditorViewModel; }
}
public bool ActiveThemeIsEditable
{
get { return AvalonDockWorkspaceViewModel.ActiveThemeViewModel.EditEnabled; }
} }
private bool ActiveDocumentIsEditable() private bool ActiveDocumentIsEditable()
@ -284,15 +308,22 @@ namespace Filtration.ViewModels
OpenTheme(themeViewModel); OpenTheme(themeViewModel);
} }
private void OpenTheme(IThemeViewModel themeViewModel) private void OnEditMasterThemeCommand()
{ {
if (AvalonDockWorkspaceViewModel.OpenDocuments.Contains(themeViewModel)) var themeViewModel =
_themeProvider.MasterThemeForScript(AvalonDockWorkspaceViewModel.ActiveScriptViewModel.Script);
OpenTheme(themeViewModel);
}
private void OpenTheme(IThemeEditorViewModel themeEditorViewModel)
{
if (AvalonDockWorkspaceViewModel.OpenDocuments.Contains(themeEditorViewModel))
{ {
AvalonDockWorkspaceViewModel.SwitchActiveDocument(themeViewModel); AvalonDockWorkspaceViewModel.SwitchActiveDocument(themeEditorViewModel);
} }
else else
{ {
AvalonDockWorkspaceViewModel.AddDocument(themeViewModel); AvalonDockWorkspaceViewModel.AddDocument(themeEditorViewModel);
} }
} }
@ -341,7 +372,7 @@ namespace Filtration.ViewModels
return; return;
} }
IThemeViewModel loadedViewModel; IThemeEditorViewModel loadedViewModel;
try try
{ {
@ -536,5 +567,26 @@ namespace Filtration.ViewModels
{ {
_avalonDockWorkspaceViewModel.ActiveScriptViewModel.ClearFilterCommand.Execute(null); _avalonDockWorkspaceViewModel.ActiveScriptViewModel.ClearFilterCommand.Execute(null);
} }
private void OnAddTextColorThemeComponentCommand()
{
_avalonDockWorkspaceViewModel.ActiveThemeViewModel.AddThemeComponentCommand.Execute(ThemeComponentType.TextColor);
}
private void OnAddBackgroundColorThemeComponentCommand()
{
_avalonDockWorkspaceViewModel.ActiveThemeViewModel.AddThemeComponentCommand.Execute(ThemeComponentType.BackgroundColor);
}
private void OnAddBorderColorThemeComponentCommand()
{
_avalonDockWorkspaceViewModel.ActiveThemeViewModel.AddThemeComponentCommand.Execute(ThemeComponentType.BorderColor);
}
private void OnDeleteThemeComponentCommand()
{
_avalonDockWorkspaceViewModel.ActiveThemeViewModel.DeleteThemeComponentCommand.Execute(
_avalonDockWorkspaceViewModel.ActiveThemeViewModel.SelectedThemeComponent);
}
} }
} }

View File

@ -56,7 +56,7 @@
</viewsAvalonDock:PanesTemplateSelector.StartPageTemplate> </viewsAvalonDock:PanesTemplateSelector.StartPageTemplate>
<viewsAvalonDock:PanesTemplateSelector.ThemeTemplate> <viewsAvalonDock:PanesTemplateSelector.ThemeTemplate>
<DataTemplate> <DataTemplate>
<themeEditorViews:ThemeControl DataContext="{Binding}" /> <themeEditorViews:ThemeEditorView DataContext="{Binding}" />
</DataTemplate> </DataTemplate>
</viewsAvalonDock:PanesTemplateSelector.ThemeTemplate> </viewsAvalonDock:PanesTemplateSelector.ThemeTemplate>
</viewsAvalonDock:PanesTemplateSelector> </viewsAvalonDock:PanesTemplateSelector>

View File

@ -25,7 +25,7 @@ namespace Filtration.Views.AvalonDock
return ItemFilterScriptTemplate; return ItemFilterScriptTemplate;
} }
if (item is IThemeViewModel) if (item is IThemeEditorViewModel)
{ {
return ThemeTemplate; return ThemeTemplate;
} }

View File

@ -58,6 +58,11 @@
BorderBrush="ForestGreen" BorderBrush="ForestGreen"
x:Name="ScriptToolsGroup" x:Name="ScriptToolsGroup"
Visibility="{Binding ActiveDocumentIsScript, Converter={StaticResource BooleanVisibilityConverterCopy}, Mode=OneWay}" /> Visibility="{Binding ActiveDocumentIsScript, Converter={StaticResource BooleanVisibilityConverterCopy}, Mode=OneWay}" />
<fluent:RibbonContextualTabGroup Header="Theme Tools"
Background="DodgerBlue"
BorderBrush="DodgerBlue"
x:Name="ThemeToolsGroup"
Visibility="{Binding ActiveDocumentIsTheme, Converter={StaticResource BooleanVisibilityConverterCopy}, Mode=OneWay}" />
</fluent:Ribbon.ContextualGroups> </fluent:Ribbon.ContextualGroups>
<fluent:RibbonTabItem Header="Script Tools" Group="{Binding ElementName=ScriptToolsGroup}"> <fluent:RibbonTabItem Header="Script Tools" Group="{Binding ElementName=ScriptToolsGroup}">
<fluent:RibbonGroupBox Header="Clipboard"> <fluent:RibbonGroupBox Header="Clipboard">
@ -86,11 +91,22 @@
<fluent:Button Header="Clear All Filters" Command="{Binding ClearFiltersCommand}" SizeDefinition="Middle" Icon="{StaticResource ClearFilterIcon}" /> <fluent:Button Header="Clear All Filters" Command="{Binding ClearFiltersCommand}" SizeDefinition="Middle" Icon="{StaticResource ClearFilterIcon}" />
</fluent:RibbonGroupBox> </fluent:RibbonGroupBox>
<fluent:RibbonGroupBox Header="Themes"> <fluent:RibbonGroupBox Header="Themes">
<fluent:Button Header="Edit Master Theme" Command="{Binding EditMasterThemeCommand}" Icon="{StaticResource ThemeIcon}" LargeIcon="{StaticResource ThemeIcon}" />
<fluent:Button Header="Apply Theme" Command="{Binding ApplyThemeToScriptCommand}" Icon="{StaticResource ThemeIcon}" LargeIcon="{StaticResource ThemeIcon}" /> <fluent:Button Header="Apply Theme" Command="{Binding ApplyThemeToScriptCommand}" Icon="{StaticResource ThemeIcon}" LargeIcon="{StaticResource ThemeIcon}" />
<fluent:Button Header="Create Theme" Command="{Binding CreateThemeCommand}" Icon="{StaticResource ThemeIcon}" LargeIcon="{StaticResource ThemeIcon}" /> <fluent:Button Header="Create Theme" Command="{Binding CreateThemeCommand}" Icon="{StaticResource ThemeIcon}" LargeIcon="{StaticResource ThemeIcon}" />
<fluent:Button Header="Replace Colours" Command="{Binding ReplaceColorsCommand}" Icon="{StaticResource ReplaceColorsIcon}" LargeIcon="{StaticResource ReplaceColorsIcon}" /> <fluent:Button Header="Replace Colours" Command="{Binding ReplaceColorsCommand}" Icon="{StaticResource ReplaceColorsIcon}" LargeIcon="{StaticResource ReplaceColorsIcon}" />
</fluent:RibbonGroupBox> </fluent:RibbonGroupBox>
</fluent:RibbonTabItem> </fluent:RibbonTabItem>
<fluent:RibbonTabItem Header="Theme Tools" Group="{Binding ElementName=ThemeToolsGroup}">
<fluent:RibbonGroupBox Header="Add Components">
<fluent:Button SizeDefinition="Middle" Header="Add Text Color" Command="{Binding AddTextColorThemeComponentCommand}" />
<fluent:Button SizeDefinition="Middle" Header="Add Background Color" Command="{Binding AddBackgroundColorThemeComponentCommand}" />
<fluent:Button SizeDefinition="Middle" Header="Add Border Color" Command="{Binding AddBorderColorThemeComponentCommand}" />
</fluent:RibbonGroupBox>
<fluent:RibbonGroupBox Header="Delete">
<fluent:Button Header="Delete Theme Component" Command="{Binding DeleteThemeComponentCommand}" />
</fluent:RibbonGroupBox>
</fluent:RibbonTabItem>
<fluent:RibbonTabItem Header="View"> <fluent:RibbonTabItem Header="View">
<fluent:RibbonGroupBox Header="Tools"> <fluent:RibbonGroupBox Header="Tools">
<fluent:ToggleButton Header="Section Browser" Width="150" SizeDefinition="Middle" Icon="{StaticResource AddSectionIcon}" IsChecked="{Binding AvalonDockWorkspaceViewModel.SectionBrowserViewModel.IsVisible}" /> <fluent:ToggleButton Header="Section Browser" Width="150" SizeDefinition="Middle" Icon="{StaticResource AddSectionIcon}" IsChecked="{Binding AvalonDockWorkspaceViewModel.SectionBrowserViewModel.IsVisible}" />
@ -104,3 +120,4 @@
</Grid> </Grid>
</DockPanel> </DockPanel>
</fluent:RibbonWindow> </fluent:RibbonWindow>